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