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