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