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 package android.server.cts; 17 18 import android.platform.test.annotations.Presubmit; 19 20 import com.android.tradefed.device.CollectingOutputReceiver; 21 import com.android.tradefed.device.DeviceNotAvailableException; 22 23 import java.util.Collections; 24 import java.util.LinkedList; 25 import java.util.List; 26 import java.util.regex.Matcher; 27 import java.util.regex.Pattern; 28 29 import static android.server.cts.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID; 30 import static android.server.cts.ActivityManagerState.STATE_RESUMED; 31 import static android.server.cts.StateLogger.log; 32 import static android.server.cts.StateLogger.logE; 33 34 /** 35 * Build: mmma -j32 cts/hostsidetests/services 36 * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsServicesHostTestCases android.server.cts.ActivityManagerDisplayTests 37 */ 38 public class ActivityManagerDisplayTests extends ActivityManagerDisplayTestBase { 39 private static final String WM_SIZE = "wm size"; 40 private static final String WM_DENSITY = "wm density"; 41 42 private static final String TEST_ACTIVITY_NAME = "TestActivity"; 43 private static final String VIRTUAL_DISPLAY_ACTIVITY = "VirtualDisplayActivity"; 44 private static final String RESIZEABLE_ACTIVITY_NAME = "ResizeableActivity"; 45 private static final String NON_RESIZEABLE_ACTIVITY_NAME = "NonResizeableActivity"; 46 private static final String SECOND_ACTIVITY_NAME = "SecondActivity"; 47 private static final String THIRD_ACTIVITY_NAME = "ThirdActivity"; 48 private static final String VR_TEST_ACTIVITY_NAME = "VrTestActivity"; 49 private static final String SECOND_PACKAGE_NAME = "android.server.cts.second"; 50 private static final String THIRD_PACKAGE_NAME = "android.server.cts.third"; 51 private static final int VR_VIRTUAL_DISPLAY_WIDTH = 70; 52 private static final int VR_VIRTUAL_DISPLAY_HEIGHT = 90; 53 private static final int VR_VIRTUAL_DISPLAY_DPI = 320; 54 55 /** Physical display metrics and overrides in the beginning of the test. */ 56 private ReportedDisplayMetrics mInitialDisplayMetrics; 57 58 @Override setUp()59 protected void setUp() throws Exception { 60 super.setUp(); 61 mInitialDisplayMetrics = getDisplayMetrics(); 62 } 63 64 @Override tearDown()65 protected void tearDown() throws Exception { 66 try { 67 enablePersistentVrMode(false); 68 restoreDisplayMetricsOverrides(); 69 } catch (DeviceNotAvailableException e) { 70 logE(e.getMessage()); 71 } 72 super.tearDown(); 73 } 74 enablePersistentVrMode(boolean enabled)75 private void enablePersistentVrMode(boolean enabled) throws Exception { 76 if (enabled) { 77 executeShellCommand("setprop vr_virtualdisplay true"); 78 executeShellCommand("vr set-persistent-vr-mode-enabled true"); 79 } else { 80 executeShellCommand("vr set-persistent-vr-mode-enabled false"); 81 executeShellCommand("setprop vr_virtualdisplay false"); 82 } 83 } 84 restoreDisplayMetricsOverrides()85 private void restoreDisplayMetricsOverrides() throws Exception { 86 if (mInitialDisplayMetrics.sizeOverrideSet) { 87 executeShellCommand(WM_SIZE + " " + mInitialDisplayMetrics.overrideWidth + "x" 88 + mInitialDisplayMetrics.overrideHeight); 89 } else { 90 executeShellCommand("wm size reset"); 91 } 92 if (mInitialDisplayMetrics.densityOverrideSet) { 93 executeShellCommand(WM_DENSITY + " " + mInitialDisplayMetrics.overrideDensity); 94 } else { 95 executeShellCommand("wm density reset"); 96 } 97 } 98 99 /** 100 * Tests that the global configuration is equal to the default display's override configuration. 101 */ testDefaultDisplayOverrideConfiguration()102 public void testDefaultDisplayOverrideConfiguration() throws Exception { 103 final ReportedDisplays reportedDisplays = getDisplaysStates(); 104 assertNotNull("Global configuration must not be empty.", reportedDisplays.mGlobalConfig); 105 final DisplayState primaryDisplay = reportedDisplays.getDisplayState(DEFAULT_DISPLAY_ID); 106 assertEquals("Primary display's configuration should not be equal to global configuration.", 107 reportedDisplays.mGlobalConfig, primaryDisplay.mOverrideConfig); 108 } 109 110 /** 111 * Tests that secondary display has override configuration set. 112 */ testCreateVirtualDisplayWithCustomConfig()113 public void testCreateVirtualDisplayWithCustomConfig() throws Exception { 114 // Create new virtual display. 115 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 116 117 // Find the density of created display. 118 final int newDensityDpi = newDisplay.getDpi(); 119 assertEquals(CUSTOM_DENSITY_DPI, newDensityDpi); 120 } 121 122 /** 123 * Tests that launch on secondary display is not permitted if device has the feature disabled. 124 * Activities requested to be launched on a secondary display in this case should land on the 125 * default display. 126 */ testMultiDisplayDisabled()127 public void testMultiDisplayDisabled() throws Exception { 128 if (supportsMultiDisplay()) { 129 // Only check devices with the feature disabled. 130 return; 131 } 132 133 // Create new virtual display. 134 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 135 136 // Launch activity on new secondary display. 137 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 138 mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME}); 139 140 mAmWmState.assertFocusedActivity("Launched activity must be focused", TEST_ACTIVITY_NAME); 141 142 // Check that activity is on the right display. 143 final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID); 144 final ActivityManagerState.ActivityStack frontStack 145 = mAmWmState.getAmState().getStackById(frontStackId); 146 assertEquals("Launched activity must be resumed", 147 getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity); 148 assertEquals("Front stack must be on the default display", DEFAULT_DISPLAY_ID, 149 frontStack.mDisplayId); 150 mAmWmState.assertFocusedStack("Focus must be on the default display", frontStackId); 151 } 152 153 /** 154 * Tests that any new activity launch in Vr mode is in Vr display. 155 */ testVrActivityLaunch()156 public void testVrActivityLaunch() throws Exception { 157 if (!supportsVrMode() || !supportsMultiDisplay()) { 158 // VR Mode is not supported on this device, bail from this test. 159 return; 160 } 161 162 // Put the device in persistent vr mode. 163 enablePersistentVrMode(true); 164 165 // Launch the VR activity. 166 launchActivity(VR_TEST_ACTIVITY_NAME); 167 mAmWmState.computeState(mDevice, new String[] {VR_TEST_ACTIVITY_NAME}); 168 mAmWmState.assertVisibility(VR_TEST_ACTIVITY_NAME, true /* visible */); 169 170 // Launch the non-VR 2D activity and check where it ends up. 171 launchActivity(LAUNCHING_ACTIVITY); 172 mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY}); 173 174 // Ensure that the subsequent activity is visible 175 mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */); 176 177 // Check that activity is launched in focused stack on primary display. 178 mAmWmState.assertFocusedActivity("Launched activity must be focused", LAUNCHING_ACTIVITY); 179 final int focusedStackId = mAmWmState.getAmState().getFocusedStackId(); 180 final ActivityManagerState.ActivityStack focusedStack 181 = mAmWmState.getAmState().getStackById(focusedStackId); 182 assertEquals("Launched activity must be resumed in focused stack", 183 getActivityComponentName(LAUNCHING_ACTIVITY), focusedStack.mResumedActivity); 184 185 // Check if the launch activity is in Vr virtual display id. 186 final ReportedDisplays reportedDisplays = getDisplaysStates(); 187 assertNotNull("Global configuration must not be empty.", reportedDisplays.mGlobalConfig); 188 final DisplayState vrDisplay = reportedDisplays.getDisplayState(VR_VIRTUAL_DISPLAY_WIDTH, 189 VR_VIRTUAL_DISPLAY_HEIGHT, VR_VIRTUAL_DISPLAY_DPI); 190 assertNotNull("Vr mode should have a virtual display", vrDisplay); 191 192 // Check if the focused activity is on this virtual stack. 193 assertEquals("Launch in Vr mode should be in virtual stack", vrDisplay.mDisplayId, 194 focusedStack.mDisplayId); 195 196 // Put the device out of persistent vr mode. 197 enablePersistentVrMode(false); 198 } 199 200 /** 201 * Tests that any activity already present is re-launched in Vr display in vr mode. 202 */ testVrActivityReLaunch()203 public void testVrActivityReLaunch() throws Exception { 204 if (!supportsVrMode() || !supportsMultiDisplay()) { 205 // VR Mode is not supported on this device, bail from this test. 206 return; 207 } 208 209 // Launch a 2D activity. 210 launchActivity(LAUNCHING_ACTIVITY); 211 212 // Put the device in persistent vr mode. 213 enablePersistentVrMode(true); 214 215 // Launch the VR activity. 216 launchActivity(VR_TEST_ACTIVITY_NAME); 217 mAmWmState.computeState(mDevice, new String[] {VR_TEST_ACTIVITY_NAME}); 218 mAmWmState.assertVisibility(VR_TEST_ACTIVITY_NAME, true /* visible */); 219 220 // Re-launch the non-VR 2D activity and check where it ends up. 221 launchActivity(LAUNCHING_ACTIVITY); 222 mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY}); 223 224 // Ensure that the subsequent activity is visible 225 mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */); 226 227 // Check that activity is launched in focused stack on primary display. 228 mAmWmState.assertFocusedActivity("Launched activity must be focused", LAUNCHING_ACTIVITY); 229 final int focusedStackId = mAmWmState.getAmState().getFocusedStackId(); 230 final ActivityManagerState.ActivityStack focusedStack 231 = mAmWmState.getAmState().getStackById(focusedStackId); 232 assertEquals("Launched activity must be resumed in focused stack", 233 getActivityComponentName(LAUNCHING_ACTIVITY), focusedStack.mResumedActivity); 234 235 // Check if the launch activity is in Vr virtual display id. 236 final ReportedDisplays reportedDisplays = getDisplaysStates(); 237 assertNotNull("Global configuration must not be empty.", reportedDisplays.mGlobalConfig); 238 final DisplayState vrDisplay = reportedDisplays.getDisplayState(VR_VIRTUAL_DISPLAY_WIDTH, 239 VR_VIRTUAL_DISPLAY_HEIGHT, VR_VIRTUAL_DISPLAY_DPI); 240 assertNotNull("Vr mode should have a virtual display", vrDisplay); 241 242 // Check if the focused activity is on this virtual stack. 243 assertEquals("Launch in Vr mode should be in virtual stack", vrDisplay.mDisplayId, 244 focusedStack.mDisplayId); 245 246 // Put the device out of persistent vr mode. 247 enablePersistentVrMode(false); 248 } 249 250 /** 251 * Tests that any new activity launch post Vr mode is in the main display. 252 */ testActivityLaunchPostVr()253 public void testActivityLaunchPostVr() throws Exception { 254 if (!supportsVrMode() || !supportsMultiDisplay()) { 255 // VR Mode is not supported on this device, bail from this test. 256 return; 257 } 258 259 // Put the device in persistent vr mode. 260 enablePersistentVrMode(true); 261 262 // Launch the VR activity. 263 launchActivity(VR_TEST_ACTIVITY_NAME); 264 mAmWmState.computeState(mDevice, new String[] {VR_TEST_ACTIVITY_NAME}); 265 mAmWmState.assertVisibility(VR_TEST_ACTIVITY_NAME, true /* visible */); 266 267 // Launch the non-VR 2D activity and check where it ends up. 268 launchActivity(ALT_LAUNCHING_ACTIVITY); 269 mAmWmState.computeState(mDevice, new String[] {ALT_LAUNCHING_ACTIVITY}); 270 271 // Ensure that the subsequent activity is visible 272 mAmWmState.assertVisibility(ALT_LAUNCHING_ACTIVITY, true /* visible */); 273 274 // Check that activity is launched in focused stack on primary display. 275 mAmWmState.assertFocusedActivity("Launched activity must be focused", ALT_LAUNCHING_ACTIVITY); 276 final int focusedStackId = mAmWmState.getAmState().getFocusedStackId(); 277 final ActivityManagerState.ActivityStack focusedStack 278 = mAmWmState.getAmState().getStackById(focusedStackId); 279 assertEquals("Launched activity must be resumed in focused stack", 280 getActivityComponentName(ALT_LAUNCHING_ACTIVITY), focusedStack.mResumedActivity); 281 282 // Check if the launch activity is in Vr virtual display id. 283 final ReportedDisplays reportedDisplays = getDisplaysStates(); 284 assertNotNull("Global configuration must not be empty.", reportedDisplays.mGlobalConfig); 285 final DisplayState vrDisplay = reportedDisplays.getDisplayState(VR_VIRTUAL_DISPLAY_WIDTH, 286 VR_VIRTUAL_DISPLAY_HEIGHT, VR_VIRTUAL_DISPLAY_DPI); 287 assertNotNull("Vr mode should have a virtual display", vrDisplay); 288 289 // Check if the focused activity is on this virtual stack. 290 assertEquals("Launch in Vr mode should be in virtual stack", vrDisplay.mDisplayId, 291 focusedStack.mDisplayId); 292 293 // Put the device out of persistent vr mode. 294 enablePersistentVrMode(false); 295 296 // There isn't a direct launch of activity which can take an user out of persistent VR mode. 297 // This sleep is to account for that delay and let device settle once it comes out of VR 298 // mode. 299 try { 300 Thread.sleep(2000); 301 } catch (Exception e) { 302 e.printStackTrace(); 303 } 304 305 // Launch the non-VR 2D activity and check where it ends up. 306 launchActivity(RESIZEABLE_ACTIVITY_NAME); 307 mAmWmState.computeState(mDevice, new String[] {RESIZEABLE_ACTIVITY_NAME}); 308 309 // Ensure that the subsequent activity is visible 310 mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */); 311 312 // Check that activity is launched in focused stack on primary display. 313 mAmWmState.assertFocusedActivity("Launched activity must be focused", RESIZEABLE_ACTIVITY_NAME); 314 final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID); 315 final ActivityManagerState.ActivityStack frontStack 316 = mAmWmState.getAmState().getStackById(frontStackId); 317 assertEquals("Launched activity must be resumed in front stack", 318 getActivityComponentName(RESIZEABLE_ACTIVITY_NAME), frontStack.mResumedActivity); 319 assertEquals("Front stack must be on primary display", 320 DEFAULT_DISPLAY_ID, frontStack.mDisplayId); 321 } 322 testCreateMultipleVirtualDisplays()323 public void testCreateMultipleVirtualDisplays() throws Exception { 324 // Create new virtual display. 325 final List<DisplayState> newDisplays = new VirtualDisplayBuilder(this).build(3); 326 destroyVirtualDisplays(); 327 getDisplayStateAfterChange(1); 328 } 329 330 /** 331 * Tests launching an activity on virtual display. 332 */ 333 @Presubmit testLaunchActivityOnSecondaryDisplay()334 public void testLaunchActivityOnSecondaryDisplay() throws Exception { 335 if (!supportsMultiDisplay()) { return; } 336 337 // Create new virtual display. 338 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 339 340 // Launch activity on new secondary display. 341 final String logSeparator = clearLogcat(); 342 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 343 mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME}); 344 345 mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused", 346 TEST_ACTIVITY_NAME); 347 348 // Check that activity is on the right display. 349 final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 350 final ActivityManagerState.ActivityStack frontStack 351 = mAmWmState.getAmState().getStackById(frontStackId); 352 assertEquals("Launched activity must be on the secondary display and resumed", 353 getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity); 354 mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId); 355 356 // Check that activity config corresponds to display config. 357 final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY_NAME, 358 logSeparator); 359 assertEquals("Activity launched on secondary display must have proper configuration", 360 CUSTOM_DENSITY_DPI, reportedSizes.densityDpi); 361 } 362 363 /** 364 * Tests launching a non-resizeable activity on virtual display. It should land on the 365 * default display. 366 */ testLaunchNonResizeableActivityOnSecondaryDisplay()367 public void testLaunchNonResizeableActivityOnSecondaryDisplay() throws Exception { 368 if (!supportsMultiDisplay()) { return; } 369 370 // Create new virtual display. 371 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 372 373 // Launch activity on new secondary display. 374 launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId); 375 mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY_NAME}); 376 377 mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused", 378 NON_RESIZEABLE_ACTIVITY_NAME); 379 380 // Check that activity is on the right display. 381 final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID); 382 final ActivityManagerState.ActivityStack frontStack = 383 mAmWmState.getAmState().getStackById(frontStackId); 384 assertEquals("Launched activity must be on the primary display and resumed", 385 getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME), 386 frontStack.mResumedActivity); 387 mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId); 388 } 389 390 /** 391 * Tests launching a non-resizeable activity on virtual display while split-screen is active 392 * on the primary display. It should land on the primary display and dismiss docked stack. 393 */ testLaunchNonResizeableActivityWithSplitScreen()394 public void testLaunchNonResizeableActivityWithSplitScreen() throws Exception { 395 if (!supportsMultiDisplay() || !supportsSplitScreenMultiWindow()) { return; } 396 397 // Start launching activity. 398 launchActivityInDockStack(LAUNCHING_ACTIVITY); 399 // Create new virtual display. 400 final DisplayState newDisplay = 401 new VirtualDisplayBuilder(this).setLaunchInSplitScreen(true).build(); 402 403 // Launch activity on new secondary display. 404 launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId); 405 mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY_NAME}); 406 407 mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused", 408 NON_RESIZEABLE_ACTIVITY_NAME); 409 410 // Check that activity is on the right display. 411 final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID); 412 final ActivityManagerState.ActivityStack frontStack = 413 mAmWmState.getAmState().getStackById(frontStackId); 414 assertEquals("Launched activity must be on the primary display and resumed", 415 getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME), 416 frontStack.mResumedActivity); 417 mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId); 418 mAmWmState.assertDoesNotContainStack("Must not contain docked stack.", DOCKED_STACK_ID); 419 } 420 421 /** 422 * Tests moving a non-resizeable activity to a virtual display. It should land on the default 423 * display. 424 */ testMoveNonResizeableActivityToSecondaryDisplay()425 public void testMoveNonResizeableActivityToSecondaryDisplay() throws Exception { 426 if (!supportsMultiDisplay()) { return; } 427 428 // Create new virtual display. 429 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 430 // Launch a non-resizeable activity on a primary display. 431 launchActivityInNewTask(NON_RESIZEABLE_ACTIVITY_NAME); 432 // Launch a resizeable activity on new secondary display to create a new stack there. 433 launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId); 434 int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 435 436 // Try to move the non-resizeable activity to new secondary display. 437 moveActivityToStack(NON_RESIZEABLE_ACTIVITY_NAME, frontStackId); 438 mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY_NAME}); 439 440 mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused", 441 NON_RESIZEABLE_ACTIVITY_NAME); 442 443 // Check that activity is on the right display. 444 frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID); 445 final ActivityManagerState.ActivityStack frontStack = 446 mAmWmState.getAmState().getStackById(frontStackId); 447 assertEquals("Launched activity must be on the primary display and resumed", 448 getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME), 449 frontStack.mResumedActivity); 450 mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId); 451 } 452 453 /** 454 * Tests launching a non-resizeable activity on virtual display from activity there. It should 455 * land on the secondary display based on the resizeability of the root activity of the task. 456 */ testLaunchNonResizeableActivityFromSecondaryDisplaySameTask()457 public void testLaunchNonResizeableActivityFromSecondaryDisplaySameTask() throws Exception { 458 if (!supportsMultiDisplay()) { return; } 459 460 // Create new virtual display. 461 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 462 463 // Launch activity on new secondary display. 464 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mDisplayId); 465 mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused", 466 LAUNCHING_ACTIVITY); 467 468 // Check that launching activity is on the secondary display. 469 int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 470 ActivityManagerState.ActivityStack frontStack = 471 mAmWmState.getAmState().getStackById(frontStackId); 472 assertEquals("Launched activity must be on the secondary display and resumed", 473 getActivityComponentName(LAUNCHING_ACTIVITY), 474 frontStack.mResumedActivity); 475 mAmWmState.assertFocusedStack("Focus must be on the secondary display", frontStackId); 476 477 // Launch non-resizeable activity from secondary display. 478 getLaunchActivityBuilder().setTargetActivityName(NON_RESIZEABLE_ACTIVITY_NAME).execute(); 479 480 // Check that non-resizeable activity is on the secondary display, because of the resizeable 481 // root of the task. 482 frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 483 frontStack = mAmWmState.getAmState().getStackById(frontStackId); 484 assertEquals("Launched activity must be on the primary display and resumed", 485 getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME), 486 frontStack.mResumedActivity); 487 mAmWmState.assertFocusedStack("Focus must be on the primary display", frontStackId); 488 } 489 490 /** 491 * Tests launching a non-resizeable activity on virtual display from activity there. It should 492 * land on some different suitable display (usually - on the default one). 493 */ testLaunchNonResizeableActivityFromSecondaryDisplayNewTask()494 public void testLaunchNonResizeableActivityFromSecondaryDisplayNewTask() throws Exception { 495 if (!supportsMultiDisplay()) { return; } 496 497 // Create new virtual display. 498 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 499 500 // Launch activity on new secondary display. 501 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mDisplayId); 502 mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused", 503 LAUNCHING_ACTIVITY); 504 505 // Check that launching activity is on the secondary display. 506 int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 507 ActivityManagerState.ActivityStack frontStack = 508 mAmWmState.getAmState().getStackById(frontStackId); 509 assertEquals("Launched activity must be on the secondary display and resumed", 510 getActivityComponentName(LAUNCHING_ACTIVITY), 511 frontStack.mResumedActivity); 512 mAmWmState.assertFocusedStack("Focus must be on the secondary display", frontStackId); 513 514 // Launch non-resizeable activity from secondary display. 515 getLaunchActivityBuilder().setTargetActivityName(NON_RESIZEABLE_ACTIVITY_NAME) 516 .setNewTask(true).setMultipleTask(true).execute(); 517 518 // Check that non-resizeable activity is on the primary display. 519 frontStackId = mAmWmState.getAmState().getFocusedStackId(); 520 frontStack = mAmWmState.getAmState().getStackById(frontStackId); 521 assertFalse("Launched activity must be on a different display", 522 newDisplay.mDisplayId == frontStack.mDisplayId); 523 assertEquals("Launched activity must be resumed", 524 getActivityComponentName(NON_RESIZEABLE_ACTIVITY_NAME), 525 frontStack.mResumedActivity); 526 mAmWmState.assertFocusedStack("Focus must be on a just launched activity", frontStackId); 527 } 528 529 /** 530 * Tests launching a not embedded activity on virtual display. It should land on the 531 * default display. 532 */ testLaunchNotEmbeddedOnVirtualDisplay()533 public void testLaunchNotEmbeddedOnVirtualDisplay() throws Exception { 534 if (!supportsMultiDisplay()) { return; } 535 536 // Create new virtual display. 537 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 538 539 final String logSeparator = clearLogcat(); 540 541 // Launch other activity with different uid and check it is launched on primary display. 542 final String broadcastAction = SECOND_PACKAGE_NAME + ".LAUNCH_BROADCAST_ACTION"; 543 final String includeStoppedPackagesFlag = " -f 0x00000020"; 544 executeShellCommand("am broadcast -a " + broadcastAction + " -p " + SECOND_PACKAGE_NAME 545 + " --ei target_display " + newDisplay.mDisplayId + includeStoppedPackagesFlag 546 + " --es package_name " + componentName 547 + " --es target_activity " + TEST_ACTIVITY_NAME); 548 549 int tries = 0; 550 boolean match = false; 551 final Pattern pattern = Pattern.compile(".*SecurityException launching activity.*"); 552 while (tries < 5 && !match) { 553 String[] logs = getDeviceLogsForComponent("LaunchBroadcastReceiver", logSeparator); 554 for (String line : logs) { 555 Matcher m = pattern.matcher(line); 556 if (m.matches()) { 557 match = true; 558 break; 559 } 560 } 561 tries++; 562 try { 563 Thread.sleep(500); 564 } catch (InterruptedException e) { 565 } 566 } 567 568 assertTrue("Expected exception not found", match); 569 570 mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME}); 571 assertFalse("Restricted activity must not be launched", 572 mAmWmState.getAmState().containsActivity(TEST_ACTIVITY_NAME)); 573 } 574 575 /** 576 * Tests launching an activity on virtual display and then launching another activity via shell 577 * command and without specifying the display id - the second activity must appear on the 578 * primary display. 579 */ 580 @Presubmit testConsequentLaunchActivity()581 public void testConsequentLaunchActivity() throws Exception { 582 if (!supportsMultiDisplay()) { return; } 583 584 // Create new virtual display. 585 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 586 587 // Launch activity on new secondary display. 588 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 589 mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME}); 590 591 mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused", 592 TEST_ACTIVITY_NAME); 593 594 // Launch second activity without specifying display. 595 launchActivity(LAUNCHING_ACTIVITY); 596 mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY}); 597 598 // Check that activity is launched in focused stack on primary display. 599 mAmWmState.assertFocusedActivity("Launched activity must be focused", LAUNCHING_ACTIVITY); 600 final int frontStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID); 601 final ActivityManagerState.ActivityStack frontStack 602 = mAmWmState.getAmState().getStackById(frontStackId); 603 assertEquals("Launched activity must be resumed in front stack", 604 getActivityComponentName(LAUNCHING_ACTIVITY), frontStack.mResumedActivity); 605 assertEquals("Front stack must be on primary display", 606 DEFAULT_DISPLAY_ID, frontStack.mDisplayId); 607 } 608 609 /** 610 * Tests launching an activity on virtual display and then launching another activity from the 611 * first one - it must appear on the secondary display, because it was launched from there. 612 */ 613 @Presubmit testConsequentLaunchActivityFromSecondaryDisplay()614 public void testConsequentLaunchActivityFromSecondaryDisplay() throws Exception { 615 if (!supportsMultiDisplay()) { return; } 616 617 // Create new virtual display. 618 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 619 620 // Launch activity on new secondary display. 621 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mDisplayId); 622 mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY}); 623 624 mAmWmState.assertFocusedActivity("Activity launched on secondary display must be resumed", 625 LAUNCHING_ACTIVITY); 626 627 // Launch second activity from app on secondary display without specifying display id. 628 getLaunchActivityBuilder().setTargetActivityName(TEST_ACTIVITY_NAME).execute(); 629 mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME}); 630 631 // Check that activity is launched in focused stack on external display. 632 mAmWmState.assertFocusedActivity("Launched activity must be focused", TEST_ACTIVITY_NAME); 633 final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 634 final ActivityManagerState.ActivityStack frontStack 635 = mAmWmState.getAmState().getStackById(frontStackId); 636 assertEquals("Launched activity must be resumed in front stack", 637 getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity); 638 } 639 640 /** 641 * Tests launching activities on secondary and then on primary display to see if the stack 642 * visibility is not affected. 643 */ 644 @Presubmit testLaunchActivitiesAffectsVisibility()645 public void testLaunchActivitiesAffectsVisibility() throws Exception { 646 if (!supportsMultiDisplay()) { return; } 647 648 // Start launching activity. 649 launchActivity(LAUNCHING_ACTIVITY); 650 // Create new virtual display. 651 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 652 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 653 654 // Launch activity on new secondary display. 655 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 656 mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */); 657 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 658 659 // Launch activity on primary display and check if it doesn't affect activity on secondary 660 // display. 661 getLaunchActivityBuilder().setTargetActivityName(RESIZEABLE_ACTIVITY_NAME).execute(); 662 mAmWmState.waitForValidState(mDevice, RESIZEABLE_ACTIVITY_NAME); 663 mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */); 664 mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */); 665 } 666 667 /** 668 * Test that move-task works when moving between displays. 669 */ 670 @Presubmit testMoveTaskBetweenDisplays()671 public void testMoveTaskBetweenDisplays() throws Exception { 672 if (!supportsMultiDisplay()) { return; } 673 674 // Create new virtual display. 675 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 676 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 677 mAmWmState.assertFocusedActivity("Virtual display activity must be focused", 678 VIRTUAL_DISPLAY_ACTIVITY); 679 final int defaultDisplayStackId = mAmWmState.getAmState().getFocusedStackId(); 680 ActivityManagerState.ActivityStack focusedStack 681 = mAmWmState.getAmState().getStackById(defaultDisplayStackId); 682 assertEquals("Focus must remain on primary display", DEFAULT_DISPLAY_ID, 683 focusedStack.mDisplayId); 684 685 // Launch activity on new secondary display. 686 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 687 mAmWmState.assertFocusedActivity("Focus must be on secondary display", TEST_ACTIVITY_NAME); 688 int focusedStackId = mAmWmState.getAmState().getFocusedStackId(); 689 focusedStack = mAmWmState.getAmState().getStackById(focusedStackId); 690 assertEquals("Focused stack must be on secondary display", 691 newDisplay.mDisplayId, focusedStack.mDisplayId); 692 693 // Move activity from secondary display to primary. 694 moveActivityToStack(TEST_ACTIVITY_NAME, defaultDisplayStackId); 695 mAmWmState.waitForFocusedStack(mDevice, defaultDisplayStackId); 696 mAmWmState.assertFocusedActivity("Focus must be on moved activity", TEST_ACTIVITY_NAME); 697 focusedStackId = mAmWmState.getAmState().getFocusedStackId(); 698 focusedStack = mAmWmState.getAmState().getStackById(focusedStackId); 699 assertEquals("Focus must return to primary display", DEFAULT_DISPLAY_ID, 700 focusedStack.mDisplayId); 701 } 702 703 /** 704 * Tests launching activities on secondary display and then removing it to see if stack focus 705 * is moved correctly. 706 * This version launches virtual display creator to fullscreen stack in split-screen. 707 */ 708 @Presubmit testStackFocusSwitchOnDisplayRemoved()709 public void testStackFocusSwitchOnDisplayRemoved() throws Exception { 710 if (!supportsMultiDisplay() || !supportsSplitScreenMultiWindow()) { return; } 711 712 // Start launching activity into docked stack. 713 launchActivityInDockStack(LAUNCHING_ACTIVITY); 714 mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */); 715 716 tryCreatingAndRemovingDisplayWithActivity(true /* splitScreen */, 717 FULLSCREEN_WORKSPACE_STACK_ID); 718 } 719 720 /** 721 * Tests launching activities on secondary display and then removing it to see if stack focus 722 * is moved correctly. 723 * This version launches virtual display creator to docked stack in split-screen. 724 */ testStackFocusSwitchOnDisplayRemoved2()725 public void testStackFocusSwitchOnDisplayRemoved2() throws Exception { 726 if (!supportsMultiDisplay() || !supportsSplitScreenMultiWindow()) { return; } 727 728 // Setup split-screen. 729 launchActivityInDockStack(RESIZEABLE_ACTIVITY_NAME); 730 731 // Start launching activity into fullscreen stack. 732 launchActivityInStack(LAUNCHING_ACTIVITY, FULLSCREEN_WORKSPACE_STACK_ID); 733 mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */); 734 735 tryCreatingAndRemovingDisplayWithActivity(true /* splitScreen */, 736 FULLSCREEN_WORKSPACE_STACK_ID); 737 } 738 739 /** 740 * Tests launching activities on secondary display and then removing it to see if stack focus 741 * is moved correctly. 742 * This version works without split-screen. 743 */ testStackFocusSwitchOnDisplayRemoved3()744 public void testStackFocusSwitchOnDisplayRemoved3() throws Exception { 745 if (!supportsMultiDisplay()) { return; } 746 747 // Start an activity on default display to determine default stack. 748 launchActivity(BROADCAST_RECEIVER_ACTIVITY); 749 final int focusedStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID); 750 // Finish probing activity. 751 executeShellCommand(FINISH_ACTIVITY_BROADCAST); 752 753 754 tryCreatingAndRemovingDisplayWithActivity(false /* splitScreen */, focusedStackId); 755 } 756 757 /** 758 * Create a virtual display, launch a test activity there, destroy the display and check if test 759 * activity is moved to a stack on the default display. 760 */ tryCreatingAndRemovingDisplayWithActivity(boolean splitScreen, int defaultStackId)761 private void tryCreatingAndRemovingDisplayWithActivity(boolean splitScreen, int defaultStackId) 762 throws Exception { 763 // Create new virtual display. 764 final VirtualDisplayBuilder builder = new VirtualDisplayBuilder(this) 765 .setPublicDisplay(true); 766 if (splitScreen) { 767 builder.setLaunchInSplitScreen(true); 768 } 769 final DisplayState newDisplay = builder.build(); 770 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 771 if (splitScreen) { 772 mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */); 773 } 774 775 // Launch activity on new secondary display. 776 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 777 mAmWmState.assertFocusedActivity("Focus must be on secondary display", 778 TEST_ACTIVITY_NAME); 779 final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 780 mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId); 781 782 // Destroy virtual display. 783 destroyVirtualDisplays(); 784 mAmWmState.waitForValidState(mDevice, TEST_ACTIVITY_NAME, defaultStackId); 785 mAmWmState.assertSanity(); 786 mAmWmState.assertValidBounds(true /* compareTaskAndStackBounds */); 787 788 // Check if the focus is switched back to primary display. 789 mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */); 790 mAmWmState.assertFocusedStack( 791 "Default stack on primary display must be focused after display removed", 792 defaultStackId); 793 mAmWmState.assertFocusedActivity( 794 "Focus must be switched back to activity on primary display", 795 TEST_ACTIVITY_NAME); 796 } 797 798 /** 799 * Tests launching activities on secondary display and then removing it to see if stack focus 800 * is moved correctly. 801 */ testStackFocusSwitchOnStackEmptied()802 public void testStackFocusSwitchOnStackEmptied() throws Exception { 803 if (!supportsMultiDisplay()) { return; } 804 805 // Create new virtual display. 806 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 807 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 808 final int focusedStackId = mAmWmState.getAmState().getFrontStackId(DEFAULT_DISPLAY_ID); 809 810 // Launch activity on new secondary display. 811 launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mDisplayId); 812 mAmWmState.assertFocusedActivity("Focus must be on secondary display", 813 BROADCAST_RECEIVER_ACTIVITY); 814 815 // Lock the device, so that activity containers will be detached. 816 sleepDevice(); 817 818 // Finish activity on secondary display. 819 executeShellCommand(FINISH_ACTIVITY_BROADCAST); 820 821 // Unlock and check if the focus is switched back to primary display. 822 wakeUpAndUnlockDevice(); 823 mAmWmState.waitForFocusedStack(mDevice, focusedStackId); 824 mAmWmState.waitForValidState(mDevice, VIRTUAL_DISPLAY_ACTIVITY); 825 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 826 mAmWmState.assertFocusedActivity("Focus must be switched back to primary display", 827 VIRTUAL_DISPLAY_ACTIVITY); 828 } 829 830 /** 831 * Tests that input events on the primary display take focus from the virtual display. 832 */ testStackFocusSwitchOnTouchEvent()833 public void testStackFocusSwitchOnTouchEvent() throws Exception { 834 if (!supportsMultiDisplay()) { return; } 835 836 // Create new virtual display. 837 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 838 839 mAmWmState.computeState(mDevice, new String[] {VIRTUAL_DISPLAY_ACTIVITY}); 840 mAmWmState.assertFocusedActivity("Focus must be switched back to primary display", 841 VIRTUAL_DISPLAY_ACTIVITY); 842 843 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 844 845 mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME}); 846 mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused", 847 TEST_ACTIVITY_NAME); 848 849 final ReportedDisplayMetrics displayMetrics = getDisplayMetrics(); 850 final int width = displayMetrics.getWidth(); 851 final int height = displayMetrics.getHeight(); 852 executeShellCommand("input tap " + (width / 2) + " " + (height / 2)); 853 854 mAmWmState.computeState(mDevice, new String[] {VIRTUAL_DISPLAY_ACTIVITY}); 855 mAmWmState.assertFocusedActivity("Focus must be switched back to primary display", 856 VIRTUAL_DISPLAY_ACTIVITY); 857 } 858 859 /** Test that system is allowed to launch on secondary displays. */ testPermissionLaunchFromSystem()860 public void testPermissionLaunchFromSystem() throws Exception { 861 if (!supportsMultiDisplay()) { return; } 862 863 // Create new virtual display. 864 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 865 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 866 mAmWmState.assertFocusedActivity("Virtual display activity must be focused", 867 VIRTUAL_DISPLAY_ACTIVITY); 868 final int defaultDisplayFocusedStackId = mAmWmState.getAmState().getFocusedStackId(); 869 ActivityManagerState.ActivityStack focusedStack 870 = mAmWmState.getAmState().getStackById(defaultDisplayFocusedStackId); 871 assertEquals("Focus must remain on primary display", DEFAULT_DISPLAY_ID, 872 focusedStack.mDisplayId); 873 874 // Launch activity on new secondary display. 875 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 876 mAmWmState.assertFocusedActivity("Focus must be on secondary display", 877 TEST_ACTIVITY_NAME); 878 final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId(); 879 focusedStack = mAmWmState.getAmState().getStackById(externalFocusedStackId); 880 assertEquals("Focused stack must be on secondary display", newDisplay.mDisplayId, 881 focusedStack.mDisplayId); 882 883 // Launch other activity with different uid and check it is launched on dynamic stack on 884 // secondary display. 885 final String startCmd = "am start -n " + SECOND_PACKAGE_NAME + "/." + SECOND_ACTIVITY_NAME 886 + " --display " + newDisplay.mDisplayId; 887 executeShellCommand(startCmd); 888 889 mAmWmState.waitForValidState(mDevice, new String[] {SECOND_ACTIVITY_NAME}, 890 null /* stackIds */, false /* compareTaskAndStackBounds */, SECOND_PACKAGE_NAME); 891 mAmWmState.assertFocusedActivity("Focus must be on newly launched app", SECOND_PACKAGE_NAME, 892 SECOND_ACTIVITY_NAME); 893 assertEquals("Activity launched by system must be on external display", 894 externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId()); 895 } 896 897 /** Tests that an activity can launch an activity from a different UID into its own task. */ testPermissionLaunchMultiUidTask()898 public void testPermissionLaunchMultiUidTask() throws Exception { 899 if (!supportsMultiDisplay()) { return; } 900 901 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 902 903 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mDisplayId); 904 mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY}); 905 906 // Check that the first activity is launched onto the secondary display 907 final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 908 ActivityManagerState.ActivityStack frontStack = 909 mAmWmState.getAmState().getStackById(frontStackId); 910 assertEquals("Activity launched on secondary display must be resumed", 911 getActivityComponentName(LAUNCHING_ACTIVITY), 912 frontStack.mResumedActivity); 913 mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId); 914 915 // Launch an activity from a different UID into the first activity's task 916 getLaunchActivityBuilder() 917 .setTargetPackage(SECOND_PACKAGE_NAME) 918 .setTargetActivityName(SECOND_ACTIVITY_NAME).execute(); 919 920 mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId); 921 frontStack = mAmWmState.getAmState().getStackById(frontStackId); 922 mAmWmState.assertFocusedActivity("Focus must be on newly launched app", 923 SECOND_PACKAGE_NAME, SECOND_ACTIVITY_NAME); 924 assertEquals("Secondary display must contain 1 task", 1, frontStack.getTasks().size()); 925 } 926 927 /** 928 * Test that launching from app that is not present on external display and doesn't own it to 929 * that external display is not allowed. 930 */ testPermissionLaunchFromDifferentApp()931 public void testPermissionLaunchFromDifferentApp() throws Exception { 932 if (!supportsMultiDisplay()) { return; } 933 934 // Create new virtual display. 935 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 936 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 937 mAmWmState.assertFocusedActivity("Virtual display activity must be focused", 938 VIRTUAL_DISPLAY_ACTIVITY); 939 final int defaultDisplayFocusedStackId = mAmWmState.getAmState().getFocusedStackId(); 940 ActivityManagerState.ActivityStack focusedStack 941 = mAmWmState.getAmState().getStackById(defaultDisplayFocusedStackId); 942 assertEquals("Focus must remain on primary display", DEFAULT_DISPLAY_ID, 943 focusedStack.mDisplayId); 944 945 // Launch activity on new secondary display. 946 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 947 mAmWmState.assertFocusedActivity("Focus must be on secondary display", 948 TEST_ACTIVITY_NAME); 949 final int externalFocusedStackId = mAmWmState.getAmState().getFocusedStackId(); 950 focusedStack = mAmWmState.getAmState().getStackById(externalFocusedStackId); 951 assertEquals("Focused stack must be on secondary display", newDisplay.mDisplayId, 952 focusedStack.mDisplayId); 953 954 final String logSeparator = clearLogcat(); 955 956 // Launch other activity with different uid and check it is launched on primary display. 957 final String broadcastAction = SECOND_PACKAGE_NAME + ".LAUNCH_BROADCAST_ACTION"; 958 final String includeStoppedPackagesFlag = " -f 0x00000020"; 959 executeShellCommand("am broadcast -a " + broadcastAction + " -p " + SECOND_PACKAGE_NAME 960 + " --ei target_display " + newDisplay.mDisplayId + includeStoppedPackagesFlag); 961 962 int tries = 0; 963 boolean match = false; 964 final Pattern pattern = Pattern.compile(".*SecurityException launching activity.*"); 965 while (tries < 5 && !match) { 966 String[] logs = getDeviceLogsForComponent("LaunchBroadcastReceiver", logSeparator); 967 for (String line : logs) { 968 Matcher m = pattern.matcher(line); 969 if (m.matches()) { 970 match = true; 971 break; 972 } 973 } 974 tries++; 975 try { 976 Thread.sleep(500); 977 } catch (InterruptedException e) { 978 } 979 } 980 981 assertTrue("Expected exception not found", match); 982 983 mAmWmState.waitForValidState(mDevice, new String[] {TEST_ACTIVITY_NAME}, 984 null /* stackIds */, false /* compareTaskAndStackBounds */, componentName); 985 mAmWmState.assertFocusedActivity( 986 "Focus must be on first activity", componentName, TEST_ACTIVITY_NAME); 987 assertEquals("Focused stack must be on secondary display's stack", 988 externalFocusedStackId, mAmWmState.getAmState().getFocusedStackId()); 989 } 990 991 /** 992 * Test that all activities that were on the private display are destroyed on display removal. 993 */ 994 @Presubmit testContentDestroyOnDisplayRemoved()995 public void testContentDestroyOnDisplayRemoved() throws Exception { 996 if (!supportsMultiDisplay()) { return; } 997 998 // Create new private virtual display. 999 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 1000 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 1001 1002 // Launch activities on new secondary display. 1003 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 1004 mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */); 1005 mAmWmState.assertFocusedActivity("Launched activity must be focused", TEST_ACTIVITY_NAME); 1006 launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId); 1007 mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */); 1008 mAmWmState.assertFocusedActivity("Launched activity must be focused", 1009 RESIZEABLE_ACTIVITY_NAME); 1010 1011 // Destroy the display and check if activities are removed from system. 1012 final String logSeparator = clearLogcat(); 1013 destroyVirtualDisplays(); 1014 final String activityName1 1015 = ActivityManagerTestBase.getActivityComponentName(TEST_ACTIVITY_NAME); 1016 final String activityName2 1017 = ActivityManagerTestBase.getActivityComponentName(RESIZEABLE_ACTIVITY_NAME); 1018 final String windowName1 1019 = ActivityManagerTestBase.getWindowName(TEST_ACTIVITY_NAME); 1020 final String windowName2 1021 = ActivityManagerTestBase.getWindowName(RESIZEABLE_ACTIVITY_NAME); 1022 mAmWmState.waitForWithAmState(mDevice, 1023 (state) -> !state.containsActivity(activityName1) 1024 && !state.containsActivity(activityName2), 1025 "Waiting for activity to be removed"); 1026 mAmWmState.waitForWithWmState(mDevice, 1027 (state) -> !state.containsWindow(windowName1) 1028 && !state.containsWindow(windowName2), 1029 "Waiting for activity window to be gone"); 1030 1031 // Check AM state. 1032 assertFalse("Activity from removed display must be destroyed", 1033 mAmWmState.getAmState().containsActivity(activityName1)); 1034 assertFalse("Activity from removed display must be destroyed", 1035 mAmWmState.getAmState().containsActivity(activityName2)); 1036 // Check WM state. 1037 assertFalse("Activity windows from removed display must be destroyed", 1038 mAmWmState.getWmState().containsWindow(windowName1)); 1039 assertFalse("Activity windows from removed display must be destroyed", 1040 mAmWmState.getWmState().containsWindow(windowName2)); 1041 // Check activity logs. 1042 assertActivityDestroyed(TEST_ACTIVITY_NAME, logSeparator); 1043 assertActivityDestroyed(RESIZEABLE_ACTIVITY_NAME, logSeparator); 1044 } 1045 1046 /** 1047 * Test that the update of display metrics updates all its content. 1048 */ 1049 @Presubmit testDisplayResize()1050 public void testDisplayResize() throws Exception { 1051 if (!supportsMultiDisplay()) { return; } 1052 1053 // Create new virtual display. 1054 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 1055 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 1056 1057 // Launch a resizeable activity on new secondary display. 1058 final String initialLogSeparator = clearLogcat(); 1059 launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId); 1060 mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */); 1061 mAmWmState.assertFocusedActivity("Launched activity must be focused", 1062 RESIZEABLE_ACTIVITY_NAME); 1063 1064 // Grab reported sizes and compute new with slight size change. 1065 final ReportedSizes initialSize = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY_NAME, 1066 initialLogSeparator); 1067 1068 // Resize the docked stack, so that activity with virtual display will also be resized. 1069 final String logSeparator = clearLogcat(); 1070 executeShellCommand(getResizeVirtualDisplayCommand()); 1071 1072 mAmWmState.waitForWithAmState(mDevice, amState -> { 1073 try { 1074 return readConfigChangeNumber(RESIZEABLE_ACTIVITY_NAME, logSeparator) == 1 1075 && amState.hasActivityState(RESIZEABLE_ACTIVITY_NAME, STATE_RESUMED); 1076 } catch (Exception e) { 1077 logE("Error waiting for valid state: " + e.getMessage()); 1078 return false; 1079 } 1080 }, "Wait for the configuration change to happen and for activity to be resumed."); 1081 1082 mAmWmState.computeState(mDevice, new String[] {RESIZEABLE_ACTIVITY_NAME, 1083 VIRTUAL_DISPLAY_ACTIVITY}, false /* compareTaskAndStackBounds */); 1084 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true); 1085 mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true); 1086 1087 // Check if activity in virtual display was resized properly. 1088 assertRelaunchOrConfigChanged(RESIZEABLE_ACTIVITY_NAME, 0 /* numRelaunch */, 1089 1 /* numConfigChange */, logSeparator); 1090 1091 final ReportedSizes updatedSize = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY_NAME, 1092 logSeparator); 1093 assertTrue(updatedSize.widthDp <= initialSize.widthDp); 1094 assertTrue(updatedSize.heightDp <= initialSize.heightDp); 1095 assertTrue(updatedSize.displayWidth == initialSize.displayWidth / 2); 1096 assertTrue(updatedSize.displayHeight == initialSize.displayHeight / 2); 1097 } 1098 1099 /** Read the number of configuration changes sent to activity from logs. */ readConfigChangeNumber(String activityName, String logSeparator)1100 private int readConfigChangeNumber(String activityName, String logSeparator) throws Exception { 1101 return (new ActivityLifecycleCounts(activityName, logSeparator)).mConfigurationChangedCount; 1102 } 1103 1104 /** 1105 * Tests that when an activity is launched with displayId specified and there is an existing 1106 * matching task on some other display - that task will moved to the target display. 1107 */ testMoveToDisplayOnLaunch()1108 public void testMoveToDisplayOnLaunch() throws Exception { 1109 if (!supportsMultiDisplay()) { return; } 1110 1111 // Launch activity with unique affinity, so it will the only one in its task. 1112 launchActivity(LAUNCHING_ACTIVITY); 1113 1114 // Create new virtual display. 1115 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 1116 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 1117 final int defaultDisplayStackId = mAmWmState.getAmState().getFocusedStackId(); 1118 // Launch something to that display so that a new stack is created. We need this to be able 1119 // to compare task numbers in stacks later. 1120 launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId); 1121 mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */); 1122 1123 final int taskNum = mAmWmState.getAmState().getStackById(defaultDisplayStackId) 1124 .getTasks().size(); 1125 final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 1126 final int taskNumOnSecondary = mAmWmState.getAmState().getStackById(frontStackId) 1127 .getTasks().size(); 1128 1129 // Launch activity on new secondary display. 1130 // Using custom command here, because normally we add flags Intent#FLAG_ACTIVITY_NEW_TASK 1131 // and Intent#FLAG_ACTIVITY_MULTIPLE_TASK when launching on some specific display. We don't 1132 // do it here as we want an existing task to be used. 1133 final String launchCommand = "am start -n " + getActivityComponentName(LAUNCHING_ACTIVITY) 1134 + " --display " + newDisplay.mDisplayId; 1135 executeShellCommand(launchCommand); 1136 mAmWmState.waitForActivityState(mDevice, LAUNCHING_ACTIVITY, STATE_RESUMED); 1137 1138 // Check that activity is brought to front. 1139 mAmWmState.assertFocusedActivity("Existing task must be brought to front", 1140 LAUNCHING_ACTIVITY); 1141 mAmWmState.assertResumedActivity("Existing task must be resumed", LAUNCHING_ACTIVITY); 1142 1143 // Check that activity is on the right display. 1144 final ActivityManagerState.ActivityStack firstFrontStack = 1145 mAmWmState.getAmState().getStackById(frontStackId); 1146 assertEquals("Activity must be moved to the secondary display", 1147 getActivityComponentName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity); 1148 mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId); 1149 1150 // Check that task has moved from primary display to secondary. 1151 final int taskNumFinal = mAmWmState.getAmState().getStackById(defaultDisplayStackId) 1152 .getTasks().size(); 1153 mAmWmState.assertEquals("Task number in default stack must be decremented.", taskNum - 1, 1154 taskNumFinal); 1155 final int taskNumFinalOnSecondary = mAmWmState.getAmState().getStackById(frontStackId) 1156 .getTasks().size(); 1157 mAmWmState.assertEquals("Task number in stack on external display must be incremented.", 1158 taskNumOnSecondary + 1, taskNumFinalOnSecondary); 1159 } 1160 1161 /** 1162 * Tests that when primary display is rotated secondary displays are not affected. 1163 */ testRotationNotAffectingSecondaryScreen()1164 public void testRotationNotAffectingSecondaryScreen() throws Exception { 1165 if (!supportsMultiDisplay()) { return; } 1166 1167 // Create new virtual display. 1168 final DisplayState newDisplay = new VirtualDisplayBuilder(this) 1169 .setResizeDisplay(false) 1170 .build(); 1171 mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 1172 1173 // Launch activity on new secondary display. 1174 String logSeparator = clearLogcat(); 1175 launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId); 1176 mAmWmState.assertFocusedActivity("Focus must be on secondary display", 1177 RESIZEABLE_ACTIVITY_NAME); 1178 final ReportedSizes initialSizes = getLastReportedSizesForActivity( 1179 RESIZEABLE_ACTIVITY_NAME, logSeparator); 1180 assertNotNull("Test activity must have reported initial sizes on launch", initialSizes); 1181 1182 // Rotate primary display and check that activity on secondary display is not affected. 1183 rotateAndCheckSameSizes(RESIZEABLE_ACTIVITY_NAME); 1184 1185 // Launch activity to secondary display when primary one is rotated. 1186 final int initialRotation = mAmWmState.getWmState().getRotation(); 1187 setDeviceRotation((initialRotation + 1) % 4); 1188 1189 logSeparator = clearLogcat(); 1190 launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId); 1191 mAmWmState.waitForActivityState(mDevice, TEST_ACTIVITY_NAME, STATE_RESUMED); 1192 mAmWmState.assertFocusedActivity("Focus must be on secondary display", 1193 TEST_ACTIVITY_NAME); 1194 final ReportedSizes testActivitySizes = getLastReportedSizesForActivity( 1195 TEST_ACTIVITY_NAME, logSeparator); 1196 assertEquals("Sizes of secondary display must not change after rotation of primary display", 1197 initialSizes, testActivitySizes); 1198 } 1199 rotateAndCheckSameSizes(String activityName)1200 private void rotateAndCheckSameSizes(String activityName) throws Exception { 1201 for (int rotation = 3; rotation >= 0; --rotation) { 1202 final String logSeparator = clearLogcat(); 1203 setDeviceRotation(rotation); 1204 final ReportedSizes rotatedSizes = getLastReportedSizesForActivity(activityName, 1205 logSeparator); 1206 assertNull("Sizes must not change after rotation", rotatedSizes); 1207 } 1208 } 1209 1210 /** 1211 * Tests that task affinity does affect what display an activity is launched on but that 1212 * matching the task component root does. 1213 */ testTaskMatchAcrossDisplays()1214 public void testTaskMatchAcrossDisplays() throws Exception { 1215 if (!supportsMultiDisplay()) { return; } 1216 1217 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 1218 1219 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mDisplayId); 1220 mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY}); 1221 1222 // Check that activity is on the right display. 1223 final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 1224 final ActivityManagerState.ActivityStack firstFrontStack = 1225 mAmWmState.getAmState().getStackById(frontStackId); 1226 assertEquals("Activity launched on secondary display must be resumed", 1227 getActivityComponentName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity); 1228 mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId); 1229 1230 executeShellCommand("am start -n " + getActivityComponentName(ALT_LAUNCHING_ACTIVITY)); 1231 mAmWmState.waitForValidState(mDevice, new String[] {ALT_LAUNCHING_ACTIVITY}, 1232 null /* stackIds */, false /* compareTaskAndStackBounds */, componentName); 1233 1234 // Check that second activity gets launched on the default display 1235 final int defaultDisplayFrontStackId = mAmWmState.getAmState().getFrontStackId( 1236 DEFAULT_DISPLAY_ID); 1237 final ActivityManagerState.ActivityStack defaultDisplayFrontStack = 1238 mAmWmState.getAmState().getStackById(defaultDisplayFrontStackId); 1239 assertEquals("Activity launched on default display must be resumed", 1240 getActivityComponentName(ALT_LAUNCHING_ACTIVITY), 1241 defaultDisplayFrontStack.mResumedActivity); 1242 mAmWmState.assertFocusedStack("Focus must be on primary display", 1243 defaultDisplayFrontStackId); 1244 1245 executeShellCommand("am start -n " + getActivityComponentName(LAUNCHING_ACTIVITY)); 1246 mAmWmState.waitForFocusedStack(mDevice, frontStackId); 1247 1248 // Check that the third intent is redirected to the first task 1249 final ActivityManagerState.ActivityStack secondFrontStack 1250 = mAmWmState.getAmState().getStackById(frontStackId); 1251 assertEquals("Activity launched on default display must be resumed", 1252 getActivityComponentName(LAUNCHING_ACTIVITY), secondFrontStack.mResumedActivity); 1253 mAmWmState.assertFocusedStack("Focus must be on primary display", frontStackId); 1254 assertEquals("Focused stack must only contain 1 task", 1255 1, secondFrontStack.getTasks().size()); 1256 assertEquals("Focused task must only contain 1 activity", 1257 1, secondFrontStack.getTasks().get(0).mActivities.size()); 1258 } 1259 1260 /** 1261 * Tests than a new task launched by an activity will end up on that activity's display 1262 * even if the focused stack is not on that activity's display. 1263 */ testNewTaskSameDisplay()1264 public void testNewTaskSameDisplay() throws Exception { 1265 if (!supportsMultiDisplay()) { return; } 1266 1267 final DisplayState newDisplay = new VirtualDisplayBuilder(this).build(); 1268 1269 launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mDisplayId); 1270 mAmWmState.computeState(mDevice, new String[] {BROADCAST_RECEIVER_ACTIVITY}); 1271 1272 // Check that the first activity is launched onto the secondary display 1273 final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId); 1274 final ActivityManagerState.ActivityStack firstFrontStack = 1275 mAmWmState.getAmState().getStackById(frontStackId); 1276 assertEquals("Activity launched on secondary display must be resumed", 1277 getActivityComponentName(BROADCAST_RECEIVER_ACTIVITY), 1278 firstFrontStack.mResumedActivity); 1279 mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId); 1280 1281 executeShellCommand("am start -n " + getActivityComponentName(TEST_ACTIVITY_NAME)); 1282 mAmWmState.waitForValidState(mDevice, new String[] {TEST_ACTIVITY_NAME}, 1283 null /* stackIds */, false /* compareTaskAndStackBounds */, componentName); 1284 1285 // Check that the second activity is launched on the default display 1286 final int focusedStackId = mAmWmState.getAmState().getFocusedStackId(); 1287 final ActivityManagerState.ActivityStack focusedStack 1288 = mAmWmState.getAmState().getStackById(focusedStackId); 1289 assertEquals("Activity launched on default display must be resumed", 1290 getActivityComponentName(TEST_ACTIVITY_NAME), focusedStack.mResumedActivity); 1291 assertEquals("Focus must be on primary display", DEFAULT_DISPLAY_ID, 1292 focusedStack.mDisplayId); 1293 1294 executeShellCommand("am broadcast -a trigger_broadcast --ez launch_activity true " 1295 + "--ez new_task true --es target_activity " + LAUNCHING_ACTIVITY); 1296 1297 // Check that the third activity ends up in a new task in the same stack as the 1298 // first activity 1299 mAmWmState.waitForValidState(mDevice, new String[] {LAUNCHING_ACTIVITY}, 1300 null /* stackIds */, false /* compareTaskAndStackBounds */, componentName); 1301 mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId); 1302 final ActivityManagerState.ActivityStack secondFrontStack = 1303 mAmWmState.getAmState().getStackById(frontStackId); 1304 assertEquals("Activity must be launched on secondary display", 1305 getActivityComponentName(LAUNCHING_ACTIVITY), 1306 secondFrontStack.mResumedActivity); 1307 assertEquals("Secondary display must contain 2 tasks", 1308 2, secondFrontStack.getTasks().size()); 1309 } 1310 1311 /** 1312 * Test that display overrides apply correctly and won't be affected by display changes. 1313 * This sets overrides to display size and density, initiates a display changed event by locking 1314 * and unlocking the phone and verifies that overrides are kept. 1315 */ 1316 @Presubmit testForceDisplayMetrics()1317 public void testForceDisplayMetrics() throws Exception { 1318 launchHomeActivity(); 1319 1320 // Read initial sizes. 1321 final ReportedDisplayMetrics originalDisplayMetrics = getDisplayMetrics(); 1322 1323 // Apply new override values that don't match the physical metrics. 1324 final int overrideWidth = (int) (originalDisplayMetrics.physicalWidth * 1.5); 1325 final int overrideHeight = (int) (originalDisplayMetrics.physicalHeight * 1.5); 1326 executeShellCommand(WM_SIZE + " " + overrideWidth + "x" + overrideHeight); 1327 final int overrideDensity = (int) (originalDisplayMetrics.physicalDensity * 1.1); 1328 executeShellCommand(WM_DENSITY + " " + overrideDensity); 1329 1330 // Check if overrides applied correctly. 1331 ReportedDisplayMetrics displayMetrics = getDisplayMetrics(); 1332 assertEquals(overrideWidth, displayMetrics.overrideWidth); 1333 assertEquals(overrideHeight, displayMetrics.overrideHeight); 1334 assertEquals(overrideDensity, displayMetrics.overrideDensity); 1335 1336 // Lock and unlock device. This will cause a DISPLAY_CHANGED event to be triggered and 1337 // might update the metrics. 1338 sleepDevice(); 1339 wakeUpAndUnlockDevice(); 1340 mAmWmState.waitForHomeActivityVisible(mDevice); 1341 1342 // Check if overrides are still applied. 1343 displayMetrics = getDisplayMetrics(); 1344 assertEquals(overrideWidth, displayMetrics.overrideWidth); 1345 assertEquals(overrideHeight, displayMetrics.overrideHeight); 1346 assertEquals(overrideDensity, displayMetrics.overrideDensity); 1347 1348 // All overrides will be cleared in tearDown. 1349 } 1350 1351 /** Get physical and override display metrics from WM. */ getDisplayMetrics()1352 private ReportedDisplayMetrics getDisplayMetrics() throws Exception { 1353 mDumpLines.clear(); 1354 final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver(); 1355 mDevice.executeShellCommand(WM_SIZE, outputReceiver); 1356 mDevice.executeShellCommand(WM_DENSITY, outputReceiver); 1357 final String dump = outputReceiver.getOutput(); 1358 mDumpLines.clear(); 1359 Collections.addAll(mDumpLines, dump.split("\\n")); 1360 return ReportedDisplayMetrics.create(mDumpLines); 1361 } 1362 1363 private static class ReportedDisplayMetrics { 1364 private static final Pattern sPhysicalSizePattern = 1365 Pattern.compile("Physical size: (\\d+)x(\\d+)"); 1366 private static final Pattern sOverrideSizePattern = 1367 Pattern.compile("Override size: (\\d+)x(\\d+)"); 1368 private static final Pattern sPhysicalDensityPattern = 1369 Pattern.compile("Physical density: (\\d+)"); 1370 private static final Pattern sOverrideDensityPattern = 1371 Pattern.compile("Override density: (\\d+)"); 1372 1373 int physicalWidth; 1374 int physicalHeight; 1375 int physicalDensity; 1376 1377 boolean sizeOverrideSet; 1378 int overrideWidth; 1379 int overrideHeight; 1380 boolean densityOverrideSet; 1381 int overrideDensity; 1382 1383 /** Get width that WM operates with. */ getWidth()1384 int getWidth() { 1385 return sizeOverrideSet ? overrideWidth : physicalWidth; 1386 } 1387 1388 /** Get height that WM operates with. */ getHeight()1389 int getHeight() { 1390 return sizeOverrideSet ? overrideHeight : physicalHeight; 1391 } 1392 1393 /** Get density that WM operates with. */ getDensity()1394 int getDensity() { 1395 return densityOverrideSet ? overrideDensity : physicalDensity; 1396 } 1397 create(LinkedList<String> dump)1398 static ReportedDisplayMetrics create(LinkedList<String> dump) { 1399 final ReportedDisplayMetrics result = new ReportedDisplayMetrics(); 1400 1401 boolean physicalSizeFound = false; 1402 boolean physicalDensityFound = false; 1403 1404 while (!dump.isEmpty()) { 1405 final String line = dump.pop().trim(); 1406 1407 Matcher matcher = sPhysicalSizePattern.matcher(line); 1408 if (matcher.matches()) { 1409 physicalSizeFound = true; 1410 log(line); 1411 result.physicalWidth = Integer.parseInt(matcher.group(1)); 1412 result.physicalHeight = Integer.parseInt(matcher.group(2)); 1413 continue; 1414 } 1415 1416 matcher = sOverrideSizePattern.matcher(line); 1417 if (matcher.matches()) { 1418 log(line); 1419 result.overrideWidth = Integer.parseInt(matcher.group(1)); 1420 result.overrideHeight = Integer.parseInt(matcher.group(2)); 1421 result.sizeOverrideSet = true; 1422 continue; 1423 } 1424 1425 matcher = sPhysicalDensityPattern.matcher(line); 1426 if (matcher.matches()) { 1427 physicalDensityFound = true; 1428 log(line); 1429 result.physicalDensity = Integer.parseInt(matcher.group(1)); 1430 continue; 1431 } 1432 1433 matcher = sOverrideDensityPattern.matcher(line); 1434 if (matcher.matches()) { 1435 log(line); 1436 result.overrideDensity = Integer.parseInt(matcher.group(1)); 1437 result.densityOverrideSet = true; 1438 continue; 1439 } 1440 } 1441 1442 assertTrue("Physical display size must be reported", physicalSizeFound); 1443 assertTrue("Physical display density must be reported", physicalDensityFound); 1444 1445 return result; 1446 } 1447 } 1448 1449 /** Assert that component received onMovedToDisplay and onConfigurationChanged callbacks. */ assertMovedToDisplay(String componentName, String logSeparator)1450 private void assertMovedToDisplay(String componentName, String logSeparator) throws Exception { 1451 final ActivityLifecycleCounts lifecycleCounts 1452 = new ActivityLifecycleCounts(componentName, logSeparator); 1453 if (lifecycleCounts.mDestroyCount != 0) { 1454 fail(componentName + " has been destroyed " + lifecycleCounts.mDestroyCount 1455 + " time(s), wasn't expecting any"); 1456 } else if (lifecycleCounts.mCreateCount != 0) { 1457 fail(componentName + " has been (re)created " + lifecycleCounts.mCreateCount 1458 + " time(s), wasn't expecting any"); 1459 } else if (lifecycleCounts.mConfigurationChangedCount != 1) { 1460 fail(componentName + " has received " 1461 + lifecycleCounts.mConfigurationChangedCount 1462 + " onConfigurationChanged() calls, expecting " + 1); 1463 } else if (lifecycleCounts.mMovedToDisplayCount != 1) { 1464 fail(componentName + " has received " 1465 + lifecycleCounts.mMovedToDisplayCount 1466 + " onMovedToDisplay() calls, expecting " + 1); 1467 } 1468 } 1469 getResizeVirtualDisplayCommand()1470 private static String getResizeVirtualDisplayCommand() { 1471 return getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY) + " -f 0x20000000" + 1472 " --es command resize_display"; 1473 } 1474 } 1475