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