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_HOME;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
23 import static android.server.wm.ComponentNameUtils.getActivityName;
24 import static android.server.wm.ComponentNameUtils.getWindowName;
25 import static android.server.wm.StateLogger.logAlways;
26 import static android.server.wm.StateLogger.logE;
27 import static android.view.Display.DEFAULT_DISPLAY;
28 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
29 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
30 
31 import static com.google.common.truth.Truth.assertWithMessage;
32 
33 import static org.hamcrest.Matchers.greaterThan;
34 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
35 import static org.junit.Assert.assertEquals;
36 import static org.junit.Assert.assertFalse;
37 import static org.junit.Assert.assertNotEquals;
38 import static org.junit.Assert.assertNotNull;
39 import static org.junit.Assert.assertThat;
40 import static org.junit.Assert.assertTrue;
41 import static org.junit.Assert.fail;
42 import static org.junit.Assume.assumeTrue;
43 
44 import android.content.ComponentName;
45 import android.graphics.Rect;
46 import android.util.SparseArray;
47 import android.view.InputEvent;
48 
49 import java.util.Arrays;
50 import java.util.List;
51 import java.util.Objects;
52 import java.util.concurrent.TimeUnit;
53 import java.util.function.Consumer;
54 import java.util.function.Function;
55 import java.util.function.Predicate;
56 import java.util.stream.Stream;
57 
58 /** Window Manager State helper class with assert and wait functions. */
59 public class WindowManagerStateHelper extends WindowManagerState {
60 
61     /**
62      * Compute AM and WM state of device, check validity and bounds.
63      * WM state will include only visible windows, stack and task bounds will be compared.
64      *
65      * @param componentNames array of activity names to wait for.
66      */
computeState(ComponentName... componentNames)67     public void computeState(ComponentName... componentNames) {
68         waitForValidState(Arrays.stream(componentNames)
69                 .map(WaitForValidActivityState::new)
70                 .toArray(WaitForValidActivityState[]::new));
71     }
72 
73     /**
74      * Compute AM and WM state of device, check validity and bounds.
75      * WM state will include only visible windows, stack and task bounds will be compared.
76      *
77      * @param waitForActivitiesVisible array of activity names to wait for.
78      */
computeState(WaitForValidActivityState... waitForActivitiesVisible)79     public void computeState(WaitForValidActivityState... waitForActivitiesVisible) {
80         waitForValidState(waitForActivitiesVisible);
81     }
82 
83     /**
84      * Wait for the activities to appear and for valid state in AM and WM.
85      *
86      * @param activityNames name list of activities to wait for.
87      */
waitForValidState(ComponentName... activityNames)88     public void waitForValidState(ComponentName... activityNames) {
89         waitForValidState(Arrays.stream(activityNames)
90                 .map(WaitForValidActivityState::new)
91                 .toArray(WaitForValidActivityState[]::new));
92 
93     }
94 
95     /**
96      * Wait for the activities to appear in proper stacks and for valid state in AM and WM.
97      * @param waitForActivitiesVisible  array of activity states to wait for.
98      */
waitForValidState(WaitForValidActivityState... waitForActivitiesVisible)99     public void waitForValidState(WaitForValidActivityState... waitForActivitiesVisible) {
100         if (!Condition.waitFor("valid stacks and activities states", () -> {
101             // TODO: Get state of AM and WM at the same time to avoid mismatches caused by
102             // requesting dump in some intermediate state.
103             computeState();
104             return !(shouldWaitForValidityCheck()
105                     || shouldWaitForValidStacks()
106                     || shouldWaitForActivities(waitForActivitiesVisible)
107                     || shouldWaitForWindows());
108         })) {
109             logE("***Waiting for states failed: " + Arrays.toString(waitForActivitiesVisible));
110         }
111     }
112 
waitForAllStoppedActivities()113     public void waitForAllStoppedActivities() {
114         if (!Condition.waitFor("all started activities have been removed", () -> {
115             computeState();
116             return !containsStartedActivities();
117         })) {
118             fail("All started activities have been removed");
119         }
120     }
121 
waitForAllNonHomeActivitiesToDestroyed()122     public void waitForAllNonHomeActivitiesToDestroyed() {
123         Condition.waitFor("all non-home activities to be destroyed", () -> {
124             computeState();
125             for (Task rootTask : getRootTasks()) {
126                 final Activity activity = rootTask.getActivity(
127                         (a) -> !a.state.equals(STATE_DESTROYED)
128                                 && a.getActivityType() != ACTIVITY_TYPE_HOME);
129                 if (activity != null) return false;
130             }
131             return true;
132         });
133     }
134 
135     /**
136      * Compute AM and WM state of device, wait for the activity records to be added, and
137      * wait for debugger window to show up.
138      *
139      * This should only be used when starting with -D (debugger) option, where we pop up the
140      * waiting-for-debugger window, but real activity window won't show up since we're waiting
141      * for debugger.
142      */
waitForDebuggerWindowVisible(ComponentName activityName)143     public void waitForDebuggerWindowVisible(ComponentName activityName) {
144         Condition.waitFor("debugger window", () -> {
145             computeState();
146             return !shouldWaitForDebuggerWindow(activityName)
147                     && !shouldWaitForActivityRecords(activityName);
148         });
149     }
150 
waitForHomeActivityVisible()151     public void waitForHomeActivityVisible() {
152         ComponentName homeActivity = getHomeActivityName();
153         // Sometimes this function is called before we know what Home Activity is
154         if (homeActivity == null) {
155             logAlways("Computing state to determine Home Activity");
156             computeState();
157             homeActivity = getHomeActivityName();
158         }
159         assertNotNull("homeActivity should not be null", homeActivity);
160         waitForValidState(homeActivity);
161     }
162 
163     /** @return {@code true} if the recents is visible; {@code false} if timeout occurs. */
waitForRecentsActivityVisible()164     public boolean waitForRecentsActivityVisible() {
165         if (isHomeRecentsComponent()) {
166             waitForHomeActivityVisible();
167             return true;
168         } else {
169             return waitForWithAmState(WindowManagerState::isRecentsActivityVisible,
170                     "recents activity to be visible");
171         }
172     }
173 
waitForDreamGone()174     public void waitForDreamGone() {
175         assertTrue("Dream must be gone",
176                 waitForWithAmState(state -> state.getDreamTask() == null, "DreamActivity gone"));
177     }
178 
isKeyguardOccluded(WindowManagerState state)179     public static boolean isKeyguardOccluded(WindowManagerState state) {
180         return state.getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY);
181     }
182 
isKeyguardShowingAndNotOccluded(WindowManagerState state)183     public static boolean isKeyguardShowingAndNotOccluded(WindowManagerState state) {
184         return state.getKeyguardControllerState().keyguardShowing
185                 && state.getKeyguardServiceDelegateState().isKeyguardAwake()
186                 && !state.getKeyguardControllerState().mKeyguardGoingAway
187                 && !state.getKeyguardControllerState().aodShowing
188                 && !state.getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY);
189     }
190 
waitForKeyguardShowingAndNotOccluded()191     public void waitForKeyguardShowingAndNotOccluded() {
192         waitForWithAmState(WindowManagerStateHelper::isKeyguardShowingAndNotOccluded,
193                 "Keyguard showing");
194     }
195 
waitForKeyguardShowingAndOccluded()196     public void waitForKeyguardShowingAndOccluded() {
197         waitForWithAmState(state -> state.getKeyguardControllerState().keyguardShowing
198                         && state.getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY),
199                 "Keyguard showing and occluded");
200     }
201 
waitAndAssertWindowShown(int windowType, boolean show)202     public void waitAndAssertWindowShown(int windowType, boolean show) {
203         assertTrue(waitFor(state -> {
204             Stream<WindowState> windows = getMatchingWindows(
205                     ws -> ws.isSurfaceShown() == show && ws.getType() == windowType);
206             return windows.findAny().isPresent();
207         }, "wait for window surface " + (show ? "show" : "hide")));
208     }
209 
waitForAodShowing()210     public void waitForAodShowing() {
211         waitForWithAmState(state -> state.getKeyguardControllerState().aodShowing, "AOD showing");
212     }
213 
waitForKeyguardGone()214     public void waitForKeyguardGone() {
215         waitForWithAmState(state -> !state.getKeyguardControllerState().keyguardShowing,
216                 "Keyguard gone");
217     }
218 
waitAndAssertKeyguardGone()219     public void waitAndAssertKeyguardGone() {
220         assertTrue("Keyguard must be gone",
221                 waitForWithAmState(
222                         state -> !state.getKeyguardControllerState().keyguardShowing,
223                         "Keyguard gone"));
224     }
225 
226     /**
227      * Wait for specific rotation for the default display.
228      * @param rotation Surface#Rotation
229      */
waitForRotation(int rotation)230     public boolean waitForRotation(int rotation) {
231         return waitForWithAmState(state -> state.getRotation() == rotation,
232                 "Rotation: " + rotation);
233     }
234 
235     /**
236      * Wait for specific orientation for the default display.
237      * @param screenOrientation ActivityInfo#ScreenOrientation
238      */
waitForLastOrientation(int screenOrientation)239     public void waitForLastOrientation(int screenOrientation) {
240         waitForWithAmState(state -> state.getLastOrientation() == screenOrientation,
241                 "LastOrientation: " + screenOrientation);
242     }
243 
244     /**
245      * @param message log message
246      * @param screenOrientation ActivityInfo#ScreenOrientation
247      */
waitAndAssertLastOrientation(String message, int screenOrientation)248     public void waitAndAssertLastOrientation(String message, int screenOrientation) {
249         if (screenOrientation != getLastOrientation()) {
250             waitForLastOrientation(screenOrientation);
251         }
252         assertEquals(message, screenOrientation, getLastOrientation());
253     }
254 
255     /** Waits for the configuration orientation (landscape or portrait) of the default display.
256      * @param configOrientation Configuration#Orientation
257      */
waitForDisplayOrientation(int configOrientation)258     public void waitForDisplayOrientation(int configOrientation) {
259         waitForWithAmState(state -> state.getDisplay(DEFAULT_DISPLAY)
260                         .mFullConfiguration.orientation == configOrientation,
261                 "orientation of default display to be " + configOrientation);
262     }
263 
264     /**
265      * Wait for the configuration orientation of the Activity.
266      * @param activityName activity
267      * @param configOrientation Configuration#Orientation
268      */
waitForActivityOrientation(ComponentName activityName, int configOrientation)269     public boolean waitForActivityOrientation(ComponentName activityName, int configOrientation) {
270         return waitForWithAmState(amState -> {
271             final Activity activity = amState.getActivity(activityName);
272             return activity != null && activity.mFullConfiguration.orientation == configOrientation;
273         }, "orientation of " + getActivityName(activityName) + " to be " + configOrientation);
274     }
275 
waitForDisplayUnfrozen()276     public void waitForDisplayUnfrozen() {
277         waitForWithAmState(state -> !state.isDisplayFrozen(), "Display unfrozen");
278     }
279 
waitForActivityState(ComponentName activityName, String activityState)280     public boolean waitForActivityState(ComponentName activityName, String activityState) {
281         return waitForWithAmState(state -> state.hasActivityState(activityName, activityState),
282                 "state of " + getActivityName(activityName) + " to be " + activityState);
283     }
284 
waitAndAssertActivityState(ComponentName activityName, String activityState)285     public void waitAndAssertActivityState(ComponentName activityName, String activityState) {
286         assertTrue(waitForActivityState(activityName, activityState));
287     }
288 
waitForActivityRemoved(ComponentName activityName)289     public void waitForActivityRemoved(ComponentName activityName) {
290         waitFor((amState) -> !amState.containsActivity(activityName)
291                 && !amState.containsWindow(getWindowName(activityName)),
292                 getActivityName(activityName) + " to be removed");
293     }
294 
waitAndAssertActivityRemoved(ComponentName activityName)295     public void waitAndAssertActivityRemoved(ComponentName activityName) {
296         waitForActivityRemoved(activityName);
297         assertNotExist(activityName);
298     }
299 
waitForFocusedStack(int windowingMode, int activityType)300     public void waitForFocusedStack(int windowingMode, int activityType) {
301         waitForWithAmState(state ->
302                         (activityType == ACTIVITY_TYPE_UNDEFINED
303                                 || state.getFocusedRootTaskActivityType() == activityType)
304                         && (windowingMode == WINDOWING_MODE_UNDEFINED
305                                 || state.getFocusedRootTaskWindowingMode() == windowingMode),
306                 "focused stack");
307     }
308 
waitForPendingActivityContain(ComponentName activity)309     public void waitForPendingActivityContain(ComponentName activity) {
310         waitForWithAmState(state -> state.pendingActivityContain(activity),
311                 getActivityName(activity) + " in pending list");
312     }
313 
waitForAppTransitionRunningOnDisplay(int displayId)314     public boolean waitForAppTransitionRunningOnDisplay(int displayId) {
315         return waitForWithAmState(
316                 state -> WindowManagerState.APP_STATE_RUNNING.equals(
317                         state.getDisplay(displayId).getAppTransitionState()),
318                 "app transition running on Display " + displayId);
319     }
320 
waitForAppTransitionIdleOnDisplay(int displayId)321     public boolean waitForAppTransitionIdleOnDisplay(int displayId) {
322         return waitForWithAmState(
323                 state -> WindowManagerState.APP_STATE_IDLE.equals(
324                         state.getDisplay(displayId).getAppTransitionState()),
325                 "app transition idle on Display " + displayId);
326     }
327 
waitAndAssertNavBarShownOnDisplay(int displayId)328     public void waitAndAssertNavBarShownOnDisplay(int displayId) {
329         assertTrue(waitForWithAmState(state -> {
330             // There should be at least one nav bar exist.
331             List<WindowState> navWindows = state.getNavBarWindowsOnDisplay(displayId);
332 
333             return !navWindows.isEmpty();
334         }, "navigation bar to show on display #" + displayId));
335     }
336 
waitAndAssertNavBarShownOnDisplay(int displayId, int expectedNavBarCount)337     public void waitAndAssertNavBarShownOnDisplay(int displayId, int expectedNavBarCount) {
338         assertTrue(waitForWithAmState(state -> {
339             List<WindowState> navWindows = state.getNavBarWindowsOnDisplay(displayId);
340 
341             return navWindows.size() == expectedNavBarCount;
342         }, expectedNavBarCount + " navigation bar(s) to show on display #" + displayId));
343     }
344 
waitAndAssertKeyguardShownOnSecondaryDisplay(int displayId)345     public void waitAndAssertKeyguardShownOnSecondaryDisplay(int displayId) {
346         assertTrue("KeyguardDialog must be shown on secondary display " + displayId,
347                 waitForWithAmState(
348                         state -> isKeyguardOnSecondaryDisplay(state, displayId),
349                         "keyguard window to show"));
350     }
351 
waitAndAssertKeyguardGoneOnSecondaryDisplay(int displayId)352     public void waitAndAssertKeyguardGoneOnSecondaryDisplay(int displayId) {
353         assertTrue("KeyguardDialog must be gone on secondary display " + displayId,
354                 waitForWithAmState(
355                         state -> !isKeyguardOnSecondaryDisplay(state, displayId),
356                         "keyguard window to dismiss"));
357     }
358 
waitForWindowSurfaceShown(String windowName, boolean shown)359     public boolean waitForWindowSurfaceShown(String windowName, boolean shown) {
360         final String message = windowName + "'s isWindowSurfaceShown to return " + shown;
361         return Condition.waitFor(new Condition<>(message, () -> {
362             computeState();
363             return isWindowSurfaceShown(windowName) == shown;
364         }).setRetryIntervalMs(200).setRetryLimit(20));
365     }
366 
367     void waitForWindowSurfaceDisappeared(String windowName) {
368         waitForWindowSurfaceShown(windowName, false);
369     }
370 
371     public void waitAndAssertWindowSurfaceShown(String windowName, boolean shown) {
372         assertTrue(waitForWindowSurfaceShown(windowName, shown));
373     }
374 
375     /** A variant of waitForWithAmState with different parameter order for better Kotlin interop. */
376     public boolean waitForWithAmState(String message, Predicate<WindowManagerState> waitCondition) {
377         return waitForWithAmState(waitCondition, message);
378     }
379 
380     public boolean waitForWithAmState(Predicate<WindowManagerState> waitCondition,
381             String message) {
382         return waitFor(waitCondition, message);
383     }
384 
385     public void waitWindowingModeTopFocus(int windowingMode, boolean topFocus, String message) {
386         waitForWithAmState(amState -> {
387             final Task rootTask = amState.getStandardRootTaskByWindowingMode(windowingMode);
388             return rootTask != null
389                     && topFocus == (amState.getFocusedTaskId() == rootTask.getRootTaskId());
390         }, message);
391     }
392 
393     public boolean waitForFocusedActivity(final String msg, final ComponentName activityName) {
394         final String activityComponentName = getActivityName(activityName);
395         return waitFor(msg, wmState ->
396                 Objects.equals(activityComponentName, wmState.getFocusedActivity())
397                 && Objects.equals(activityComponentName, wmState.getFocusedApp()));
398     }
399 
400     /** A variant of waitFor with different parameter order for better Kotlin interop. */
401     public boolean waitFor(String message, Predicate<WindowManagerState> waitCondition) {
402         return waitFor(waitCondition, message);
403     }
404 
405     /** @return {@code true} if the wait is successful; {@code false} if timeout occurs. */
406     public boolean waitFor(Predicate<WindowManagerState> waitCondition, String message) {
407         return Condition.waitFor(message, () -> {
408             computeState();
409             return waitCondition.test(this);
410         });
411     }
412 
413     /** Waits for non-null result from {@code function} and returns it. */
414     public <T> T waitForResult(String message, Function<WindowManagerState, T> function) {
415         return waitForResult(message, function, Objects::nonNull);
416     }
417 
418     public <T> T waitForResult(String message, Function<WindowManagerState, T> function,
419             Predicate<T> validator) {
420         return Condition.waitForResult(new Condition<T>(message)
421                 .setResultSupplier(() -> {
422                     computeState();
423                     return function.apply(this);
424                 })
425                 .setResultValidator(validator));
426     }
427 
428     /**
429      * @return true if should wait for valid stacks state.
430      */
431     private boolean shouldWaitForValidStacks() {
432         final int stackCount = getRootTaskCount();
433         if (stackCount == 0) {
434             logAlways("***stackCount=" + stackCount);
435             return true;
436         }
437         final int resumedActivitiesCount = getResumedActivitiesCount();
438         if (!getKeyguardControllerState().keyguardShowing && resumedActivitiesCount < 1) {
439             logAlways("***resumedActivitiesCount=" + resumedActivitiesCount);
440             return true;
441         }
442         if (getFocusedActivity() == null) {
443             logAlways("***focusedActivity=null");
444             return true;
445         }
446         return false;
447     }
448 
449     public void waitAndAssertAppFocus(String appPackageName, long waitTime) {
450         final Condition<String> condition = new Condition<>(appPackageName + " to be focused");
451         Condition.waitFor(condition.setResultSupplier(() -> {
452             computeState();
453             return getFocusedApp();
454         }).setResultValidator(focusedAppName -> {
455             return focusedAppName != null && appPackageName.equals(
456                     ComponentName.unflattenFromString(focusedAppName).getPackageName());
457         }).setOnFailure(focusedAppName -> {
458             fail("Timed out waiting for focus on app "
459                     + appPackageName + ", last was " + focusedAppName);
460         }).setRetryIntervalMs(100).setRetryLimit((int) waitTime / 100));
461     }
462 
463     /**
464      * Waits until the given activity is ready for input, this is only needed when directly
465      * injecting input on screen via
466      * {@link android.hardware.input.InputManager#injectInputEvent(InputEvent, int)}.
467      */
468     public <T extends android.app.Activity> void waitUntilActivityReadyForInputInjection(T activity,
469             String tag, String windowDumpErrMsg) throws InterruptedException {
470         // If we requested an orientation change, just waiting for the window to be visible is not
471         // sufficient. We should first wait for the transitions to stop, and the for app's UI thread
472         // to process them before making sure the window is visible.
473         CtsWindowInfoUtils.waitForStableWindowGeometry(5, TimeUnit.SECONDS);
474         if (activity.getWindow() != null
475                 && !CtsWindowInfoUtils.waitForWindowOnTop(activity.getWindow())) {
476             CtsWindowInfoUtils.dumpWindowsOnScreen(tag, windowDumpErrMsg);
477             fail("Activity window did not become visible: " + activity);
478         }
479     }
480 
481     /**
482      * @return true if should wait for some activities to become visible.
483      */
484     private boolean shouldWaitForActivities(WaitForValidActivityState... waitForActivitiesVisible) {
485         if (waitForActivitiesVisible == null || waitForActivitiesVisible.length == 0) {
486             return false;
487         }
488         // If the caller is interested in us waiting for some particular activity windows to be
489         // visible before compute the state. Check for the visibility of those activity windows
490         // and for placing them in correct stacks (if requested).
491         boolean allActivityWindowsVisible = true;
492         boolean tasksInCorrectStacks = true;
493         for (final WaitForValidActivityState state : waitForActivitiesVisible) {
494             final ComponentName activityName = state.activityName;
495             final String windowName = state.windowName;
496             final int stackId = state.stackId;
497             final int windowingMode = state.windowingMode;
498             final int activityType = state.activityType;
499 
500             final List<WindowState> matchingWindowStates =
501                     getMatchingVisibleWindowState(windowName);
502             boolean activityWindowVisible = !matchingWindowStates.isEmpty();
503             if (!activityWindowVisible) {
504                 logAlways("Activity window not visible: " + windowName);
505                 allActivityWindowsVisible = false;
506             } else if (activityName != null
507                     && !isActivityVisible(activityName)) {
508                 logAlways("Activity not visible: " + getActivityName(activityName));
509                 allActivityWindowsVisible = false;
510             } else {
511                 // Check if window is already the correct state requested by test.
512                 boolean windowInCorrectState = false;
513                 for (WindowState ws : matchingWindowStates) {
514                     if (stackId != INVALID_STACK_ID && ws.getStackId() != stackId) {
515                         continue;
516                     }
517                     if (!ws.isWindowingModeCompatible(windowingMode)) {
518                         continue;
519                     }
520                     if (activityType != ACTIVITY_TYPE_UNDEFINED
521                             && ws.getActivityType() != activityType) {
522                         continue;
523                     }
524                     windowInCorrectState = true;
525                     break;
526                 }
527 
528                 if (!windowInCorrectState) {
529                     logAlways("Window in incorrect stack: " + state);
530                     tasksInCorrectStacks = false;
531                 }
532             }
533         }
534         return !allActivityWindowsVisible || !tasksInCorrectStacks;
535     }
536 
537     /**
538      * @return true if should wait valid windows state.
539      */
540     private boolean shouldWaitForWindows() {
541         if (getFrontWindow() == null) {
542             logAlways("***frontWindow=null");
543             return true;
544         }
545         if (getFocusedWindow() == null) {
546             logAlways("***focusedWindow=null");
547             return true;
548         }
549         if (getFocusedApp() == null) {
550             logAlways("***focusedApp=null");
551             return true;
552         }
553 
554         return false;
555     }
556 
557     private boolean shouldWaitForDebuggerWindow(ComponentName activityName) {
558         List<WindowState> matchingWindowStates =
559                 getMatchingVisibleWindowState(activityName.getPackageName());
560         for (WindowState ws : matchingWindowStates) {
561             if (ws.isDebuggerWindow()) {
562                 return false;
563             }
564         }
565         logAlways("Debugger window not available yet");
566         return true;
567     }
568 
569     private boolean shouldWaitForActivityRecords(ComponentName... activityNames) {
570         // Check if the activity records we're looking for is already added.
571         for (final ComponentName activityName : activityNames) {
572             if (!isActivityVisible(activityName)) {
573                 logAlways("ActivityRecord " + getActivityName(activityName) + " not visible yet");
574                 return true;
575             }
576         }
577         return false;
578     }
579 
580     private boolean shouldWaitForValidityCheck() {
581         try {
582             assertValidity();
583         } catch (Throwable t) {
584             logAlways("Waiting for validity check: " + t.toString());
585             return true;
586         }
587         return false;
588     }
589 
590     public void assertValidity() {
591         assertThat("Must have root task", getRootTaskCount(), greaterThan(0));
592         // TODO: Update when keyguard will be shown on multiple displays
593         if (!getKeyguardControllerState().keyguardShowing) {
594             assertThat("There should be at least one resumed activity in the system.",
595                     getResumedActivitiesCount(), greaterThanOrEqualTo(1));
596         }
597         assertNotNull("Must have focus activity.", getFocusedActivity());
598 
599         for (Task rootTask : getRootTasks()) {
600             final int taskId = rootTask.mRootTaskId;
601             for (Task task : rootTask.getTasks()) {
602                 assertEquals("Root task can only contain its own tasks", taskId,
603                         task.mRootTaskId);
604             }
605         }
606 
607         assertNotNull("Must have front window.", getFrontWindow());
608         assertNotNull("Must have focused window.", getFocusedWindow());
609         assertNotNull("Must have app.", getFocusedApp());
610     }
611 
612     public void assertContainsStack(String msg, int windowingMode, int activityType) {
613         assertTrue(msg, containsRootTasks(windowingMode, activityType));
614     }
615 
616     public void assertDoesNotContainStack(String msg, int windowingMode, int activityType) {
617         assertFalse(msg, containsRootTasks(windowingMode, activityType));
618     }
619 
620     public void assertFrontStack(String msg, int windowingMode, int activityType) {
621         assertFrontStackOnDisplay(msg, windowingMode, activityType, DEFAULT_DISPLAY);
622     }
623 
624     public void assertFrontStackOnDisplay(String msg, int windowingMode, int activityType,
625             int displayId) {
626         if (windowingMode != WINDOWING_MODE_UNDEFINED) {
627             assertEquals(msg, windowingMode, getFrontRootTaskWindowingMode(displayId));
628         }
629         if (activityType != ACTIVITY_TYPE_UNDEFINED) {
630             assertEquals(msg, activityType, getFrontRootTaskActivityType(displayId));
631         }
632     }
633 
634     public void assertFrontStackActivityType(String msg, int activityType) {
635         assertEquals(msg, activityType, getFrontRootTaskActivityType(DEFAULT_DISPLAY));
636     }
637 
638     public void assertFocusedRootTask(String msg, int taskId) {
639         assertEquals(msg, taskId, getFocusedTaskId());
640     }
641 
642     public void assertFocusedRootTask(String msg, int windowingMode, int activityType) {
643         if (windowingMode != WINDOWING_MODE_UNDEFINED) {
644             assertEquals(msg, windowingMode, getFocusedRootTaskWindowingMode());
645         }
646         if (activityType != ACTIVITY_TYPE_UNDEFINED) {
647             assertEquals(msg, activityType, getFocusedRootTaskActivityType());
648         }
649     }
650 
651     public void assertFocusedActivity(final String msg, final ComponentName activityName) {
652         final String activityComponentName = getActivityName(activityName);
653         assertEquals(msg, activityComponentName, getFocusedActivity());
654         assertEquals(msg, activityComponentName, getFocusedApp());
655     }
656 
657     public boolean waitForFocusedActivity(final ComponentName activityName) {
658         final String activityComponentName = getActivityName(activityName);
659         final String message = activityComponentName + " to be focused";
660         return Condition.waitFor(new Condition<>(message, () -> {
661             boolean focusedActivityMatching = activityComponentName.equals(getFocusedActivity());
662             boolean focusedAppMatching = activityComponentName.equals(getFocusedApp());
663             return focusedActivityMatching && focusedAppMatching;
664         }).setRetryIntervalMs(200).setRetryLimit(20));
665     }
666 
667     public void waitAndAssertFocusedActivity(final String msg, final ComponentName activityName) {
668         assertTrue(msg, waitForFocusedActivity(activityName));
669     }
670 
671     public void assertFocusedAppOnDisplay(final String msg, final ComponentName activityName,
672             final int displayId) {
673         final String activityComponentName = getActivityName(activityName);
674         assertEquals(msg, activityComponentName, getDisplay(displayId).getFocusedApp());
675     }
676 
677     public void assertNotFocusedActivity(String msg, ComponentName activityName) {
678         assertNotEquals(msg, getFocusedActivity(), getActivityName(activityName));
679         assertNotEquals(msg, getFocusedApp(), getActivityName(activityName));
680     }
681 
682     public void assertResumedActivity(final String msg, final ComponentName activityName) {
683         assertEquals(msg, getActivityName(activityName),
684                 getFocusedActivity());
685     }
686 
687     /** Asserts that each display has correct resumed activity. */
688     public void assertResumedActivities(final String msg,
689             Consumer<SparseArray<ComponentName>> resumedActivitiesMapping) {
690         final SparseArray<ComponentName> resumedActivities = new SparseArray<>();
691         resumedActivitiesMapping.accept(resumedActivities);
692         for (int i = 0; i < resumedActivities.size(); i++) {
693             final int displayId = resumedActivities.keyAt(i);
694             final ComponentName activityComponent = resumedActivities.valueAt(i);
695             assertEquals("Error asserting resumed activity on display " + displayId + ": " + msg,
696                     activityComponent != null ? getActivityName(activityComponent) : null,
697                     getResumedActivityOnDisplay(displayId));
698         }
699     }
700 
701     public void assertNotResumedActivity(String msg, ComponentName activityName) {
702         assertNotEquals(msg, getFocusedActivity(), getActivityName(activityName));
703     }
704 
705     public void assertFocusedWindow(String msg, String windowName) {
706         assertEquals(msg, windowName, getFocusedWindow());
707     }
708 
709     public void assertNotFocusedWindow(String msg, String windowName) {
710         assertNotEquals(msg, getFocusedWindow(), windowName);
711     }
712 
713     public void assertNotExist(final ComponentName activityName) {
714         final String windowName = getWindowName(activityName);
715         assertFalse("Activity=" + getActivityName(activityName) + " must NOT exist.",
716                 containsActivity(activityName));
717         assertFalse("Window=" + windowName + " must NOT exits.",
718                 containsWindow(windowName));
719     }
720 
721     public void waitAndAssertVisibilityGone(final ComponentName activityName) {
722         // Sometimes the surface can be shown due to the late animation.
723         // Wait for the animation is done.
724         waitForWindowSurfaceDisappeared(getWindowName(activityName));
725         assertVisibility(activityName, false);
726     }
727 
728     public void assertVisibility(final ComponentName activityName, final boolean visible) {
729         final String windowName = getWindowName(activityName);
730         // Check existence of activity and window.
731         assertTrue("Activity=" + getActivityName(activityName) + " must exist.",
732                 containsActivity(activityName));
733         assertTrue("Window=" + windowName + " must exist.", containsWindow(windowName));
734 
735         // Check visibility of activity and window.
736         assertEquals("Activity=" + getActivityName(activityName) + " must" + (visible ? "" : " NOT")
737                 + " be visible.", visible, isActivityVisible(activityName));
738         assertEquals("Window=" + windowName + " must" + (visible ? "" : " NOT")
739                         + " have shown surface.",
740                 visible, isWindowSurfaceShown(windowName));
741     }
742 
743     public void assertHomeActivityVisible(boolean visible) {
744         final ComponentName homeActivity = getHomeActivityName();
745         assertNotNull(homeActivity);
746         assertVisibility(homeActivity, visible);
747     }
748 
749     /**
750      * Asserts that the device default display minimum width is larger than the minimum task width.
751      */
752     public void assertDeviceDefaultDisplaySizeForMultiWindow(String errorMessage) {
753         computeState();
754         final int minTaskSizePx = defaultMinimalTaskSize(DEFAULT_DISPLAY);
755         final WindowManagerState.DisplayContent display = getDisplay(DEFAULT_DISPLAY);
756         final Rect displayRect = display.getDisplayRect();
757         if (Math.min(displayRect.width(), displayRect.height()) < minTaskSizePx) {
758             fail(errorMessage);
759         }
760     }
761 
762     /**
763      * Asserts that the device default display minimum width is not smaller than the minimum width
764      * for split-screen required by CDD.
765      */
766     public void assertDeviceDefaultDisplaySizeForSplitScreen(String errorMessage) {
767         computeState();
768         final int minDisplaySizePx = defaultMinimalDisplaySizeForSplitScreen(DEFAULT_DISPLAY);
769         final WindowManagerState.DisplayContent display = getDisplay(DEFAULT_DISPLAY);
770         final Rect displayRect = display.getDisplayRect();
771         if (Math.max(displayRect.width(), displayRect.height()) < minDisplaySizePx) {
772             fail(errorMessage);
773         }
774     }
775 
776     public void assertKeyguardShowingAndOccluded() {
777         assertTrue("Keyguard must be showing",
778                 getKeyguardControllerState().keyguardShowing);
779         assertFalse("keyguard must not be going away",
780                 getKeyguardControllerState().mKeyguardGoingAway);
781         assertTrue("Keyguard must be occluded",
782                 getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY));
783     }
784 
785     public void assertKeyguardShowingAndNotOccluded() {
786         assertTrue("Keyguard must be showing",
787                 getKeyguardControllerState().keyguardShowing);
788         assertFalse("Keyguard must not be going away",
789                 getKeyguardControllerState().mKeyguardGoingAway);
790         assertFalse("Keyguard must not be occluded",
791                 getKeyguardControllerState().isKeyguardOccluded(DEFAULT_DISPLAY));
792     }
793 
794     public void assertKeyguardGone() {
795         assertFalse("Keyguard is not shown",
796                 getKeyguardControllerState().keyguardShowing);
797         assertFalse("Keyguard must not be going away",
798                 getKeyguardControllerState().mKeyguardGoingAway);
799     }
800 
801     public void assertKeyguardShownOnSecondaryDisplay(int displayId) {
802         assertTrue("KeyguardDialog must be shown on display " + displayId,
803                 isKeyguardOnSecondaryDisplay(this, displayId));
804     }
805 
806     public void assertKeyguardGoneOnSecondaryDisplay(int displayId) {
807         assertFalse("KeyguardDialog must be gone on display " + displayId,
808                 isKeyguardOnSecondaryDisplay(this, displayId));
809     }
810 
811     public void assertAodShowing() {
812         assertTrue("AOD is showing",
813                 getKeyguardControllerState().aodShowing);
814     }
815 
816     public void assertAodNotShowing() {
817         assertFalse("AOD is not showing",
818                 getKeyguardControllerState().aodShowing);
819     }
820 
821     public void assertIllegalTaskState() {
822         computeState();
823         final List<Task> tasks = getRootTasks();
824         for (Task task : tasks) {
825             task.forAllTasks((t) -> assertWithMessage("Empty task was found, id = " + t.mTaskId)
826                     .that(t.mTasks.size() + t.mTaskFragments.size() + t.mActivities.size())
827                     .isGreaterThan(0));
828             if (task.isLeafTask()) {
829                 continue;
830             }
831             assertWithMessage("Non-leaf task cannot have affinity set, id = " + task.mTaskId)
832                     .that(task.mAffinity).isEmpty();
833         }
834     }
835 
836     public void assumePendingActivityContain(ComponentName activity) {
837         assumeTrue(pendingActivityContain(activity));
838     }
839 
840     public void assertActivityDisplayed(final ComponentName activityName) {
841         assertWindowDisplayed(getWindowName(activityName));
842     }
843 
844     public void assertWindowDisplayed(final String windowName) {
845         waitForValidState(WaitForValidActivityState.forWindow(windowName));
846         assertTrue(windowName + " is visible", isWindowSurfaceShown(windowName));
847     }
848 
849     public void waitAndAssertImePickerShownOnDisplay(int displayId, String message) {
850         if (!Condition.waitFor(message, () -> {
851             computeState();
852             return getMatchingWindowType(TYPE_INPUT_METHOD_DIALOG).stream().anyMatch(
853                     w -> w.getDisplayId() == displayId && w.isSurfaceShown());
854         })) {
855             fail(message);
856         }
857     }
858 
859     public void waitAndAssertImeWindowShownOnDisplay(int displayId) {
860         final WindowState imeWinState = Condition.waitForResult("IME window",
861                 condition -> condition
862                         .setResultSupplier(this::getImeWindowState)
863                         .setResultValidator(
864                                 w -> w != null && w.isSurfaceShown()
865                                         && w.getDisplayId() == displayId));
866 
867         assertNotNull("IME window must exist", imeWinState);
868         assertTrue("IME window must be shown", imeWinState.isSurfaceShown());
869         assertEquals("IME window must be on the given display", displayId,
870                 imeWinState.getDisplayId());
871     }
872 
873     public void waitAndAssertImeWindowHiddenOnDisplay(int displayId) {
874         final WindowState imeWinState = Condition.waitForResult("IME window",
875                 condition -> condition
876                         .setResultSupplier(this::getImeWindowState)
877                         .setResultValidator(w -> w == null
878                                 || (!w.isSurfaceShown() && w.getDisplayId() == displayId)));
879 
880         if (imeWinState == null) {
881             return;
882         }
883         assertFalse("IME window must be hidden", imeWinState.isSurfaceShown());
884         assertEquals("IME window must be on the given display", displayId,
885                 imeWinState.getDisplayId());
886     }
887 
888     public WindowState getImeWindowState() {
889         computeState();
890         return getInputMethodWindowState();
891     }
892 
893     /**
894      * @return the window state for the given {@param activityName}'s window.
895      */
896     public WindowState getWindowState(ComponentName activityName) {
897         String windowName = getWindowName(activityName);
898         computeState(activityName);
899         final List<WindowManagerState.WindowState> tempWindowList =
900                 getMatchingVisibleWindowState(windowName);
901         return tempWindowList.get(0);
902     }
903 
904     boolean isScreenPortrait(int displayId) {
905         final Rect displayRect = getDisplay(displayId).getDisplayRect();
906         return displayRect.height() > displayRect.width();
907     }
908 
909     private static boolean isKeyguardOnSecondaryDisplay(
910             WindowManagerState windowManagerState, int displayId) {
911         final List<WindowManagerState.WindowState> states =
912                 windowManagerState.getMatchingWindowType(TYPE_KEYGUARD_DIALOG);
913         for (WindowManagerState.WindowState ws : states) {
914             if (ws.getDisplayId() == displayId) return true;
915         }
916         return false;
917     }
918 }
919