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 com.android.server.wm;
18 
19 import static android.app.KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
22 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
25 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
26 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
27 import static android.view.Display.DEFAULT_DISPLAY;
28 import static android.view.Display.TYPE_VIRTUAL;
29 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
30 
31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
33 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
34 import static com.android.server.wm.ActivityRecord.State.FINISHING;
35 import static com.android.server.wm.ActivityRecord.State.PAUSED;
36 import static com.android.server.wm.ActivityRecord.State.PAUSING;
37 import static com.android.server.wm.ActivityRecord.State.RESUMED;
38 import static com.android.server.wm.ActivityRecord.State.STOPPED;
39 import static com.android.server.wm.ActivityRecord.State.STOPPING;
40 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
41 import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
42 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
43 
44 import static com.google.common.truth.Truth.assertThat;
45 
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertFalse;
48 import static org.junit.Assert.assertNotEquals;
49 import static org.junit.Assert.assertNotNull;
50 import static org.junit.Assert.assertNull;
51 import static org.junit.Assert.assertTrue;
52 import static org.mockito.ArgumentMatchers.any;
53 import static org.mockito.ArgumentMatchers.anyBoolean;
54 import static org.mockito.ArgumentMatchers.anyInt;
55 import static org.mockito.ArgumentMatchers.contains;
56 import static org.mockito.ArgumentMatchers.eq;
57 import static org.mockito.ArgumentMatchers.refEq;
58 import static org.mockito.Mockito.clearInvocations;
59 import static org.mockito.Mockito.mock;
60 import static org.mockito.Mockito.never;
61 import static org.mockito.Mockito.reset;
62 import static org.mockito.Mockito.spy;
63 import static org.mockito.Mockito.times;
64 import static org.mockito.Mockito.verify;
65 
66 import android.app.ActivityOptions;
67 import android.app.WindowConfiguration;
68 import android.content.ComponentName;
69 import android.content.Intent;
70 import android.content.pm.ActivityInfo;
71 import android.content.pm.ApplicationInfo;
72 import android.content.pm.ResolveInfo;
73 import android.content.res.Configuration;
74 import android.content.res.Resources;
75 import android.os.UserHandle;
76 import android.platform.test.annotations.Presubmit;
77 import android.util.MergedConfiguration;
78 import android.util.Pair;
79 
80 import androidx.test.filters.MediumTest;
81 
82 import com.android.internal.app.ResolverActivity;
83 
84 import org.junit.Before;
85 import org.junit.Test;
86 import org.junit.runner.RunWith;
87 
88 import java.util.ArrayList;
89 import java.util.Arrays;
90 import java.util.List;
91 import java.util.function.Consumer;
92 
93 /**
94  * Tests for {@link RootWindowContainer}.
95  *
96  * Build/Install/Run:
97  *  atest WmTests:RootWindowContainerTests
98  */
99 @MediumTest
100 @Presubmit
101 @RunWith(WindowTestRunner.class)
102 public class RootWindowContainerTests extends WindowTestsBase {
103 
104     @Before
setUp()105     public void setUp() throws Exception {
106         doNothing().when(mAtm).updateSleepIfNeededLocked();
107     }
108 
109     @Test
testUpdateDefaultDisplayWindowingModeOnSettingsRetrieved()110     public void testUpdateDefaultDisplayWindowingModeOnSettingsRetrieved() {
111         assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
112                 mWm.getDefaultDisplayContentLocked().getWindowingMode());
113 
114         mWm.mIsPc = true;
115         mWm.mAtmService.mSupportsFreeformWindowManagement = true;
116 
117         mWm.mRoot.onSettingsRetrieved();
118 
119         assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
120                 mWm.getDefaultDisplayContentLocked().getWindowingMode());
121     }
122 
123     /**
124      * This test ensures that an existing single instance activity with alias name can be found by
125      * the same activity info. So {@link ActivityStarter#getReusableTask} won't miss it that leads
126      * to create an unexpected new instance.
127      */
128     @Test
testFindActivityByTargetComponent()129     public void testFindActivityByTargetComponent() {
130         final ComponentName aliasComponent = ComponentName.createRelative(
131                 DEFAULT_COMPONENT_PACKAGE_NAME, ".AliasActivity");
132         final ComponentName targetComponent = ComponentName.createRelative(
133                 aliasComponent.getPackageName(), ".TargetActivity");
134         final ActivityRecord activity = new ActivityBuilder(mWm.mAtmService)
135                 .setComponent(aliasComponent)
136                 .setTargetActivity(targetComponent.getClassName())
137                 .setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE)
138                 .setCreateTask(true)
139                 .build();
140 
141         assertEquals(activity, mWm.mRoot.findActivity(activity.intent, activity.info,
142                 false /* compareIntentFilters */));
143     }
144 
145     @Test
testAllPausedActivitiesComplete()146     public void testAllPausedActivitiesComplete() {
147         DisplayContent displayContent = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
148         ActivityRecord activity = createActivityRecord(displayContent);
149         Task task = activity.getTask();
150         task.setPausingActivity(activity);
151 
152         activity.setState(PAUSING, "test PAUSING");
153         assertThat(mWm.mRoot.allPausedActivitiesComplete()).isFalse();
154 
155         activity.setState(PAUSED, "test PAUSED");
156         assertThat(mWm.mRoot.allPausedActivitiesComplete()).isTrue();
157 
158         activity.setState(STOPPED, "test STOPPED");
159         assertThat(mWm.mRoot.allPausedActivitiesComplete()).isTrue();
160 
161         activity.setState(STOPPING, "test STOPPING");
162         assertThat(mWm.mRoot.allPausedActivitiesComplete()).isTrue();
163 
164         activity.setState(FINISHING, "test FINISHING");
165         assertThat(mWm.mRoot.allPausedActivitiesComplete()).isTrue();
166     }
167 
168     @Test
testTaskLayerRank()169     public void testTaskLayerRank() {
170         final Task rootTask = new TaskBuilder(mSupervisor).build();
171         final Task task1 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
172         new ActivityBuilder(mAtm).setTask(task1).build().mVisibleRequested = true;
173         mWm.mRoot.rankTaskLayers();
174 
175         assertEquals(1, task1.mLayerRank);
176         // Only tasks that directly contain activities have a ranking.
177         assertEquals(Task.LAYER_RANK_INVISIBLE, rootTask.mLayerRank);
178 
179         final Task task2 = new TaskBuilder(mSupervisor).build();
180         new ActivityBuilder(mAtm).setTask(task2).build().mVisibleRequested = true;
181         mWm.mRoot.rankTaskLayers();
182 
183         // Note that ensureActivitiesVisible is disabled in SystemServicesTestRule, so both the
184         // activities have the visible rank.
185         assertEquals(2, task1.mLayerRank);
186         // The task2 is the top task, so it has a lower rank as a higher priority oom score.
187         assertEquals(1, task2.mLayerRank);
188 
189         task2.moveToBack("test", null /* task */);
190         // RootWindowContainer#invalidateTaskLayers should post to update.
191         waitHandlerIdle(mWm.mH);
192 
193         assertEquals(1, task1.mLayerRank);
194         assertEquals(2, task2.mLayerRank);
195     }
196 
197     @Test
testForceStopPackage()198     public void testForceStopPackage() {
199         final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
200         final ActivityRecord activity = task.getTopMostActivity();
201         final WindowProcessController wpc = activity.app;
202         final ActivityRecord[] activities = {
203                 activity,
204                 new ActivityBuilder(mWm.mAtmService).setTask(task).setUseProcess(wpc).build(),
205                 new ActivityBuilder(mWm.mAtmService).setTask(task).setUseProcess(wpc).build()
206         };
207         activities[0].detachFromProcess();
208         activities[1].finishing = true;
209         activities[1].destroyImmediately("test");
210         spyOn(wpc);
211         doReturn(true).when(wpc).isRemoved();
212 
213         mWm.mAtmService.mInternal.onForceStopPackage(wpc.mInfo.packageName, true /* doit */,
214                 false /* evenPersistent */, wpc.mUserId);
215         // The activity without process should be removed.
216         assertEquals(2, task.getChildCount());
217 
218         wpc.handleAppDied();
219         // The activities with process should be removed because WindowProcessController#isRemoved.
220         assertFalse(task.hasChild());
221         assertFalse(wpc.hasActivities());
222     }
223 
224     /**
225      * This test ensures that we do not try to restore a task based off an invalid task id. We
226      * should expect {@code null} to be returned in this case.
227      */
228     @Test
testRestoringInvalidTask()229     public void testRestoringInvalidTask() {
230         mRootWindowContainer.getDefaultDisplay().removeAllTasks();
231         Task task = mRootWindowContainer.anyTaskForId(0 /*taskId*/,
232                 MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
233         assertNull(task);
234     }
235 
236     /**
237      * This test ensures that an existing task in the pinned root task is moved to the fullscreen
238      * activity root task when a new task is added.
239      */
240     @Test
testReplacingTaskInPinnedRootTask()241     public void testReplacingTaskInPinnedRootTask() {
242         Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
243                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
244         final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
245                 .setTask(fullscreenTask).build();
246         final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
247                 .setTask(fullscreenTask).build();
248 
249         fullscreenTask.moveToFront("testReplacingTaskInPinnedRootTask");
250 
251         // Ensure full screen root task has both tasks.
252         ensureTaskPlacement(fullscreenTask, firstActivity, secondActivity);
253 
254         // Move first activity to pinned root task.
255         mRootWindowContainer.moveActivityToPinnedRootTask(firstActivity, "initialMove");
256 
257         final TaskDisplayArea taskDisplayArea = fullscreenTask.getDisplayArea();
258         Task pinnedRootTask = taskDisplayArea.getRootPinnedTask();
259         // Ensure a task has moved over.
260         ensureTaskPlacement(pinnedRootTask, firstActivity);
261         ensureTaskPlacement(fullscreenTask, secondActivity);
262 
263         // Move second activity to pinned root task.
264         mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "secondMove");
265 
266         // Need to get root tasks again as a new instance might have been created.
267         pinnedRootTask = taskDisplayArea.getRootPinnedTask();
268         fullscreenTask = taskDisplayArea.getRootTask(WINDOWING_MODE_FULLSCREEN,
269                 ACTIVITY_TYPE_STANDARD);
270         // Ensure root tasks have swapped tasks.
271         ensureTaskPlacement(pinnedRootTask, secondActivity);
272         ensureTaskPlacement(fullscreenTask, firstActivity);
273     }
274 
275     @Test
testMovingBottomMostRootTaskActivityToPinnedRootTask()276     public void testMovingBottomMostRootTaskActivityToPinnedRootTask() {
277         final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
278                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
279         final ActivityRecord firstActivity = new ActivityBuilder(mAtm)
280                 .setTask(fullscreenTask).build();
281         final Task task = firstActivity.getTask();
282 
283         final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
284                 .setTask(fullscreenTask).build();
285 
286         fullscreenTask.moveTaskToBack(task);
287 
288         // Ensure full screen task has both tasks.
289         ensureTaskPlacement(fullscreenTask, firstActivity, secondActivity);
290         assertEquals(task.getTopMostActivity(), secondActivity);
291         firstActivity.setState(STOPPED, "testMovingBottomMostRootTaskActivityToPinnedRootTask");
292 
293 
294         // Move first activity to pinned root task.
295         mRootWindowContainer.moveActivityToPinnedRootTask(secondActivity, "initialMove");
296 
297         assertTrue(firstActivity.mRequestForceTransition);
298     }
299 
ensureTaskPlacement(Task task, ActivityRecord... activities)300     private static void ensureTaskPlacement(Task task, ActivityRecord... activities) {
301         final ArrayList<ActivityRecord> taskActivities = new ArrayList<>();
302 
303         task.forAllActivities((Consumer<ActivityRecord>) taskActivities::add, false);
304 
305         assertEquals("Expecting " + Arrays.deepToString(activities) + " got " + taskActivities,
306                 taskActivities.size(), activities != null ? activities.length : 0);
307 
308         if (activities == null) {
309             return;
310         }
311 
312         for (ActivityRecord activity : activities) {
313             assertTrue(taskActivities.contains(activity));
314         }
315     }
316 
317     @Test
testApplySleepTokens()318     public void testApplySleepTokens() {
319         final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
320         final KeyguardController keyguard = mSupervisor.getKeyguardController();
321         final Task task = new TaskBuilder(mSupervisor)
322                 .setDisplay(display)
323                 .setOnTop(false)
324                 .build();
325 
326         // Make sure we wake and resume in the case the display is turning on and the keyguard is
327         // not showing.
328         verifySleepTokenBehavior(display, keyguard, task, true /*displaySleeping*/,
329                 false /* displayShouldSleep */, true /* isFocusedTask */,
330                 false /* keyguardShowing */, true /* expectWakeFromSleep */,
331                 true /* expectResumeTopActivity */);
332 
333         // Make sure we wake and don't resume when the display is turning on and the keyguard is
334         // showing.
335         verifySleepTokenBehavior(display, keyguard, task, true /*displaySleeping*/,
336                 false /* displayShouldSleep */, true /* isFocusedTask */,
337                 true /* keyguardShowing */, true /* expectWakeFromSleep */,
338                 false /* expectResumeTopActivity */);
339 
340         // Make sure we wake and don't resume when the display is turning on and the keyguard is
341         // not showing as unfocused.
342         verifySleepTokenBehavior(display, keyguard, task, true /*displaySleeping*/,
343                 false /* displayShouldSleep */, false /* isFocusedTask */,
344                 false /* keyguardShowing */, true /* expectWakeFromSleep */,
345                 false /* expectResumeTopActivity */);
346 
347         // Should not do anything if the display state hasn't changed.
348         verifySleepTokenBehavior(display, keyguard, task, false /*displaySleeping*/,
349                 false /* displayShouldSleep */, true /* isFocusedTask */,
350                 false /* keyguardShowing */, false /* expectWakeFromSleep */,
351                 false /* expectResumeTopActivity */);
352     }
353 
verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard, Task task, boolean displaySleeping, boolean displayShouldSleep, boolean isFocusedTask, boolean keyguardShowing, boolean expectWakeFromSleep, boolean expectResumeTopActivity)354     private void verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard,
355             Task task, boolean displaySleeping, boolean displayShouldSleep,
356             boolean isFocusedTask, boolean keyguardShowing, boolean expectWakeFromSleep,
357             boolean expectResumeTopActivity) {
358         reset(task);
359 
360         doReturn(displayShouldSleep).when(display).shouldSleep();
361         doReturn(displaySleeping).when(display).isSleeping();
362         doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt());
363 
364         doReturn(isFocusedTask).when(task).isFocusedRootTaskOnDisplay();
365         doReturn(isFocusedTask ? task : null).when(display).getFocusedRootTask();
366         TaskDisplayArea defaultTaskDisplayArea = display.getDefaultTaskDisplayArea();
367         doReturn(isFocusedTask ? task : null).when(defaultTaskDisplayArea).getFocusedRootTask();
368         mRootWindowContainer.applySleepTokens(true);
369         verify(task, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleeping();
370         verify(task, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked(
371                 null /* target */, null /* targetOptions */);
372     }
373 
374     @Test
testAwakeFromSleepingWithAppConfiguration()375     public void testAwakeFromSleepingWithAppConfiguration() {
376         final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
377         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
378         activity.moveFocusableActivityToTop("test");
379         assertTrue(activity.getRootTask().isFocusedRootTaskOnDisplay());
380         ActivityRecordTests.setRotatedScreenOrientationSilently(activity);
381 
382         final Configuration rotatedConfig = new Configuration();
383         display.computeScreenConfiguration(rotatedConfig, display.getDisplayRotation()
384                 .rotationForOrientation(activity.getOrientation(), display.getRotation()));
385         assertNotEquals(activity.getConfiguration().orientation, rotatedConfig.orientation);
386         // Assume the activity was shown in different orientation. For example, the top activity is
387         // landscape and the portrait lockscreen is shown.
388         activity.setLastReportedConfiguration(
389                 new MergedConfiguration(mAtm.getGlobalConfiguration(), rotatedConfig));
390         activity.setState(STOPPED, "sleep");
391 
392         display.setIsSleeping(true);
393         doReturn(false).when(display).shouldSleep();
394         // Allow to resume when awaking.
395         setBooted(mAtm);
396         mRootWindowContainer.applySleepTokens(true);
397 
398         // The display orientation should be changed by the activity so there is no relaunch.
399         verify(activity, never()).relaunchActivityLocked(anyBoolean());
400         assertEquals(rotatedConfig.orientation, display.getConfiguration().orientation);
401     }
402 
403     /**
404      * Verifies that removal of activity with task and root task is done correctly.
405      */
406     @Test
testRemovingRootTaskOnAppCrash()407     public void testRemovingRootTaskOnAppCrash() {
408         final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
409                 .getDefaultTaskDisplayArea();
410         final int originalRootTaskCount = defaultTaskDisplayArea.getRootTaskCount();
411         final Task rootTask = defaultTaskDisplayArea.createRootTask(
412                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
413         final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(rootTask).build();
414 
415         assertEquals(originalRootTaskCount + 1, defaultTaskDisplayArea.getRootTaskCount());
416 
417         // Let's pretend that the app has crashed.
418         firstActivity.app.setThread(null);
419         mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
420 
421         // Verify that the root task was removed.
422         assertEquals(originalRootTaskCount, defaultTaskDisplayArea.getRootTaskCount());
423     }
424 
425     /**
426      * Verifies that removal of activities with task and root task is done correctly when there are
427      * several task display areas.
428      */
429     @Test
testRemovingRootTaskOnAppCrash_multipleDisplayAreas()430     public void testRemovingRootTaskOnAppCrash_multipleDisplayAreas() {
431         final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
432                 .getDefaultTaskDisplayArea();
433         final int originalRootTaskCount = defaultTaskDisplayArea.getRootTaskCount();
434         final Task rootTask = defaultTaskDisplayArea.createRootTask(
435                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
436         final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(rootTask).build();
437         assertEquals(originalRootTaskCount + 1, defaultTaskDisplayArea.getRootTaskCount());
438 
439         final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent();
440         final TaskDisplayArea secondTaskDisplayArea = createTaskDisplayArea(
441                 dc, mRootWindowContainer.mWmService, "TestTaskDisplayArea", FEATURE_VENDOR_FIRST);
442         final Task secondRootTask = secondTaskDisplayArea.createRootTask(
443                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
444         new ActivityBuilder(mAtm).setTask(secondRootTask).setUseProcess(firstActivity.app).build();
445         assertEquals(1, secondTaskDisplayArea.getRootTaskCount());
446 
447         // Let's pretend that the app has crashed.
448         firstActivity.app.setThread(null);
449         mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
450 
451         // Verify that the root tasks were removed.
452         assertEquals(originalRootTaskCount, defaultTaskDisplayArea.getRootTaskCount());
453         assertEquals(0, secondTaskDisplayArea.getRootTaskCount());
454     }
455 
456     @Test
testFocusability()457     public void testFocusability() {
458         final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
459                 .getDefaultTaskDisplayArea();
460         final Task task = defaultTaskDisplayArea.createRootTask(
461                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
462         final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
463 
464         // Created tasks are focusable by default.
465         assertTrue(task.isTopActivityFocusable());
466         assertTrue(activity.isFocusable());
467 
468         // If the task is made unfocusable, its activities should inherit that.
469         task.setFocusable(false);
470         assertFalse(task.isTopActivityFocusable());
471         assertFalse(activity.isFocusable());
472 
473         final Task pinnedTask = defaultTaskDisplayArea.createRootTask(
474                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
475         final ActivityRecord pinnedActivity = new ActivityBuilder(mAtm)
476                 .setTask(pinnedTask).build();
477 
478         // We should not be focusable when in pinned mode
479         assertFalse(pinnedTask.isTopActivityFocusable());
480         assertFalse(pinnedActivity.isFocusable());
481 
482         // Add flag forcing focusability.
483         pinnedActivity.info.flags |= FLAG_ALWAYS_FOCUSABLE;
484 
485         // Task with FLAG_ALWAYS_FOCUSABLE should be focusable.
486         assertTrue(pinnedTask.isTopActivityFocusable());
487         assertTrue(pinnedActivity.isFocusable());
488     }
489 
490     /**
491      * Verify that home root task would be moved to front when the top activity is Recents.
492      */
493     @Test
testFindTaskToMoveToFrontWhenRecentsOnTop()494     public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
495         // Create root task/task on default display.
496         final Task targetRootTask = new TaskBuilder(mSupervisor)
497                 .setCreateActivity(true)
498                 .setOnTop(false)
499                 .build();
500         final Task targetTask = targetRootTask.getBottomMostTask();
501 
502         // Create Recents on top of the display.
503         final Task rootTask = new TaskBuilder(mSupervisor)
504                 .setCreateActivity(true)
505                 .setActivityType(ACTIVITY_TYPE_RECENTS)
506                 .build();
507 
508         final String reason = "findTaskToMoveToFront";
509         mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
510                 false);
511 
512         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
513         verify(taskDisplayArea).moveHomeRootTaskToFront(contains(reason));
514     }
515 
516     /**
517      * Verify that home root task won't be moved to front if the top activity on other display is
518      * Recents.
519      */
520     @Test
testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay()521     public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() {
522         // Create tasks on default display.
523         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
524         final Task targetRootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
525                 ACTIVITY_TYPE_STANDARD, false /* onTop */);
526         final Task targetTask = new TaskBuilder(mSupervisor).setParentTaskFragment(targetRootTask)
527                 .build();
528 
529         // Create Recents on secondary display.
530         final TestDisplayContent secondDisplay = addNewDisplayContentAt(
531                 DisplayContent.POSITION_TOP);
532         final Task rootTask = secondDisplay.getDefaultTaskDisplayArea()
533                 .createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS, true /* onTop */);
534         new ActivityBuilder(mAtm).setTask(rootTask).build();
535 
536         final String reason = "findTaskToMoveToFront";
537         mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
538                 false);
539 
540         verify(taskDisplayArea, never()).moveHomeRootTaskToFront(contains(reason));
541     }
542 
543     /**
544      * Verify if a root task is not at the topmost position, it should be able to resume its
545      * activity if the root task is the top focused.
546      */
547     @Test
testResumeActivityWhenNonTopmostRootTaskIsTopFocused()548     public void testResumeActivityWhenNonTopmostRootTaskIsTopFocused() {
549         // Create a root task at bottom.
550         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
551         final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
552                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
553         final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(rootTask).build();
554         taskDisplayArea.positionChildAt(POSITION_BOTTOM, rootTask, false /*includingParents*/);
555 
556         // Assume the task is not at the topmost position (e.g. behind always-on-top root tasks)
557         // but it is the current top focused task.
558         assertFalse(rootTask.isTopRootTaskInDisplayArea());
559         doReturn(rootTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
560 
561         // Use the task as target to resume.
562         mRootWindowContainer.resumeFocusedTasksTopActivities(rootTask, activity,
563                 null /* targetOptions */);
564 
565         // Verify the target task should resume its activity.
566         verify(rootTask, times(1)).resumeTopActivityUncheckedLocked(
567                 eq(activity), eq(null /* targetOptions */), eq(false));
568     }
569 
570     /**
571      * Verify that home activity will be started on a display even if another display has a
572      * focusable activity.
573      */
574     @Test
testResumeFocusedRootTasksStartsHomeActivity_NoActivities()575     public void testResumeFocusedRootTasksStartsHomeActivity_NoActivities() {
576         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
577         taskDisplayArea.getRootHomeTask().removeIfPossible();
578         taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
579 
580         doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
581 
582         mAtm.setBooted(true);
583 
584         // Trigger resume on all displays
585         mRootWindowContainer.resumeFocusedTasksTopActivities();
586 
587         // Verify that home activity was started on the default display
588         verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea));
589     }
590 
591     /**
592      * Verify that home activity will be started on a display even if another display has a
593      * focusable activity.
594      */
595     @Test
testResumeFocusedRootTasksStartsHomeActivity_ActivityOnSecondaryScreen()596     public void testResumeFocusedRootTasksStartsHomeActivity_ActivityOnSecondaryScreen() {
597         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
598         taskDisplayArea.getRootHomeTask().removeIfPossible();
599         taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
600 
601         // Create an activity on secondary display.
602         final TestDisplayContent secondDisplay = addNewDisplayContentAt(
603                 DisplayContent.POSITION_TOP);
604         final Task rootTask = secondDisplay.getDefaultTaskDisplayArea().createRootTask(
605                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
606         new ActivityBuilder(mAtm).setTask(rootTask).build();
607 
608         doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any());
609 
610         mAtm.setBooted(true);
611 
612         // Trigger resume on all displays
613         mRootWindowContainer.resumeFocusedTasksTopActivities();
614 
615         // Verify that home activity was started on the default display
616         verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea));
617     }
618 
619     /**
620      * Verify that a lingering transition is being executed in case the activity to be resumed is
621      * already resumed
622      */
623     @Test
testResumeActivityLingeringTransition()624     public void testResumeActivityLingeringTransition() {
625         // Create a root task at top.
626         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
627         final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
628                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
629         final ActivityRecord activity = new ActivityBuilder(mAtm)
630                 .setTask(rootTask).setOnTop(true).build();
631         activity.setState(RESUMED, "test");
632 
633         // Assume the task is at the topmost position
634         assertTrue(rootTask.isTopRootTaskInDisplayArea());
635 
636         // Use the task as target to resume.
637         mRootWindowContainer.resumeFocusedTasksTopActivities();
638 
639         // Verify the lingering app transition is being executed because it's already resumed
640         verify(rootTask, times(1)).executeAppTransition(any());
641     }
642 
643     @Test
testResumeActivityLingeringTransition_notExecuted()644     public void testResumeActivityLingeringTransition_notExecuted() {
645         // Create a root task at bottom.
646         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
647         final Task rootTask = spy(taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
648                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
649         final ActivityRecord activity = new ActivityBuilder(mAtm)
650                 .setTask(rootTask).setOnTop(true).build();
651         activity.setState(RESUMED, "test");
652         taskDisplayArea.positionChildAt(POSITION_BOTTOM, rootTask, false /*includingParents*/);
653 
654         // Assume the task is at the topmost position
655         assertFalse(rootTask.isTopRootTaskInDisplayArea());
656         doReturn(rootTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
657 
658         // Use the task as target to resume.
659         mRootWindowContainer.resumeFocusedTasksTopActivities();
660 
661         // Verify the lingering app transition is being executed because it's already resumed
662         verify(rootTask, never()).executeAppTransition(any());
663     }
664 
665     /**
666      * Tests that home activities can be started on the displays that supports system decorations.
667      */
668     @Test
testStartHomeOnAllDisplays()669     public void testStartHomeOnAllDisplays() {
670         mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
671         mockResolveSecondaryHomeActivity();
672 
673         // Create secondary displays.
674         final TestDisplayContent secondDisplay =
675                 new TestDisplayContent.Builder(mAtm, 1000, 1500)
676                         .setSystemDecorations(true).build();
677 
678         doReturn(true).when(mRootWindowContainer)
679                 .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
680         doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
681                 anyBoolean());
682 
683         mRootWindowContainer.startHomeOnAllDisplays(0, "testStartHome");
684 
685         assertTrue(mRootWindowContainer.getDefaultDisplay().getTopRootTask().isActivityTypeHome());
686         assertNotNull(secondDisplay.getTopRootTask());
687         assertTrue(secondDisplay.getTopRootTask().isActivityTypeHome());
688     }
689 
690     /**
691      * Tests that home activities won't be started before booting when display added.
692      */
693     @Test
testNotStartHomeBeforeBoot()694     public void testNotStartHomeBeforeBoot() {
695         final int displayId = 1;
696         final boolean isBooting = mAtm.mAmInternal.isBooting();
697         final boolean isBooted = mAtm.mAmInternal.isBooted();
698         try {
699             mAtm.mAmInternal.setBooting(false);
700             mAtm.mAmInternal.setBooted(false);
701             mRootWindowContainer.onDisplayAdded(displayId);
702             verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
703         } finally {
704             mAtm.mAmInternal.setBooting(isBooting);
705             mAtm.mAmInternal.setBooted(isBooted);
706         }
707     }
708 
709     /**
710      * Tests whether home can be started if being instrumented.
711      */
712     @Test
testCanStartHomeWhenInstrumented()713     public void testCanStartHomeWhenInstrumented() {
714         final ActivityInfo info = new ActivityInfo();
715         info.applicationInfo = new ApplicationInfo();
716         final WindowProcessController app = mock(WindowProcessController.class);
717         doReturn(app).when(mAtm).getProcessController(any(), anyInt());
718 
719         // Can not start home if we don't want to start home while home is being instrumented.
720         doReturn(true).when(app).isInstrumenting();
721         final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer
722                 .getDefaultTaskDisplayArea();
723         assertFalse(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
724                 false /* allowInstrumenting*/));
725 
726         // Can start home for other cases.
727         assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
728                 true /* allowInstrumenting*/));
729 
730         doReturn(false).when(app).isInstrumenting();
731         assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
732                 false /* allowInstrumenting*/));
733         assertTrue(mRootWindowContainer.canStartHomeOnDisplayArea(info, defaultTaskDisplayArea,
734                 true /* allowInstrumenting*/));
735     }
736 
737     /**
738      * Tests that secondary home activity should not be resolved if device is still locked.
739      */
740     @Test
testStartSecondaryHomeOnDisplayWithUserKeyLocked()741     public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() {
742         // Create secondary displays.
743         final TestDisplayContent secondDisplay =
744                 new TestDisplayContent.Builder(mAtm, 1000, 1500)
745                         .setSystemDecorations(true).build();
746 
747         // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false.
748         final int currentUser = mRootWindowContainer.mCurrentUser;
749         mRootWindowContainer.mCurrentUser = -1;
750 
751         mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
752                 secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */);
753 
754         try {
755             verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any());
756         } finally {
757             mRootWindowContainer.mCurrentUser = currentUser;
758         }
759     }
760 
761     /**
762      * Tests that secondary home activity should not be resolved if display does not support system
763      * decorations.
764      */
765     @Test
testStartSecondaryHomeOnDisplayWithoutSysDecorations()766     public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() {
767         // Create secondary displays.
768         final TestDisplayContent secondDisplay =
769                 new TestDisplayContent.Builder(mAtm, 1000, 1500)
770                         .setSystemDecorations(false).build();
771 
772         mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
773                 secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */);
774 
775         verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any());
776     }
777 
778     /**
779      * Tests that when starting {@link ResolverActivity} for home, it should use the standard
780      * activity type (in a new root task) so the order of back stack won't be broken.
781      */
782     @Test
testStartResolverActivityForHome()783     public void testStartResolverActivityForHome() {
784         final ActivityInfo info = new ActivityInfo();
785         info.applicationInfo = new ApplicationInfo();
786         info.applicationInfo.packageName = "android";
787         info.name = ResolverActivity.class.getName();
788         doReturn(info).when(mRootWindowContainer).resolveHomeActivity(anyInt(), any());
789 
790         mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "test", DEFAULT_DISPLAY);
791         final ActivityRecord resolverActivity = mRootWindowContainer.topRunningActivity();
792 
793         assertEquals(info, resolverActivity.info);
794         assertEquals(ACTIVITY_TYPE_STANDARD, resolverActivity.getRootTask().getActivityType());
795     }
796 
797     /**
798      * Tests that secondary home should be selected if primary home not set.
799      */
800     @Test
testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet()801     public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet() {
802         // Setup: primary home not set.
803         final Intent primaryHomeIntent = mAtm.getHomeIntent();
804         final ActivityInfo aInfoPrimary = new ActivityInfo();
805         aInfoPrimary.name = ResolverActivity.class.getName();
806         doReturn(aInfoPrimary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
807                 refEq(primaryHomeIntent));
808         // Setup: set secondary home.
809         mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */);
810 
811         // Run the test.
812         final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
813                 .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
814         final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
815         assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
816         assertEquals(aInfoSecondary.applicationInfo.packageName,
817                 resolvedInfo.first.applicationInfo.packageName);
818     }
819 
820     /**
821      * Tests that the default secondary home activity is always picked when it is in forced by
822      * config_useSystemProvidedLauncherForSecondary.
823      */
824     @Test
testResolveSecondaryHomeActivityForced()825     public void testResolveSecondaryHomeActivityForced() {
826         // SetUp: set primary home.
827         mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
828         // SetUp: set secondary home and force it.
829         mockResolveHomeActivity(false /* primaryHome */, true /* forceSystemProvided */);
830         final Intent secondaryHomeIntent =
831                 mAtm.getSecondaryHomeIntent(null /* preferredPackage */);
832         final List<ResolveInfo> resolutions = new ArrayList<>();
833         final ResolveInfo resolveInfo = new ResolveInfo();
834         final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
835         resolveInfo.activityInfo = aInfoSecondary;
836         resolutions.add(resolveInfo);
837         doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(),
838                 refEq(secondaryHomeIntent));
839         doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
840                 anyBoolean());
841 
842         // Run the test.
843         final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
844                 .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
845         assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
846         assertEquals(aInfoSecondary.applicationInfo.packageName,
847                 resolvedInfo.first.applicationInfo.packageName);
848     }
849 
850     /**
851      * Tests that secondary home should be selected if primary home not support secondary displays
852      * or there is no matched activity in the same package as selected primary home.
853      */
854     @Test
testResolveSecondaryHomeActivityWhenPrimaryHomeNotSupportMultiDisplay()855     public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSupportMultiDisplay() {
856         // Setup: there is no matched activity in the same package as selected primary home.
857         mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
858         final List<ResolveInfo> resolutions = new ArrayList<>();
859         doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
860         // Setup: set secondary home.
861         mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */);
862 
863         // Run the test.
864         final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
865                 .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
866         final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
867         assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
868         assertEquals(aInfoSecondary.applicationInfo.packageName,
869                 resolvedInfo.first.applicationInfo.packageName);
870     }
871     /**
872      * Tests that primary home activity should be selected if it already support secondary displays.
873      */
874     @Test
testResolveSecondaryHomeActivityWhenPrimaryHomeSupportMultiDisplay()875     public void testResolveSecondaryHomeActivityWhenPrimaryHomeSupportMultiDisplay() {
876         // SetUp: set primary home.
877         mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
878         // SetUp: put primary home info on 2nd item
879         final List<ResolveInfo> resolutions = new ArrayList<>();
880         final ResolveInfo infoFake1 = new ResolveInfo();
881         infoFake1.activityInfo = new ActivityInfo();
882         infoFake1.activityInfo.name = "fakeActivity1";
883         infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
884         infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
885         final ResolveInfo infoFake2 = new ResolveInfo();
886         final ActivityInfo aInfoPrimary = getFakeHomeActivityInfo(true /* primaryHome */);
887         infoFake2.activityInfo = aInfoPrimary;
888         resolutions.add(infoFake1);
889         resolutions.add(infoFake2);
890         doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
891 
892         doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
893                 anyBoolean());
894 
895         // Run the test.
896         final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
897                 .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
898         assertEquals(aInfoPrimary.name, resolvedInfo.first.name);
899         assertEquals(aInfoPrimary.applicationInfo.packageName,
900                 resolvedInfo.first.applicationInfo.packageName);
901     }
902 
903     /**
904      * Tests that the first one that matches should be selected if there are multiple activities.
905      */
906     @Test
testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay()907     public void testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay() {
908         // SetUp: set primary home.
909         mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
910         // Setup: prepare two eligible activity info.
911         final List<ResolveInfo> resolutions = new ArrayList<>();
912         final ResolveInfo infoFake1 = new ResolveInfo();
913         infoFake1.activityInfo = new ActivityInfo();
914         infoFake1.activityInfo.name = "fakeActivity1";
915         infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
916         infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
917         final ResolveInfo infoFake2 = new ResolveInfo();
918         infoFake2.activityInfo = new ActivityInfo();
919         infoFake2.activityInfo.name = "fakeActivity2";
920         infoFake2.activityInfo.applicationInfo = new ApplicationInfo();
921         infoFake2.activityInfo.applicationInfo.packageName = "fakePackage2";
922         resolutions.add(infoFake1);
923         resolutions.add(infoFake2);
924         doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
925 
926         doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplayArea(any(), any(),
927                 anyBoolean());
928 
929         // Use the first one of matched activities in the same package as selected primary home.
930         final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
931                 .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class));
932 
933         assertEquals(infoFake1.activityInfo.applicationInfo.packageName,
934                 resolvedInfo.first.applicationInfo.packageName);
935         assertEquals(infoFake1.activityInfo.name, resolvedInfo.first.name);
936     }
937 
938     /**
939      * Test that {@link RootWindowContainer#getLaunchRootTask} with the real caller id will get the
940      * expected root task when requesting the activity launch on the secondary display.
941      */
942     @Test
testGetLaunchRootTaskWithRealCallerId()943     public void testGetLaunchRootTaskWithRealCallerId() {
944         // Create a non-system owned virtual display.
945         final TestDisplayContent secondaryDisplay =
946                 new TestDisplayContent.Builder(mAtm, 1000, 1500)
947                         .setType(TYPE_VIRTUAL).setOwnerUid(100).build();
948 
949         // Create an activity with specify the original launch pid / uid.
950         final ActivityRecord r = new ActivityBuilder(mAtm).setLaunchedFromPid(200)
951                 .setLaunchedFromUid(200).build();
952 
953         // Simulate ActivityStarter to find a launch root task for requesting the activity to launch
954         // on the secondary display with realCallerId.
955         final ActivityOptions options = ActivityOptions.makeBasic();
956         options.setLaunchDisplayId(secondaryDisplay.mDisplayId);
957         options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
958         doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId,
959                 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info);
960         final Task result = mRootWindowContainer.getLaunchRootTask(r, options,
961                 null /* task */, null /* sourceTask */, true /* onTop */, null /* launchParams */,
962                 0 /* launchFlags */, 300 /* test realCallerPid */,
963                 300 /* test realCallerUid */);
964 
965         // Assert that the root task is returned as expected.
966         assertNotNull(result);
967         assertEquals("The display ID of the root task should same as secondary display ",
968                 secondaryDisplay.mDisplayId, result.getDisplayId());
969     }
970 
971     @Test
testGetValidLaunchRootTaskOnDisplayWithCandidateRootTask()972     public void testGetValidLaunchRootTaskOnDisplayWithCandidateRootTask() {
973         // Create a root task with an activity on secondary display.
974         final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mAtm, 300,
975                 600).build();
976         final Task task = new TaskBuilder(mSupervisor)
977                 .setDisplay(secondaryDisplay).build();
978         final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task).build();
979 
980         // Make sure the root task is valid and can be reused on default display.
981         final Task rootTask = mRootWindowContainer.getValidLaunchRootTaskInTaskDisplayArea(
982                 mRootWindowContainer.getDefaultTaskDisplayArea(), activity, task,
983                 null /* options */, null /* launchParams */);
984         assertEquals(task, rootTask);
985     }
986 
987     @Test
testSwitchUser_missingHomeRootTask()988     public void testSwitchUser_missingHomeRootTask() {
989         final Task fullscreenTask = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
990                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
991         doReturn(fullscreenTask).when(mRootWindowContainer).getTopDisplayFocusedRootTask();
992 
993         final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
994         Task rootHomeTask = taskDisplayArea.getRootHomeTask();
995         if (rootHomeTask != null) {
996             rootHomeTask.removeImmediately();
997         }
998         assertNull(taskDisplayArea.getRootHomeTask());
999 
1000         int currentUser = mRootWindowContainer.mCurrentUser;
1001         int otherUser = currentUser + 1;
1002 
1003         mRootWindowContainer.switchUser(otherUser, null);
1004 
1005         assertNotNull(taskDisplayArea.getRootHomeTask());
1006         assertEquals(taskDisplayArea.getTopRootTask(), taskDisplayArea.getRootHomeTask());
1007     }
1008 
1009     @Test
testLockAllProfileTasks()1010     public void testLockAllProfileTasks() {
1011         final int profileUid = UserHandle.PER_USER_RANGE + UserHandle.MIN_SECONDARY_USER_ID;
1012         final int profileUserId = UserHandle.getUserId(profileUid);
1013         // Create an activity belonging to the profile user.
1014         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
1015                 .setUid(profileUid).build();
1016         final Task task = activity.getTask();
1017 
1018         // Create another activity belonging to current user on top.
1019         final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
1020         topActivity.intent.setAction(Intent.ACTION_MAIN);
1021 
1022         // Make sure the listeners will be notified for putting the task to locked state
1023         TaskChangeNotificationController controller = mAtm.getTaskChangeNotificationController();
1024         spyOn(controller);
1025         mWm.mRoot.lockAllProfileTasks(profileUserId);
1026         verify(controller).notifyTaskProfileLocked(eq(task.mTaskId), eq(profileUserId));
1027 
1028         // Create the work lock activity on top of the task
1029         final ActivityRecord workLockActivity = new ActivityBuilder(mAtm).setTask(task).build();
1030         workLockActivity.intent.setAction(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
1031         doReturn(workLockActivity.mActivityComponent).when(mAtm).getSysUiServiceComponentLocked();
1032 
1033         // Make sure the listener won't be notified again.
1034         clearInvocations(controller);
1035         mWm.mRoot.lockAllProfileTasks(profileUserId);
1036         verify(controller, never()).notifyTaskProfileLocked(anyInt(), anyInt());
1037     }
1038 
1039     /**
1040      * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
1041      * info for test cases.
1042      *
1043      * @param primaryHome Indicate to use primary home intent as parameter, otherwise, use
1044      *                    secondary home intent.
1045      * @param forceSystemProvided Indicate to force using system provided home activity.
1046      */
mockResolveHomeActivity(boolean primaryHome, boolean forceSystemProvided)1047     private void mockResolveHomeActivity(boolean primaryHome, boolean forceSystemProvided) {
1048         ActivityInfo targetActivityInfo = getFakeHomeActivityInfo(primaryHome);
1049         Intent targetIntent;
1050         if (primaryHome) {
1051             targetIntent = mAtm.getHomeIntent();
1052         } else {
1053             Resources resources = mContext.getResources();
1054             spyOn(resources);
1055             doReturn(targetActivityInfo.applicationInfo.packageName).when(resources).getString(
1056                     com.android.internal.R.string.config_secondaryHomePackage);
1057             doReturn(forceSystemProvided).when(resources).getBoolean(
1058                     com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
1059             targetIntent = mAtm.getSecondaryHomeIntent(null /* preferredPackage */);
1060         }
1061         doReturn(targetActivityInfo).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
1062                 refEq(targetIntent));
1063     }
1064 
1065     /**
1066      * Mock {@link RootWindowContainer#resolveSecondaryHomeActivity} for returning consistent
1067      * activity info for test cases.
1068      */
mockResolveSecondaryHomeActivity()1069     private void mockResolveSecondaryHomeActivity() {
1070         final Intent secondaryHomeIntent = mAtm
1071                 .getSecondaryHomeIntent(null /* preferredPackage */);
1072         final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false);
1073         doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer)
1074                 .resolveSecondaryHomeActivity(anyInt(), any());
1075     }
1076 
getFakeHomeActivityInfo(boolean primaryHome)1077     private ActivityInfo getFakeHomeActivityInfo(boolean primaryHome) {
1078         final ActivityInfo aInfo = new ActivityInfo();
1079         aInfo.name = primaryHome ? "fakeHomeActivity" : "fakeSecondaryHomeActivity";
1080         aInfo.applicationInfo = new ApplicationInfo();
1081         aInfo.applicationInfo.packageName =
1082                 primaryHome ? "fakeHomePackage" : "fakeSecondaryHomePackage";
1083         return  aInfo;
1084     }
1085 }
1086 
1087