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