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.ActivityTask; 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.getFrontStackActivityType(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 stack there. 287 virtualLauncher.launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay); 288 final int externalFrontStackId = 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 stack on secondary display. 296 moveActivityToRootTaskOrOnTop(NON_RESIZEABLE_ACTIVITY, externalFrontStackId); 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 newFrontStackId = mWmState.getFocusedStackId(); 354 final ActivityTask newFrontStack = mWmState.getRootTask(newFrontStackId); 355 assertEquals("Launched activity must be on the same display", newDisplay.mId, 356 newFrontStack.mDisplayId); 357 assertEquals("Launched activity must be resumed", 358 getActivityName(NON_RESIZEABLE_ACTIVITY), 359 newFrontStack.mResumedActivity); 360 mWmState.assertFocusedStack( 361 "Top stack must be the one with just launched activity", 362 newFrontStackId); 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 stack 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 stack 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 stack 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 stack 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 stack 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 stack 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 stack is created. We need this to be 609 // able to compare task numbers in stacks later. 610 launchActivityOnDisplay(RESIZEABLE_ACTIVITY, newDisplay.mId); 611 mWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */); 612 613 final int stackNum = mWmState.getDisplay(DEFAULT_DISPLAY).mRootTasks.size(); 614 final int stackNumOnSecondary = 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 stack for standard type & 632 // fullscreen activity, we check the number of stacks here 633 final int stackNumFinal = mWmState.getDisplay(DEFAULT_DISPLAY) 634 .mRootTasks.size(); 635 assertEquals("Stack number in default stack must be decremented.", stackNum - 1, 636 stackNumFinal); 637 final int stackNumFinalOnSecondary = mWmState 638 .getDisplay(newDisplay.mId).mRootTasks.size(); 639 assertEquals("Stack number on external display must be incremented.", 640 stackNumOnSecondary + 1, stackNumFinalOnSecondary); 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 stackNum = 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 stackNumFinal = mWmState.getDisplay(DEFAULT_DISPLAY) 675 .mRootTasks.size(); 676 assertEquals("Stack number in default stack must be decremented.", stackNum - 1, 677 stackNumFinal); 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 frontStackId = mWmState.getFrontRootTaskId(newDisplay.mId); 694 final ActivityTask firstFrontStack = mWmState.getRootTask(frontStackId); 695 assertEquals("Activity launched on secondary display must be resumed", 696 getActivityName(LAUNCHING_ACTIVITY), 697 firstFrontStack.mResumedActivity); 698 mWmState.assertFocusedStack("Top stack must be on secondary display", frontStackId); 699 700 executeShellCommand("am start -n " + getActivityName(ALT_LAUNCHING_ACTIVITY)); 701 mWmState.waitForValidState(ALT_LAUNCHING_ACTIVITY); 702 703 // Check that second activity gets launched on the default display despite 704 // the affinity match on the secondary display. 705 final int displayFrontStackId = mWmState.getFrontRootTaskId(newDisplay.mId); 706 final ActivityTask displayFrontStack = 707 mWmState.getRootTask(displayFrontStackId); 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 ActivityTask secondFrontStack = mWmState.getRootTask(frontStackId); 717 final int secondFrontStackId = mWmState.getFrontRootTaskId(newDisplay.mId); 718 assertEquals("Activity launched on secondary display must be resumed", 719 getActivityName(ALT_LAUNCHING_ACTIVITY), 720 displayFrontStack.mResumedActivity); 721 mWmState.assertFocusedStack("Top stack must be on primary display", secondFrontStackId); 722 assertEquals("Second display must contain 2 root tasks", 2, 723 mWmState.getDisplay(newDisplay.mId).getRootTasks().size()); 724 assertEquals("Top task must contain 2 activities", 2, 725 secondFrontStack.getActivities().size()); 726 } 727 728 /** 729 * Tests that an activity is launched on the preferred display where the caller resided when 730 * both displays have matching tasks. 731 */ 732 @Test testTaskMatchOrderAcrossDisplays()733 public void testTaskMatchOrderAcrossDisplays() { 734 getLaunchActivityBuilder().setUseInstrumentation() 735 .setTargetActivity(TEST_ACTIVITY).setNewTask(true) 736 .setDisplayId(DEFAULT_DISPLAY).execute(); 737 final int stackId = mWmState.getFrontRootTaskId(DEFAULT_DISPLAY); 738 739 getLaunchActivityBuilder().setUseInstrumentation() 740 .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY).setNewTask(true) 741 .setDisplayId(DEFAULT_DISPLAY).execute(); 742 743 final DisplayContent newDisplay = createManagedVirtualDisplaySession().createDisplay(); 744 getLaunchActivityBuilder().setUseInstrumentation().setWithShellPermission(true) 745 .setTargetActivity(TEST_ACTIVITY).setNewTask(true) 746 .setDisplayId(newDisplay.mId).execute(); 747 assertNotEquals("Top focus stack should not be on default display", 748 stackId, mWmState.getFocusedStackId()); 749 750 mBroadcastActionTrigger.launchActivityNewTask(getActivityName(TEST_ACTIVITY)); 751 waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY, 752 "Activity must be launched on default display"); 753 mWmState.assertFocusedStack("Top focus stack must be on the default display", stackId); 754 } 755 756 /** 757 * Tests that the task affinity search respects the launch display id. 758 */ 759 @Test testLaunchDisplayAffinityMatch()760 public void testLaunchDisplayAffinityMatch() { 761 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 762 .setSimulateDisplay(true).createDisplay(); 763 764 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId); 765 766 // Check that activity is on the secondary display. 767 final int frontStackId = mWmState.getFrontRootTaskId(newDisplay.mId); 768 final ActivityTask firstFrontStack = mWmState.getRootTask(frontStackId); 769 assertEquals("Activity launched on secondary display must be resumed", 770 getActivityName(LAUNCHING_ACTIVITY), firstFrontStack.mResumedActivity); 771 mWmState.assertFocusedStack("Focus must be on secondary display", frontStackId); 772 773 // We don't want FLAG_ACTIVITY_MULTIPLE_TASK, so we can't use launchActivityOnDisplay 774 executeShellCommand("am start -n " + getActivityName(ALT_LAUNCHING_ACTIVITY) 775 + " -f 0x10000000" // FLAG_ACTIVITY_NEW_TASK 776 + " --display " + newDisplay.mId); 777 mWmState.computeState(ALT_LAUNCHING_ACTIVITY); 778 779 // Check that second activity gets launched into the affinity matching 780 // task on the secondary display 781 final int secondFrontStackId = mWmState.getFrontRootTaskId(newDisplay.mId); 782 final ActivityTask secondFrontStack = 783 mWmState.getRootTask(secondFrontStackId); 784 assertEquals("Activity launched on secondary display must be resumed", 785 getActivityName(ALT_LAUNCHING_ACTIVITY), 786 secondFrontStack.mResumedActivity); 787 mWmState.assertFocusedStack("Top stack must be on secondary display", secondFrontStackId); 788 assertEquals("Second display must only contain 1 task", 789 1, mWmState.getDisplay(newDisplay.mId).getRootTasks().size()); 790 assertEquals("Top stack task must contain 2 activities", 791 2, secondFrontStack.getActivities().size()); 792 } 793 794 /** 795 * Tests that a new activity launched by an activity will end up on the same display 796 * even if the task stack is not on the top for the display. 797 */ 798 @Test testNewTaskSameDisplay()799 public void testNewTaskSameDisplay() { 800 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 801 .setSimulateDisplay(true) 802 .createDisplay(); 803 804 launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId); 805 806 // Check that the first activity is launched onto the secondary display 807 waitAndAssertTopResumedActivity(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId, 808 "Activity launched on secondary display must be resumed"); 809 810 executeShellCommand("am start -n " + getActivityName(TEST_ACTIVITY)); 811 812 // Check that the second activity is launched on the same display 813 waitAndAssertTopResumedActivity(TEST_ACTIVITY, newDisplay.mId, 814 "Activity launched on default display must be resumed"); 815 816 mBroadcastActionTrigger.launchActivityNewTask(getActivityName(LAUNCHING_ACTIVITY)); 817 818 // Check that the third activity ends up in a new stack in the same display where the 819 // first activity lands 820 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, newDisplay.mId, 821 "Activity must be launched on secondary display"); 822 assertEquals("Secondary display must contain 2 stacks", 2, 823 mWmState.getDisplay(newDisplay.mId).mRootTasks.size()); 824 } 825 826 /** 827 * Tests that a new task launched by an activity will end up on the same display 828 * even if the focused stack is not on that activity's display. 829 */ 830 @Test testNewTaskDefaultDisplay()831 public void testNewTaskDefaultDisplay() { 832 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 833 .setSimulateDisplay(true) 834 .createDisplay(); 835 836 launchActivityOnDisplay(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId); 837 838 // Check that the first activity is launched onto the secondary display 839 waitAndAssertTopResumedActivity(BROADCAST_RECEIVER_ACTIVITY, newDisplay.mId, 840 "Activity launched on secondary display must be resumed"); 841 842 launchActivityOnDisplay(SECOND_ACTIVITY, DEFAULT_DISPLAY); 843 844 // Check that the second activity is launched on the default display because the affinity 845 // is different 846 waitAndAssertTopResumedActivity(SECOND_ACTIVITY, DEFAULT_DISPLAY, 847 "Activity launched on default display must be resumed"); 848 assertBothDisplaysHaveResumedActivities(pair(DEFAULT_DISPLAY, SECOND_ACTIVITY), 849 pair(newDisplay.mId, BROADCAST_RECEIVER_ACTIVITY)); 850 851 mBroadcastActionTrigger.launchActivityNewTask(getActivityName(LAUNCHING_ACTIVITY)); 852 853 // Check that the third activity ends up in a new stack in the same display where the 854 // first activity lands 855 waitAndAssertTopResumedActivity(LAUNCHING_ACTIVITY, newDisplay.mId, 856 "Activity must be launched on secondary display"); 857 assertEquals("Secondary display must contain 2 stacks", 2, 858 mWmState.getDisplay(newDisplay.mId).mRootTasks.size()); 859 assertBothDisplaysHaveResumedActivities(pair(DEFAULT_DISPLAY, SECOND_ACTIVITY), 860 pair(newDisplay.mId, LAUNCHING_ACTIVITY)); 861 } 862 863 /** 864 * Test that launching an activity implicitly will end up on the same display 865 */ 866 @Test testLaunchingFromApplicationContext()867 public void testLaunchingFromApplicationContext() { 868 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 869 .setSimulateDisplay(true) 870 .createDisplay(); 871 872 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId, 873 extraBool(KEY_LAUNCH_ACTIVITY, true), extraBool(KEY_LAUNCH_IMPLICIT, true), 874 extraBool(KEY_NEW_TASK, true), extraBool(KEY_USE_APPLICATION_CONTEXT, true), 875 extraString(KEY_ACTION, IMPLICIT_TARGET_SECOND_TEST_ACTION)); 876 waitAndAssertTopResumedActivity(IMPLICIT_TARGET_SECOND_ACTIVITY, newDisplay.mId, 877 "Implicitly launched activity must launch on the same display"); 878 } 879 880 /** 881 * Test that launching an activity from pending intent will end up on the same display 882 */ 883 @Test testLaunchingFromPendingIntent()884 public void testLaunchingFromPendingIntent() { 885 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 886 .setSimulateDisplay(true) 887 .createDisplay(); 888 889 launchActivityOnDisplay(LAUNCHING_ACTIVITY, newDisplay.mId, 890 extraBool(KEY_LAUNCH_ACTIVITY, true), 891 extraBool(KEY_LAUNCH_IMPLICIT, true), 892 extraBool(KEY_NEW_TASK, true), 893 extraBool(KEY_USE_APPLICATION_CONTEXT, true), 894 extraBool(KEY_LAUNCH_PENDING, true), 895 extraString(KEY_ACTION, IMPLICIT_TARGET_SECOND_TEST_ACTION)); 896 897 waitAndAssertTopResumedActivity(IMPLICIT_TARGET_SECOND_ACTIVITY, newDisplay.mId, 898 "Activity launched from pending intent must launch on the same display"); 899 } 900 901 /** 902 * Tests than an immediate launch after new display creation is handled correctly. 903 */ 904 @Test testImmediateLaunchOnNewDisplay()905 public void testImmediateLaunchOnNewDisplay() { 906 // Create new virtual display and immediately launch an activity on it. 907 SurfaceView surfaceView = new SurfaceView(mContext); 908 final VirtualDisplay virtualDisplay = mDm.createVirtualDisplay( 909 "testImmediateLaunchOnNewDisplay", /*width=*/ 400, /*height=*/ 400, 910 /*densityDpi=*/ 320, surfaceView.getHolder().getSurface(), 911 DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); 912 try { 913 int displayId = virtualDisplay.getDisplay().getDisplayId(); 914 ComponentName componentName = new ComponentName(mContext, 915 ImmediateLaunchTestActivity.class); 916 getLaunchActivityBuilder().setTargetActivity(componentName).setDisplayId( 917 displayId).setUseInstrumentation().execute(); 918 919 // Check that activity is launched and placed correctly. 920 waitAndAssertActivityStateOnDisplay(componentName, STATE_RESUMED, displayId, 921 "Test activity must be on top"); 922 final int frontStackId = mWmState.getFrontRootTaskId(displayId); 923 final ActivityTask firstFrontStack = mWmState.getRootTask(frontStackId); 924 assertEquals("Activity launched on secondary display must be resumed", 925 getActivityName(componentName), firstFrontStack.mResumedActivity); 926 } finally { 927 virtualDisplay.release(); 928 } 929 930 } 931 932 @Test testLaunchPendingIntentActivity()933 public void testLaunchPendingIntentActivity() throws Exception { 934 final DisplayContent displayContent = createManagedVirtualDisplaySession() 935 .setSimulateDisplay(true) 936 .createDisplay(); 937 938 // Activity should be launched on primary display by default. 939 getPendingIntentActivity(TEST_ACTIVITY).send(); 940 waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY, 941 "Activity launched on primary display and on top"); 942 943 final int resultCode = 1; 944 // Activity should be launched on target display according to the caller context. 945 final Context displayContext = 946 mContext.createDisplayContext(mDm.getDisplay(displayContent.mId)); 947 getPendingIntentActivity(TOP_ACTIVITY).send(displayContext, resultCode, null /* intent */); 948 waitAndAssertTopResumedActivity(TOP_ACTIVITY, displayContent.mId, 949 "Activity launched on secondary display and on top"); 950 951 // Activity should be brought to front on the same display if it already existed. 952 getPendingIntentActivity(TEST_ACTIVITY).send(displayContext, resultCode, null /* intent */); 953 waitAndAssertTopResumedActivity(TEST_ACTIVITY, DEFAULT_DISPLAY, 954 "Activity launched on primary display and on top"); 955 956 // Activity should be moved to target display. 957 final ActivityOptions options = ActivityOptions.makeBasic(); 958 options.setLaunchDisplayId(displayContent.mId); 959 getPendingIntentActivity(TEST_ACTIVITY).send(mContext, resultCode, null /* intent */, 960 null /* onFinished */, null /* handler */, null /* requiredPermission */, 961 options.toBundle()); 962 waitAndAssertTopResumedActivity(TEST_ACTIVITY, displayContent.mId, 963 "Activity launched on secondary display and on top"); 964 } 965 966 @Test testLaunchActivityClearTask()967 public void testLaunchActivityClearTask() { 968 assertBroughtExistingTaskToAnotherDisplay(FLAG_ACTIVITY_CLEAR_TASK, LAUNCHING_ACTIVITY); 969 } 970 971 @Test testLaunchActivityClearTop()972 public void testLaunchActivityClearTop() { 973 assertBroughtExistingTaskToAnotherDisplay(FLAG_ACTIVITY_CLEAR_TOP, LAUNCHING_ACTIVITY); 974 } 975 976 @Test testLaunchActivitySingleTop()977 public void testLaunchActivitySingleTop() { 978 assertBroughtExistingTaskToAnotherDisplay(FLAG_ACTIVITY_SINGLE_TOP, TEST_ACTIVITY); 979 } 980 981 @Test testLaunchActivitySingleTopOnNewDisplay()982 public void testLaunchActivitySingleTopOnNewDisplay() { 983 launchActivity(SINGLE_TOP_ACTIVITY); 984 waitAndAssertTopResumedActivity(SINGLE_TOP_ACTIVITY, DEFAULT_DISPLAY, 985 "Activity launched on primary display and on top"); 986 final int taskId = mWmState.getTaskByActivity(SINGLE_TOP_ACTIVITY).getTaskId(); 987 988 // Create new virtual display. 989 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 990 .setSimulateDisplay(true) 991 .createDisplay(); 992 993 // Launch activity on new secondary display. 994 getLaunchActivityBuilder() 995 .setUseInstrumentation() 996 .setTargetActivity(SINGLE_TOP_ACTIVITY) 997 .allowMultipleInstances(false) 998 .setDisplayId(newDisplay.mId).execute(); 999 1000 waitAndAssertTopResumedActivity(SINGLE_TOP_ACTIVITY, newDisplay.mId, 1001 "Activity launched on secondary display must be on top"); 1002 1003 final int taskId2 = mWmState.getTaskByActivity(SINGLE_TOP_ACTIVITY).getTaskId(); 1004 assertEquals("Activity must be in the same task.", taskId, taskId2); 1005 assertEquals("Activity is the only member of its task", 1, 1006 mWmState.getActivityCountInTask(taskId2, null)); 1007 } 1008 1009 /** 1010 * This test case tests the behavior that a fullscreen activity was started on top of the 1011 * no-history activity from default display while sleeping. The no-history activity from 1012 * the external display should not be finished. 1013 */ 1014 @Test testLaunchNoHistoryActivityOnNewDisplay()1015 public void testLaunchNoHistoryActivityOnNewDisplay() { 1016 launchActivity(NO_HISTORY_ACTIVITY); 1017 waitAndAssertTopResumedActivity(NO_HISTORY_ACTIVITY, DEFAULT_DISPLAY, 1018 "Activity launched on primary display and on top"); 1019 1020 final int taskId = mWmState.getTaskByActivity(NO_HISTORY_ACTIVITY).getTaskId(); 1021 1022 final PrimaryDisplayStateSession displayStateSession = 1023 mObjectTracker.manage(new PrimaryDisplayStateSession()); 1024 1025 // Create new virtual display. 1026 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 1027 .setSimulateDisplay(true) 1028 .createDisplay(); 1029 1030 launchActivityOnDisplay(NO_HISTORY_ACTIVITY2, newDisplay.mId); 1031 1032 // Check that the activity is resumed on the external display 1033 waitAndAssertActivityStateOnDisplay(NO_HISTORY_ACTIVITY2, STATE_RESUMED, newDisplay.mId, 1034 "Activity launched on external display must be resumed"); 1035 final int taskId2 = mWmState.getTaskByActivity(NO_HISTORY_ACTIVITY2).getTaskId(); 1036 1037 displayStateSession.turnScreenOff(); 1038 launchActivityOnDisplay(SHOW_WHEN_LOCKED_ACTIVITY, DEFAULT_DISPLAY); 1039 1040 assertNotEquals("Activity must not be in the same task.", taskId, taskId2); 1041 assertEquals("No-history activity is the member of its task", 1, 1042 mWmState.getActivityCountInTask(taskId2, NO_HISTORY_ACTIVITY2)); 1043 assertFalse("No-history activity should not be finished.", 1044 mWmState.hasActivityState(NO_HISTORY_ACTIVITY2, STATE_DESTROYED)); 1045 } 1046 assertBroughtExistingTaskToAnotherDisplay(int flags, ComponentName topActivity)1047 private void assertBroughtExistingTaskToAnotherDisplay(int flags, ComponentName topActivity) { 1048 // Start TEST_ACTIVITY on top of LAUNCHING_ACTIVITY within the same task 1049 getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY).execute(); 1050 1051 final DisplayContent newDisplay = createManagedVirtualDisplaySession() 1052 .setSimulateDisplay(true) 1053 .createDisplay(); 1054 1055 // Start LAUNCHING_ACTIVITY on secondary display with target flags, verify the task 1056 // be reparented to secondary display 1057 getLaunchActivityBuilder() 1058 .setUseInstrumentation() 1059 .setTargetActivity(LAUNCHING_ACTIVITY) 1060 .setIntentFlags(flags) 1061 .allowMultipleInstances(false) 1062 .setDisplayId(newDisplay.mId).execute(); 1063 waitAndAssertTopResumedActivity(topActivity, newDisplay.mId, 1064 "Activity launched on secondary display and on top"); 1065 } 1066 getPendingIntentActivity(ComponentName activity)1067 private PendingIntent getPendingIntentActivity(ComponentName activity) { 1068 final Intent intent = new Intent(); 1069 intent.setClassName(activity.getPackageName(), activity.getClassName()); 1070 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1071 return PendingIntent.getActivity(mContext, 1 /* requestCode */, intent, 1072 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); 1073 } 1074 1075 public static class ImmediateLaunchTestActivity extends Activity {} 1076 } 1077