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.am; 18 19 import static android.app.ActivityManager.StackId.INVALID_STACK_ID; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 25 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 26 import static android.server.am.ComponentNameUtils.getActivityName; 27 import static android.server.am.ComponentNameUtils.getWindowName; 28 import static android.server.am.StateLogger.log; 29 import static android.server.am.StateLogger.logAlways; 30 import static android.server.am.StateLogger.logE; 31 import static android.util.DisplayMetrics.DENSITY_DEFAULT; 32 import static android.view.Display.DEFAULT_DISPLAY; 33 34 import static org.hamcrest.Matchers.greaterThan; 35 import static org.hamcrest.Matchers.lessThan; 36 import static org.junit.Assert.assertEquals; 37 import static org.junit.Assert.assertFalse; 38 import static org.junit.Assert.assertNotEquals; 39 import static org.junit.Assert.assertNotNull; 40 import static org.junit.Assert.assertNull; 41 import static org.junit.Assert.assertThat; 42 import static org.junit.Assert.assertTrue; 43 import static org.junit.Assert.fail; 44 45 import android.content.ComponentName; 46 import android.graphics.Rect; 47 import android.os.SystemClock; 48 import android.server.am.ActivityManagerState.ActivityStack; 49 import android.server.am.ActivityManagerState.ActivityTask; 50 import android.server.am.WindowManagerState.Display; 51 import android.server.am.WindowManagerState.WindowStack; 52 import android.server.am.WindowManagerState.WindowState; 53 import android.server.am.WindowManagerState.WindowTask; 54 55 import java.util.Arrays; 56 import java.util.List; 57 import java.util.Objects; 58 import java.util.function.BiPredicate; 59 import java.util.function.BooleanSupplier; 60 import java.util.function.Predicate; 61 import java.util.stream.Collectors; 62 63 /** 64 * Combined state of the activity manager and window manager. 65 */ 66 public class ActivityAndWindowManagersState { 67 68 // Default minimal size of resizable task, used if none is set explicitly. 69 // Must be kept in sync with 'default_minimal_size_resizable_task' dimen from frameworks/base. 70 private static final int DEFAULT_RESIZABLE_TASK_SIZE_DP = 220; 71 72 // Default minimal size of a resizable PiP task, used if none is set explicitly. 73 // Must be kept in sync with 'default_minimal_size_pip_resizable_task' dimen from 74 // frameworks/base. 75 private static final int DEFAULT_PIP_RESIZABLE_TASK_SIZE_DP = 108; 76 77 private final ActivityManagerState mAmState = new ActivityManagerState(); 78 private final WindowManagerState mWmState = new WindowManagerState(); 79 80 /** 81 * Compute AM and WM state of device, check sanity and bounds. 82 * WM state will include only visible windows, stack and task bounds will be compared. 83 * 84 * @param componentNames array of activity names to wait for. 85 */ computeState(ComponentName... componentNames)86 public void computeState(ComponentName... componentNames) { 87 waitForValidState(true /* compareTaskAndStackBounds */, 88 Arrays.stream(componentNames) 89 .map(WaitForValidActivityState::new) 90 .toArray(WaitForValidActivityState[]::new)); 91 } 92 93 /** 94 * Compute AM and WM state of device, check sanity and bounds. 95 * WM state will include only visible windows, stack and task bounds will be compared. 96 * 97 * @param waitForActivitiesVisible array of activity names to wait for. 98 */ computeState(WaitForValidActivityState... waitForActivitiesVisible)99 public void computeState(WaitForValidActivityState... waitForActivitiesVisible) { 100 waitForValidState(true /* compareTaskAndStackBounds */, waitForActivitiesVisible); 101 } 102 103 /** 104 * Compute AM and WM state of device, check sanity and bounds. 105 * 106 * @param compareTaskAndStackBounds pass 'true' if stack and task bounds should be compared, 107 * 'false' otherwise. 108 * @param waitForActivitiesVisible array of activity states to wait for. 109 */ computeState(boolean compareTaskAndStackBounds, WaitForValidActivityState... waitForActivitiesVisible)110 void computeState(boolean compareTaskAndStackBounds, 111 WaitForValidActivityState... waitForActivitiesVisible) { 112 waitForValidState(compareTaskAndStackBounds, waitForActivitiesVisible); 113 } 114 115 /** 116 * Wait for the activities to appear and for valid state in AM and WM. 117 * 118 * @param activityNames name list of activities to wait for. 119 */ waitForValidState(ComponentName... activityNames)120 public void waitForValidState(ComponentName... activityNames) { 121 waitForValidState(false /* compareTaskAndStackBounds */, 122 Arrays.stream(activityNames) 123 .map(WaitForValidActivityState::new) 124 .toArray(WaitForValidActivityState[]::new)); 125 126 } 127 128 /** Wait for the activity to appear and for valid state in AM and WM. */ waitForValidState(WaitForValidActivityState... waitForActivityVisible)129 void waitForValidState(WaitForValidActivityState... waitForActivityVisible) { 130 waitForValidState(false /* compareTaskAndStackBounds */, waitForActivityVisible); 131 } 132 133 /** 134 * Wait for the activities to appear in proper stacks and for valid state in AM and WM. 135 * 136 * @param compareTaskAndStackBounds flag indicating if we should compare task and stack bounds 137 * for equality. 138 * @param waitForActivitiesVisible array of activity states to wait for. 139 */ waitForValidState(boolean compareTaskAndStackBounds, WaitForValidActivityState... waitForActivitiesVisible)140 private void waitForValidState(boolean compareTaskAndStackBounds, 141 WaitForValidActivityState... waitForActivitiesVisible) { 142 for (int retry = 1; retry <= 5; retry++) { 143 // TODO: Get state of AM and WM at the same time to avoid mismatches caused by 144 // requesting dump in some intermediate state. 145 mAmState.computeState(); 146 mWmState.computeState(); 147 if (shouldWaitForSanityCheck(compareTaskAndStackBounds) 148 || shouldWaitForValidStacks(compareTaskAndStackBounds) 149 || shouldWaitForActivities(waitForActivitiesVisible) 150 || shouldWaitForWindows()) { 151 logAlways("***Waiting for valid stacks and activities states... retry=" + retry); 152 SystemClock.sleep(1000); 153 } else { 154 return; 155 } 156 } 157 logE("***Waiting for states failed: " + Arrays.toString(waitForActivitiesVisible)); 158 } 159 160 /** 161 * Ensures all exiting windows have been removed. 162 */ waitForAllExitingWindows()163 void waitForAllExitingWindows() { 164 List<WindowState> exitingWindows = null; 165 for (int retry = 1; retry <= 5; retry++) { 166 mWmState.computeState(); 167 exitingWindows = mWmState.getExitingWindows(); 168 if (exitingWindows.isEmpty()) { 169 return; 170 } 171 logAlways("***Waiting for all exiting windows have been removed... retry=" + retry); 172 SystemClock.sleep(1000); 173 } 174 fail("All exiting windows have been removed, actual=" + exitingWindows.stream() 175 .map(WindowState::getName) 176 .collect(Collectors.joining(","))); 177 } 178 waitForAllStoppedActivities()179 void waitForAllStoppedActivities() { 180 for (int retry = 1; retry <= 5; retry++) { 181 mAmState.computeState(); 182 if (!mAmState.containsStartedActivities()) { 183 return; 184 } 185 logAlways("***Waiting for all started activities have been removed... retry=" + retry); 186 SystemClock.sleep(1500); 187 } 188 fail("All started activities have been removed"); 189 } 190 191 /** 192 * Compute AM and WM state of device, wait for the activity records to be added, and 193 * wait for debugger window to show up. 194 * 195 * This should only be used when starting with -D (debugger) option, where we pop up the 196 * waiting-for-debugger window, but real activity window won't show up since we're waiting 197 * for debugger. 198 */ waitForDebuggerWindowVisible(ComponentName activityName)199 void waitForDebuggerWindowVisible(ComponentName activityName) { 200 for (int retry = 1; retry <= 5; retry++) { 201 mAmState.computeState(); 202 mWmState.computeState(); 203 if (shouldWaitForDebuggerWindow(activityName) 204 || shouldWaitForActivityRecords(activityName)) { 205 logAlways("***Waiting for debugger window... retry=" + retry); 206 SystemClock.sleep(1000); 207 } else { 208 return; 209 } 210 } 211 logE("***Waiting for debugger window failed"); 212 } 213 waitForHomeActivityVisible()214 boolean waitForHomeActivityVisible() { 215 ComponentName homeActivity = mAmState.getHomeActivityName(); 216 // Sometimes this function is called before we know what Home Activity is 217 if (homeActivity == null) { 218 logAlways("Computing state to determine Home Activity"); 219 computeState(true); 220 homeActivity = mAmState.getHomeActivityName(); 221 } 222 assertNotNull("homeActivity should not be null", homeActivity); 223 waitForValidState(homeActivity); 224 return mAmState.isHomeActivityVisible(); 225 } 226 227 /** 228 * @return true if recents activity is visible. Devices without recents will return false 229 */ waitForRecentsActivityVisible()230 boolean waitForRecentsActivityVisible() { 231 if (mAmState.isHomeRecentsComponent()) { 232 return waitForHomeActivityVisible(); 233 } 234 235 waitForWithAmState(ActivityManagerState::isRecentsActivityVisible, 236 "***Waiting for recents activity to be visible..."); 237 return mAmState.isRecentsActivityVisible(); 238 } 239 waitForKeyguardShowingAndNotOccluded()240 void waitForKeyguardShowingAndNotOccluded() { 241 waitForWithAmState(state -> state.getKeyguardControllerState().keyguardShowing 242 && !state.getKeyguardControllerState().keyguardOccluded, 243 "***Waiting for Keyguard showing..."); 244 } 245 waitForKeyguardShowingAndOccluded()246 void waitForKeyguardShowingAndOccluded() { 247 waitForWithAmState(state -> state.getKeyguardControllerState().keyguardShowing 248 && state.getKeyguardControllerState().keyguardOccluded, 249 "***Waiting for Keyguard showing and occluded..."); 250 } 251 waitForKeyguardGone()252 void waitForKeyguardGone() { 253 waitForWithAmState(state -> !state.getKeyguardControllerState().keyguardShowing, 254 "***Waiting for Keyguard gone..."); 255 } 256 257 /** Wait for specific rotation for the default display. Values are Surface#Rotation */ waitForRotation(int rotation)258 void waitForRotation(int rotation) { 259 waitForWithWmState(state -> state.getRotation() == rotation, 260 "***Waiting for Rotation: " + rotation); 261 } 262 263 /** 264 * Wait for specific orientation for the default display. 265 * Values are ActivityInfo.ScreenOrientation 266 */ waitForLastOrientation(int orientation)267 void waitForLastOrientation(int orientation) { 268 waitForWithWmState(state -> state.getLastOrientation() == orientation, 269 "***Waiting for LastOrientation: " + orientation); 270 } 271 waitForDisplayUnfrozen()272 void waitForDisplayUnfrozen() { 273 waitForWithWmState(state -> !state.isDisplayFrozen(), 274 "***Waiting for Display unfrozen"); 275 } 276 waitForActivityState(ComponentName activityName, String activityState)277 public void waitForActivityState(ComponentName activityName, String activityState) { 278 waitForWithAmState(state -> state.hasActivityState(activityName, activityState), 279 "***Waiting for Activity State: " + activityState); 280 } 281 282 @Deprecated waitForFocusedStack(int stackId)283 void waitForFocusedStack(int stackId) { 284 waitForWithAmState(state -> state.getFocusedStackId() == stackId, 285 "***Waiting for focused stack..."); 286 } 287 waitForFocusedStack(int windowingMode, int activityType)288 void waitForFocusedStack(int windowingMode, int activityType) { 289 waitForWithAmState(state -> 290 (activityType == ACTIVITY_TYPE_UNDEFINED 291 || state.getFocusedStackActivityType() == activityType) 292 && (windowingMode == WINDOWING_MODE_UNDEFINED 293 || state.getFocusedStackWindowingMode() == windowingMode), 294 "***Waiting for focused stack..."); 295 } 296 waitForAppTransitionIdle()297 void waitForAppTransitionIdle() { 298 waitForWithWmState( 299 state -> WindowManagerState.APP_STATE_IDLE.equals(state.getAppTransitionState()), 300 "***Waiting for app transition idle..."); 301 } 302 waitForWithAmState(Predicate<ActivityManagerState> waitCondition, String message)303 void waitForWithAmState(Predicate<ActivityManagerState> waitCondition, String message) { 304 waitFor((amState, wmState) -> waitCondition.test(amState), message); 305 } 306 waitForWithWmState(Predicate<WindowManagerState> waitCondition, String message)307 void waitForWithWmState(Predicate<WindowManagerState> waitCondition, String message) { 308 waitFor((amState, wmState) -> waitCondition.test(wmState), message); 309 } 310 waitFor( BiPredicate<ActivityManagerState, WindowManagerState> waitCondition, String message)311 void waitFor( 312 BiPredicate<ActivityManagerState, WindowManagerState> waitCondition, String message) { 313 waitFor(message, () -> { 314 mAmState.computeState(); 315 mWmState.computeState(); 316 return waitCondition.test(mAmState, mWmState); 317 }); 318 } 319 waitFor(String message, BooleanSupplier waitCondition)320 void waitFor(String message, BooleanSupplier waitCondition) { 321 for (int retry = 1; retry <= 5; retry++) { 322 if (waitCondition.getAsBoolean()) { 323 return; 324 } 325 logAlways(message + " retry=" + retry); 326 SystemClock.sleep(1000); 327 } 328 logE(message + " failed"); 329 } 330 331 /** 332 * @return true if should wait for valid stacks state. 333 */ shouldWaitForValidStacks(boolean compareTaskAndStackBounds)334 private boolean shouldWaitForValidStacks(boolean compareTaskAndStackBounds) { 335 if (!taskListsInAmAndWmAreEqual()) { 336 // We want to wait for equal task lists in AM and WM in case we caught them in the 337 // middle of some state change operations. 338 logAlways("***taskListsInAmAndWmAreEqual=false"); 339 return true; 340 } 341 if (!stackBoundsInAMAndWMAreEqual()) { 342 // We want to wait a little for the stacks in AM and WM to have equal bounds as there 343 // might be a transition animation ongoing when we got the states from WM AM separately. 344 logAlways("***stackBoundsInAMAndWMAreEqual=false"); 345 return true; 346 } 347 try { 348 // Temporary fix to avoid catching intermediate state with different task bounds in AM 349 // and WM. 350 assertValidBounds(compareTaskAndStackBounds); 351 } catch (AssertionError e) { 352 logAlways("***taskBoundsInAMAndWMAreEqual=false : " + e.getMessage()); 353 return true; 354 } 355 final int stackCount = mAmState.getStackCount(); 356 if (stackCount == 0) { 357 logAlways("***stackCount=" + stackCount); 358 return true; 359 } 360 final int resumedActivitiesCount = mAmState.getResumedActivitiesCount(); 361 if (!mAmState.getKeyguardControllerState().keyguardShowing && resumedActivitiesCount != 1) { 362 logAlways("***resumedActivitiesCount=" + resumedActivitiesCount); 363 return true; 364 } 365 if (mAmState.getFocusedActivity() == null) { 366 logAlways("***focusedActivity=null"); 367 return true; 368 } 369 return false; 370 } 371 372 /** 373 * @return true if should wait for some activities to become visible. 374 */ shouldWaitForActivities(WaitForValidActivityState... waitForActivitiesVisible)375 private boolean shouldWaitForActivities(WaitForValidActivityState... waitForActivitiesVisible) { 376 if (waitForActivitiesVisible == null || waitForActivitiesVisible.length == 0) { 377 return false; 378 } 379 // If the caller is interested in us waiting for some particular activity windows to be 380 // visible before compute the state. Check for the visibility of those activity windows 381 // and for placing them in correct stacks (if requested). 382 boolean allActivityWindowsVisible = true; 383 boolean tasksInCorrectStacks = true; 384 for (final WaitForValidActivityState state : waitForActivitiesVisible) { 385 final ComponentName activityName = state.activityName; 386 final String windowName = state.windowName; 387 final int stackId = state.stackId; 388 final int windowingMode = state.windowingMode; 389 final int activityType = state.activityType; 390 391 final List<WindowState> matchingWindowStates = 392 mWmState.getMatchingVisibleWindowState(windowName); 393 boolean activityWindowVisible = !matchingWindowStates.isEmpty(); 394 if (!activityWindowVisible) { 395 logAlways("Activity window not visible: " + windowName); 396 allActivityWindowsVisible = false; 397 } else if (activityName != null 398 && !mAmState.isActivityVisible(activityName)) { 399 logAlways("Activity not visible: " + getActivityName(activityName)); 400 allActivityWindowsVisible = false; 401 } else { 402 // Check if window is already the correct state requested by test. 403 boolean windowInCorrectState = false; 404 for (WindowState ws : matchingWindowStates) { 405 if (stackId != INVALID_STACK_ID && ws.getStackId() != stackId) { 406 continue; 407 } 408 if (windowingMode != WINDOWING_MODE_UNDEFINED 409 && ws.getWindowingMode() != windowingMode) { 410 continue; 411 } 412 if (activityType != ACTIVITY_TYPE_UNDEFINED 413 && ws.getActivityType() != activityType) { 414 continue; 415 } 416 windowInCorrectState = true; 417 break; 418 } 419 420 if (!windowInCorrectState) { 421 logAlways("Window in incorrect stack: " + state); 422 tasksInCorrectStacks = false; 423 } 424 } 425 } 426 return !allActivityWindowsVisible || !tasksInCorrectStacks; 427 } 428 429 /** 430 * @return true if should wait valid windows state. 431 */ shouldWaitForWindows()432 private boolean shouldWaitForWindows() { 433 if (mWmState.getFrontWindow() == null) { 434 logAlways("***frontWindow=null"); 435 return true; 436 } 437 if (mWmState.getFocusedWindow() == null) { 438 logAlways("***focusedWindow=null"); 439 return true; 440 } 441 if (mWmState.getFocusedApp() == null) { 442 logAlways("***focusedApp=null"); 443 return true; 444 } 445 446 return false; 447 } 448 shouldWaitForDebuggerWindow(ComponentName activityName)449 private boolean shouldWaitForDebuggerWindow(ComponentName activityName) { 450 List<WindowState> matchingWindowStates = 451 mWmState.getMatchingVisibleWindowState(activityName.getPackageName()); 452 for (WindowState ws : matchingWindowStates) { 453 if (ws.isDebuggerWindow()) { 454 return false; 455 } 456 } 457 logAlways("Debugger window not available yet"); 458 return true; 459 } 460 shouldWaitForActivityRecords(ComponentName... activityNames)461 private boolean shouldWaitForActivityRecords(ComponentName... activityNames) { 462 // Check if the activity records we're looking for is already added. 463 for (final ComponentName activityName : activityNames) { 464 if (!mAmState.isActivityVisible(activityName)) { 465 logAlways("ActivityRecord " + getActivityName(activityName) + " not visible yet"); 466 return true; 467 } 468 } 469 return false; 470 } 471 shouldWaitForSanityCheck(boolean compareTaskAndStackBounds)472 private boolean shouldWaitForSanityCheck(boolean compareTaskAndStackBounds) { 473 try { 474 assertSanity(); 475 assertValidBounds(compareTaskAndStackBounds); 476 } catch (Throwable t) { 477 logAlways("Waiting for sanity check: " + t.toString()); 478 return true; 479 } 480 return false; 481 } 482 getAmState()483 ActivityManagerState getAmState() { 484 return mAmState; 485 } 486 getWmState()487 public WindowManagerState getWmState() { 488 return mWmState; 489 } 490 assertSanity()491 void assertSanity() { 492 assertThat("Must have stacks", mAmState.getStackCount(), greaterThan(0)); 493 if (!mAmState.getKeyguardControllerState().keyguardShowing) { 494 assertEquals("There should be one and only one resumed activity in the system.", 495 1, mAmState.getResumedActivitiesCount()); 496 } 497 assertNotNull("Must have focus activity.", mAmState.getFocusedActivity()); 498 499 for (ActivityStack aStack : mAmState.getStacks()) { 500 final int stackId = aStack.mStackId; 501 for (ActivityTask aTask : aStack.getTasks()) { 502 assertEquals("Stack can only contain its own tasks", stackId, aTask.mStackId); 503 } 504 } 505 506 assertNotNull("Must have front window.", mWmState.getFrontWindow()); 507 assertNotNull("Must have focused window.", mWmState.getFocusedWindow()); 508 assertNotNull("Must have app.", mWmState.getFocusedApp()); 509 } 510 assertContainsStack(String msg, int windowingMode, int activityType)511 void assertContainsStack(String msg, int windowingMode, int activityType) { 512 assertTrue(msg, mAmState.containsStack(windowingMode, activityType)); 513 assertTrue(msg, mWmState.containsStack(windowingMode, activityType)); 514 } 515 assertDoesNotContainStack(String msg, int windowingMode, int activityType)516 void assertDoesNotContainStack(String msg, int windowingMode, int activityType) { 517 assertFalse(msg, mAmState.containsStack(windowingMode, activityType)); 518 assertFalse(msg, mWmState.containsStack(windowingMode, activityType)); 519 } 520 assertFrontStack(String msg, int stackId)521 void assertFrontStack(String msg, int stackId) { 522 assertEquals(msg, stackId, mAmState.getFrontStackId(DEFAULT_DISPLAY)); 523 assertEquals(msg, stackId, mWmState.getFrontStackId(DEFAULT_DISPLAY)); 524 } 525 assertFrontStack(String msg, int windowingMode, int activityType)526 void assertFrontStack(String msg, int windowingMode, int activityType) { 527 if (windowingMode != WINDOWING_MODE_UNDEFINED) { 528 assertEquals(msg, windowingMode, 529 mAmState.getFrontStackWindowingMode(DEFAULT_DISPLAY)); 530 } 531 if (activityType != ACTIVITY_TYPE_UNDEFINED) { 532 assertEquals(msg, activityType, mAmState.getFrontStackActivityType(DEFAULT_DISPLAY)); 533 } 534 } 535 assertFrontStackActivityType(String msg, int activityType)536 void assertFrontStackActivityType(String msg, int activityType) { 537 assertEquals(msg, activityType, mAmState.getFrontStackActivityType(DEFAULT_DISPLAY)); 538 assertEquals(msg, activityType, mWmState.getFrontStackActivityType(DEFAULT_DISPLAY)); 539 } 540 541 @Deprecated assertFocusedStack(String msg, int stackId)542 void assertFocusedStack(String msg, int stackId) { 543 assertEquals(msg, stackId, mAmState.getFocusedStackId()); 544 } 545 assertFocusedStack(String msg, int windowingMode, int activityType)546 void assertFocusedStack(String msg, int windowingMode, int activityType) { 547 if (windowingMode != WINDOWING_MODE_UNDEFINED) { 548 assertEquals(msg, windowingMode, mAmState.getFocusedStackWindowingMode()); 549 } 550 if (activityType != ACTIVITY_TYPE_UNDEFINED) { 551 assertEquals(msg, activityType, mAmState.getFocusedStackActivityType()); 552 } 553 } 554 assertFocusedActivity(final String msg, final ComponentName activityName)555 void assertFocusedActivity(final String msg, final ComponentName activityName) { 556 final String activityComponentName = getActivityName(activityName); 557 assertEquals(msg, activityComponentName, mAmState.getFocusedActivity()); 558 assertEquals(msg, activityComponentName, mWmState.getFocusedApp()); 559 } 560 assertNotFocusedActivity(String msg, ComponentName activityName)561 void assertNotFocusedActivity(String msg, ComponentName activityName) { 562 assertNotEquals(msg, mAmState.getFocusedActivity(), getActivityName(activityName)); 563 assertNotEquals(msg, mWmState.getFocusedApp(), getActivityName(activityName)); 564 } 565 assertResumedActivity(final String msg, final ComponentName activityName)566 public void assertResumedActivity(final String msg, final ComponentName activityName) { 567 assertEquals(msg, getActivityName(activityName), mAmState.getResumedActivity()); 568 } 569 assertNotResumedActivity(String msg, ComponentName activityName)570 void assertNotResumedActivity(String msg, ComponentName activityName) { 571 assertNotEquals(msg, mAmState.getResumedActivity(), getActivityName(activityName)); 572 } 573 assertFocusedWindow(String msg, String windowName)574 void assertFocusedWindow(String msg, String windowName) { 575 assertEquals(msg, windowName, mWmState.getFocusedWindow()); 576 } 577 assertNotFocusedWindow(String msg, String windowName)578 void assertNotFocusedWindow(String msg, String windowName) { 579 assertNotEquals(msg, mWmState.getFocusedWindow(), windowName); 580 } 581 assertFrontWindow(String msg, String windowName)582 void assertFrontWindow(String msg, String windowName) { 583 assertEquals(msg, windowName, mWmState.getFrontWindow()); 584 } 585 assertVisibility(final ComponentName activityName, final boolean visible)586 public void assertVisibility(final ComponentName activityName, final boolean visible) { 587 final String windowName = getWindowName(activityName); 588 final boolean activityVisible = mAmState.isActivityVisible(activityName); 589 final boolean windowVisible = mWmState.isWindowVisible(windowName); 590 591 assertEquals("Activity=" + getActivityName(activityName) + " must" + (visible ? "" : " NOT") 592 + " be visible.", visible, activityVisible); 593 assertEquals("Window=" + windowName + " must" + (visible ? "" : " NOT") + " be visible.", 594 visible, windowVisible); 595 } 596 assertHomeActivityVisible(boolean visible)597 void assertHomeActivityVisible(boolean visible) { 598 final ComponentName homeActivity = mAmState.getHomeActivityName(); 599 assertNotNull(homeActivity); 600 assertVisibility(homeActivity, visible); 601 } 602 603 /** 604 * Asserts that the device default display minimim width is larger than the minimum task width. 605 */ assertDeviceDefaultDisplaySize(String errorMessage)606 void assertDeviceDefaultDisplaySize(String errorMessage) { 607 computeState(true); 608 final int minTaskSizePx = defaultMinimalTaskSize(DEFAULT_DISPLAY); 609 final Display display = getWmState().getDisplay(DEFAULT_DISPLAY); 610 final Rect displayRect = display.getDisplayRect(); 611 if (Math.min(displayRect.width(), displayRect.height()) < minTaskSizePx) { 612 fail(errorMessage); 613 } 614 } 615 assertKeyguardShowingAndOccluded()616 public void assertKeyguardShowingAndOccluded() { 617 assertTrue("Keyguard is showing", 618 getAmState().getKeyguardControllerState().keyguardShowing); 619 assertTrue("Keyguard is occluded", 620 getAmState().getKeyguardControllerState().keyguardOccluded); 621 } 622 assertKeyguardShowingAndNotOccluded()623 public void assertKeyguardShowingAndNotOccluded() { 624 assertTrue("Keyguard is showing", 625 getAmState().getKeyguardControllerState().keyguardShowing); 626 assertFalse("Keyguard is not occluded", 627 getAmState().getKeyguardControllerState().keyguardOccluded); 628 } 629 assertKeyguardGone()630 public void assertKeyguardGone() { 631 assertFalse("Keyguard is not shown", 632 getAmState().getKeyguardControllerState().keyguardShowing); 633 } 634 taskListsInAmAndWmAreEqual()635 boolean taskListsInAmAndWmAreEqual() { 636 for (ActivityStack aStack : mAmState.getStacks()) { 637 final int stackId = aStack.mStackId; 638 final WindowStack wStack = mWmState.getStack(stackId); 639 if (wStack == null) { 640 log("Waiting for stack setup in WM, stackId=" + stackId); 641 return false; 642 } 643 644 for (ActivityTask aTask : aStack.getTasks()) { 645 if (wStack.getTask(aTask.mTaskId) == null) { 646 log("Task is in AM but not in WM, waiting for it to settle, taskId=" 647 + aTask.mTaskId); 648 return false; 649 } 650 } 651 652 for (WindowTask wTask : wStack.mTasks) { 653 if (aStack.getTask(wTask.mTaskId) == null) { 654 log("Task is in WM but not in AM, waiting for it to settle, taskId=" 655 + wTask.mTaskId); 656 return false; 657 } 658 } 659 } 660 return true; 661 } 662 663 /** Get the stack position on its display. */ getStackIndexByActivityType(int activityType)664 int getStackIndexByActivityType(int activityType) { 665 int wmStackIndex = mWmState.getStackIndexByActivityType(activityType); 666 int amStackIndex = mAmState.getStackIndexByActivityType(activityType); 667 assertEquals("Window and activity manager must have the same stack position index", 668 amStackIndex, wmStackIndex); 669 return wmStackIndex; 670 } 671 stackBoundsInAMAndWMAreEqual()672 boolean stackBoundsInAMAndWMAreEqual() { 673 for (ActivityStack aStack : mAmState.getStacks()) { 674 final int stackId = aStack.mStackId; 675 final WindowStack wStack = mWmState.getStack(stackId); 676 if (aStack.isFullscreen() != wStack.isFullscreen()) { 677 log("Waiting for correct fullscreen state, stackId=" + stackId); 678 return false; 679 } 680 681 final Rect aStackBounds = aStack.getBounds(); 682 final Rect wStackBounds = wStack.getBounds(); 683 684 if (aStack.isFullscreen()) { 685 if (aStackBounds != null) { 686 log("Waiting for correct stack state in AM, stackId=" + stackId); 687 return false; 688 } 689 } else if (!Objects.equals(aStackBounds, wStackBounds)) { 690 // If stack is not fullscreen - comparing bounds. Not doing it always because 691 // for fullscreen stack bounds in WM can be either null or equal to display size. 692 log("Waiting for stack bound equality in AM and WM, stackId=" + stackId); 693 return false; 694 } 695 } 696 697 return true; 698 } 699 700 /** 701 * Check task bounds when docked to top/left. 702 */ assertDockedTaskBounds(int taskWidth, int taskHeight, ComponentName activityName)703 void assertDockedTaskBounds(int taskWidth, int taskHeight, ComponentName activityName) { 704 // Task size can be affected by default minimal size. 705 int defaultMinimalTaskSize = defaultMinimalTaskSize( 706 mAmState.getStandardStackByWindowingMode( 707 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).mDisplayId); 708 int targetWidth = Math.max(taskWidth, defaultMinimalTaskSize); 709 int targetHeight = Math.max(taskHeight, defaultMinimalTaskSize); 710 711 assertEquals(new Rect(0, 0, targetWidth, targetHeight), 712 mAmState.getTaskByActivity(activityName).getBounds()); 713 } 714 assertValidBounds(boolean compareTaskAndStackBounds)715 void assertValidBounds(boolean compareTaskAndStackBounds) { 716 // Cycle through the stacks and tasks to figure out if the home stack is resizable 717 final ActivityTask homeTask = mAmState.getHomeTask(); 718 final boolean homeStackIsResizable = homeTask != null 719 && homeTask.getResizeMode() == RESIZE_MODE_RESIZEABLE; 720 721 for (ActivityStack aStack : mAmState.getStacks()) { 722 final int stackId = aStack.mStackId; 723 final WindowStack wStack = mWmState.getStack(stackId); 724 assertNotNull("stackId=" + stackId + " in AM but not in WM?", wStack); 725 726 assertEquals("Stack fullscreen state in AM and WM must be equal stackId=" + stackId, 727 aStack.isFullscreen(), wStack.isFullscreen()); 728 729 final Rect aStackBounds = aStack.getBounds(); 730 final Rect wStackBounds = wStack.getBounds(); 731 732 if (aStack.isFullscreen()) { 733 assertNull("Stack bounds in AM must be null stackId=" + stackId, aStackBounds); 734 } else { 735 assertEquals("Stack bounds in AM and WM must be equal stackId=" + stackId, 736 aStackBounds, wStackBounds); 737 } 738 739 for (ActivityTask aTask : aStack.getTasks()) { 740 final int taskId = aTask.mTaskId; 741 final WindowTask wTask = wStack.getTask(taskId); 742 assertNotNull( 743 "taskId=" + taskId + " in AM but not in WM? stackId=" + stackId, wTask); 744 745 final boolean aTaskIsFullscreen = aTask.isFullscreen(); 746 final boolean wTaskIsFullscreen = wTask.isFullscreen(); 747 assertEquals("Task fullscreen state in AM and WM must be equal taskId=" + taskId 748 + ", stackId=" + stackId, aTaskIsFullscreen, wTaskIsFullscreen); 749 750 final Rect aTaskBounds = aTask.getBounds(); 751 final Rect wTaskBounds = wTask.getBounds(); 752 753 if (aTaskIsFullscreen) { 754 assertNull("Task bounds in AM must be null for fullscreen taskId=" + taskId, 755 aTaskBounds); 756 } else if (!homeStackIsResizable && mWmState.isDockedStackMinimized() 757 && !isScreenPortrait(aStack.mDisplayId)) { 758 // When minimized using non-resizable launcher in landscape mode, it will move 759 // the task offscreen in the negative x direction unlike portrait that crops. 760 // The x value in the task bounds will not match the stack bounds since the 761 // only the task was moved. 762 assertEquals("Task bounds in AM and WM must match width taskId=" + taskId 763 + ", stackId" + stackId, aTaskBounds.width(), 764 wTaskBounds.width()); 765 assertEquals("Task bounds in AM and WM must match height taskId=" + taskId 766 + ", stackId" + stackId, aTaskBounds.height(), 767 wTaskBounds.height()); 768 assertEquals("Task bounds must match stack bounds y taskId=" + taskId 769 + ", stackId" + stackId, aTaskBounds.top, 770 wTaskBounds.top); 771 assertEquals("Task and stack bounds must match width taskId=" + taskId 772 + ", stackId" + stackId, aStackBounds.width(), 773 wTaskBounds.width()); 774 assertEquals("Task and stack bounds must match height taskId=" + taskId 775 + ", stackId" + stackId, aStackBounds.height(), 776 wTaskBounds.height()); 777 assertEquals("Task and stack bounds must match y taskId=" + taskId 778 + ", stackId" + stackId, aStackBounds.top, 779 wTaskBounds.top); 780 } else { 781 assertEquals("Task bounds in AM and WM must be equal taskId=" + taskId 782 + ", stackId=" + stackId, aTaskBounds, wTaskBounds); 783 784 if (compareTaskAndStackBounds 785 && aStack.getWindowingMode() != WINDOWING_MODE_FREEFORM) { 786 int aTaskMinWidth = aTask.getMinWidth(); 787 int aTaskMinHeight = aTask.getMinHeight(); 788 789 if (aTaskMinWidth == -1 || aTaskMinHeight == -1) { 790 // Minimal dimension(s) not set for task - it should be using defaults. 791 int defaultMinimalSize = 792 aStack.getWindowingMode() == WINDOWING_MODE_PINNED 793 ? defaultMinimalPinnedTaskSize(aStack.mDisplayId) 794 : defaultMinimalTaskSize(aStack.mDisplayId); 795 796 if (aTaskMinWidth == -1) { 797 aTaskMinWidth = defaultMinimalSize; 798 } 799 if (aTaskMinHeight == -1) { 800 aTaskMinHeight = defaultMinimalSize; 801 } 802 } 803 804 if (aStackBounds.width() >= aTaskMinWidth 805 && aStackBounds.height() >= aTaskMinHeight 806 || aStack.getWindowingMode() == WINDOWING_MODE_PINNED) { 807 // Bounds are not smaller then minimal possible, so stack and task 808 // bounds must be equal. 809 assertEquals("Task bounds must be equal to stack bounds taskId=" 810 + taskId + ", stackId=" + stackId, aStackBounds, wTaskBounds); 811 } else if (aStack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY 812 && homeStackIsResizable && mWmState.isDockedStackMinimized()) { 813 // Portrait if the display height is larger than the width 814 if (isScreenPortrait(aStack.mDisplayId)) { 815 assertEquals("Task width must be equal to stack width taskId=" 816 + taskId + ", stackId=" + stackId, 817 aStackBounds.width(), wTaskBounds.width()); 818 assertThat("Task height must be greater than stack height " 819 + "taskId=" + taskId + ", stackId=" + stackId, 820 aStackBounds.height(), lessThan(wTaskBounds.height())); 821 assertEquals("Task and stack x position must be equal taskId=" 822 + taskId + ", stackId=" + stackId, 823 wTaskBounds.left, wStackBounds.left); 824 } else { 825 assertThat("Task width must be greater than stack width taskId=" 826 + taskId + ", stackId=" + stackId, 827 aStackBounds.width(), lessThan(wTaskBounds.width())); 828 assertEquals("Task height must be equal to stack height taskId=" 829 + taskId + ", stackId=" + stackId, 830 aStackBounds.height(), wTaskBounds.height()); 831 assertEquals("Task and stack y position must be equal taskId=" 832 + taskId + ", stackId=" + stackId, wTaskBounds.top, 833 wStackBounds.top); 834 } 835 } else { 836 // Minimal dimensions affect task size, so bounds of task and stack must 837 // be different - will compare dimensions instead. 838 int targetWidth = Math.max(aTaskMinWidth, aStackBounds.width()); 839 assertEquals("Task width must be set according to minimal width" 840 + " taskId=" + taskId + ", stackId=" + stackId, 841 targetWidth, wTaskBounds.width()); 842 int targetHeight = Math.max(aTaskMinHeight, aStackBounds.height()); 843 assertEquals("Task height must be set according to minimal height" 844 + " taskId=" + taskId + ", stackId=" + stackId, 845 targetHeight, wTaskBounds.height()); 846 } 847 } 848 } 849 } 850 } 851 } 852 assertActivityDisplayed(final ComponentName activityName)853 public void assertActivityDisplayed(final ComponentName activityName) throws Exception { 854 assertWindowDisplayed(getWindowName(activityName)); 855 } 856 assertWindowDisplayed(final String windowName)857 public void assertWindowDisplayed(final String windowName) throws Exception { 858 waitForValidState(WaitForValidActivityState.forWindow(windowName)); 859 assertTrue(windowName + "is visible", getWmState().isWindowVisible(windowName)); 860 } 861 isScreenPortrait()862 boolean isScreenPortrait() { 863 final int displayId = mAmState.getStandardStackByWindowingMode( 864 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).mDisplayId; 865 return isScreenPortrait(displayId); 866 } 867 isScreenPortrait(int displayId)868 boolean isScreenPortrait(int displayId) { 869 final Rect displayRect = mWmState.getDisplay(displayId).getDisplayRect(); 870 return displayRect.height() > displayRect.width(); 871 } 872 dpToPx(float dp, int densityDpi)873 static int dpToPx(float dp, int densityDpi) { 874 return (int) (dp * densityDpi / DENSITY_DEFAULT + 0.5f); 875 } 876 defaultMinimalTaskSize(int displayId)877 private int defaultMinimalTaskSize(int displayId) { 878 return dpToPx(DEFAULT_RESIZABLE_TASK_SIZE_DP, mWmState.getDisplay(displayId).getDpi()); 879 } 880 defaultMinimalPinnedTaskSize(int displayId)881 private int defaultMinimalPinnedTaskSize(int displayId) { 882 return dpToPx(DEFAULT_PIP_RESIZABLE_TASK_SIZE_DP, mWmState.getDisplay(displayId).getDpi()); 883 } 884 } 885