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