1 /* 2 * Copyright (C) 2019 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.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 23 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; 24 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; 25 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; 26 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 27 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; 28 import static android.server.wm.ActivityLauncher.KEY_ACTION; 29 import static android.server.wm.ActivityLauncher.KEY_LAUNCH_ACTIVITY; 30 import static android.server.wm.ActivityLauncher.KEY_LAUNCH_IMPLICIT; 31 import static android.server.wm.ActivityLauncher.KEY_LAUNCH_PENDING; 32 import static android.server.wm.ActivityLauncher.KEY_NEW_TASK; 33 import static android.server.wm.ActivityLauncher.KEY_USE_APPLICATION_CONTEXT; 34 import static android.server.wm.CliIntentExtra.extraBool; 35 import static android.server.wm.CliIntentExtra.extraString; 36 import static android.server.wm.ComponentNameUtils.getActivityName; 37 import static android.server.wm.ShellCommandHelper.executeShellCommand; 38 import static android.server.wm.UiDeviceUtils.pressHomeButton; 39 import static android.server.wm.WindowManagerState.STATE_DESTROYED; 40 import static android.server.wm.WindowManagerState.STATE_RESUMED; 41 import static android.server.wm.WindowManagerState.STATE_STOPPED; 42 import static android.server.wm.app.Components.ALT_LAUNCHING_ACTIVITY; 43 import static android.server.wm.app.Components.BROADCAST_RECEIVER_ACTIVITY; 44 import static android.server.wm.app.Components.LAUNCHING_ACTIVITY; 45 import static android.server.wm.app.Components.NON_RESIZEABLE_ACTIVITY; 46 import static android.server.wm.app.Components.NO_HISTORY_ACTIVITY; 47 import static android.server.wm.app.Components.NO_HISTORY_ACTIVITY2; 48 import static android.server.wm.app.Components.RESIZEABLE_ACTIVITY; 49 import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_ACTIVITY; 50 import static android.server.wm.app.Components.SINGLE_TOP_ACTIVITY; 51 import static android.server.wm.app.Components.TEST_ACTIVITY; 52 import static android.server.wm.app.Components.TOP_ACTIVITY; 53 import static android.server.wm.app.Components.VIRTUAL_DISPLAY_ACTIVITY; 54 import static android.server.wm.second.Components.IMPLICIT_TARGET_SECOND_ACTIVITY; 55 import static android.server.wm.second.Components.IMPLICIT_TARGET_SECOND_TEST_ACTION; 56 import static android.server.wm.second.Components.SECOND_ACTIVITY; 57 import static android.server.wm.second.Components.SECOND_LAUNCH_BROADCAST_ACTION; 58 import static android.server.wm.second.Components.SECOND_LAUNCH_BROADCAST_RECEIVER; 59 import static android.server.wm.third.Components.THIRD_ACTIVITY; 60 import static android.view.Display.DEFAULT_DISPLAY; 61 62 import static org.junit.Assert.assertEquals; 63 import static org.junit.Assert.assertFalse; 64 import static org.junit.Assert.assertNotEquals; 65 import static org.junit.Assert.assertTrue; 66 import static org.junit.Assume.assumeTrue; 67 68 import android.app.Activity; 69 import android.app.ActivityOptions; 70 import android.app.PendingIntent; 71 import android.content.ComponentName; 72 import android.content.Context; 73 import android.content.Intent; 74 import android.content.res.Configuration; 75 import android.hardware.display.DisplayManager; 76 import android.hardware.display.VirtualDisplay; 77 import android.os.Bundle; 78 import android.platform.test.annotations.Presubmit; 79 import android.server.wm.CommandSession.ActivitySession; 80 import android.server.wm.CommandSession.SizeInfo; 81 import android.server.wm.WindowManagerState.DisplayContent; 82 import android.server.wm.WindowManagerState.Task; 83 import android.view.SurfaceView; 84 85 import org.junit.Before; 86 import org.junit.Test; 87 88 /** 89 * Build/Install/Run: 90 * atest CtsWindowManagerDeviceTestCases:MultiDisplayActivityLaunchTests 91 * 92 * Tests activity launching behavior on multi-display environment. 93 */ 94 @Presubmit 95 @android.server.wm.annotation.Group3 96 public class MultiDisplayActivityLaunchTests extends MultiDisplayTestBase { 97 98 @Before 99 @Override setUp()100 public void setUp() throws Exception { 101 super.setUp(); 102 assumeTrue(supportsMultiDisplay()); 103 } 104 105 /** 106 * Tests launching an activity on virtual display. 107 */ 108 @Test testLaunchActivityOnSecondaryDisplay()109 public void testLaunchActivityOnSecondaryDisplay() throws Exception { 110 validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_STANDARD); 111 } 112 113 /** 114 * Tests launching a recent activity on virtual display. 115 */ 116 @Test testLaunchRecentActivityOnSecondaryDisplay()117 public void testLaunchRecentActivityOnSecondaryDisplay() throws Exception { 118 validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_RECENTS); 119 } 120 121 /** 122 * Tests launching an assistant activity on virtual display. 123 */ 124 @Test testLaunchAssistantActivityOnSecondaryDisplay()125 public void testLaunchAssistantActivityOnSecondaryDisplay() { 126 validateActivityLaunchOnNewDisplay(ACTIVITY_TYPE_ASSISTANT); 127 } 128 validateActivityLaunchOnNewDisplay(int activityType)129 private void validateActivityLaunchOnNewDisplay(int activityType) { 130 // Create new virtual display. 131 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 132 .setSimulateDisplay(true).createDisplay(); 133 134 // Launch activity on new secondary display. 135 separateTestJournal(); 136 getLaunchActivityBuilder().setUseInstrumentation().setWithShellPermission(true) 137 .setTargetActivity(TEST_ACTIVITY).setNewTask(true) 138 .setMultipleTask(true).setActivityType(activityType) 139 .setDisplayId(newDisplay.mId).execute(); 140 waitAndAssertTopResumedActivity(TEST_ACTIVITY, newDisplay.mId, 141 "Activity launched on secondary display must be focused and on top"); 142 143 // Check that activity config corresponds to display config. 144 final SizeInfo reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY); 145 assertEquals("Activity launched on secondary display must have proper configuration", 146 CUSTOM_DENSITY_DPI, reportedSizes.densityDpi); 147 148 assertEquals("Top activity must have correct activity type", activityType, 149 mWmState.getFrontRootTaskActivityType(newDisplay.mId)); 150 } 151 152 /** 153 * Tests launching an activity on primary display explicitly. 154 */ 155 @Test testLaunchActivityOnPrimaryDisplay()156 public void testLaunchActivityOnPrimaryDisplay() throws Exception { 157 // Launch activity on primary display explicitly. 158 launchActivityOnDisplay(LAUNCHING_ACTIVITY, DEFAULT_DISPLAY); 159 160 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, DEFAULT_DISPLAY, 161 "Activity launched on primary display must be focused and on top"); 162 163 // Launch another activity on primary display using the first one 164 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).setNewTask(true) 165 .setMultipleTask(true).setDisplayId(DEFAULT_DISPLAY).execute(); 166 mWmState.computeState(TEST_ACTIVITY); 167 168 waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY, 169 "Activity launched on primary display must be focused"); 170 } 171 172 /** 173 * Tests launching an existing activity from an activity that resides on secondary display. An 174 * existing activity on a different display should be moved to the display of the launching 175 * activity. 176 */ 177 @Test testLaunchActivityFromSecondaryDisplay()178 public void testLaunchActivityFromSecondaryDisplay() { 179 getLaunchActivityBuilder().setUseInstrumentation() 180 .setTargetActivity(TEST_ACTIVITY).setNewTask(true) 181 .setDisplayId(DEFAULT_DISPLAY).execute(); 182 183 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 184 .setSimulateDisplay(true) 185 .createDisplay(); 186 final int newDisplayId = newDisplay.mId; 187 188 getLaunchActivityBuilder().setUseInstrumentation() 189 .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY).setNewTask(true) 190 .setDisplayId(newDisplayId).execute(); 191 waitAndAssertTopResumedActivity(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId, 192 "Activity should be resumed on secondary display"); 193 194 mayLaunchHomeActivityForCar(); 195 mBroadcastActionTrigger.launchActivityNewTask(getActivityName(TEST_ACTIVITY)); 196 waitAndAssertTopResumedActivity(TEST_ACTIVITY, newDisplayId, 197 "Activity should be resumed on secondary display"); 198 199 getLaunchActivityBuilder().setUseInstrumentation() 200 .setTargetActivity(TEST_ACTIVITY).setNewTask(true) 201 .setDisplayId(DEFAULT_DISPLAY).execute(); 202 waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY, 203 "Activity should be the top resumed on default display"); 204 } 205 206 /** 207 * Tests that an activity can be launched on a secondary display while the primary 208 * display is off. 209 */ 210 @Test testLaunchExternalDisplayActivityWhilePrimaryOff()211 public void testLaunchExternalDisplayActivityWhilePrimaryOff() { 212 // Leanback devices may launch a live broadcast app during screen off-on cycles. 213 final boolean mayLaunchActivityOnScreenOff = isLeanBack(); 214 215 // Launch something on the primary display so we know there is a resumed activity there 216 launchActivity(RESIZEABLE_ACTIVITY); 217 waitAndAssertTopResumedActivity(RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY, 218 "Activity launched on primary display must be resumed"); 219 220 final PrimaryDisplayStateSession displayStateSession = 221 mObjectTracker.manage(new PrimaryDisplayStateSession()); 222 final ExternalDisplaySession externalDisplaySession = createManagedExternalDisplaySession(); 223 displayStateSession.turnScreenOff(); 224 225 // Make sure there is no resumed activity when the primary display is off 226 if (!mayLaunchActivityOnScreenOff) { 227 waitAndAssertActivityState(RESIZEABLE_ACTIVITY, STATE_STOPPED, 228 "Activity launched on primary display must be stopped after turning off"); 229 assertEquals("Unexpected resumed activity", 230 0, mWmState.getResumedActivitiesCount()); 231 } 232 233 final DisplayContent newDisplay = externalDisplaySession 234 .setCanShowWithInsecureKeyguard(true).createVirtualDisplay(); 235 236 launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId); 237 238 // Check that the test activity is resumed on the external display 239 waitAndAssertActivityStateOnDisplay(TEST_ACTIVITY, STATE_RESUMED, newDisplay.mId, 240 "Activity launched on external display must be resumed"); 241 if (!mayLaunchActivityOnScreenOff) { 242 mWmState.assertFocusedAppOnDisplay("App on default display must still be focused", 243 RESIZEABLE_ACTIVITY, DEFAULT_DISPLAY); 244 } 245 } 246 247 /** 248 * Tests launching a non-resizeable activity on virtual display. It should land on the 249 * virtual display with correct configuration. 250 */ 251 @Test testLaunchNonResizeableActivityOnSecondaryDisplay()252 public void testLaunchNonResizeableActivityOnSecondaryDisplay() { 253 // Create new virtual display. 254 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 255 .setSimulateDisplay(true).createDisplay(); 256 257 // Launch activity on new secondary display. 258 launchActivityOnDisplay(NON_RESIZEABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN, newDisplay.mId); 259 260 waitAndAssertTopResumedActivity(NON_RESIZEABLE_ACTIVITY, newDisplay.mId, 261 "Activity requested to launch on secondary display must be focused"); 262 263 final Configuration taskConfig = mWmState 264 .getTaskByActivity(NON_RESIZEABLE_ACTIVITY).mFullConfiguration; 265 final Configuration displayConfig = mWmState 266 .getDisplay(newDisplay.mId).mFullConfiguration; 267 268 // Check that activity config corresponds to display config. 269 assertEquals("Activity launched on secondary display must have proper configuration", 270 taskConfig.densityDpi, displayConfig.densityDpi); 271 272 assertEquals("Activity launched on secondary display must have proper configuration", 273 taskConfig.windowConfiguration.getBounds(), 274 displayConfig.windowConfiguration.getBounds()); 275 } 276 277 /** 278 * Tests successfully moving a non-resizeable activity to a virtual display. 279 */ 280 @Test testMoveNonResizeableActivityToSecondaryDisplay()281 public void testMoveNonResizeableActivityToSecondaryDisplay() { 282 final VirtualDisplayLauncher virtualLauncher = 283 mObjectTracker.manage(new VirtualDisplayLauncher()); 284 // Create new virtual display. 285 final DisplayContent newDisplay = virtualLauncher 286 .setSimulateDisplay(true).createDisplay(); 287 // Launch a non-resizeable activity on a primary display. 288 final ActivitySession nonResizeableSession = virtualLauncher.launchActivity( 289 builder -> builder.setTargetActivity(NON_RESIZEABLE_ACTIVITY).setNewTask(true)); 290 291 // Launch a resizeable activity on new secondary display to create a new task there. 292 virtualLauncher.launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay); 293 final int externalFrontRootTaskId = mWmState 294 .getFrontRootTaskId(newDisplay.mId); 295 296 // Clear lifecycle callback history before moving the activity so the later verification 297 // can get the callbacks which are related to the reparenting. 298 nonResizeableSession.takeCallbackHistory(); 299 300 mayLaunchHomeActivityForCar(); 301 // Try to move the non-resizeable activity to the top of the root task on secondary display. 302 moveActivityToRootTaskOrOnTop(NON_RESIZEABLE_ACTIVITY, externalFrontRootTaskId); 303 // Wait for a while to check that it will move. 304 assertTrue("Non-resizeable activity should be moved", 305 mWmState.waitForWithAmState( 306 state -> newDisplay.mId == state 307 .getDisplayByActivity(NON_RESIZEABLE_ACTIVITY), 308 "seeing if activity won't be moved")); 309 310 waitAndAssertTopResumedActivity(NON_RESIZEABLE_ACTIVITY, newDisplay.mId, 311 "The moved non-resizeable activity must be focused"); 312 assertActivityLifecycle(nonResizeableSession, true /* relaunched */); 313 } 314 315 /** 316 * Tests launching a non-resizeable activity on virtual display from activity there. It should 317 * land on the secondary display based on the resizeability of the root activity of the task. 318 */ 319 @Test testLaunchNonResizeableActivityFromSecondaryDisplaySameTask()320 public void testLaunchNonResizeableActivityFromSecondaryDisplaySameTask() { 321 // Create new simulated display. 322 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 323 .setSimulateDisplay(true) 324 .createDisplay(); 325 326 // Launch activity on new secondary display. 327 launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId); 328 waitAndAssertTopResumedActivity(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId, 329 "Activity launched on secondary display must be focused"); 330 331 // Launch non-resizeable activity from secondary display. 332 mBroadcastActionTrigger.launchActivityNewTask(getActivityName(NON_RESIZEABLE_ACTIVITY)); 333 waitAndAssertTopResumedActivity(NON_RESIZEABLE_ACTIVITY, newDisplay.mId, 334 "Launched activity must be on the secondary display and resumed"); 335 } 336 337 /** 338 * Tests launching a non-resizeable activity on virtual display in a new task from activity 339 * there. It must land on the display as its caller. 340 */ 341 @Test testLaunchNonResizeableActivityFromSecondaryDisplayNewTask()342 public void testLaunchNonResizeableActivityFromSecondaryDisplayNewTask() { 343 // Create new virtual display. 344 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 345 .setSimulateDisplay(true).createDisplay(); 346 347 // Launch activity on new secondary display. 348 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 349 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, newDisplay.mId, 350 "Activity launched on secondary display must be focused"); 351 352 // Launch non-resizeable activity from secondary display in a new task. 353 getLaunchActivityBuilder().setTargetActivity(NON_RESIZEABLE_ACTIVITY) 354 .setNewTask(true).setMultipleTask(true).execute(); 355 356 mWmState.waitForActivityState(NON_RESIZEABLE_ACTIVITY, STATE_RESUMED); 357 358 // Check that non-resizeable activity is on the same display. 359 final int newFrontRootTaskId = mWmState.getFocusedTaskId(); 360 final Task newFrontRootTask = mWmState.getRootTask(newFrontRootTaskId); 361 assertEquals("Launched activity must be on the same display", newDisplay.mId, 362 newFrontRootTask.mDisplayId); 363 assertEquals("Launched activity must be resumed", 364 getActivityName(NON_RESIZEABLE_ACTIVITY), 365 newFrontRootTask.mResumedActivity); 366 mWmState.assertFocusedRootTask( 367 "Top task must be the one with just launched activity", 368 newFrontRootTaskId); 369 mWmState.assertResumedActivity("NON_RESIZEABLE_ACTIVITY not resumed", 370 NON_RESIZEABLE_ACTIVITY); 371 } 372 373 /** 374 * Tests launching an activity on virtual display and then launching another activity 375 * via shell command and without specifying the display id - the second activity 376 * must appear on the same display due to process affinity. 377 */ 378 @Test testConsequentLaunchActivity()379 public void testConsequentLaunchActivity() { 380 // Create new virtual display. 381 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 382 .setSimulateDisplay(true).createDisplay(); 383 384 // Launch activity on new secondary display. 385 launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId); 386 387 waitAndAssertTopResumedActivity(TEST_ACTIVITY, newDisplay.mId, 388 "Activity launched on secondary display must be on top"); 389 390 // Launch second activity without specifying display. 391 launchActivity(LAUNCHING_ACTIVITY); 392 393 // Check that activity is launched in focused task on the new display. 394 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, newDisplay.mId, 395 "Launched activity must be focused"); 396 mWmState.assertResumedActivity("LAUNCHING_ACTIVITY must be resumed", LAUNCHING_ACTIVITY); 397 } 398 399 /** 400 * Tests launching an activity on a virtual display and then launching another activity in 401 * a new process via shell command and without specifying the display id - the second activity 402 * must appear on the primary display. 403 */ 404 @Test testConsequentLaunchActivityInNewProcess()405 public void testConsequentLaunchActivityInNewProcess() { 406 // Create new virtual display. 407 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 408 .setSimulateDisplay(true).createDisplay(); 409 410 // Launch activity on new secondary display. 411 launchActivityOnDisplay(TEST_ACTIVITY, newDisplay.mId); 412 413 waitAndAssertTopResumedActivity(TEST_ACTIVITY, newDisplay.mId, 414 "Activity launched on secondary display must be on top"); 415 416 // Launch second activity without specifying display. 417 launchActivity(SECOND_ACTIVITY); 418 419 // Check that activity is launched in focused task on primary display. 420 waitAndAssertTopResumedActivity(SECOND_ACTIVITY, DEFAULT_DISPLAY, 421 "Launched activity must be focused"); 422 assertBothDisplaysHaveResumedActivities(pair(newDisplay.mId, TEST_ACTIVITY), 423 pair(DEFAULT_DISPLAY, SECOND_ACTIVITY)); 424 } 425 426 /** 427 * Tests launching an activity on simulated display and then launching another activity from the 428 * first one - it must appear on the secondary display, because it was launched from there. 429 */ 430 @Test testConsequentLaunchActivityFromSecondaryDisplay()431 public void testConsequentLaunchActivityFromSecondaryDisplay() { 432 // Create new simulated display. 433 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 434 .setSimulateDisplay(true) 435 .createDisplay(); 436 437 // Launch activity on new secondary display. 438 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 439 440 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, newDisplay.mId, 441 "Activity launched on secondary display must be on top"); 442 443 // Launch second activity from app on secondary display without specifying display id. 444 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).execute(); 445 446 // Check that activity is launched in focused task on external display. 447 waitAndAssertTopResumedActivity(TEST_ACTIVITY, newDisplay.mId, 448 "Launched activity must be on top"); 449 } 450 451 /** 452 * Tests launching an activity on virtual display and then launching another activity from the 453 * first one - it must appear on the secondary display, because it was launched from there. 454 */ 455 @Test testConsequentLaunchActivityFromVirtualDisplay()456 public void testConsequentLaunchActivityFromVirtualDisplay() { 457 // Create new virtual display. 458 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 459 .setSimulateDisplay(true).createDisplay(); 460 461 // Launch activity on new secondary display. 462 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 463 464 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, newDisplay.mId, 465 "Activity launched on secondary display must be on top"); 466 467 // Launch second activity from app on secondary display without specifying display id. 468 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).execute(); 469 mWmState.computeState(TEST_ACTIVITY); 470 471 // Check that activity is launched in focused task on external display. 472 waitAndAssertTopResumedActivity(TEST_ACTIVITY, newDisplay.mId, 473 "Launched activity must be on top"); 474 } 475 476 /** 477 * Tests launching an activity on virtual display and then launching another activity from the 478 * first one with specifying the target display - it must appear on the secondary display. 479 */ 480 @Test testConsequentLaunchActivityFromVirtualDisplayToTargetDisplay()481 public void testConsequentLaunchActivityFromVirtualDisplayToTargetDisplay() { 482 // Create new virtual display. 483 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 484 .setSimulateDisplay(true).createDisplay(); 485 486 // Launch activity on new secondary display. 487 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 488 489 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, newDisplay.mId, 490 "Activity launched on secondary display must be on top"); 491 492 // Launch second activity from app on secondary display specifying same display id. 493 getLaunchActivityBuilder() 494 .setTargetActivity(SECOND_ACTIVITY) 495 .setDisplayId(newDisplay.mId) 496 .execute(); 497 498 // Check that activity is launched in focused task on external display. 499 waitAndAssertTopResumedActivity(SECOND_ACTIVITY, newDisplay.mId, 500 "Launched activity must be on top"); 501 502 // Launch other activity with different uid and check if it has launched successfully. 503 getLaunchActivityBuilder() 504 .setUseBroadcastReceiver(SECOND_LAUNCH_BROADCAST_RECEIVER, 505 SECOND_LAUNCH_BROADCAST_ACTION) 506 .setDisplayId(newDisplay.mId) 507 .setTargetActivity(THIRD_ACTIVITY) 508 .execute(); 509 510 // Check that activity is launched in focused task on external display. 511 waitAndAssertTopResumedActivity(THIRD_ACTIVITY, newDisplay.mId, 512 "Launched activity must be on top"); 513 } 514 515 /** 516 * Tests that when an {@link Activity} is running on one display but is started from a second 517 * display then the {@link Activity} is moved to the second display. 518 */ 519 @Test testLaunchExistingActivityReparentDisplay()520 public void testLaunchExistingActivityReparentDisplay() { 521 // Create new virtual display. 522 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 523 .setSimulateDisplay(true).createDisplay(); 524 525 launchActivityOnDisplay(SECOND_ACTIVITY, DEFAULT_DISPLAY); 526 527 waitAndAssertTopResumedActivity(SECOND_ACTIVITY, DEFAULT_DISPLAY, 528 "Must launch activity on same display."); 529 530 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId, 531 extraBool(KEY_USE_APPLICATION_CONTEXT, true), extraBool(KEY_NEW_TASK, true), 532 extraBool(KEY_LAUNCH_ACTIVITY, true), extraBool(KEY_LAUNCH_IMPLICIT, true), 533 extraString(KEY_ACTION, IMPLICIT_TARGET_SECOND_TEST_ACTION)); 534 535 waitAndAssertTopResumedActivity(IMPLICIT_TARGET_SECOND_ACTIVITY, newDisplay.mId, 536 "Must launch activity on same display."); 537 } 538 539 /** 540 * Tests launching an activity to secondary display from activity on primary display. 541 */ 542 @Test testLaunchActivityFromAppToSecondaryDisplay()543 public void testLaunchActivityFromAppToSecondaryDisplay() { 544 // Start launching activity. 545 launchActivity(LAUNCHING_ACTIVITY); 546 547 // Create new simulated display. 548 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 549 .setSimulateDisplay(true) 550 .createDisplay(); 551 552 // Launch activity on secondary display from the app on primary display. 553 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY) 554 .setDisplayId(newDisplay.mId).execute(); 555 556 // Check that activity is launched on external display. 557 waitAndAssertTopResumedActivity(TEST_ACTIVITY, newDisplay.mId, 558 "Activity launched on secondary display must be focused"); 559 assertBothDisplaysHaveResumedActivities(pair(DEFAULT_DISPLAY, LAUNCHING_ACTIVITY), 560 pair(newDisplay.mId, TEST_ACTIVITY)); 561 } 562 563 /** Tests that launching app from pending activity queue on external display is allowed. */ 564 @Test testLaunchPendingActivityOnSecondaryDisplay()565 public void testLaunchPendingActivityOnSecondaryDisplay() { 566 pressHomeButton(); 567 // Create new simulated display. 568 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 569 .setSimulateDisplay(true) 570 .createDisplay(); 571 final Bundle bundle = ActivityOptions.makeBasic(). 572 setLaunchDisplayId(newDisplay.mId).toBundle(); 573 final Intent intent = new Intent(Intent.ACTION_VIEW) 574 .setComponent(SECOND_ACTIVITY) 575 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) 576 .putExtra(KEY_LAUNCH_ACTIVITY, true) 577 .putExtra(KEY_NEW_TASK, true); 578 mContext.startActivity(intent, bundle); 579 580 // If home key was pressed, stopAppSwitches will be called. 581 // Since this test case is not start activity from shell, it won't grant 582 // STOP_APP_SWITCHES and this activity should be put into pending activity queue 583 // and this activity should been launched after 584 // ActivityTaskManagerService.APP_SWITCH_DELAY_TIME 585 mWmState.waitForPendingActivityContain(SECOND_ACTIVITY); 586 // If the activity is not pending, skip this test. 587 mWmState.assumePendingActivityContain(SECOND_ACTIVITY); 588 // In order to speed up test case without waiting for APP_SWITCH_DELAY_TIME, we launch 589 // another activity with LaunchActivityBuilder, in this way the activity can be start 590 // directly and also trigger pending activity to be launched. 591 getLaunchActivityBuilder() 592 .setTargetActivity(THIRD_ACTIVITY) 593 .execute(); 594 mWmState.waitForValidState(SECOND_ACTIVITY); 595 waitAndAssertTopResumedActivity(THIRD_ACTIVITY, DEFAULT_DISPLAY, 596 "Top activity must be the newly launched one"); 597 mWmState.assertVisibility(SECOND_ACTIVITY, true); 598 assertEquals("Activity launched by app on secondary display must be on that display", 599 newDisplay.mId, mWmState.getDisplayByActivity(SECOND_ACTIVITY)); 600 } 601 602 /** 603 * Tests that when an activity is launched with displayId specified and there is an existing 604 * matching task on some other display - that task will moved to the target display. 605 */ 606 @Test testMoveToDisplayOnLaunch()607 public void testMoveToDisplayOnLaunch() { 608 // Launch activity with unique affinity, so it will the only one in its task. 609 launchActivity(LAUNCHING_ACTIVITY); 610 611 // Create new virtual display. 612 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 613 mWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 614 // Launch something to that display so that a new task is created. We need this to be 615 // able to compare task numbers in tasks later. 616 launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId); 617 mWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */); 618 619 final int rootTaskNum = mWmState.getDisplay(DEFAULT_DISPLAY).mRootTasks.size(); 620 final int rootTaskNumOnSecondary = mWmState 621 .getDisplay(newDisplay.mId).mRootTasks.size(); 622 623 // Launch activity on new secondary display. 624 // Using custom command here, because normally we add flags 625 // {@link Intent#FLAG_ACTIVITY_NEW_TASK} and {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK} 626 // when launching on some specific display. We don't do it here as we want an existing 627 // task to be used. 628 final String launchCommand = "am start -n " + getActivityName(LAUNCHING_ACTIVITY) 629 + " --display " + newDisplay.mId; 630 executeShellCommand(launchCommand); 631 632 // Check that activity is brought to front. 633 waitAndAssertActivityStateOnDisplay(LAUNCHING_ACTIVITY, STATE_RESUMED, newDisplay.mId, 634 "Existing task must be brought to front"); 635 636 // Check that task has moved from primary display to secondary. 637 // Since it is 1-to-1 relationship between task and root task for standard type & 638 // fullscreen activity, we check the number of root tasks here 639 final int rootTaskNumFinal = mWmState.getDisplay(DEFAULT_DISPLAY) 640 .mRootTasks.size(); 641 assertEquals("Root task number in default root task must be decremented.", rootTaskNum - 1, 642 rootTaskNumFinal); 643 final int rootTaskNumFinalOnSecondary = mWmState 644 .getDisplay(newDisplay.mId).mRootTasks.size(); 645 assertEquals("Root task number on external display must be incremented.", 646 rootTaskNumOnSecondary + 1, rootTaskNumFinalOnSecondary); 647 } 648 649 /** 650 * Tests that when an activity is launched with displayId specified and there is an existing 651 * matching task on some other display - that task will moved to the target display. 652 */ 653 @Test testMoveToEmptyDisplayOnLaunch()654 public void testMoveToEmptyDisplayOnLaunch() { 655 // Launch activity with unique affinity, so it will the only one in its task. And choose 656 // resizeable activity to prevent the test activity be relaunched when launch it to another 657 // display, which may affect on this test case. 658 launchActivity(RESIZEABLE_ACTIVITY); 659 660 // Create new virtual display. 661 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 662 mWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */); 663 664 final int rootTaskNum = mWmState.getDisplay(DEFAULT_DISPLAY).mRootTasks.size(); 665 666 // Launch activity on new secondary display. 667 // Using custom command here, because normally we add flags 668 // {@link Intent#FLAG_ACTIVITY_NEW_TASK} and {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK} 669 // when launching on some specific display. We don't do it here as we want an existing 670 // task to be used. 671 final String launchCommand = "am start -n " + getActivityName(RESIZEABLE_ACTIVITY) 672 + " --display " + newDisplay.mId; 673 executeShellCommand(launchCommand); 674 675 // Check that activity is brought to front. 676 waitAndAssertActivityStateOnDisplay(RESIZEABLE_ACTIVITY, STATE_RESUMED, newDisplay.mId, 677 "Existing task must be brought to front"); 678 679 // Check that task has moved from primary display to secondary. 680 final int rootTaskNumFinal = mWmState.getDisplay(DEFAULT_DISPLAY) 681 .mRootTasks.size(); 682 assertEquals("Root task number in default root task must be decremented.", rootTaskNum - 1, 683 rootTaskNumFinal); 684 } 685 686 /** 687 * Tests that if a second task has the same affinity as a running task but in a separate 688 * process the second task launches in the same display. 689 */ 690 @Test testLaunchSameAffinityLaunchesSameDisplay()691 public void testLaunchSameAffinityLaunchesSameDisplay() { 692 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 693 .setSimulateDisplay(true).createDisplay(); 694 695 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 696 mWmState.computeState(LAUNCHING_ACTIVITY); 697 698 // Check that activity is on the secondary display. 699 final int frontRootTaskId = mWmState.getFrontRootTaskId(newDisplay.mId); 700 final Task firstFrontRootTask = mWmState.getRootTask(frontRootTaskId); 701 assertEquals("Activity launched on secondary display must be resumed", 702 getActivityName(LAUNCHING_ACTIVITY), 703 firstFrontRootTask.mResumedActivity); 704 mWmState.assertFocusedRootTask("Top root task must be on secondary display", 705 frontRootTaskId); 706 707 executeShellCommand("am start -n " + getActivityName(ALT_LAUNCHING_ACTIVITY)); 708 mWmState.waitForValidState(ALT_LAUNCHING_ACTIVITY); 709 710 // Check that second activity gets launched on the default display despite 711 // the affinity match on the secondary display. 712 final int displayFrontRootTaskId = mWmState.getFrontRootTaskId(newDisplay.mId); 713 final Task displayFrontRootTask = mWmState.getRootTask(displayFrontRootTaskId); 714 waitAndAssertTopResumedActivity(ALT_LAUNCHING_ACTIVITY, newDisplay.mId, 715 "Activity launched on same display must be resumed"); 716 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 717 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, newDisplay.mId, 718 "Existing task must be brought to front"); 719 720 // Check that the third intent is redirected to the first task due to the root 721 // component match on the secondary display. 722 final Task secondFrontRootTask = mWmState.getRootTask(frontRootTaskId); 723 final int secondFrontRootTaskId = mWmState.getFrontRootTaskId(newDisplay.mId); 724 assertEquals("Activity launched on secondary display must be resumed", 725 getActivityName(ALT_LAUNCHING_ACTIVITY), 726 displayFrontRootTask.mResumedActivity); 727 mWmState.assertFocusedRootTask("Top root task must be on primary display", 728 secondFrontRootTaskId); 729 assertEquals("Second display must contain 2 root tasks", 2, 730 mWmState.getDisplay(newDisplay.mId).getRootTasks().size()); 731 assertEquals("Top task must contain 2 activities", 2, 732 secondFrontRootTask.getActivities().size()); 733 } 734 735 /** 736 * Tests that an activity is launched on the preferred display where the caller resided when 737 * both displays have matching tasks. 738 */ 739 @Test testTaskMatchOrderAcrossDisplays()740 public void testTaskMatchOrderAcrossDisplays() { 741 getLaunchActivityBuilder().setUseInstrumentation() 742 .setTargetActivity(TEST_ACTIVITY).setNewTask(true) 743 .setDisplayId(DEFAULT_DISPLAY).execute(); 744 final int rootTaskId = mWmState.getFrontRootTaskId(DEFAULT_DISPLAY); 745 746 getLaunchActivityBuilder().setUseInstrumentation() 747 .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY).setNewTask(true) 748 .setDisplayId(DEFAULT_DISPLAY).execute(); 749 750 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 751 getLaunchActivityBuilder().setUseInstrumentation().setWithShellPermission(true) 752 .setTargetActivity(TEST_ACTIVITY).setNewTask(true) 753 .setDisplayId(newDisplay.mId).execute(); 754 assertNotEquals("Top focus root task should not be on default display", 755 rootTaskId, mWmState.getFocusedTaskId()); 756 757 mBroadcastActionTrigger.launchActivityNewTask(getActivityName(TEST_ACTIVITY)); 758 waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY, 759 "Activity must be launched on default display"); 760 mWmState.assertFocusedRootTask("Top focus root task must be on the default display", 761 rootTaskId); 762 } 763 764 /** 765 * Tests that the task affinity search respects the launch display id. 766 */ 767 @Test testLaunchDisplayAffinityMatch()768 public void testLaunchDisplayAffinityMatch() { 769 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 770 .setSimulateDisplay(true).createDisplay(); 771 772 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 773 774 // Check that activity is on the secondary display. 775 final int frontRootTaskId = mWmState.getFrontRootTaskId(newDisplay.mId); 776 final Task firstFrontRootTask = mWmState.getRootTask(frontRootTaskId); 777 assertEquals("Activity launched on secondary display must be resumed", 778 getActivityName(LAUNCHING_ACTIVITY), firstFrontRootTask.mResumedActivity); 779 mWmState.assertFocusedRootTask("Focus must be on secondary display", frontRootTaskId); 780 781 // We don't want FLAG_ACTIVITY_MULTIPLE_TASK, so we can't use launchActivityOnDisplay 782 executeShellCommand("am start -n " + getActivityName(ALT_LAUNCHING_ACTIVITY) 783 + " -f 0x10000000" // FLAG_ACTIVITY_NEW_TASK 784 + " --display " + newDisplay.mId); 785 mWmState.computeState(ALT_LAUNCHING_ACTIVITY); 786 787 // Check that second activity gets launched into the affinity matching 788 // task on the secondary display 789 final int secondFrontRootTaskId = mWmState.getFrontRootTaskId(newDisplay.mId); 790 final Task secondFrontRootTask = 791 mWmState.getRootTask(secondFrontRootTaskId); 792 assertEquals("Activity launched on secondary display must be resumed", 793 getActivityName(ALT_LAUNCHING_ACTIVITY), 794 secondFrontRootTask.mResumedActivity); 795 mWmState.assertFocusedRootTask("Top root task must be on secondary display", 796 secondFrontRootTaskId); 797 assertEquals("Second display must only contain 1 task", 798 1, mWmState.getDisplay(newDisplay.mId).getRootTasks().size()); 799 assertEquals("Top root task must contain 2 activities", 800 2, secondFrontRootTask.getActivities().size()); 801 } 802 803 /** 804 * Tests that a new activity launched by an activity will end up on the same display 805 * even if the root task is not on the top for the display. 806 */ 807 @Test testNewTaskSameDisplay()808 public void testNewTaskSameDisplay() { 809 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 810 .setSimulateDisplay(true) 811 .createDisplay(); 812 813 launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId); 814 815 // Check that the first activity is launched onto the secondary display 816 waitAndAssertTopResumedActivity(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId, 817 "Activity launched on secondary display must be resumed"); 818 819 executeShellCommand("am start -n " + getActivityName(TEST_ACTIVITY)); 820 821 // Check that the second activity is launched on the same display 822 waitAndAssertTopResumedActivity(TEST_ACTIVITY, newDisplay.mId, 823 "Activity launched on default display must be resumed"); 824 825 mBroadcastActionTrigger.launchActivityNewTask(getActivityName(LAUNCHING_ACTIVITY)); 826 827 // Check that the third activity ends up in a new task in the same display where the 828 // first activity lands 829 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, newDisplay.mId, 830 "Activity must be launched on secondary display"); 831 assertEquals("Secondary display must contain 2 root tasks", 2, 832 mWmState.getDisplay(newDisplay.mId).mRootTasks.size()); 833 } 834 835 /** 836 * Tests that a new task launched by an activity will end up on the same display 837 * even if the focused task is not on that activity's display. 838 */ 839 @Test testNewTaskDefaultDisplay()840 public void testNewTaskDefaultDisplay() { 841 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 842 .setSimulateDisplay(true) 843 .createDisplay(); 844 845 launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId); 846 847 // Check that the first activity is launched onto the secondary display 848 waitAndAssertTopResumedActivity(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId, 849 "Activity launched on secondary display must be resumed"); 850 851 launchActivityOnDisplay(SECOND_ACTIVITY, DEFAULT_DISPLAY); 852 853 // Check that the second activity is launched on the default display because the affinity 854 // is different 855 waitAndAssertTopResumedActivity(SECOND_ACTIVITY, DEFAULT_DISPLAY, 856 "Activity launched on default display must be resumed"); 857 assertBothDisplaysHaveResumedActivities(pair(DEFAULT_DISPLAY, SECOND_ACTIVITY), 858 pair(newDisplay.mId, BROADCAST_RECEIVER_ACTIVITY)); 859 860 mBroadcastActionTrigger.launchActivityNewTask(getActivityName(LAUNCHING_ACTIVITY)); 861 862 // Check that the third activity ends up in a new task in the same display where the 863 // first activity lands 864 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, newDisplay.mId, 865 "Activity must be launched on secondary display"); 866 assertEquals("Secondary display must contain 2 root tasks", 2, 867 mWmState.getDisplay(newDisplay.mId).mRootTasks.size()); 868 assertBothDisplaysHaveResumedActivities(pair(DEFAULT_DISPLAY, SECOND_ACTIVITY), 869 pair(newDisplay.mId, LAUNCHING_ACTIVITY)); 870 } 871 872 /** 873 * Test that launching an activity implicitly will end up on the same display 874 */ 875 @Test testLaunchingFromApplicationContext()876 public void testLaunchingFromApplicationContext() { 877 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 878 .setSimulateDisplay(true) 879 .createDisplay(); 880 881 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId, 882 extraBool(KEY_LAUNCH_ACTIVITY, true), extraBool(KEY_LAUNCH_IMPLICIT, true), 883 extraBool(KEY_NEW_TASK, true), extraBool(KEY_USE_APPLICATION_CONTEXT, true), 884 extraString(KEY_ACTION, IMPLICIT_TARGET_SECOND_TEST_ACTION)); 885 waitAndAssertTopResumedActivity(IMPLICIT_TARGET_SECOND_ACTIVITY, newDisplay.mId, 886 "Implicitly launched activity must launch on the same display"); 887 } 888 889 /** 890 * Test that launching an activity from pending intent will end up on the same display 891 */ 892 @Test testLaunchingFromPendingIntent()893 public void testLaunchingFromPendingIntent() { 894 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 895 .setSimulateDisplay(true) 896 .createDisplay(); 897 898 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId, 899 extraBool(KEY_LAUNCH_ACTIVITY, true), 900 extraBool(KEY_LAUNCH_IMPLICIT, true), 901 extraBool(KEY_NEW_TASK, true), 902 extraBool(KEY_USE_APPLICATION_CONTEXT, true), 903 extraBool(KEY_LAUNCH_PENDING, true), 904 extraString(KEY_ACTION, IMPLICIT_TARGET_SECOND_TEST_ACTION)); 905 906 waitAndAssertTopResumedActivity(IMPLICIT_TARGET_SECOND_ACTIVITY, newDisplay.mId, 907 "Activity launched from pending intent must launch on the same display"); 908 } 909 910 /** 911 * Tests than an immediate launch after new display creation is handled correctly. 912 */ 913 @Test testImmediateLaunchOnNewDisplay()914 public void testImmediateLaunchOnNewDisplay() { 915 // Create new virtual display and immediately launch an activity on it. 916 SurfaceView surfaceView = new SurfaceView(mContext); 917 final VirtualDisplay virtualDisplay = mDm.createVirtualDisplay( 918 "testImmediateLaunchOnNewDisplay", /*width=*/ 400, /*height=*/ 400, 919 /*densityDpi=*/ 320, surfaceView.getHolder().getSurface(), 920 DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); 921 try { 922 int displayId = virtualDisplay.getDisplay().getDisplayId(); 923 ComponentName componentName = new ComponentName(mContext, 924 ImmediateLaunchTestActivity.class); 925 getLaunchActivityBuilder().setTargetActivity(componentName).setDisplayId( 926 displayId).setUseInstrumentation().execute(); 927 928 // Check that activity is launched and placed correctly. 929 waitAndAssertActivityStateOnDisplay(componentName, STATE_RESUMED, displayId, 930 "Test activity must be on top"); 931 final int frontRootTaskId = mWmState.getFrontRootTaskId(displayId); 932 final Task firstFrontRootTask = mWmState.getRootTask(frontRootTaskId); 933 assertEquals("Activity launched on secondary display must be resumed", 934 getActivityName(componentName), firstFrontRootTask.mResumedActivity); 935 } finally { 936 virtualDisplay.release(); 937 } 938 939 } 940 941 @Test testLaunchPendingIntentActivity()942 public void testLaunchPendingIntentActivity() throws Exception { 943 final DisplayContent displayContent = createManagedVirtualDisplaySession() 944 .setSimulateDisplay(true) 945 .createDisplay(); 946 947 // Activity should be launched on primary display by default. 948 getPendingIntentActivity(TEST_ACTIVITY).send(); 949 waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY, 950 "Activity launched on primary display and on top"); 951 952 final int resultCode = 1; 953 // Activity should be launched on target display according to the caller context. 954 final Context displayContext = 955 mContext.createDisplayContext(mDm.getDisplay(displayContent.mId)); 956 getPendingIntentActivity(TOP_ACTIVITY).send(displayContext, resultCode, null /* intent */); 957 waitAndAssertTopResumedActivity(TOP_ACTIVITY, displayContent.mId, 958 "Activity launched on secondary display and on top"); 959 960 // Activity should be brought to front on the same display if it already existed. 961 getPendingIntentActivity(TEST_ACTIVITY).send(displayContext, resultCode, null /* intent */); 962 waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY, 963 "Activity launched on primary display and on top"); 964 965 mayLaunchHomeActivityForCar(); 966 // Activity should be moved to target display. 967 final ActivityOptions options = ActivityOptions.makeBasic(); 968 options.setLaunchDisplayId(displayContent.mId); 969 getPendingIntentActivity(TEST_ACTIVITY).send(mContext, resultCode, null /* intent */, 970 null /* onFinished */, null /* handler */, null /* requiredPermission */, 971 options.toBundle()); 972 waitAndAssertTopResumedActivity(TEST_ACTIVITY, displayContent.mId, 973 "Activity launched on secondary display and on top"); 974 } 975 976 @Test testLaunchActivityClearTask()977 public void testLaunchActivityClearTask() { 978 assertBroughtExistingTaskToAnotherDisplay(FLAG_ACTIVITY_CLEAR_TASK, LAUNCHING_ACTIVITY); 979 } 980 981 @Test testLaunchActivityClearTop()982 public void testLaunchActivityClearTop() { 983 assertBroughtExistingTaskToAnotherDisplay(FLAG_ACTIVITY_CLEAR_TOP, LAUNCHING_ACTIVITY); 984 } 985 986 @Test testLaunchActivitySingleTop()987 public void testLaunchActivitySingleTop() { 988 assertBroughtExistingTaskToAnotherDisplay(FLAG_ACTIVITY_SINGLE_TOP, TEST_ACTIVITY); 989 } 990 991 @Test testLaunchActivitySingleTopOnNewDisplay()992 public void testLaunchActivitySingleTopOnNewDisplay() { 993 launchActivity(SINGLE_TOP_ACTIVITY); 994 waitAndAssertTopResumedActivity(SINGLE_TOP_ACTIVITY, DEFAULT_DISPLAY, 995 "Activity launched on primary display and on top"); 996 final int taskId = mWmState.getTaskByActivity(SINGLE_TOP_ACTIVITY).getTaskId(); 997 998 // Create new virtual display. 999 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 1000 .setSimulateDisplay(true) 1001 .createDisplay(); 1002 1003 mayLaunchHomeActivityForCar(); 1004 // Launch activity on new secondary display. 1005 getLaunchActivityBuilder() 1006 .setUseInstrumentation() 1007 .setTargetActivity(SINGLE_TOP_ACTIVITY) 1008 .allowMultipleInstances(false) 1009 .setDisplayId(newDisplay.mId).execute(); 1010 1011 waitAndAssertTopResumedActivity(SINGLE_TOP_ACTIVITY, newDisplay.mId, 1012 "Activity launched on secondary display must be on top"); 1013 1014 final int taskId2 = mWmState.getTaskByActivity(SINGLE_TOP_ACTIVITY).getTaskId(); 1015 assertEquals("Activity must be in the same task.", taskId, taskId2); 1016 assertEquals("Activity is the only member of its task", 1, 1017 mWmState.getActivityCountInTask(taskId2, null)); 1018 } 1019 1020 /** 1021 * This test case tests the behavior that a fullscreen activity was started on top of the 1022 * no-history activity from default display while sleeping. The no-history activity from 1023 * the external display should not be finished. 1024 */ 1025 @Test testLaunchNoHistoryActivityOnNewDisplay()1026 public void testLaunchNoHistoryActivityOnNewDisplay() { 1027 launchActivity(NO_HISTORY_ACTIVITY); 1028 waitAndAssertTopResumedActivity(NO_HISTORY_ACTIVITY, DEFAULT_DISPLAY, 1029 "Activity launched on primary display and on top"); 1030 1031 final int taskId = mWmState.getTaskByActivity(NO_HISTORY_ACTIVITY).getTaskId(); 1032 1033 final PrimaryDisplayStateSession displayStateSession = 1034 mObjectTracker.manage(new PrimaryDisplayStateSession()); 1035 1036 // Create new virtual display. 1037 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 1038 .setSimulateDisplay(true) 1039 .createDisplay(); 1040 1041 launchActivityOnDisplay(NO_HISTORY_ACTIVITY2, newDisplay.mId); 1042 1043 // Check that the activity is resumed on the external display 1044 waitAndAssertActivityStateOnDisplay(NO_HISTORY_ACTIVITY2, STATE_RESUMED, newDisplay.mId, 1045 "Activity launched on external display must be resumed"); 1046 final int taskId2 = mWmState.getTaskByActivity(NO_HISTORY_ACTIVITY2).getTaskId(); 1047 1048 displayStateSession.turnScreenOff(); 1049 launchActivityOnDisplay(SHOW_WHEN_LOCKED_ACTIVITY, DEFAULT_DISPLAY); 1050 1051 assertNotEquals("Activity must not be in the same task.", taskId, taskId2); 1052 assertEquals("No-history activity is the member of its task", 1, 1053 mWmState.getActivityCountInTask(taskId2, NO_HISTORY_ACTIVITY2)); 1054 assertFalse("No-history activity should not be finished.", 1055 mWmState.hasActivityState(NO_HISTORY_ACTIVITY2, STATE_DESTROYED)); 1056 } 1057 assertBroughtExistingTaskToAnotherDisplay(int flags, ComponentName topActivity)1058 private void assertBroughtExistingTaskToAnotherDisplay(int flags, ComponentName topActivity) { 1059 // Start TEST_ACTIVITY on top of LAUNCHING_ACTIVITY within the same task 1060 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).execute(); 1061 1062 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 1063 .setSimulateDisplay(true) 1064 .createDisplay(); 1065 1066 mayLaunchHomeActivityForCar(); 1067 // Start LAUNCHING_ACTIVITY on secondary display with target flags, verify the task 1068 // be reparented to secondary display 1069 getLaunchActivityBuilder() 1070 .setUseInstrumentation() 1071 .setTargetActivity(LAUNCHING_ACTIVITY) 1072 .setIntentFlags(flags) 1073 .allowMultipleInstances(false) 1074 .setDisplayId(newDisplay.mId).execute(); 1075 waitAndAssertTopResumedActivity(topActivity, newDisplay.mId, 1076 "Activity launched on secondary display and on top"); 1077 } 1078 mayLaunchHomeActivityForCar()1079 private void mayLaunchHomeActivityForCar() { 1080 if (isCar()) { 1081 // CarLauncher has a TaskView, and which launches the embedded task when it becomes 1082 // visible and this can disrupt the top focused state of the test activity. 1083 // So we'd like to make Home visible in advance to prevent that. 1084 launchHomeActivity(); 1085 } 1086 } 1087 getPendingIntentActivity(ComponentName activity)1088 private PendingIntent getPendingIntentActivity(ComponentName activity) { 1089 final Intent intent = new Intent(); 1090 intent.setClassName(activity.getPackageName(), activity.getClassName()); 1091 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1092 return PendingIntent.getActivity(mContext, 1 /* requestCode */, intent, 1093 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); 1094 } 1095 1096 public static class ImmediateLaunchTestActivity extends Activity {} 1097 } 1098