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.lifecycle;
18 
19 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
20 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
21 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
22 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
23 import static android.content.Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP;
24 import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
25 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
26 import static android.server.wm.ComponentNameUtils.getActivityName;
27 import static android.server.wm.UiDeviceUtils.pressWakeupButton;
28 import static android.server.wm.WindowManagerState.STATE_DESTROYED;
29 import static android.server.wm.WindowManagerState.STATE_RESUMED;
30 import static android.server.wm.app.Components.ALIAS_TEST_ACTIVITY;
31 import static android.server.wm.app.Components.NO_HISTORY_ACTIVITY;
32 import static android.server.wm.app.Components.SHOW_WHEN_LOCKED_TRANSLUCENT_ACTIVITY;
33 import static android.server.wm.app.Components.TEST_ACTIVITY;
34 import static android.server.wm.lifecycle.LifecycleLog.ActivityCallback.ON_STOP;
35 import static android.view.Display.DEFAULT_DISPLAY;
36 
37 import static org.junit.Assert.assertEquals;
38 import static org.junit.Assert.assertNotEquals;
39 import static org.junit.Assert.assertTrue;
40 import static org.junit.Assume.assumeTrue;
41 
42 import android.app.Activity;
43 import android.app.WindowConfiguration;
44 import android.content.ComponentName;
45 import android.content.Intent;
46 import android.os.Bundle;
47 import android.platform.test.annotations.Presubmit;
48 import android.server.wm.ActivityLauncher;
49 import android.server.wm.WindowManagerState;
50 import android.server.wm.app.Components;
51 import android.util.Log;
52 import android.view.WindowManager;
53 
54 import org.junit.Test;
55 
56 import java.util.List;
57 import java.util.function.Predicate;
58 
59 /**
60  * Build/Install/Run:
61  *     atest CtsWindowManagerDeviceTestCases: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(StandardActivity.class);
69     private static final ComponentName SECOND_STANDARD_ACTIVITY
70             = getComponentName(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:
96      * - {@code FLAG_ACTIVITY_CLEAR_TOP}
97      * - {@code FLAG_ACTIVITY_RESET_TASK_IF_NEEDED}
98      * - {@code FLAG_ACTIVITY_NEW_TASK}
99      */
100     @Test
testClearTopNewTaskResetTask()101     public void testClearTopNewTaskResetTask() throws Exception {
102         // Start activity normally
103         launchActivityAndWait(FirstActivity.class);
104 
105         // Navigate home
106         launchHomeActivity();
107         waitAndAssertActivityStates(state(FirstActivity.class, ON_STOP));
108         getLifecycleLog().clear();
109 
110         // Start activity again with flags in question. Verify activity is resumed.
111         // A new instance of activity will be created, and the old one destroyed.
112         final Activity secondLaunchActivity = new Launcher(FirstActivity.class)
113                 .setFlags(FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_NEW_TASK
114                         | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
115                 .launch();
116         mWmState.waitForActivityState(secondLaunchActivity.getComponentName(), STATE_RESUMED);
117         assertEquals("The activity should be started and be resumed",
118                 getActivityName(secondLaunchActivity.getComponentName()),
119                 mWmState.getTopActivityName(0));
120     }
121 
122     /**
123      * This test case tests "standard" activity behavior.
124      * A first launched standard activity and a second launched standard activity
125      * must be in same task.
126      */
127     @Test
testLaunchStandardActivity()128     public void testLaunchStandardActivity() {
129         // Launch a standard activity.
130         launchActivity(STANDARD_ACTIVITY);
131 
132         final int taskId = mWmState.getTaskByActivity(STANDARD_ACTIVITY).getTaskId();
133         final int instances = mWmState.getActivityCountInTask(taskId, null);
134 
135         // Launch a second standard activity.
136         launchActivity(SECOND_STANDARD_ACTIVITY);
137 
138         // Make sure instances in task are increased.
139         assertEquals("instances of activity in task must be increased.", instances + 1,
140                 mWmState.getActivityCountInTask(taskId, null));
141 
142         // Make sure the stack for the second standard activity is front.
143         assertEquals("The stack for the second standard activity must be front.",
144                 getActivityName(SECOND_STANDARD_ACTIVITY),
145                 mWmState.getTopActivityName(0));
146 
147         // Make sure the standard activity and the second standard activity are in same task.
148         assertEquals("Activity must be in same task.", taskId,
149                 mWmState.getTaskByActivity(SECOND_STANDARD_ACTIVITY).getTaskId());
150     }
151 
152     /**
153      * This test case tests show-when-locked behavior for a "no-history" activity.
154      * The no-history activity should be resumed over lockscreen.
155      */
156     @Test
testLaunchNoHistoryActivityShowWhenLocked()157     public void testLaunchNoHistoryActivityShowWhenLocked() {
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 finished.
692         assertEquals("Instance of the activity in its task must be cleared", 0,
693                 mWmState.getActivityCountInTask(taskId, FINISH_ON_TASK_LAUNCH_ACTIVITY));
694     }
695 
696     @Test
testActivityWithDocumentIntoExisting()697     public void testActivityWithDocumentIntoExisting() {
698         // Launch a documentLaunchMode="intoExisting" activity
699         launchActivityWithData(DOCUMENT_INTO_EXISTING_ACTIVITY, "test");
700         waitAndAssertActivityState(DOCUMENT_INTO_EXISTING_ACTIVITY, STATE_RESUMED,
701                 "Activity should be resumed");
702         final int taskId = mWmState.getTaskByActivity(DOCUMENT_INTO_EXISTING_ACTIVITY).getTaskId();
703 
704         // Navigate home
705         launchHomeActivity();
706 
707         // Launch the alias activity.
708         final ComponentName componentName = new ComponentName(mContext.getPackageName(),
709                 DocumentIntoExistingActivity.class.getPackageName()
710                         + ".ActivityStarterTests$DocumentIntoExistingAliasActivity");
711         launchActivityWithData(componentName, "test");
712 
713         waitAndAssertActivityState(DOCUMENT_INTO_EXISTING_ACTIVITY, STATE_RESUMED,
714                 "Activity should be resumed");
715         final int taskId2 = mWmState.getTaskByActivity(DOCUMENT_INTO_EXISTING_ACTIVITY).getTaskId();
716         assertEquals("Activity must be in the same task.", taskId, taskId2);
717         assertEquals("Activity is the only member of its task", 1,
718                 mWmState.getActivityCountInTask(taskId2, null));
719     }
720 
721     /**
722      * This test case tests behavior of activity with relinquishTaskIdentify attribute. Ensure the
723      * relinquishTaskIdentity work if the activities are in the same app.
724      */
725     @Test
testActivityWithRelinquishTaskIdentity()726     public void testActivityWithRelinquishTaskIdentity() {
727         // Launch a relinquishTaskIdentity activity and test activity with different affinity into
728         // a same task.
729         getLaunchActivityBuilder().setTargetActivity(RELINQUISHTASKIDENTITY_ACTIVITY)
730                 .setIntentExtra(extra -> extra.putBoolean(
731                         RelinquishTaskIdentityActivity.EXTRA_LAUNCHED, true))
732                 .setUseInstrumentation()
733                 .setWaitForLaunched(true)
734                 .execute();
735         // get the task affinity(e.g. 10825:android.server.wm.cts) without the uid information
736         String affinity = mWmState.getTaskByActivity(RELINQUISHTASKIDENTITY_ACTIVITY).getAffinity();
737         affinity = affinity.substring(affinity.indexOf(":") + 1);
738 
739         final int taskId = mWmState.getTaskByActivity(RELINQUISHTASKIDENTITY_ACTIVITY).getTaskId();
740         final int taskId2 = mWmState.getTaskByActivity(TEST_LAUNCHING_ACTIVITY).getTaskId();
741 
742         // verify the activities are in the same task
743         assertEquals("Activity must be in the same task.", taskId, taskId2);
744         // verify the relinquishTaskIdentify function should work since the activities are in the
745         // same app
746         assertNotEquals("Affinity should not be same with the package name.",
747                 RELINQUISHTASKIDENTITY_ACTIVITY.getPackageName(), affinity);
748     }
749 
750     // Test activity
751     public static class RelinquishTaskIdentityActivity extends Activity {
752         public static final String EXTRA_LAUNCHED = "extraLaunched";
753         @Override
onCreate(Bundle icicle)754         protected void onCreate(Bundle icicle) {
755             super.onCreate(icicle);
756             if (getIntent().getBooleanExtra(EXTRA_LAUNCHED, false)) {
757                 startActivityForResult(
758                         new Intent(this, TestLaunchingActivity.class), 1 /* requestCode */);
759             }
760         }
761     }
762 
763     // Test activity
764     public static class StandardActivity extends Activity {
765     }
766 
767     // Test activity
768     public static class SecondStandardActivity extends Activity {
769     }
770 
771     // Test activity
772     public static class StandardWithSingleTopActivity extends Activity {
773 
774         @Override
onCreate(Bundle savedInstanceState)775         protected void onCreate(Bundle savedInstanceState) {
776             super.onCreate(savedInstanceState);
777             final Intent intent = new Intent().setComponent(
778                     new ComponentName(this /* context */, getClass()));
779             intent.addFlags(FLAG_ACTIVITY_SINGLE_TOP);
780             startActivity(intent);
781         }
782     }
783 
784     // Test activity
785     public static class ClearTaskOnLaunchActivity extends Activity {
786     }
787 
788     // Test activity
789     public static class FinishOnTaskLaunchActivity extends Activity {
790     }
791 
792     // Test activity
793     public static class SingleTopActivity extends Activity {
794     }
795 
796     // Test activity
797     public static class SingleTaskActivity extends Activity {
798     }
799 
800     // Test activity
801     public static class SingleInstanceActivity extends Activity {
802         public static final String EXTRA_SHOW_WHEN_LOCKED = "showWhenLocked";
803         @Override
onCreate(Bundle icicle)804         protected void onCreate(Bundle icicle) {
805             super.onCreate(icicle);
806             if (getIntent().getBooleanExtra(EXTRA_SHOW_WHEN_LOCKED, false)) {
807                 setShowWhenLocked(true);
808             }
809         }
810     }
811 
812     // Test activity
813     public static class DocumentIntoExistingActivity extends Activity {
814     }
815 
816     // Launching activity
817     public static class TestLaunchingActivity extends Activity {
818         @Override
onCreate(Bundle savedInstanceState)819         protected void onCreate(Bundle savedInstanceState) {
820             super.onCreate(savedInstanceState);
821 
822             final Intent intent = getIntent();
823             if (intent != null) {
824                 ActivityLauncher.launchActivityFromExtras(this, intent.getExtras());
825             }
826         }
827 
828         @Override
onNewIntent(Intent intent)829         protected void onNewIntent(Intent intent) {
830             super.onNewIntent(intent);
831             ActivityLauncher.launchActivityFromExtras(this, intent.getExtras());
832         }
833     }
834 
835     public static class LaunchingAndFinishActivity extends TestLaunchingActivity {
836         @Override
onCreate(Bundle savedInstanceState)837         protected void onCreate(Bundle savedInstanceState) {
838             super.onCreate(savedInstanceState);
839             finish();
840         }
841     }
842 }
843