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