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