1 /*
2  * Copyright (C) 2018 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.activity.lifecycle;
18 
19 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
21 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
22 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
23 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
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_PREVIOUS_IS_TOP;
27 import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
28 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
29 import static android.server.wm.ComponentNameUtils.getActivityName;
30 import static android.server.wm.UiDeviceUtils.pressWakeupButton;
31 import static android.server.wm.WindowManagerState.STATE_DESTROYED;
32 import static android.server.wm.WindowManagerState.STATE_RESUMED;
33 import static android.server.wm.activity.lifecycle.LifecycleConstants.ON_STOP;
34 import static android.server.wm.activity.lifecycle.LifecycleConstants.getComponentName;
35 import static android.server.wm.app.Components.ALIAS_TEST_ACTIVITY;
36 import static android.server.wm.app.Components.NO_HISTORY_ACTIVITY;
37 import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY;
38 import static android.server.wm.app.Components.TEST_ACTIVITY;
39 
40 import static org.junit.Assert.assertEquals;
41 import static org.junit.Assert.assertNotEquals;
42 import static org.junit.Assert.assertTrue;
43 import static org.junit.Assume.assumeTrue;
44 import static org.junit.Assume.assumeFalse;
45 
46 import android.app.Activity;
47 import android.content.ComponentName;
48 import android.content.Intent;
49 import android.os.Bundle;
50 import android.platform.test.annotations.Presubmit;
51 import android.server.wm.ActivityLauncher;
52 import android.server.wm.HelperActivities;
53 import android.server.wm.LockScreenSession;
54 import android.server.wm.WaitForValidActivityState;
55 import android.server.wm.app.Components;
56 
57 import org.junit.Test;
58 
59 /**
60  * Build/Install/Run:
61  *     atest CtsWindowManagerDeviceActivity:ActivityStarterTests
62  */
63 @Presubmit
64 @android.server.wm.annotation.Group3
65 public class ActivityStarterTests extends ActivityLifecycleClientTestBase {
66 
67     private static final ComponentName STANDARD_ACTIVITY
68             = getComponentName(HelperActivities.StandardActivity.class);
69     private static final ComponentName SECOND_STANDARD_ACTIVITY
70             = getComponentName(HelperActivities.SecondStandardActivity.class);
71     private static final ComponentName SINGLE_TOP_ACTIVITY
72             = getComponentName(SingleTopActivity.class);
73     private static final ComponentName SINGLE_INSTANCE_ACTIVITY
74             = getComponentName(SingleInstanceActivity.class);
75     private static final ComponentName SINGLE_TASK_ACTIVITY
76             = getComponentName(SingleTaskActivity.class);
77     private static final ComponentName STANDARD_SINGLE_TOP_ACTIVITY
78             = getComponentName(StandardWithSingleTopActivity.class);
79     private static final ComponentName TEST_LAUNCHING_ACTIVITY
80             = getComponentName(TestLaunchingActivity.class);
81     private static final ComponentName LAUNCHING_AND_FINISH_ACTIVITY
82             = getComponentName(LaunchingAndFinishActivity.class);
83     private static final ComponentName CLEAR_TASK_ON_LAUNCH_ACTIVITY
84             = getComponentName(ClearTaskOnLaunchActivity.class);
85     private static final ComponentName FINISH_ON_TASK_LAUNCH_ACTIVITY
86             = getComponentName(FinishOnTaskLaunchActivity.class);
87     private static final ComponentName DOCUMENT_INTO_EXISTING_ACTIVITY
88             = getComponentName(DocumentIntoExistingActivity.class);
89     private static final ComponentName RELINQUISHTASKIDENTITY_ACTIVITY
90             = getComponentName(RelinquishTaskIdentityActivity.class);
91 
92 
93     /**
94      * Ensures that the following launch flag combination works when starting an activity which is
95      * already running: - {@code FLAG_ACTIVITY_CLEAR_TOP} - {@code
96      * FLAG_ACTIVITY_RESET_TASK_IF_NEEDED} - {@code FLAG_ACTIVITY_NEW_TASK}
97      */
98     @Test
testClearTopNewTaskResetTask()99     public void testClearTopNewTaskResetTask() throws Exception {
100         // Start activity normally
101         launchActivityAndWait(FirstActivity.class);
102 
103         // Navigate home
104         launchHomeActivity();
105         waitAndAssertActivityStates(state(FirstActivity.class, ON_STOP));
106         getTransitionLog().clear();
107 
108         // Start activity again with flags in question. Verify activity is resumed.
109         // A new instance of activity will be created, and the old one destroyed.
110         final Activity secondLaunchActivity = new Launcher(FirstActivity.class)
111                 .setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_NEW_TASK
112                         | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
113                 .launch();
114         mWmState.waitForActivityState(secondLaunchActivity.getComponentName(), STATE_RESUMED);
115         assertEquals("The activity should be started and be resumed",
116                 getActivityName(secondLaunchActivity.getComponentName()),
117                 mWmState.getTopActivityName(0));
118     }
119 
120     /**
121      * This test case tests "standard" activity behavior.
122      * A first launched standard activity and a second launched standard activity
123      * must be in same task.
124      */
125     @Test
testLaunchStandardActivity()126     public void testLaunchStandardActivity() {
127         // Launch a standard activity.
128         launchActivity(STANDARD_ACTIVITY);
129 
130         final int taskId = mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId();
131         final int instances = mWmState.getActivityCountInTask(taskId, null);
132 
133         // Launch a second standard activity.
134         launchActivity(SECOND_STANDARD_ACTIVITY);
135 
136         // Make sure instances in task are increased.
137         assertEquals("instances of activity in task must be increased.", instances + 1,
138                 mWmState.getActivityCountInTask(taskId, null));
139 
140         // Make sure the stack for the second standard activity is front.
141         assertEquals("The stack for the second standard activity must be front.",
142                 getActivityName(SECOND_STANDARD_ACTIVITY),
143                 mWmState.getTopActivityName(0));
144 
145         // Make sure the standard activity and the second standard activity are in same task.
146         assertEquals("Activity must be in same task.", taskId,
147                 mWmState.getTaskByActivity(SECOND_STANDARD_ACTIVITY).getTaskId());
148     }
149 
150     /**
151      * This test case tests show-when-locked behavior for a "no-history" activity.
152      * The no-history activity should be resumed over lockscreen.
153      */
154     @Test
testLaunchNoHistoryActivityShowWhenLocked()155     public void testLaunchNoHistoryActivityShowWhenLocked() {
156         // Allow TV devices to skip this test.
157         assumeFalse(isLeanBack());
158         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
159         lockScreenSession.sleepDevice();
160 
161         getLaunchActivityBuilder().setTargetActivity(NO_HISTORY_ACTIVITY)
162                 .setIntentExtra(extra -> extra.putBoolean(
163                         Components.NoHistoryActivity.EXTRA_SHOW_WHEN_LOCKED, true))
164                 .setUseInstrumentation().execute();
165         waitAndAssertActivityState(NO_HISTORY_ACTIVITY, STATE_RESUMED,
166             "Activity should be resumed");
167     }
168 
169     /**
170      * This test case tests the behavior for a "no-history" activity after turning the screen off.
171      * The no-history activity must be resumed over lockscreen when launched again.
172      */
173     @Test
testNoHistoryActivityNotFinished()174     public void testNoHistoryActivityNotFinished() {
175         assumeTrue(supportsLockScreen());
176 
177         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
178         // Launch a no-history activity
179         getLaunchActivityBuilder().setTargetActivity(NO_HISTORY_ACTIVITY)
180                 .setIntentExtra(extra -> extra.putBoolean(
181                         Components.NoHistoryActivity.EXTRA_SHOW_WHEN_LOCKED, true))
182                 .setUseInstrumentation().execute();
183 
184         // Wait for the activity resumed.
185         mWmState.waitForActivityState(NO_HISTORY_ACTIVITY, STATE_RESUMED);
186 
187         lockScreenSession.sleepDevice();
188 
189         // Launch a no-history activity
190         launchActivity(NO_HISTORY_ACTIVITY);
191 
192         // Wait for the activity resumed
193         waitAndAssertActivityState(NO_HISTORY_ACTIVITY, STATE_RESUMED,
194                 "Activity must be resumed");
195     }
196 
197     /**
198      * This test case tests the behavior that a fullscreen activity was started on top of the
199      * no-history activity within different tasks during sleeping. The no-history activity must be
200      * finished.
201      */
202     @Test
testNoHistoryActivityWithDifferentTask()203     public void testNoHistoryActivityWithDifferentTask() {
204         assumeTrue(supportsLockScreen());
205 
206         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
207         // Launch a no-history activity
208         getLaunchActivityBuilder().setTargetActivity(NO_HISTORY_ACTIVITY)
209                 .setIntentExtra(extra -> extra.putBoolean(
210                         Components.NoHistoryActivity.EXTRA_SHOW_WHEN_LOCKED, true))
211                 .setWaitForLaunched(false)
212                 .setUseInstrumentation()
213                 .execute();
214 
215         // Wait for the activity resumed.
216         waitAndAssertActivityState(NO_HISTORY_ACTIVITY, STATE_RESUMED,
217                 "Activity must be resumed");
218         final int taskId = mWmState.getTaskByActivity(NO_HISTORY_ACTIVITY).getTaskId();
219         lockScreenSession.sleepDevice();
220 
221         // Launch a single instance activity
222         getLaunchActivityBuilder().setTargetActivity(SINGLE_INSTANCE_ACTIVITY)
223                 .setIntentExtra(extra -> extra.putBoolean(
224                         SingleInstanceActivity.EXTRA_SHOW_WHEN_LOCKED, true))
225                 .setWaitForLaunched(false)
226                 .setUseInstrumentation()
227                 .execute();
228 
229         // Make sure the activity is finished.
230         final String waitFinishMsg = "Instance of no-history activity must not exist";
231         assertTrue(waitFinishMsg, mWmState.waitForWithAmState(
232                 amState -> 0 == amState.getActivityCountInTask(taskId, NO_HISTORY_ACTIVITY),
233                 waitFinishMsg));
234 
235         // Turn the screen on after the test is completed to prevent keyDispatchingTimedOut during
236         // the lockScreenSession close.
237         pressWakeupButton();
238     }
239 
240     /**
241      * This test case tests the behavior that a translucent activity was started on top of the
242      * no-history activity during sleeping. The no-history activity must not be finished.
243      */
244     @Test
testNoHistoryActivityWithTranslucentActivity()245     public void testNoHistoryActivityWithTranslucentActivity() {
246         assumeTrue(supportsLockScreen());
247 
248         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
249         // Launch a no-history activity
250         getLaunchActivityBuilder().setTargetActivity(NO_HISTORY_ACTIVITY)
251                 .setIntentExtra(extra -> extra.putBoolean(
252                         Components.NoHistoryActivity.EXTRA_SHOW_WHEN_LOCKED, true))
253                 .setWaitForLaunched(false)
254                 .setUseInstrumentation()
255                 .execute();
256 
257         // Wait for the activity resumed.
258         waitAndAssertActivityState(NO_HISTORY_ACTIVITY, STATE_RESUMED,
259                 "Activity must be resumed");
260 
261         final int taskId = mWmState.getTaskByActivity(NO_HISTORY_ACTIVITY).getTaskId();
262         lockScreenSession.sleepDevice();
263         launchActivityNoWait(SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY);
264 
265         final String waitFinishMsg = "Instance of no-history activity must exist";
266         assertTrue(waitFinishMsg, mWmState.waitForWithAmState(
267                 amState -> 1 == amState.getActivityCountInTask(taskId, NO_HISTORY_ACTIVITY),
268                 waitFinishMsg));
269 
270         // Turn the screen on after the test is completed to prevent keyDispatchingTimedOut during
271         // the lockScreenSession close.
272         pressWakeupButton();
273     }
274 
275     /**
276      * This test case tests "single top" activity behavior.
277      * - A first launched standard activity and a second launched single top
278      * activity are in same task.
279      * - A new instance of single top activity is not created if task
280      * already has a its activity at the top of its task.
281      */
282     @Test
testLaunchSingleTopActivity()283     public void testLaunchSingleTopActivity() {
284         // Launch a standard activity.
285         launchActivity(STANDARD_ACTIVITY);
286 
287         final int taskId = mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId();
288 
289         // Launch a single top activity.
290         launchActivity(SINGLE_TOP_ACTIVITY);
291 
292         final int instances = mWmState.getActivityCountInTask(taskId, null);
293 
294         // Make sure the single top activity is in focus.
295         mWmState.assertFocusedActivity(SINGLE_TOP_ACTIVITY + "must be focused Activity",
296                 SINGLE_TOP_ACTIVITY);
297 
298         // Make sure the stack for the single top activity is front.
299         assertEquals("The stack for the single top activity must be front.",
300                 getActivityName(SINGLE_TOP_ACTIVITY),
301                 mWmState.getTopActivityName(0));
302 
303         // Make sure the standard activity and the single top activity are in same task.
304         assertEquals("Two activities must be in same task.", taskId,
305                 mWmState.getTaskByActivity(SINGLE_TOP_ACTIVITY).getTaskId());
306 
307         // Launch a single top activity.
308         launchActivity(SINGLE_TOP_ACTIVITY);
309 
310         // Make sure that instances of activity are not increased.
311         assertEquals("instances of activity must not be increased.", instances,
312                 mWmState.getActivityCountInTask(taskId, null));
313     }
314 
315     /**
316      * This test case tests "single instance" activity behavior.
317      * - A first launched standard activity and a second launched single instance
318      * activity are not in same task.
319      * - A single instance activity is always the single and only member of its task.
320      */
321     @Test
testLaunchSingleInstanceActivity()322     public void testLaunchSingleInstanceActivity() {
323         // Launch a standard activity.
324         launchActivity(STANDARD_ACTIVITY);
325 
326         final int firstTaskId = mWmState
327                 .getTaskByActivity(STANDARD_ACTIVITY).getTaskId();
328 
329         // Launch a single instance activity
330         launchActivity(SINGLE_INSTANCE_ACTIVITY);
331 
332         final int secondTaskId = mWmState
333                 .getTaskByActivity(SINGLE_INSTANCE_ACTIVITY).getTaskId();
334 
335         // Make sure the single instance activity is in focus.
336         mWmState.assertFocusedActivity(SINGLE_INSTANCE_ACTIVITY + "must be focused Activity",
337                 SINGLE_INSTANCE_ACTIVITY);
338         // Make sure the single instance activity is front.
339         assertEquals("The stack for the single instance activity must be front.",
340                 getActivityName(SINGLE_INSTANCE_ACTIVITY),
341                 mWmState.getTopActivityName(0));
342 
343         // Make sure the standard activity and the test activity are not in same task.
344         assertNotEquals("Activity must be in different task.", firstTaskId, secondTaskId);
345 
346         // Make sure the single instance activity is only member of its task.
347         assertEquals("Single instance activity is only member of its task", 1,
348                 mWmState.getActivityCountInTask(secondTaskId, null));
349     }
350 
351     /**
352      * This test case tests "single task" activity behavior.
353      * - A first launched standard activity and a second launched single task activity
354      * are in same task.
355      * - Instance of single task activity is only one in its task.
356      */
357     @Test
testLaunchSingleTaskActivity()358     public void testLaunchSingleTaskActivity() {
359         // Launch a standard activity.
360         launchActivity(STANDARD_ACTIVITY);
361 
362         final int taskId = mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId();
363 
364         // Launch a single task activity
365         launchActivity(SINGLE_TASK_ACTIVITY);
366 
367         // Make sure the single task activity is in focus.
368         mWmState.assertFocusedActivity(SINGLE_TASK_ACTIVITY + "must be focused Activity",
369                 SINGLE_TASK_ACTIVITY);
370 
371         // Make sure the stack for the single task activity is front.
372         assertEquals("The stack for the single task activity must be front.",
373                 getActivityName(SINGLE_TASK_ACTIVITY),
374                 mWmState.getTopActivityName(0));
375 
376         // Make sure the test activity is in same task.
377         assertEquals("Activity must be in same task.", taskId,
378                 mWmState.getTaskByActivity(SINGLE_TASK_ACTIVITY).getTaskId());
379 
380         // Launch a second standard activity
381         launchActivity(SECOND_STANDARD_ACTIVITY);
382 
383         // Launch a single task activity again.
384         launchActivity(SINGLE_TASK_ACTIVITY);
385         mWmState.waitForActivityRemoved(SECOND_STANDARD_ACTIVITY);
386 
387         // Make sure the number of instances for single task activity is only one.
388         assertEquals("Instance of single task activity in its task must be only one", 1,
389                 mWmState.getActivityCountInTask(taskId, SINGLE_TASK_ACTIVITY));
390         // Make sure that instance of standard activity does not exists.
391         assertEquals("Instance of second standard activity must not exist.", 0,
392                 mWmState.getActivityCountInTask(taskId, SECOND_STANDARD_ACTIVITY));
393 
394     }
395 
396     /**
397      * Tests that the existing task would be brought to top while launching alias activity or
398      * real activity without creating new activity instances, tasks, or stacks.
399      */
400     @Test
testLaunchAliasActivity()401     public void testLaunchAliasActivity() {
402         // Launch alias activity.
403         getLaunchActivityBuilder().setUseInstrumentation().setTargetActivity(ALIAS_TEST_ACTIVITY)
404                 .setIntentFlags(FLAG_ACTIVITY_NEW_TASK).execute();
405 
406         final int testStacks = countTestRootTasks();
407         final int taskId = mWmState.getTaskByActivity(ALIAS_TEST_ACTIVITY).getTaskId();
408 
409         // Return to home and launch the alias activity again.
410         launchHomeActivity();
411         getLaunchActivityBuilder().setUseInstrumentation().setTargetActivity(ALIAS_TEST_ACTIVITY)
412                 .setIntentFlags(FLAG_ACTIVITY_NEW_TASK).execute();
413         assertEquals("Instance of the activity in its task must be only one", 1,
414                 mWmState.getActivityCountInTask(taskId, ALIAS_TEST_ACTIVITY));
415         assertEquals("Test stack count should not be increased.", testStacks,
416                 countTestRootTasks());
417 
418         // Return to home and launch the real activity.
419         launchHomeActivity();
420         getLaunchActivityBuilder().setUseInstrumentation().setTargetActivity(TEST_ACTIVITY)
421                 .setIntentFlags(FLAG_ACTIVITY_NEW_TASK).execute();
422         assertEquals("Instance of the activity in its task must be only one", 1,
423                 mWmState.getActivityCountInTask(taskId, ALIAS_TEST_ACTIVITY));
424         assertEquals("Test stack count should not be increased.", testStacks,
425                 countTestRootTasks());
426     }
427 
countTestRootTasks()428     private int countTestRootTasks() {
429         return mWmState.getRootTasksCount(
430                 t -> ALIAS_TEST_ACTIVITY.getPackageName().equals(t.getPackageName()));
431     }
432 
433     /**
434      * This test case tests behavior of activities launched with FLAG_ACTIVITY_NEW_TASK
435      * and FLAG_ACTIVITY_CLEAR_TASK.
436      * A first launched activity is finished, then a second activity is created if the
437      * second activity is launched with FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_CLEAR_TASK.
438      */
439     @Test
testLaunchActivityWithFlagNewTaskAndClearTask()440     public void testLaunchActivityWithFlagNewTaskAndClearTask() {
441         // Launch a standard activity with FLAG_ACTIVITY_NEW_TASK.
442         getLaunchActivityBuilder()
443                 .setTargetActivity(STANDARD_ACTIVITY)
444                 .setIntentFlags(FLAG_ACTIVITY_NEW_TASK)
445                 .execute();
446 
447         final int taskId = mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId();
448 
449         // Launch Activity with FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_CLEAR_TASK.
450         getLaunchActivityBuilder()
451                 .setTargetActivity(STANDARD_ACTIVITY)
452                 .setLaunchingActivity(TEST_LAUNCHING_ACTIVITY)
453                 .setIntentFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)
454                 .execute();
455 
456         mWmState.waitForActivityState(STANDARD_ACTIVITY, STATE_DESTROYED);
457 
458         // Make sure the number of instances for standard activity is one
459         // because previous standard activity to be finished due to FLAG_ACTIVITY_CLEAR_TASK.
460         assertEquals("Instance of activity must be one", 1,
461                 mWmState.getActivityCountInTask(taskId, STANDARD_ACTIVITY));
462 
463         // Make sure the stack for the standard activity is front.
464         assertEquals("The stack for the standard activity must be front.",
465                 getActivityName(STANDARD_ACTIVITY),
466                 mWmState.getTopActivityName(0));
467     }
468 
469     /**
470      * This test case tests behavior of activity launched with FLAG_ACTIVITY_CLEAR_TOP.
471      * A top activity is finished when an activity is launched with FLAG_ACTIVITY_CLEAR_TOP.
472      */
473     @Test
testLaunchActivityWithFlagClearTop()474     public void testLaunchActivityWithFlagClearTop() {
475         // Launch a standard activity
476         getLaunchActivityBuilder()
477                 .setTargetActivity(STANDARD_ACTIVITY)
478                 .setUseInstrumentation()
479                 .execute();
480 
481         final int taskId = mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId();
482 
483         // Launch a second standard activity
484         getLaunchActivityBuilder()
485                 .setTargetActivity(SECOND_STANDARD_ACTIVITY)
486                 .setUseInstrumentation()
487                 .execute();
488 
489         // Launch a standard activity again with CLEAR_TOP_FLAG
490         getLaunchActivityBuilder()
491                 .setTargetActivity(STANDARD_ACTIVITY)
492                 .setUseInstrumentation()
493                 .setIntentFlags(FLAG_ACTIVITY_CLEAR_TOP)
494                 .execute();
495 
496         mWmState.waitForActivityState(STANDARD_ACTIVITY, STATE_RESUMED);
497 
498         // Make sure that the standard activity is in focus.
499         mWmState.assertFocusedActivity(STANDARD_ACTIVITY + "must be focused Activity",
500                 STANDARD_ACTIVITY);
501 
502         // Make sure the stack for the standard activity is front.
503         assertEquals("The stack for the standard activity must be front.",
504                 getActivityName(STANDARD_ACTIVITY),
505                 mWmState.getTopActivityName(0));
506 
507         // Make sure the activity is not in same task.
508         assertEquals("Activity must be in same task.", taskId,
509                 mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId());
510         // Make sure the second standard activity is finished.
511         final String waitFinishMsg = "Instance of second standard activity must not exist";
512         assertTrue(waitFinishMsg, mWmState.waitForWithAmState(
513                 amState -> 0 == amState.getActivityCountInTask(taskId, SECOND_STANDARD_ACTIVITY),
514                 waitFinishMsg));
515     }
516 
517     @Test
testLaunchActivityWithFlagPreviousIsTop()518     public void testLaunchActivityWithFlagPreviousIsTop() {
519         // Launch a standard activity
520         getLaunchActivityBuilder()
521                 .setTargetActivity(SINGLE_TOP_ACTIVITY)
522                 .execute();
523 
524         final int taskId = mWmState.getTaskByActivity(
525                 SINGLE_TOP_ACTIVITY).getTaskId();
526 
527         // Launch a standard activity again with PREVIOUS_IS_TOP
528         getLaunchActivityBuilder()
529                 .setTargetActivity(SINGLE_TOP_ACTIVITY)
530                 .setLaunchingActivity(LAUNCHING_AND_FINISH_ACTIVITY)
531                 .setIntentFlags(FLAG_ACTIVITY_PREVIOUS_IS_TOP)
532                 .execute();
533 
534         assertEquals("Instance of activity must be one", 1,
535                 mWmState.getActivityCountInTask(taskId, SINGLE_TOP_ACTIVITY));
536     }
537 
538     /**
539      * This test case tests behavior of activity launched with FLAG_ACTIVITY_SINGLE_TOP.
540      * A single top activity must not be launched if it is already running at the top
541      * of the history stack.
542      */
543     @Test
testLaunchActivityWithFlagSingleTop()544     public void testLaunchActivityWithFlagSingleTop() {
545         // Launch a standard activity
546         getLaunchActivityBuilder()
547                 .setUseInstrumentation()
548                 .setTargetActivity(STANDARD_ACTIVITY)
549                 .execute();
550 
551         final int taskId = mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId();
552 
553         // Launch a standard activity with SINGLE_TOP flag.
554         // This standard activity launches a standard activity with single top flag.
555         getLaunchActivityBuilder()
556                 .setTargetActivity(STANDARD_SINGLE_TOP_ACTIVITY)
557                 .setUseInstrumentation()
558                 .setIntentFlags(FLAG_ACTIVITY_SINGLE_TOP)
559                 .execute();
560 
561         mWmState.waitForActivityState(STANDARD_SINGLE_TOP_ACTIVITY, STATE_RESUMED);
562 
563         // Make sure that a new instance is not created if it is already running at the top
564         // of the history stack.
565         assertEquals("Multiple single top activities must not be created.", 1,
566                 mWmState
567                         .getActivityCountInTask(taskId, STANDARD_SINGLE_TOP_ACTIVITY));
568 
569 
570         // Make sure that activity is in focus.
571         mWmState.assertFocusedActivity(STANDARD_SINGLE_TOP_ACTIVITY + "must be focused Activity",
572                 STANDARD_SINGLE_TOP_ACTIVITY);
573         // Make sure the stack for the single top activity is front.
574         assertEquals("The stack for the single top activity must be front.",
575                 getActivityName(STANDARD_SINGLE_TOP_ACTIVITY),
576                 mWmState.getTopActivityName(0));
577 
578         // Make sure the standard activity and the single top activity are in same task.
579         assertEquals("Activity must be in same task.", taskId,
580                 mWmState.getTaskByActivity(STANDARD_SINGLE_TOP_ACTIVITY)
581                         .getTaskId());
582     }
583 
584     /**
585      * This test case tests behavior of activity launched with FLAG_ACTIVITY_MULTIPLE_TASK
586      * and FLAG_ACTIVITY_NEW_TASK.
587      * Second launched activity which is launched with FLAG_ACTIVITY_MULTIPLE_TASK and
588      * FLAG_ACTIVITY_NEW_TASK is created in new task/stack. So, a first launched activity
589      * and a second launched activity are in different task/stack.
590      */
591     @Test
testActivityWithFlagMultipleTaskAndNewTask()592     public void testActivityWithFlagMultipleTaskAndNewTask() {
593         // Launch a standard activity
594         getLaunchActivityBuilder()
595                 .setTargetActivity(STANDARD_ACTIVITY)
596                 .setIntentFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
597                 .execute();
598 
599         final int taskId = mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId();
600 
601         // Launch a standard activity with FLAG_ACTIVITY_MULTIPLE_TASK|FLAG_ACTIVITY_NEW_TASK
602         getLaunchActivityBuilder()
603                 .setTargetActivity(STANDARD_ACTIVITY)
604                 .setLaunchingActivity(TEST_LAUNCHING_ACTIVITY)
605                 .setIntentFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
606                 .execute();
607 
608         // Make sure the stack for the standard activity is front.
609         assertEquals("The stack for the standard activity must be front.",
610                 getActivityName(STANDARD_ACTIVITY),
611                 mWmState.getTopActivityName(0));
612         // Make sure the first standard activity and second standard activity are not in same task.
613         assertNotEquals("Activity must not be in same task.", taskId,
614                 mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId());
615     }
616 
617     /**
618      * This test case tests behavior of activity launched with ClearTaskOnLaunch attribute and
619      * FLAG_ACTIVITY_RESET_TASK_IF_NEEDED. The activities above will be removed from the task when
620      * the clearTaskonlaunch activity is re-launched again.
621      */
622     @Test
testActivityWithClearTaskOnLaunch()623     public void testActivityWithClearTaskOnLaunch() {
624         // Launch a clearTaskonlaunch activity
625         getLaunchActivityBuilder()
626                 .setUseInstrumentation()
627                 .setTargetActivity(CLEAR_TASK_ON_LAUNCH_ACTIVITY)
628                 .setIntentFlags(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
629                 .execute();
630         mWmState.waitForActivityState(CLEAR_TASK_ON_LAUNCH_ACTIVITY, STATE_RESUMED);
631         final int taskId = mWmState.getTaskByActivity(CLEAR_TASK_ON_LAUNCH_ACTIVITY).getTaskId();
632 
633         // Launch a standard activity
634         getLaunchActivityBuilder()
635                 .setUseInstrumentation()
636                 .setTargetActivity(STANDARD_ACTIVITY)
637                 .execute();
638         mWmState.waitForActivityState(STANDARD_ACTIVITY, STATE_RESUMED);
639 
640         // Return to home
641         launchHomeActivity();
642 
643         // Launch the clearTaskonlaunch activity again
644         getLaunchActivityBuilder()
645                 .setUseInstrumentation()
646                 .setTargetActivity(CLEAR_TASK_ON_LAUNCH_ACTIVITY)
647                 .setIntentFlags(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
648                 .execute();
649         mWmState.waitForActivityState(CLEAR_TASK_ON_LAUNCH_ACTIVITY, STATE_RESUMED);
650         mWmState.waitForActivityState(STANDARD_ACTIVITY, STATE_DESTROYED);
651 
652         // Make sure the task for the clearTaskonlaunch activity is front.
653         assertEquals("The task for the clearTaskonlaunch activity must be front.",
654                 getActivityName(CLEAR_TASK_ON_LAUNCH_ACTIVITY),
655                 mWmState.getTopActivityName(0));
656 
657         assertEquals("Instance of the activity in its task must be cleared", 0,
658                 mWmState.getActivityCountInTask(taskId, STANDARD_ACTIVITY));
659     }
660 
661     /**
662      * This test case tests behavior of activity with finishOnTaskLaunch attribute when the
663      * activity's task is relaunched from home, this activity should be finished.
664      */
665     @Test
testActivityWithFinishOnTaskLaunch()666     public void testActivityWithFinishOnTaskLaunch() {
667         // Launch a standard activity.
668         launchActivity(STANDARD_ACTIVITY);
669 
670         final int taskId = mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId();
671         final int instances = mWmState.getActivityCountInTask(taskId, null);
672 
673         // Launch a activity with finishOnTaskLaunch
674         launchActivity(FINISH_ON_TASK_LAUNCH_ACTIVITY);
675 
676         // Make sure instances in task are increased.
677         assertEquals("instances of activity in task must be increased.", instances + 1,
678                 mWmState.getActivityCountInTask(taskId, null));
679 
680         // Navigate home
681         launchHomeActivity();
682 
683         // Simulate to launch the activity from home again
684         getLaunchActivityBuilder()
685                 .setUseInstrumentation()
686                 .setTargetActivity(STANDARD_ACTIVITY)
687                 .setIntentFlags(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
688                 .execute();
689         mWmState.waitForActivityState(STANDARD_ACTIVITY, STATE_RESUMED);
690 
691         // Make sure the activity is removed.
692         mWmState.waitAndAssertActivityRemoved(FINISH_ON_TASK_LAUNCH_ACTIVITY);
693     }
694 
695     @Test
testActivityWithDocumentIntoExisting()696     public void testActivityWithDocumentIntoExisting() {
697         // Launch a documentLaunchMode="intoExisting" activity
698         launchActivityWithData(DOCUMENT_INTO_EXISTING_ACTIVITY, "test");
699         waitAndAssertActivityState(DOCUMENT_INTO_EXISTING_ACTIVITY, STATE_RESUMED,
700                 "Activity should be resumed");
701         final int taskId = mWmState.getTaskByActivity(DOCUMENT_INTO_EXISTING_ACTIVITY).getTaskId();
702 
703         // Navigate home
704         launchHomeActivity();
705 
706         // Launch the alias activity.
707         final ComponentName componentName = new ComponentName(mContext.getPackageName(),
708                 DocumentIntoExistingActivity.class.getPackageName()
709                         + ".ActivityStarterTests$DocumentIntoExistingAliasActivity");
710         launchActivityWithData(componentName, "test");
711 
712         waitAndAssertActivityState(DOCUMENT_INTO_EXISTING_ACTIVITY, STATE_RESUMED,
713                 "Activity should be resumed");
714         final int taskId2 = mWmState.getTaskByActivity(DOCUMENT_INTO_EXISTING_ACTIVITY).getTaskId();
715         assertEquals("Activity must be in the same task.", taskId, taskId2);
716         assertEquals("Activity is the only member of its task", 1,
717                 mWmState.getActivityCountInTask(taskId2, null));
718     }
719 
720     /**
721      * This test case tests behavior of activity with relinquishTaskIdentify attribute. Ensure the
722      * relinquishTaskIdentity work if the activities are in the same app.
723      */
724     @Test
testActivityWithRelinquishTaskIdentity()725     public void testActivityWithRelinquishTaskIdentity() {
726         // Launch a relinquishTaskIdentity activity and test activity with different affinity into
727         // a same task.
728         getLaunchActivityBuilder().setTargetActivity(RELINQUISHTASKIDENTITY_ACTIVITY)
729                 .setIntentExtra(extra -> extra.putBoolean(
730                         RelinquishTaskIdentityActivity.EXTRA_LAUNCHED, true))
731                 .setUseInstrumentation()
732                 .setWaitForLaunched(true)
733                 .execute();
734         // get the task affinity(e.g. 10825:android.server.wm.cts) without the uid information
735         String affinity = mWmState.getTaskByActivity(RELINQUISHTASKIDENTITY_ACTIVITY).getAffinity();
736         affinity = affinity.substring(affinity.indexOf(":") + 1);
737 
738         final int taskId = mWmState.getTaskByActivity(RELINQUISHTASKIDENTITY_ACTIVITY).getTaskId();
739         final int taskId2 = mWmState.getTaskByActivity(TEST_LAUNCHING_ACTIVITY).getTaskId();
740 
741         // verify the activities are in the same task
742         assertEquals("Activity must be in the same task.", taskId, taskId2);
743         // verify the relinquishTaskIdentify function should work since the activities are in the
744         // same app
745         assertNotEquals("Affinity should not be same with the package name.",
746                 RELINQUISHTASKIDENTITY_ACTIVITY.getPackageName(), affinity);
747     }
748 
749     /**
750      * This test case tests behavior of activity with launch_adjacent and new_task. Ensure the flags
751      * make activity in multi-window mode.
752      */
753     @Test
testLaunchActivityWithLaunchAdjacentAndNewTask()754     public void testLaunchActivityWithLaunchAdjacentAndNewTask() {
755         assumeTrue("Skipping test: no split multi-window support",
756                 supportsSplitScreenMultiWindow());
757 
758         mTaskOrganizer.registerOrganizerIfNeeded();
759 
760         // Launch activity with FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_LAUNCH_ADJACENT.
761         launchAndAssertActivityWindowingMode(
762                 FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_LAUNCH_ADJACENT,
763                 WINDOWING_MODE_MULTI_WINDOW);
764     }
765 
766     /**
767      * This test case tests behavior of activity with launch_adjacent. Ensure the flag is ignored
768      * if without new_task together.
769      */
770     @Test
testLaunchActivityWithLaunchAdjacent()771     public void testLaunchActivityWithLaunchAdjacent() {
772         assumeTrue("Skipping test: no split multi-window support",
773                 supportsSplitScreenMultiWindow());
774 
775         // Launch activity with FLAG_ACTIVITY_LAUNCH_ADJACENT only.
776         launchAndAssertActivityWindowingMode(FLAG_ACTIVITY_LAUNCH_ADJACENT,
777                 WINDOWING_MODE_FULLSCREEN);
778     }
779 
launchAndAssertActivityWindowingMode(int flags, int expectWindowingMode)780     private void launchAndAssertActivityWindowingMode(int flags, int expectWindowingMode) {
781         getLaunchActivityBuilder()
782                 .setTargetActivity(STANDARD_ACTIVITY)
783                 .setIntentFlags(flags)
784                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
785                 .execute();
786 
787         // wait for the expected windowing mode
788         mWmState.waitForValidState(new WaitForValidActivityState.Builder(STANDARD_ACTIVITY)
789                 .setWindowingMode(expectWindowingMode)
790                 .build());
791 
792         assertEquals(expectWindowingMode,
793                 mWmState.getActivity(STANDARD_ACTIVITY).getWindowingMode());
794     }
795 
796     // Test activity
797     public static class RelinquishTaskIdentityActivity extends Activity {
798         public static final String EXTRA_LAUNCHED = "extraLaunched";
799         @Override
onCreate(Bundle icicle)800         protected void onCreate(Bundle icicle) {
801             super.onCreate(icicle);
802             if (getIntent().getBooleanExtra(EXTRA_LAUNCHED, false)) {
803                 startActivityForResult(
804                         new Intent(this, TestLaunchingActivity.class), 1 /* requestCode */);
805             }
806         }
807     }
808 
809     // Test activity
810     public static class StandardWithSingleTopActivity extends Activity {
811 
812         @Override
onCreate(Bundle savedInstanceState)813         protected void onCreate(Bundle savedInstanceState) {
814             super.onCreate(savedInstanceState);
815             final Intent intent = new Intent().setComponent(
816                     new ComponentName(this /* context */, getClass()));
817             intent.addFlags(FLAG_ACTIVITY_SINGLE_TOP);
818             startActivity(intent);
819         }
820     }
821 
822     // Test activity
823     public static class ClearTaskOnLaunchActivity extends Activity {
824     }
825 
826     // Test activity
827     public static class FinishOnTaskLaunchActivity extends Activity {
828     }
829 
830     // Test activity
831     public static class SingleTopActivity extends Activity {
832     }
833 
834     // Test activity
835     public static class SingleTaskActivity extends Activity {
836     }
837 
838     // Test activity
839     public static class SingleInstanceActivity extends Activity {
840         public static final String EXTRA_SHOW_WHEN_LOCKED = "showWhenLocked";
841         @Override
onCreate(Bundle icicle)842         protected void onCreate(Bundle icicle) {
843             super.onCreate(icicle);
844             if (getIntent().getBooleanExtra(EXTRA_SHOW_WHEN_LOCKED, false)) {
845                 setShowWhenLocked(true);
846             }
847         }
848     }
849 
850     // Test activity
851     public static class DocumentIntoExistingActivity extends Activity {
852     }
853 
854     // Launching activity
855     public static class TestLaunchingActivity extends Activity {
856         @Override
onCreate(Bundle savedInstanceState)857         protected void onCreate(Bundle savedInstanceState) {
858             super.onCreate(savedInstanceState);
859 
860             final Intent intent = getIntent();
861             if (intent != null) {
862                 ActivityLauncher.launchActivityFromExtras(this, intent.getExtras());
863             }
864         }
865 
866         @Override
onNewIntent(Intent intent)867         protected void onNewIntent(Intent intent) {
868             super.onNewIntent(intent);
869             ActivityLauncher.launchActivityFromExtras(this, intent.getExtras());
870         }
871     }
872 
873     public static class LaunchingAndFinishActivity extends TestLaunchingActivity {
874         @Override
onCreate(Bundle savedInstanceState)875         protected void onCreate(Bundle savedInstanceState) {
876             super.onCreate(savedInstanceState);
877             finish();
878         }
879     }
880 }
881