Home | History | Annotate | Download | only in lifecycle
      1 package android.server.am.lifecycle;
      2 
      3 import static android.server.am.StateLogger.log;
      4 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_ACTIVITY_RESULT;
      5 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback
      6         .ON_MULTI_WINDOW_MODE_CHANGED;
      7 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_NEW_INTENT;
      8 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_PAUSE;
      9 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_POST_CREATE;
     10 import static android.server.am.lifecycle.LifecycleLog.ActivityCallback.ON_STOP;
     11 
     12 import android.annotation.Nullable;
     13 import android.app.Activity;
     14 import android.content.ComponentName;
     15 import android.content.Intent;
     16 import android.content.pm.ActivityInfo;
     17 import android.content.res.Configuration;
     18 import android.os.Bundle;
     19 import android.os.Handler;
     20 import android.server.am.ActivityManagerTestBase;
     21 import android.server.am.lifecycle.LifecycleLog.ActivityCallback;
     22 import android.support.test.InstrumentationRegistry;
     23 import android.support.test.rule.ActivityTestRule;
     24 import android.support.test.runner.lifecycle.ActivityLifecycleMonitor;
     25 import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
     26 import android.util.Pair;
     27 
     28 import org.junit.After;
     29 import org.junit.Before;
     30 
     31 import java.util.List;
     32 
     33 /** Base class for device-side tests that verify correct activity lifecycle transitions. */
     34 public class ActivityLifecycleClientTestBase extends ActivityManagerTestBase {
     35 
     36     static final String EXTRA_RECREATE = "recreate";
     37     static final String EXTRA_FINISH_IN_ON_RESUME = "finish_in_on_resume";
     38     static final String EXTRA_FINISH_AFTER_RESUME = "finish_after_resume";
     39 
     40     static final ComponentName CALLBACK_TRACKING_ACTIVITY =
     41             getComponentName(CallbackTrackingActivity.class);
     42 
     43     static final ComponentName CONFIG_CHANGE_HANDLING_ACTIVITY =
     44             getComponentName(ConfigChangeHandlingActivity.class);
     45 
     46     final ActivityTestRule mFirstActivityTestRule = new ActivityTestRule(FirstActivity.class,
     47             true /* initialTouchMode */, false /* launchActivity */);
     48 
     49     final ActivityTestRule mSecondActivityTestRule = new ActivityTestRule(SecondActivity.class,
     50             true /* initialTouchMode */, false /* launchActivity */);
     51 
     52     final ActivityTestRule mTranslucentActivityTestRule = new ActivityTestRule(
     53             TranslucentActivity.class, true /* initialTouchMode */, false /* launchActivity */);
     54 
     55     final ActivityTestRule mSecondTranslucentActivityTestRule = new ActivityTestRule(
     56             SecondTranslucentActivity.class, true /* initialTouchMode */,
     57             false /* launchActivity */);
     58 
     59     final ActivityTestRule mLaunchForResultActivityTestRule = new ActivityTestRule(
     60             LaunchForResultActivity.class, true /* initialTouchMode */, false /* launchActivity */);
     61 
     62     final ActivityTestRule mCallbackTrackingActivityTestRule = new ActivityTestRule(
     63             CallbackTrackingActivity.class, true /* initialTouchMode */,
     64             false /* launchActivity */);
     65 
     66     final ActivityTestRule mSingleTopActivityTestRule = new ActivityTestRule(
     67             SingleTopActivity.class, true /* initialTouchMode */, false /* launchActivity */);
     68 
     69     final ActivityTestRule mConfigChangeHandlingActivityTestRule = new ActivityTestRule(
     70             ConfigChangeHandlingActivity.class, true /* initialTouchMode */,
     71             false /* launchActivity */);
     72 
     73     private final ActivityLifecycleMonitor mLifecycleMonitor = ActivityLifecycleMonitorRegistry
     74             .getInstance();
     75     private static LifecycleLog mLifecycleLog;
     76     private LifecycleTracker mLifecycleTracker;
     77 
     78     @Before
     79     @Override
     80     public void setUp() throws Exception {
     81         super.setUp();
     82         // Log transitions for all activities that belong to this app.
     83         mLifecycleLog = new LifecycleLog();
     84         mLifecycleMonitor.addLifecycleCallback(mLifecycleLog);
     85 
     86         // Track transitions and allow waiting for pending activity states.
     87         mLifecycleTracker = new LifecycleTracker(mLifecycleLog);
     88         mLifecycleMonitor.addLifecycleCallback(mLifecycleTracker);
     89     }
     90 
     91     @After
     92     @Override
     93     public void tearDown() throws Exception {
     94         mLifecycleMonitor.removeLifecycleCallback(mLifecycleLog);
     95         mLifecycleMonitor.removeLifecycleCallback(mLifecycleTracker);
     96         super.tearDown();
     97     }
     98 
     99     /** Launch an activity given a class. */
    100     protected Activity launchActivity(Class<? extends Activity> activityClass) {
    101         final Intent intent = new Intent(InstrumentationRegistry.getTargetContext(), activityClass);
    102         return InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
    103     }
    104 
    105     /**
    106      * Blocking call that will wait for activities to reach expected states with timeout.
    107      */
    108     @SafeVarargs
    109     final void waitAndAssertActivityStates(Pair<Activity, ActivityCallback>... activityCallbacks) {
    110         log("Start waitAndAssertActivityCallbacks");
    111         mLifecycleTracker.waitAndAssertActivityStates(activityCallbacks);
    112     }
    113 
    114     /**
    115      * Blocking call that will wait for activities to perform the expected sequence of transitions.
    116      * @see LifecycleTracker#waitForActivityTransitions(Class, List)
    117      */
    118     final void waitForActivityTransitions(Class<? extends Activity> activityClass,
    119             List<ActivityCallback> expectedTransitions) {
    120         log("Start waitAndAssertActivityTransition");
    121         mLifecycleTracker.waitForActivityTransitions(activityClass, expectedTransitions);
    122     }
    123 
    124     LifecycleLog getLifecycleLog() {
    125         return mLifecycleLog;
    126     }
    127 
    128     static Pair<Activity, ActivityCallback> state(Activity activity, ActivityCallback stage) {
    129         return new Pair<>(activity, stage);
    130     }
    131 
    132     /**
    133      * Returns a pair of the activity and the state it should be in based on the configuration of
    134      * occludingActivity.
    135      */
    136     static Pair<Activity, ActivityCallback> occludedActivityState(
    137             Activity activity, Activity occludingActivity) {
    138         return occludedActivityState(activity, isTranslucent(occludingActivity));
    139     }
    140 
    141     /**
    142      * Returns a pair of the activity and the state it should be in based on
    143      * occludingActivityIsTranslucent.
    144      */
    145     static Pair<Activity, ActivityCallback> occludedActivityState(
    146             Activity activity, boolean occludingActivityIsTranslucent) {
    147         // Activities behind a translucent activity should be in the paused state since they are
    148         // still visible. Otherwise, they should be in the stopped state.
    149         return new Pair<>(activity, occludedActivityState(occludingActivityIsTranslucent));
    150     }
    151 
    152     static ActivityCallback occludedActivityState(boolean occludingActivityIsTranslucent) {
    153         return occludingActivityIsTranslucent ? ON_PAUSE : ON_STOP;
    154     }
    155 
    156     /** Returns true if the input activity is translucent. */
    157     static boolean isTranslucent(Activity activity) {
    158         return ActivityInfo.isTranslucentOrFloating(activity.getWindow().getWindowStyle());
    159     }
    160 
    161     // Test activity
    162     public static class FirstActivity extends Activity {
    163     }
    164 
    165     // Test activity
    166     public static class SecondActivity extends Activity {
    167     }
    168 
    169     // Translucent test activity
    170     public static class TranslucentActivity extends Activity {
    171     }
    172 
    173     // Translucent test activity
    174     public static class SecondTranslucentActivity extends Activity {
    175     }
    176 
    177     /**
    178      * Base activity that records callbacks other then main lifecycle transitions.
    179      */
    180     public static class CallbackTrackingActivity extends Activity {
    181         @Override
    182         protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    183             super.onActivityResult(requestCode, resultCode, data);
    184             mLifecycleLog.onActivityCallback(this, ON_ACTIVITY_RESULT);
    185         }
    186 
    187         @Override
    188         protected void onPostCreate(@Nullable Bundle savedInstanceState) {
    189             super.onPostCreate(savedInstanceState);
    190             mLifecycleLog.onActivityCallback(this, ON_POST_CREATE);
    191         }
    192 
    193         @Override
    194         protected void onNewIntent(Intent intent) {
    195             super.onNewIntent(intent);
    196             mLifecycleLog.onActivityCallback(this, ON_NEW_INTENT);
    197         }
    198 
    199         @Override
    200         public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {
    201             mLifecycleLog.onActivityCallback(this, ON_MULTI_WINDOW_MODE_CHANGED);
    202         }
    203     }
    204 
    205     /**
    206      * Test activity that launches {@link ResultActivity} for result.
    207      */
    208     public static class LaunchForResultActivity extends CallbackTrackingActivity {
    209 
    210         @Override
    211         protected void onCreate(Bundle savedInstanceState) {
    212             super.onCreate(savedInstanceState);
    213             startForResult();
    214         }
    215 
    216         private void startForResult() {
    217             final Intent intent = new Intent(this, ResultActivity.class);
    218             intent.putExtras(getIntent());
    219             startActivityForResult(intent, 1 /* requestCode */);
    220         }
    221     }
    222 
    223     /** Test activity that is started for result and finishes itself in ON_RESUME. */
    224     public static class ResultActivity extends Activity {
    225         @Override
    226         protected void onResume() {
    227             super.onResume();
    228             setResult(RESULT_OK);
    229             final Intent intent = getIntent();
    230             if (intent.getBooleanExtra(EXTRA_FINISH_IN_ON_RESUME, false)) {
    231                 finish();
    232             } else if (intent.getBooleanExtra(EXTRA_FINISH_AFTER_RESUME, false)) {
    233                 new Handler().postDelayed(() -> finish(), 2000);
    234             }
    235         }
    236     }
    237 
    238     /** Test activity that can call {@link Activity#recreate()} if requested in a new intent. */
    239     public static class SingleTopActivity extends CallbackTrackingActivity {
    240 
    241         @Override
    242         protected void onNewIntent(Intent intent) {
    243             super.onNewIntent(intent);
    244             if (intent != null && intent.getBooleanExtra(EXTRA_RECREATE, false)) {
    245                 recreate();
    246             }
    247         }
    248     }
    249 
    250     // Config change handling activity
    251     public static class ConfigChangeHandlingActivity extends CallbackTrackingActivity {
    252     }
    253 
    254     static ComponentName getComponentName(Class<? extends Activity> activity) {
    255         return new ComponentName(InstrumentationRegistry.getContext(), activity);
    256     }
    257 }
    258