Home | History | Annotate | Download | only in lifecycle
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package android.server.wm.lifecycle;
     18 
     19 import static org.junit.Assert.fail;
     20 
     21 import android.app.Activity;
     22 import android.server.wm.lifecycle.LifecycleLog.ActivityCallback;
     23 import android.util.Pair;
     24 
     25 import java.util.ArrayList;
     26 import java.util.List;
     27 import java.util.function.BooleanSupplier;
     28 
     29 /**
     30  * Gets notified about activity lifecycle updates and provides blocking mechanism to wait until
     31  * expected activity states are reached.
     32  */
     33 public class LifecycleTracker implements LifecycleLog.LifecycleTrackerCallback {
     34 
     35     private LifecycleLog mLifecycleLog;
     36 
     37     LifecycleTracker(LifecycleLog lifecycleLog) {
     38         mLifecycleLog = lifecycleLog;
     39         mLifecycleLog.setLifecycleTracker(this);
     40     }
     41 
     42     void waitAndAssertActivityStates(
     43             Pair<Class<? extends Activity>, ActivityCallback>[] activityCallbacks) {
     44         final boolean waitResult = waitForConditionWithTimeout(
     45                 () -> pendingCallbacks(activityCallbacks).isEmpty(), 5 * 1000);
     46 
     47         if (!waitResult) {
     48             fail("Expected lifecycle states not achieved: " + pendingCallbacks(activityCallbacks));
     49         }
     50     }
     51 
     52     /**
     53      * Waits for a specific sequence of events to happen.
     54      * When there is a possibility of some lifecycle state happening more than once in a sequence,
     55      * it is better to use this method instead of {@link #waitAndAssertActivityStates(Pair[])}.
     56      * Otherwise we might stop tracking too early.
     57      */
     58     void waitForActivityTransitions(Class<? extends Activity> activityClass,
     59             List<ActivityCallback> expectedTransitions) {
     60         waitForConditionWithTimeout(
     61                 () -> mLifecycleLog.getActivityLog(activityClass).equals(expectedTransitions),
     62                 5 * 1000);
     63     }
     64 
     65     @Override
     66     synchronized public void onActivityLifecycleChanged() {
     67         notify();
     68     }
     69 
     70     /** Get a list of activity states that were not reached yet. */
     71     private List<Pair<Class<? extends Activity>, ActivityCallback>> pendingCallbacks(
     72             Pair<Class<? extends Activity>, ActivityCallback>[] activityCallbacks) {
     73         final List<Pair<Class<? extends Activity>, ActivityCallback>> notReachedActivityCallbacks =
     74                 new ArrayList<>();
     75 
     76         for (Pair<Class<? extends Activity>, ActivityCallback> callbackPair : activityCallbacks) {
     77             final Class<? extends Activity> activityClass = callbackPair.first;
     78             final List<ActivityCallback> transitionList =
     79                     mLifecycleLog.getActivityLog(activityClass);
     80             if (transitionList.isEmpty()
     81                     || transitionList.get(transitionList.size() - 1) != callbackPair.second) {
     82                 // The activity either hasn't got any state transitions yet or the current state is
     83                 // not the one we expect.
     84                 notReachedActivityCallbacks.add(callbackPair);
     85             }
     86         }
     87         return notReachedActivityCallbacks;
     88     }
     89 
     90     /** Blocking call to wait for a condition to become true with max timeout. */
     91     synchronized private boolean waitForConditionWithTimeout(BooleanSupplier waitCondition,
     92             long timeoutMs) {
     93         final long timeout = System.currentTimeMillis() + timeoutMs;
     94         while (!waitCondition.getAsBoolean()) {
     95             final long waitMs = timeout - System.currentTimeMillis();
     96             if (waitMs <= 0) {
     97                 // Timeout expired.
     98                 return false;
     99             }
    100             try {
    101                 wait(timeoutMs);
    102             } catch (InterruptedException e) {
    103                 // Weird, let's retry.
    104             }
    105         }
    106         return true;
    107     }
    108 }
    109