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