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