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