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