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