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