Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2016 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;
     18 
     19 import static android.app.ActivityTaskManager.INVALID_STACK_ID;
     20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
     21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
     22 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
     23 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
     24 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
     25 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
     26 import static android.server.wm.ComponentNameUtils.getActivityName;
     27 import static android.server.wm.ComponentNameUtils.getWindowName;
     28 import static android.server.wm.StateLogger.log;
     29 import static android.server.wm.StateLogger.logAlways;
     30 import static android.server.wm.StateLogger.logE;
     31 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
     32 import static android.view.Display.DEFAULT_DISPLAY;
     33 
     34 import static org.hamcrest.Matchers.greaterThan;
     35 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
     36 import static org.hamcrest.Matchers.lessThan;
     37 import static org.junit.Assert.assertEquals;
     38 import static org.junit.Assert.assertFalse;
     39 import static org.junit.Assert.assertNotEquals;
     40 import static org.junit.Assert.assertNotNull;
     41 import static org.junit.Assert.assertNull;
     42 import static org.junit.Assert.assertThat;
     43 import static org.junit.Assert.assertTrue;
     44 import static org.junit.Assert.fail;
     45 import static org.junit.Assume.assumeTrue;
     46 
     47 import android.content.ComponentName;
     48 import android.graphics.Rect;
     49 import android.os.SystemClock;
     50 import android.server.wm.ActivityManagerState.ActivityStack;
     51 import android.server.wm.ActivityManagerState.ActivityTask;
     52 import android.server.wm.WindowManagerState.Display;
     53 import android.server.wm.WindowManagerState.WindowStack;
     54 import android.server.wm.WindowManagerState.WindowState;
     55 import android.server.wm.WindowManagerState.WindowTask;
     56 import android.util.SparseArray;
     57 
     58 import java.util.Arrays;
     59 import java.util.List;
     60 import java.util.Objects;
     61 import java.util.function.BiPredicate;
     62 import java.util.function.BooleanSupplier;
     63 import java.util.function.Predicate;
     64 import java.util.function.Supplier;
     65 import java.util.stream.Collectors;
     66 
     67 /**
     68  * Combined state of the activity manager and window manager.
     69  */
     70 public class ActivityAndWindowManagersState {
     71 
     72     // Default minimal size of resizable task, used if none is set explicitly.
     73     // Must be kept in sync with 'default_minimal_size_resizable_task' dimen from frameworks/base.
     74     private static final int DEFAULT_RESIZABLE_TASK_SIZE_DP = 220;
     75 
     76     // Default minimal size of a resizable PiP task, used if none is set explicitly.
     77     // Must be kept in sync with 'default_minimal_size_pip_resizable_task' dimen from
     78     // frameworks/base.
     79     private static final int DEFAULT_PIP_RESIZABLE_TASK_SIZE_DP = 108;
     80 
     81     private final ActivityManagerState mAmState = new ActivityManagerState();
     82     private final WindowManagerState mWmState = new WindowManagerState();
     83 
     84     /**
     85      * Compute AM and WM state of device, check sanity and bounds.
     86      * WM state will include only visible windows, stack and task bounds will be compared.
     87      *
     88      * @param componentNames array of activity names to wait for.
     89      */
     90     public void computeState(ComponentName... componentNames) {
     91         waitForValidState(true /* compareTaskAndStackBounds */,
     92                 Arrays.stream(componentNames)
     93                         .map(WaitForValidActivityState::new)
     94                         .toArray(WaitForValidActivityState[]::new));
     95     }
     96 
     97     /**
     98      * Compute AM and WM state of device, check sanity and bounds.
     99      * WM state will include only visible windows, stack and task bounds will be compared.
    100      *
    101      * @param waitForActivitiesVisible array of activity names to wait for.
    102      */
    103     public void computeState(WaitForValidActivityState... waitForActivitiesVisible) {
    104         waitForValidState(true /* compareTaskAndStackBounds */, waitForActivitiesVisible);
    105     }
    106 
    107     /**
    108      * Compute AM and WM state of device, check sanity and bounds.
    109      *
    110      * @param compareTaskAndStackBounds pass 'true' if stack and task bounds should be compared,
    111      *                                  'false' otherwise.
    112      * @param waitForActivitiesVisible  array of activity states to wait for.
    113      */
    114     void computeState(boolean compareTaskAndStackBounds,
    115             WaitForValidActivityState... waitForActivitiesVisible) {
    116         waitForValidState(compareTaskAndStackBounds, waitForActivitiesVisible);
    117     }
    118 
    119     /**
    120      * Wait for the activities to appear and for valid state in AM and WM.
    121      *
    122      * @param activityNames name list of activities to wait for.
    123      */
    124     public void waitForValidState(ComponentName... activityNames) {
    125         waitForValidState(false /* compareTaskAndStackBounds */,
    126                 Arrays.stream(activityNames)
    127                         .map(WaitForValidActivityState::new)
    128                         .toArray(WaitForValidActivityState[]::new));
    129 
    130     }
    131 
    132     /** Wait for the activity to appear and for valid state in AM and WM. */
    133     void waitForValidState(WaitForValidActivityState... waitForActivityVisible) {
    134         waitForValidState(false /* compareTaskAndStackBounds */, waitForActivityVisible);
    135     }
    136 
    137     /**
    138      * Wait for the activities to appear in proper stacks and for valid state in AM and WM.
    139      *
    140      * @param compareTaskAndStackBounds flag indicating if we should compare task and stack bounds
    141      *                                  for equality.
    142      * @param waitForActivitiesVisible  array of activity states to wait for.
    143      */
    144     private void waitForValidState(boolean compareTaskAndStackBounds,
    145             WaitForValidActivityState... waitForActivitiesVisible) {
    146         for (int retry = 1; retry <= 5; retry++) {
    147             // TODO: Get state of AM and WM at the same time to avoid mismatches caused by
    148             // requesting dump in some intermediate state.
    149             mAmState.computeState();
    150             mWmState.computeState();
    151             if (shouldWaitForSanityCheck(compareTaskAndStackBounds)
    152                     || shouldWaitForValidStacks(compareTaskAndStackBounds)
    153                     || shouldWaitForActivities(waitForActivitiesVisible)
    154                     || shouldWaitForWindows()) {
    155                 logAlways("***Waiting for valid stacks and activities states... retry=" + retry);
    156                 SystemClock.sleep(1000);
    157             } else {
    158                 return;
    159             }
    160         }
    161         logE("***Waiting for states failed: " + Arrays.toString(waitForActivitiesVisible));
    162     }
    163 
    164     /**
    165      * Ensures all exiting windows have been removed.
    166      */
    167     void waitForAllExitingWindows() {
    168         List<WindowState> exitingWindows = null;
    169         for (int retry = 1; retry <= 5; retry++) {
    170             mWmState.computeState();
    171             exitingWindows = mWmState.getExitingWindows();
    172             if (exitingWindows.isEmpty()) {
    173                 return;
    174             }
    175             logAlways("***Waiting for all exiting windows have been removed... retry=" + retry);
    176             SystemClock.sleep(1000);
    177         }
    178         fail("All exiting windows have been removed, actual=" + exitingWindows.stream()
    179                 .map(WindowState::getName)
    180                 .collect(Collectors.joining(",")));
    181     }
    182 
    183     void waitForAllStoppedActivities() {
    184         for (int retry = 1; retry <= 5; retry++) {
    185             mAmState.computeState();
    186             if (!mAmState.containsStartedActivities()) {
    187                 return;
    188             }
    189             logAlways("***Waiting for all started activities have been removed... retry=" + retry);
    190             SystemClock.sleep(1500);
    191         }
    192         fail("All started activities have been removed");
    193     }
    194 
    195     /**
    196      * Compute AM and WM state of device, wait for the activity records to be added, and
    197      * wait for debugger window to show up.
    198      *
    199      * This should only be used when starting with -D (debugger) option, where we pop up the
    200      * waiting-for-debugger window, but real activity window won't show up since we're waiting
    201      * for debugger.
    202      */
    203     void waitForDebuggerWindowVisible(ComponentName activityName) {
    204         for (int retry = 1; retry <= 5; retry++) {
    205             mAmState.computeState();
    206             mWmState.computeState();
    207             if (shouldWaitForDebuggerWindow(activityName)
    208                     || shouldWaitForActivityRecords(activityName)) {
    209                 logAlways("***Waiting for debugger window... retry=" + retry);
    210                 SystemClock.sleep(1000);
    211             } else {
    212                 return;
    213             }
    214         }
    215         logE("***Waiting for debugger window failed");
    216     }
    217 
    218     <T> T waitForValidProduct(Supplier<T> supplier, String productName, Predicate<T> tester) {
    219         T product = null;
    220         for (int retry = 1; retry <= 5; retry++) {
    221             product = supplier.get();
    222             if (product != null) {
    223                 if (tester.test(product)) {
    224                     break;
    225                 }
    226             }
    227             logAlways("***Waiting for valid " + productName + "... retry=" + retry);
    228             SystemClock.sleep(1000);
    229         }
    230         return product;
    231     }
    232 
    233     void waitForHomeActivityVisible() {
    234         ComponentName homeActivity = mAmState.getHomeActivityName();
    235         // Sometimes this function is called before we know what Home Activity is
    236         if (homeActivity == null) {
    237             logAlways("Computing state to determine Home Activity");
    238             computeState(true);
    239             homeActivity = mAmState.getHomeActivityName();
    240         }
    241         assertNotNull("homeActivity should not be null", homeActivity);
    242         waitForValidState(homeActivity);
    243     }
    244 
    245     void waitForRecentsActivityVisible() {
    246         if (mAmState.isHomeRecentsComponent()) {
    247             waitForHomeActivityVisible();
    248         } else {
    249             waitForWithAmState(ActivityManagerState::isRecentsActivityVisible,
    250                     "***Waiting for recents activity to be visible...");
    251         }
    252     }
    253 
    254     void waitForKeyguardShowingAndNotOccluded() {
    255         waitForWithAmState(state -> state.getKeyguardControllerState().keyguardShowing
    256                         && !state.getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY),
    257                 "***Waiting for Keyguard showing...");
    258     }
    259 
    260     void waitForKeyguardShowingAndOccluded() {
    261         waitForWithAmState(state -> state.getKeyguardControllerState().keyguardShowing
    262                         && state.getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY),
    263                 "***Waiting for Keyguard showing and occluded...");
    264     }
    265 
    266     void waitForAodShowing() {
    267         waitForWithAmState(state -> state.getKeyguardControllerState().aodShowing,
    268                 "***Waiting for AOD showing...");
    269 
    270     }
    271 
    272     void waitForKeyguardGone() {
    273         waitForWithAmState(state -> !state.getKeyguardControllerState().keyguardShowing,
    274                 "***Waiting for Keyguard gone...");
    275     }
    276 
    277     /** Wait for specific rotation for the default display. Values are Surface#Rotation */
    278     void waitForRotation(int rotation) {
    279         waitForWithWmState(state -> state.getRotation() == rotation,
    280                 "***Waiting for Rotation: " + rotation);
    281     }
    282 
    283     /**
    284      * Wait for specific orientation for the default display.
    285      * Values are ActivityInfo.ScreenOrientation
    286      */
    287     void waitForLastOrientation(int orientation) {
    288         waitForWithWmState(state -> state.getLastOrientation() == orientation,
    289                 "***Waiting for LastOrientation: " + orientation);
    290     }
    291 
    292     /**
    293      * Wait for orientation for the Activity
    294      */
    295     void waitForActivityOrientation(ComponentName activityName, int orientation) {
    296         waitForWithAmState(amState -> {
    297             final ActivityTask task = amState.getTaskByActivity(activityName);
    298             if (task == null) {
    299                 return false;
    300             }
    301             return task.mFullConfiguration.orientation == orientation;
    302         }, "***Waiting for Activity orientation: " + orientation);
    303     }
    304 
    305     void waitForDisplayUnfrozen() {
    306         waitForWithWmState(state -> !state.isDisplayFrozen(),
    307                 "***Waiting for Display unfrozen");
    308     }
    309 
    310     public void waitForActivityState(ComponentName activityName, String activityState) {
    311         waitForWithAmState(state -> state.hasActivityState(activityName, activityState),
    312                 "***Waiting for Activity State: " + activityState);
    313     }
    314 
    315     public void waitForActivityRemoved(ComponentName activityName) {
    316         waitForWithAmState((state) -> !state.containsActivity(activityName),
    317                 "Waiting for activity to be removed");
    318         waitForWithWmState((state) -> !state.containsWindow(getWindowName(activityName)),
    319                 "Waiting for activity window to be gone");
    320     }
    321 
    322     @Deprecated
    323     void waitForFocusedStack(int stackId) {
    324         waitForWithAmState(state -> state.getFocusedStackId() == stackId,
    325                 "***Waiting for focused stack...");
    326     }
    327 
    328     void waitForFocusedStack(int windowingMode, int activityType) {
    329         waitForWithAmState(state ->
    330                         (activityType == ACTIVITY_TYPE_UNDEFINED
    331                                 || state.getFocusedStackActivityType() == activityType)
    332                         && (windowingMode == WINDOWING_MODE_UNDEFINED
    333                                 || state.getFocusedStackWindowingMode() == windowingMode),
    334                 "***Waiting for focused stack...");
    335     }
    336 
    337     void waitForPendingActivityContain(ComponentName activity) {
    338         waitForWithAmState(state -> state.pendingActivityContain(activity),
    339                 "***Waiting for activity in pending list...");
    340     }
    341 
    342     void waitForAppTransitionIdleOnDisplay(int displayId) {
    343         waitForWithWmState(
    344                 state -> WindowManagerState.APP_STATE_IDLE.equals(
    345                         state.getDisplay(displayId).getAppTransitionState()),
    346                 "***Waiting for app transition idle on Display " + displayId + " ...");
    347     }
    348 
    349 
    350     void waitAndAssertNavBarShownOnDisplay(int displayId) {
    351         waitForWithWmState(
    352                 state -> state.getAndAssertSingleNavBarWindowOnDisplay(displayId) != null,
    353                 "***Waiting for navigation bar #" + displayId + " show...");
    354         final WindowState ws = getWmState().getAndAssertSingleNavBarWindowOnDisplay(displayId);
    355 
    356         assertNotNull(ws);
    357     }
    358 
    359     public void waitForWithAmState(Predicate<ActivityManagerState> waitCondition, String message) {
    360         waitFor((amState, wmState) -> waitCondition.test(amState), message);
    361     }
    362 
    363     public void waitForWithWmState(Predicate<WindowManagerState> waitCondition, String message) {
    364         waitFor((amState, wmState) -> waitCondition.test(wmState), message);
    365     }
    366 
    367     void waitFor(
    368             BiPredicate<ActivityManagerState, WindowManagerState> waitCondition, String message) {
    369         waitFor(message, () -> {
    370             mAmState.computeState();
    371             mWmState.computeState();
    372             return waitCondition.test(mAmState, mWmState);
    373         });
    374     }
    375 
    376     void waitFor(String message, BooleanSupplier waitCondition) {
    377         for (int retry = 1; retry <= 5; retry++) {
    378             if (waitCondition.getAsBoolean()) {
    379                 return;
    380             }
    381             logAlways(message + " retry=" + retry);
    382             SystemClock.sleep(1000);
    383         }
    384         logE(message + " failed");
    385     }
    386 
    387     /**
    388      * @return true if should wait for valid stacks state.
    389      */
    390     private boolean shouldWaitForValidStacks(boolean compareTaskAndStackBounds) {
    391         if (!taskListsInAmAndWmAreEqual()) {
    392             // We want to wait for equal task lists in AM and WM in case we caught them in the
    393             // middle of some state change operations.
    394             logAlways("***taskListsInAmAndWmAreEqual=false");
    395             return true;
    396         }
    397         if (!stackBoundsInAMAndWMAreEqual()) {
    398             // We want to wait a little for the stacks in AM and WM to have equal bounds as there
    399             // might be a transition animation ongoing when we got the states from WM AM separately.
    400             logAlways("***stackBoundsInAMAndWMAreEqual=false");
    401             return true;
    402         }
    403         try {
    404             // Temporary fix to avoid catching intermediate state with different task bounds in AM
    405             // and WM.
    406             assertValidBounds(compareTaskAndStackBounds);
    407         } catch (AssertionError e) {
    408             logAlways("***taskBoundsInAMAndWMAreEqual=false : " + e.getMessage());
    409             return true;
    410         }
    411         final int stackCount = mAmState.getStackCount();
    412         if (stackCount == 0) {
    413             logAlways("***stackCount=" + stackCount);
    414             return true;
    415         }
    416         final int resumedActivitiesCount = mAmState.getResumedActivitiesCount();
    417         if (!mAmState.getKeyguardControllerState().keyguardShowing && resumedActivitiesCount < 1) {
    418             logAlways("***resumedActivitiesCount=" + resumedActivitiesCount);
    419             return true;
    420         }
    421         if (mAmState.getFocusedActivity() == null) {
    422             logAlways("***focusedActivity=null");
    423             return true;
    424         }
    425         return false;
    426     }
    427 
    428     /**
    429      * @return true if should wait for some activities to become visible.
    430      */
    431     private boolean shouldWaitForActivities(WaitForValidActivityState... waitForActivitiesVisible) {
    432         if (waitForActivitiesVisible == null || waitForActivitiesVisible.length == 0) {
    433             return false;
    434         }
    435         // If the caller is interested in us waiting for some particular activity windows to be
    436         // visible before compute the state. Check for the visibility of those activity windows
    437         // and for placing them in correct stacks (if requested).
    438         boolean allActivityWindowsVisible = true;
    439         boolean tasksInCorrectStacks = true;
    440         for (final WaitForValidActivityState state : waitForActivitiesVisible) {
    441             final ComponentName activityName = state.activityName;
    442             final String windowName = state.windowName;
    443             final int stackId = state.stackId;
    444             final int windowingMode = state.windowingMode;
    445             final int activityType = state.activityType;
    446 
    447             final List<WindowState> matchingWindowStates =
    448                     mWmState.getMatchingVisibleWindowState(windowName);
    449             boolean activityWindowVisible = !matchingWindowStates.isEmpty();
    450             if (!activityWindowVisible) {
    451                 logAlways("Activity window not visible: " + windowName);
    452                 allActivityWindowsVisible = false;
    453             } else if (activityName != null
    454                     && !mAmState.isActivityVisible(activityName)) {
    455                 logAlways("Activity not visible: " + getActivityName(activityName));
    456                 allActivityWindowsVisible = false;
    457             } else {
    458                 // Check if window is already the correct state requested by test.
    459                 boolean windowInCorrectState = false;
    460                 for (WindowState ws : matchingWindowStates) {
    461                     if (stackId != INVALID_STACK_ID && ws.getStackId() != stackId) {
    462                         continue;
    463                     }
    464                     if (windowingMode != WINDOWING_MODE_UNDEFINED
    465                             && ws.getWindowingMode() != windowingMode) {
    466                         continue;
    467                     }
    468                     if (activityType != ACTIVITY_TYPE_UNDEFINED
    469                             && ws.getActivityType() != activityType) {
    470                         continue;
    471                     }
    472                     windowInCorrectState = true;
    473                     break;
    474                 }
    475 
    476                 if (!windowInCorrectState) {
    477                     logAlways("Window in incorrect stack: " + state);
    478                     tasksInCorrectStacks = false;
    479                 }
    480             }
    481         }
    482         return !allActivityWindowsVisible || !tasksInCorrectStacks;
    483     }
    484 
    485     /**
    486      * @return true if should wait valid windows state.
    487      */
    488     private boolean shouldWaitForWindows() {
    489         if (mWmState.getFrontWindow() == null) {
    490             logAlways("***frontWindow=null");
    491             return true;
    492         }
    493         if (mWmState.getFocusedWindow() == null) {
    494             logAlways("***focusedWindow=null");
    495             return true;
    496         }
    497         if (mWmState.getFocusedApp() == null) {
    498             logAlways("***focusedApp=null");
    499             return true;
    500         }
    501 
    502         return false;
    503     }
    504 
    505     private boolean shouldWaitForDebuggerWindow(ComponentName activityName) {
    506         List<WindowState> matchingWindowStates =
    507                 mWmState.getMatchingVisibleWindowState(activityName.getPackageName());
    508         for (WindowState ws : matchingWindowStates) {
    509             if (ws.isDebuggerWindow()) {
    510                 return false;
    511             }
    512         }
    513         logAlways("Debugger window not available yet");
    514         return true;
    515     }
    516 
    517     private boolean shouldWaitForActivityRecords(ComponentName... activityNames) {
    518         // Check if the activity records we're looking for is already added.
    519         for (final ComponentName activityName : activityNames) {
    520             if (!mAmState.isActivityVisible(activityName)) {
    521                 logAlways("ActivityRecord " + getActivityName(activityName) + " not visible yet");
    522                 return true;
    523             }
    524         }
    525         return false;
    526     }
    527 
    528     private boolean shouldWaitForSanityCheck(boolean compareTaskAndStackBounds) {
    529         try {
    530             assertSanity();
    531             assertValidBounds(compareTaskAndStackBounds);
    532         } catch (Throwable t) {
    533             logAlways("Waiting for sanity check: " + t.toString());
    534             return true;
    535         }
    536         return false;
    537     }
    538 
    539     public ActivityManagerState getAmState() {
    540         return mAmState;
    541     }
    542 
    543     public WindowManagerState getWmState() {
    544         return mWmState;
    545     }
    546 
    547     void assertSanity() {
    548         assertThat("Must have stacks", mAmState.getStackCount(), greaterThan(0));
    549         // TODO: Update when keyguard will be shown on multiple displays
    550         if (!mAmState.getKeyguardControllerState().keyguardShowing) {
    551             assertThat("There should be at least one resumed activity in the system.",
    552                     mAmState.getResumedActivitiesCount(), greaterThanOrEqualTo(1));
    553         }
    554         assertNotNull("Must have focus activity.", mAmState.getFocusedActivity());
    555 
    556         for (ActivityStack aStack : mAmState.getStacks()) {
    557             final int stackId = aStack.mStackId;
    558             for (ActivityTask aTask : aStack.getTasks()) {
    559                 assertEquals("Stack can only contain its own tasks", stackId, aTask.mStackId);
    560             }
    561         }
    562 
    563         assertNotNull("Must have front window.", mWmState.getFrontWindow());
    564         assertNotNull("Must have focused window.", mWmState.getFocusedWindow());
    565         assertNotNull("Must have app.", mWmState.getFocusedApp());
    566     }
    567 
    568     void assertContainsStack(String msg, int windowingMode, int activityType) {
    569         assertTrue(msg, mAmState.containsStack(windowingMode, activityType));
    570         assertTrue(msg, mWmState.containsStack(windowingMode, activityType));
    571     }
    572 
    573     void assertDoesNotContainStack(String msg, int windowingMode, int activityType) {
    574         assertFalse(msg, mAmState.containsStack(windowingMode, activityType));
    575         assertFalse(msg, mWmState.containsStack(windowingMode, activityType));
    576     }
    577 
    578     public void assertFrontStack(String msg, int windowingMode, int activityType) {
    579         assertFrontStackOnDisplay(msg, windowingMode, activityType, DEFAULT_DISPLAY);
    580     }
    581 
    582     void assertFrontStackOnDisplay(String msg, int windowingMode, int activityType, int displayId) {
    583         if (windowingMode != WINDOWING_MODE_UNDEFINED) {
    584             assertEquals(msg, windowingMode,
    585                     mAmState.getFrontStackWindowingMode(displayId));
    586         }
    587         if (activityType != ACTIVITY_TYPE_UNDEFINED) {
    588             assertEquals(msg, activityType, mAmState.getFrontStackActivityType(displayId));
    589         }
    590     }
    591 
    592     void assertFrontStackActivityType(String msg, int activityType) {
    593         assertEquals(msg, activityType, mAmState.getFrontStackActivityType(DEFAULT_DISPLAY));
    594         assertEquals(msg, activityType, mWmState.getFrontStackActivityType(DEFAULT_DISPLAY));
    595     }
    596 
    597     void assertFocusedStack(String msg, int stackId) {
    598         assertEquals(msg, stackId, mAmState.getFocusedStackId());
    599     }
    600 
    601     void assertFocusedStack(String msg, int windowingMode, int activityType) {
    602         if (windowingMode != WINDOWING_MODE_UNDEFINED) {
    603             assertEquals(msg, windowingMode, mAmState.getFocusedStackWindowingMode());
    604         }
    605         if (activityType != ACTIVITY_TYPE_UNDEFINED) {
    606             assertEquals(msg, activityType, mAmState.getFocusedStackActivityType());
    607         }
    608     }
    609 
    610     public void assertFocusedActivity(final String msg, final ComponentName activityName) {
    611         final String activityComponentName = getActivityName(activityName);
    612         assertEquals(msg, activityComponentName, mAmState.getFocusedActivity());
    613         assertEquals(msg, activityComponentName, mWmState.getFocusedApp());
    614     }
    615 
    616     void assertFocusedAppOnDisplay(final String msg, final ComponentName activityName,
    617             final int displayId) {
    618         final String activityComponentName = getActivityName(activityName);
    619         assertEquals(msg, activityComponentName, mWmState.getDisplay(displayId).getFocusedApp());
    620     }
    621 
    622     void assertNotFocusedActivity(String msg, ComponentName activityName) {
    623         assertNotEquals(msg, mAmState.getFocusedActivity(), getActivityName(activityName));
    624         assertNotEquals(msg, mWmState.getFocusedApp(), getActivityName(activityName));
    625     }
    626 
    627     public void assertResumedActivity(final String msg, final ComponentName activityName) {
    628         assertEquals(msg, getActivityName(activityName),
    629                 mAmState.getFocusedActivity());
    630     }
    631 
    632     /** Asserts that each display has correct resumed activity. */
    633     public void assertResumedActivities(final String msg,
    634             SparseArray<ComponentName> resumedActivities) {
    635         for (int i = 0; i < resumedActivities.size(); i++) {
    636             final int displayId = resumedActivities.keyAt(i);
    637             final ComponentName activityComponent = resumedActivities.valueAt(i);
    638             assertEquals("Error asserting resumed activity on display " + displayId + ": " + msg,
    639                     activityComponent != null ? getActivityName(activityComponent) : null,
    640                     mAmState.getResumedActivityOnDisplay(displayId));
    641         }
    642     }
    643 
    644     void assertNotResumedActivity(String msg, ComponentName activityName) {
    645         assertNotEquals(msg, mAmState.getFocusedActivity(), getActivityName(activityName));
    646     }
    647 
    648     void assertFocusedWindow(String msg, String windowName) {
    649         assertEquals(msg, windowName, mWmState.getFocusedWindow());
    650     }
    651 
    652     void assertNotFocusedWindow(String msg, String windowName) {
    653         assertNotEquals(msg, mWmState.getFocusedWindow(), windowName);
    654     }
    655 
    656     void assertNotExist(final ComponentName activityName) {
    657         final String windowName = getWindowName(activityName);
    658         assertFalse("Activity=" + getActivityName(activityName) + " must NOT exist.",
    659                 mAmState.containsActivity(activityName));
    660         assertFalse("Window=" + windowName + " must NOT exits.",
    661                 mWmState.containsWindow(windowName));
    662     }
    663 
    664     public void assertVisibility(final ComponentName activityName, final boolean visible) {
    665         final String windowName = getWindowName(activityName);
    666         // Check existence of activity and window.
    667         assertTrue("Activity=" + getActivityName(activityName) + " must exist.",
    668                 mAmState.containsActivity(activityName));
    669         assertTrue("Window=" + windowName + " must exist.", mWmState.containsWindow(windowName));
    670 
    671         // Check visibility of activity and window.
    672         assertEquals("Activity=" + getActivityName(activityName) + " must" + (visible ? "" : " NOT")
    673                 + " be visible.", visible, mAmState.isActivityVisible(activityName));
    674         assertEquals("Window=" + windowName + " must" + (visible ? "" : " NOT") + " be visible.",
    675                 visible, mWmState.isWindowVisible(windowName));
    676     }
    677 
    678     void assertHomeActivityVisible(boolean visible) {
    679         final ComponentName homeActivity = mAmState.getHomeActivityName();
    680         assertNotNull(homeActivity);
    681         assertVisibility(homeActivity, visible);
    682     }
    683 
    684     /**
    685      * Asserts that the device default display minimim width is larger than the minimum task width.
    686      */
    687     void assertDeviceDefaultDisplaySize(String errorMessage) {
    688         computeState(true);
    689         final int minTaskSizePx = defaultMinimalTaskSize(DEFAULT_DISPLAY);
    690         final Display display = getWmState().getDisplay(DEFAULT_DISPLAY);
    691         final Rect displayRect = display.getDisplayRect();
    692         if (Math.min(displayRect.width(), displayRect.height()) < minTaskSizePx) {
    693             fail(errorMessage);
    694         }
    695     }
    696 
    697     public void assertKeyguardShowingAndOccluded() {
    698         assertTrue("Keyguard is showing",
    699                 getAmState().getKeyguardControllerState().keyguardShowing);
    700         assertTrue("Keyguard is occluded",
    701                 getAmState().getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY));
    702     }
    703 
    704     public void assertKeyguardShowingAndNotOccluded() {
    705         assertTrue("Keyguard is showing",
    706                 getAmState().getKeyguardControllerState().keyguardShowing);
    707         assertFalse("Keyguard is not occluded",
    708                 getAmState().getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY));
    709     }
    710 
    711     public void assertKeyguardGone() {
    712         assertFalse("Keyguard is not shown",
    713                 getAmState().getKeyguardControllerState().keyguardShowing);
    714     }
    715 
    716     public void assertAodShowing() {
    717         assertTrue("AOD is showing",
    718                 getAmState().getKeyguardControllerState().aodShowing);
    719     }
    720 
    721     public void assertAodNotShowing() {
    722         assertFalse("AOD is not showing",
    723                 getAmState().getKeyguardControllerState().aodShowing);
    724     }
    725 
    726     public void assumePendingActivityContain(ComponentName activity) {
    727         assumeTrue(getAmState().pendingActivityContain(activity));
    728     }
    729 
    730     boolean taskListsInAmAndWmAreEqual() {
    731         for (ActivityStack aStack : mAmState.getStacks()) {
    732             final int stackId = aStack.mStackId;
    733             final WindowStack wStack = mWmState.getStack(stackId);
    734             if (wStack == null) {
    735                 log("Waiting for stack setup in WM, stackId=" + stackId);
    736                 return false;
    737             }
    738 
    739             for (ActivityTask aTask : aStack.getTasks()) {
    740                 if (wStack.getTask(aTask.mTaskId) == null) {
    741                     log("Task is in AM but not in WM, waiting for it to settle, taskId="
    742                             + aTask.mTaskId);
    743                     return false;
    744                 }
    745             }
    746 
    747             for (WindowTask wTask : wStack.mTasks) {
    748                 if (aStack.getTask(wTask.mTaskId) == null) {
    749                     log("Task is in WM but not in AM, waiting for it to settle, taskId="
    750                             + wTask.mTaskId);
    751                     return false;
    752                 }
    753             }
    754         }
    755         return true;
    756     }
    757 
    758     /** Get the stack position on its display. */
    759     int getStackIndexByActivityType(int activityType) {
    760         int wmStackIndex = mWmState.getStackIndexByActivityType(activityType);
    761         int amStackIndex = mAmState.getStackIndexByActivityType(activityType);
    762         assertEquals("Window and activity manager must have the same stack position index",
    763                 amStackIndex, wmStackIndex);
    764         return wmStackIndex;
    765     }
    766 
    767     boolean stackBoundsInAMAndWMAreEqual() {
    768         for (ActivityStack aStack : mAmState.getStacks()) {
    769             final int stackId = aStack.mStackId;
    770             final WindowStack wStack = mWmState.getStack(stackId);
    771             if (aStack.isFullscreen() != wStack.isFullscreen()) {
    772                 log("Waiting for correct fullscreen state, stackId=" + stackId);
    773                 return false;
    774             }
    775 
    776             final Rect aStackBounds = aStack.getBounds();
    777             final Rect wStackBounds = wStack.getBounds();
    778 
    779             if (aStack.isFullscreen()) {
    780                 if (aStackBounds != null) {
    781                     log("Waiting for correct stack state in AM, stackId=" + stackId);
    782                     return false;
    783                 }
    784             } else if (!Objects.equals(aStackBounds, wStackBounds)) {
    785                 // If stack is not fullscreen - comparing bounds. Not doing it always because
    786                 // for fullscreen stack bounds in WM can be either null or equal to display size.
    787                 log("Waiting for stack bound equality in AM and WM, stackId=" + stackId);
    788                 return false;
    789             }
    790         }
    791 
    792         return true;
    793     }
    794 
    795     /**
    796      * Check task bounds when docked to top/left.
    797      */
    798     void assertDockedTaskBounds(int taskWidth, int taskHeight, ComponentName activityName) {
    799         // Task size can be affected by default minimal size.
    800         int defaultMinimalTaskSize = defaultMinimalTaskSize(
    801                 mAmState.getStandardStackByWindowingMode(
    802                         WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).mDisplayId);
    803         int targetWidth = Math.max(taskWidth, defaultMinimalTaskSize);
    804         int targetHeight = Math.max(taskHeight, defaultMinimalTaskSize);
    805 
    806         assertEquals(new Rect(0, 0, targetWidth, targetHeight),
    807                 mAmState.getTaskByActivity(activityName).getBounds());
    808     }
    809 
    810     void assertValidBounds(boolean compareTaskAndStackBounds) {
    811         // Cycle through the stacks and tasks to figure out if the home stack is resizable
    812         final ActivityTask homeTask = mAmState.getHomeTask();
    813         final boolean homeStackIsResizable = homeTask != null
    814                 && homeTask.getResizeMode() == RESIZE_MODE_RESIZEABLE;
    815 
    816         for (ActivityStack aStack : mAmState.getStacks()) {
    817             final int stackId = aStack.mStackId;
    818             final WindowStack wStack = mWmState.getStack(stackId);
    819             assertNotNull("stackId=" + stackId + " in AM but not in WM?", wStack);
    820 
    821             assertEquals("Stack fullscreen state in AM and WM must be equal stackId=" + stackId,
    822                     aStack.isFullscreen(), wStack.isFullscreen());
    823 
    824             final Rect aStackBounds = aStack.getBounds();
    825             final Rect wStackBounds = wStack.getBounds();
    826 
    827             if (aStack.isFullscreen()) {
    828                 assertNull("Stack bounds in AM must be null stackId=" + stackId, aStackBounds);
    829             } else {
    830                 assertEquals("Stack bounds in AM and WM must be equal stackId=" + stackId,
    831                         aStackBounds, wStackBounds);
    832             }
    833 
    834             for (ActivityTask aTask : aStack.getTasks()) {
    835                 final int taskId = aTask.mTaskId;
    836                 final WindowTask wTask = wStack.getTask(taskId);
    837                 assertNotNull(
    838                         "taskId=" + taskId + " in AM but not in WM? stackId=" + stackId, wTask);
    839 
    840                 final boolean aTaskIsFullscreen = aTask.isFullscreen();
    841                 final boolean wTaskIsFullscreen = wTask.isFullscreen();
    842                 assertEquals("Task fullscreen state in AM and WM must be equal taskId=" + taskId
    843                         + ", stackId=" + stackId, aTaskIsFullscreen, wTaskIsFullscreen);
    844 
    845                 final Rect aTaskBounds = aTask.getBounds();
    846                 final Rect wTaskBounds = wTask.getBounds();
    847 
    848                 if (aTaskIsFullscreen) {
    849                     assertNull("Task bounds in AM must be null for fullscreen taskId=" + taskId,
    850                             aTaskBounds);
    851                 } else if (!homeStackIsResizable && mWmState.isDockedStackMinimized()
    852                         && !isScreenPortrait(aStack.mDisplayId)) {
    853                     // When minimized using non-resizable launcher in landscape mode, it will move
    854                     // the task offscreen in the negative x direction unlike portrait that crops.
    855                     // The x value in the task bounds will not match the stack bounds since the
    856                     // only the task was moved.
    857                     assertEquals("Task bounds in AM and WM must match width taskId=" + taskId
    858                                     + ", stackId" + stackId, aTaskBounds.width(),
    859                             wTaskBounds.width());
    860                     assertEquals("Task bounds in AM and WM must match height taskId=" + taskId
    861                                     + ", stackId" + stackId, aTaskBounds.height(),
    862                             wTaskBounds.height());
    863                     assertEquals("Task bounds must match stack bounds y taskId=" + taskId
    864                                     + ", stackId" + stackId, aTaskBounds.top,
    865                             wTaskBounds.top);
    866                     assertEquals("Task and stack bounds must match width taskId=" + taskId
    867                                     + ", stackId" + stackId, aStackBounds.width(),
    868                             wTaskBounds.width());
    869                     assertEquals("Task and stack bounds must match height taskId=" + taskId
    870                                     + ", stackId" + stackId, aStackBounds.height(),
    871                             wTaskBounds.height());
    872                     assertEquals("Task and stack bounds must match y taskId=" + taskId
    873                                     + ", stackId" + stackId, aStackBounds.top,
    874                             wTaskBounds.top);
    875                 } else {
    876                     assertEquals("Task bounds in AM and WM must be equal taskId=" + taskId
    877                             + ", stackId=" + stackId, aTaskBounds, wTaskBounds);
    878 
    879                     if (compareTaskAndStackBounds
    880                             && aStack.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
    881                         int aTaskMinWidth = aTask.getMinWidth();
    882                         int aTaskMinHeight = aTask.getMinHeight();
    883 
    884                         if (aTaskMinWidth == -1 || aTaskMinHeight == -1) {
    885                             // Minimal dimension(s) not set for task - it should be using defaults.
    886                             int defaultMinimalSize =
    887                                     aStack.getWindowingMode() == WINDOWING_MODE_PINNED
    888                                     ? defaultMinimalPinnedTaskSize(aStack.mDisplayId)
    889                                     : defaultMinimalTaskSize(aStack.mDisplayId);
    890 
    891                             if (aTaskMinWidth == -1) {
    892                                 aTaskMinWidth = defaultMinimalSize;
    893                             }
    894                             if (aTaskMinHeight == -1) {
    895                                 aTaskMinHeight = defaultMinimalSize;
    896                             }
    897                         }
    898 
    899                         if (aStackBounds.width() >= aTaskMinWidth
    900                                 && aStackBounds.height() >= aTaskMinHeight
    901                                 || aStack.getWindowingMode() == WINDOWING_MODE_PINNED) {
    902                             // Bounds are not smaller then minimal possible, so stack and task
    903                             // bounds must be equal.
    904                             assertEquals("Task bounds must be equal to stack bounds taskId="
    905                                     + taskId + ", stackId=" + stackId, aStackBounds, wTaskBounds);
    906                         } else if (aStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
    907                                 && homeStackIsResizable && mWmState.isDockedStackMinimized()) {
    908                             // Portrait if the display height is larger than the width
    909                             if (isScreenPortrait(aStack.mDisplayId)) {
    910                                 assertEquals("Task width must be equal to stack width taskId="
    911                                                 + taskId + ", stackId=" + stackId,
    912                                         aStackBounds.width(), wTaskBounds.width());
    913                                 assertThat("Task height must be greater than stack height "
    914                                                 + "taskId=" + taskId + ", stackId=" + stackId,
    915                                         aStackBounds.height(), lessThan(wTaskBounds.height()));
    916                                 assertEquals("Task and stack x position must be equal taskId="
    917                                                 + taskId + ", stackId=" + stackId,
    918                                         wTaskBounds.left, wStackBounds.left);
    919                             } else {
    920                                 assertThat("Task width must be greater than stack width taskId="
    921                                                 + taskId + ", stackId=" + stackId,
    922                                         aStackBounds.width(), lessThan(wTaskBounds.width()));
    923                                 assertEquals("Task height must be equal to stack height taskId="
    924                                                 + taskId + ", stackId=" + stackId,
    925                                         aStackBounds.height(), wTaskBounds.height());
    926                                 assertEquals("Task and stack y position must be equal taskId="
    927                                                 + taskId + ", stackId=" + stackId, wTaskBounds.top,
    928                                         wStackBounds.top);
    929                             }
    930                         } else {
    931                             // Minimal dimensions affect task size, so bounds of task and stack must
    932                             // be different - will compare dimensions instead.
    933                             int targetWidth = Math.max(aTaskMinWidth, aStackBounds.width());
    934                             assertEquals("Task width must be set according to minimal width"
    935                                             + " taskId=" + taskId + ", stackId=" + stackId,
    936                                     targetWidth, wTaskBounds.width());
    937                             int targetHeight = Math.max(aTaskMinHeight, aStackBounds.height());
    938                             assertEquals("Task height must be set according to minimal height"
    939                                             + " taskId=" + taskId + ", stackId=" + stackId,
    940                                     targetHeight, wTaskBounds.height());
    941                         }
    942                     }
    943                 }
    944             }
    945         }
    946     }
    947 
    948     public void assertActivityDisplayed(final ComponentName activityName) throws Exception {
    949         assertWindowDisplayed(getWindowName(activityName));
    950     }
    951 
    952     public void assertWindowDisplayed(final String windowName) throws Exception {
    953         waitForValidState(WaitForValidActivityState.forWindow(windowName));
    954         assertTrue(windowName + "is visible", getWmState().isWindowVisible(windowName));
    955     }
    956 
    957     void waitAndAssertImeWindowShownOnDisplay(int displayId) {
    958         final WindowManagerState.WindowState imeWinState = waitForValidProduct(
    959                 this::getImeWindowState, "IME window",
    960                 w -> w.isShown() && w.getDisplayId() == displayId);
    961         assertNotNull("IME window must exist", imeWinState);
    962         assertTrue("IME window must be shown", imeWinState.isShown());
    963         assertEquals("IME window must be on the given display", displayId,
    964                 imeWinState.getDisplayId());
    965     }
    966 
    967     WindowManagerState.WindowState getImeWindowState() {
    968         final WindowManagerState wmState = getWmState();
    969         wmState.computeState();
    970         return wmState.getInputMethodWindowState();
    971     }
    972 
    973     boolean isScreenPortrait() {
    974         final int displayId = mAmState.getStandardStackByWindowingMode(
    975             WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).mDisplayId;
    976         return isScreenPortrait(displayId);
    977     }
    978 
    979     boolean isScreenPortrait(int displayId) {
    980         final Rect displayRect = mWmState.getDisplay(displayId).getDisplayRect();
    981         return displayRect.height() > displayRect.width();
    982     }
    983 
    984     static int dpToPx(float dp, int densityDpi) {
    985         return (int) (dp * densityDpi / DENSITY_DEFAULT + 0.5f);
    986     }
    987 
    988     private int defaultMinimalTaskSize(int displayId) {
    989         return dpToPx(DEFAULT_RESIZABLE_TASK_SIZE_DP, mWmState.getDisplay(displayId).getDpi());
    990     }
    991 
    992     private int defaultMinimalPinnedTaskSize(int displayId) {
    993         return dpToPx(DEFAULT_PIP_RESIZABLE_TASK_SIZE_DP, mWmState.getDisplay(displayId).getDpi());
    994     }
    995 }
    996