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