blob: 0ef25824df2a38eca4977a10c4109092de034352 [file] [log] [blame]
Wale Ogunwaled32da472018-11-16 07:19:28 -08001/*
2 * Copyright (C) 2018 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
17package com.android.server.wm;
18
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -070019import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
Wale Ogunwaled32da472018-11-16 07:19:28 -080020import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
21import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
22import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
24import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
25import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
26import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
Wale Ogunwaled32da472018-11-16 07:19:28 -080027import static android.view.Display.DEFAULT_DISPLAY;
lumarkf65e02d2019-09-14 19:25:21 +080028import static android.view.Display.TYPE_VIRTUAL;
Chilun2ef71f72018-11-16 17:57:15 +080029
Louis Chang3ff72a82019-12-17 12:12:59 +080030import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
Wale Ogunwaled32da472018-11-16 07:19:28 -080031import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
32import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
33import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
34import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
35import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
Keun young Park340546a2019-05-06 16:27:44 -070036import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
Wale Ogunwaled32da472018-11-16 07:19:28 -080037import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
38import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -070039import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
Louis Chang149d5c82019-12-30 09:47:39 +080040import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
Chilun2ef71f72018-11-16 17:57:15 +080041
Wale Ogunwaled32da472018-11-16 07:19:28 -080042import static org.junit.Assert.assertEquals;
43import static org.junit.Assert.assertFalse;
44import static org.junit.Assert.assertNotNull;
45import static org.junit.Assert.assertNull;
46import static org.junit.Assert.assertTrue;
47import static org.mockito.ArgumentMatchers.any;
48import static org.mockito.ArgumentMatchers.anyBoolean;
49import static org.mockito.ArgumentMatchers.anyInt;
50import static org.mockito.ArgumentMatchers.contains;
51import static org.mockito.ArgumentMatchers.eq;
Chilun2ef71f72018-11-16 17:57:15 +080052import static org.mockito.ArgumentMatchers.refEq;
Wale Ogunwaled32da472018-11-16 07:19:28 -080053
54import android.app.ActivityOptions;
Chilun2ef71f72018-11-16 17:57:15 +080055import android.content.Intent;
Wale Ogunwaled32da472018-11-16 07:19:28 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
Chilun2ef71f72018-11-16 17:57:15 +080058import android.content.pm.ResolveInfo;
Keun young Park340546a2019-05-06 16:27:44 -070059import android.content.res.Resources;
Wale Ogunwaled32da472018-11-16 07:19:28 -080060import android.graphics.Rect;
Wale Ogunwaled32da472018-11-16 07:19:28 -080061import android.platform.test.annotations.Presubmit;
Chilun2ef71f72018-11-16 17:57:15 +080062import android.util.Pair;
63
Wale Ogunwaled32da472018-11-16 07:19:28 -080064import androidx.test.filters.MediumTest;
Chilun2ef71f72018-11-16 17:57:15 +080065
66import com.android.internal.app.ResolverActivity;
Jorim Jaggia5cf6802019-04-26 19:43:11 +020067import com.android.server.wm.ActivityStack.ActivityState;
Chilun2ef71f72018-11-16 17:57:15 +080068
Wale Ogunwaled32da472018-11-16 07:19:28 -080069import org.junit.Before;
70import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +080071import org.junit.runner.RunWith;
Wale Ogunwaled32da472018-11-16 07:19:28 -080072
73import java.util.ArrayList;
Garfield Tan26835f02019-02-07 14:38:38 -080074import java.util.Arrays;
Chilun2ef71f72018-11-16 17:57:15 +080075import java.util.List;
Wale Ogunwalea38654f2019-11-17 20:37:15 -080076import java.util.function.Consumer;
Wale Ogunwaled32da472018-11-16 07:19:28 -080077
78/**
Louis Chang149d5c82019-12-30 09:47:39 +080079 * Tests for the {@link RootWindowContainer} class.
Wale Ogunwaled32da472018-11-16 07:19:28 -080080 *
81 * Build/Install/Run:
Riddle Hsuff9e8282019-04-24 23:55:11 +080082 * atest WmTests:RootActivityContainerTests
Wale Ogunwaled32da472018-11-16 07:19:28 -080083 */
84@MediumTest
85@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +080086@RunWith(WindowTestRunner.class)
Wale Ogunwaled32da472018-11-16 07:19:28 -080087public class RootActivityContainerTests extends ActivityTestsBase {
88 private ActivityStack mFullscreenStack;
89
90 @Before
91 public void setUp() throws Exception {
Louis Chang149d5c82019-12-30 09:47:39 +080092 mFullscreenStack = mRootWindowContainer.getDefaultDisplay().createStack(
Wale Ogunwaled32da472018-11-16 07:19:28 -080093 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Louis Chang3ff72a82019-12-17 12:12:59 +080094 doNothing().when(mService).updateSleepIfNeededLocked();
Wale Ogunwaled32da472018-11-16 07:19:28 -080095 }
96
97 /**
98 * This test ensures that we do not try to restore a task based off an invalid task id. We
99 * should expect {@code null} to be returned in this case.
100 */
101 @Test
102 public void testRestoringInvalidTask() {
Louis Chang149d5c82019-12-30 09:47:39 +0800103 mRootWindowContainer.getDefaultDisplay().removeAllTasks();
104 Task task = mRootWindowContainer.anyTaskForId(0 /*taskId*/,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800105 MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
106 assertNull(task);
107 }
108
109 /**
110 * This test ensures that an existing task in the pinned stack is moved to the fullscreen
111 * activity stack when a new task is added.
112 */
113 @Test
114 public void testReplacingTaskInPinnedStack() {
115 final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
116 .setStack(mFullscreenStack).build();
Louis Changcdec0802019-11-11 11:45:07 +0800117 final Task task = firstActivity.getTask();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800118
Ben Lin6db8fb22019-10-18 16:03:44 -0700119 final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(task)
Wale Ogunwaled32da472018-11-16 07:19:28 -0800120 .setStack(mFullscreenStack).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800121
122 mFullscreenStack.moveToFront("testReplacingTaskInPinnedStack");
123
124 // Ensure full screen stack has both tasks.
Ben Lin6db8fb22019-10-18 16:03:44 -0700125 ensureStackPlacement(mFullscreenStack, firstActivity, secondActivity);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800126
127 // Move first activity to pinned stack.
128 final Rect sourceBounds = new Rect();
Louis Chang149d5c82019-12-30 09:47:39 +0800129 mRootWindowContainer.moveActivityToPinnedStack(firstActivity, sourceBounds,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800130 0f /*aspectRatio*/, "initialMove");
131
Louis Chang677921f2019-12-06 16:44:24 +0800132 final DisplayContent display = mFullscreenStack.getDisplay();
Wale Ogunwale734b8962020-01-21 12:17:42 -0800133 ActivityStack pinnedStack = display.getRootPinnedTask();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800134 // Ensure a task has moved over.
Ben Lin6db8fb22019-10-18 16:03:44 -0700135 ensureStackPlacement(pinnedStack, firstActivity);
136 ensureStackPlacement(mFullscreenStack, secondActivity);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800137
138 // Move second activity to pinned stack.
Louis Chang149d5c82019-12-30 09:47:39 +0800139 mRootWindowContainer.moveActivityToPinnedStack(secondActivity, sourceBounds,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800140 0f /*aspectRatio*/, "secondMove");
141
142 // Need to get stacks again as a new instance might have been created.
Wale Ogunwale734b8962020-01-21 12:17:42 -0800143 pinnedStack = display.getRootPinnedTask();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800144 mFullscreenStack = display.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
145 // Ensure stacks have swapped tasks.
Ben Lin6db8fb22019-10-18 16:03:44 -0700146 ensureStackPlacement(pinnedStack, secondActivity);
147 ensureStackPlacement(mFullscreenStack, firstActivity);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800148 }
149
Ben Lin6db8fb22019-10-18 16:03:44 -0700150 private static void ensureStackPlacement(ActivityStack stack, ActivityRecord... activities) {
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900151 final Task task = stack.getBottomMostTask();
Ben Lin6db8fb22019-10-18 16:03:44 -0700152 final ArrayList<ActivityRecord> stackActivities = new ArrayList<>();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800153
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800154 task.forAllActivities((Consumer<ActivityRecord>) stackActivities::add, false);
Ben Lin6db8fb22019-10-18 16:03:44 -0700155
156 assertEquals("Expecting " + Arrays.deepToString(activities) + " got " + stackActivities,
157 stackActivities.size(), activities != null ? activities.length : 0);
158
159 if (activities == null) {
Wale Ogunwaled32da472018-11-16 07:19:28 -0800160 return;
161 }
162
Ben Lin6db8fb22019-10-18 16:03:44 -0700163 for (ActivityRecord activity : activities) {
164 assertTrue(stackActivities.contains(activity));
Wale Ogunwaled32da472018-11-16 07:19:28 -0800165 }
166 }
167
168 @Test
169 public void testApplySleepTokens() {
Louis Chang149d5c82019-12-30 09:47:39 +0800170 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800171 final KeyguardController keyguard = mSupervisor.getKeyguardController();
Louis Chang149d5c82019-12-30 09:47:39 +0800172 final ActivityStack stack = new StackBuilder(mRootWindowContainer)
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -0700173 .setCreateActivity(false)
174 .setDisplay(display)
175 .setOnTop(false)
176 .build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800177
178 // Make sure we wake and resume in the case the display is turning on and the keyguard is
179 // not showing.
180 verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
181 false /* displayShouldSleep */, true /* isFocusedStack */,
182 false /* keyguardShowing */, true /* expectWakeFromSleep */,
183 true /* expectResumeTopActivity */);
184
185 // Make sure we wake and don't resume when the display is turning on and the keyguard is
186 // showing.
187 verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
188 false /* displayShouldSleep */, true /* isFocusedStack */,
189 true /* keyguardShowing */, true /* expectWakeFromSleep */,
190 false /* expectResumeTopActivity */);
191
192 // Make sure we wake and don't resume when the display is turning on and the keyguard is
193 // not showing as unfocused.
194 verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
195 false /* displayShouldSleep */, false /* isFocusedStack */,
196 false /* keyguardShowing */, true /* expectWakeFromSleep */,
197 false /* expectResumeTopActivity */);
198
199 // Should not do anything if the display state hasn't changed.
200 verifySleepTokenBehavior(display, keyguard, stack, false /*displaySleeping*/,
201 false /* displayShouldSleep */, true /* isFocusedStack */,
202 false /* keyguardShowing */, false /* expectWakeFromSleep */,
203 false /* expectResumeTopActivity */);
204 }
205
Louis Chang677921f2019-12-06 16:44:24 +0800206 private void verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800207 ActivityStack stack, boolean displaySleeping, boolean displayShouldSleep,
208 boolean isFocusedStack, boolean keyguardShowing, boolean expectWakeFromSleep,
209 boolean expectResumeTopActivity) {
210 reset(stack);
211
212 doReturn(displayShouldSleep).when(display).shouldSleep();
213 doReturn(displaySleeping).when(display).isSleeping();
214 doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt());
215
216 doReturn(isFocusedStack).when(stack).isFocusedStackOnDisplay();
217 doReturn(isFocusedStack ? stack : null).when(display).getFocusedStack();
Louis Chang149d5c82019-12-30 09:47:39 +0800218 mRootWindowContainer.applySleepTokens(true);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800219 verify(stack, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked();
220 verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked(
221 null /* target */, null /* targetOptions */);
222 }
223
224 /**
225 * Verifies that removal of activity with task and stack is done correctly.
226 */
227 @Test
228 public void testRemovingStackOnAppCrash() {
Louis Chang149d5c82019-12-30 09:47:39 +0800229 final DisplayContent defaultDisplay = mRootWindowContainer.getDefaultDisplay();
Louis Chang2453d062019-11-19 22:30:48 +0800230 final int originalStackCount = defaultDisplay.getStackCount();
Louis Chang149d5c82019-12-30 09:47:39 +0800231 final ActivityStack stack = mRootWindowContainer.getDefaultDisplay().createStack(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800232 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
233 final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
234 .setStack(stack).build();
235
Louis Chang2453d062019-11-19 22:30:48 +0800236 assertEquals(originalStackCount + 1, defaultDisplay.getStackCount());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800237
238 // Let's pretend that the app has crashed.
239 firstActivity.app.setThread(null);
Louis Chang149d5c82019-12-30 09:47:39 +0800240 mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
Wale Ogunwaled32da472018-11-16 07:19:28 -0800241
242 // Verify that the stack was removed.
Louis Chang2453d062019-11-19 22:30:48 +0800243 assertEquals(originalStackCount, defaultDisplay.getStackCount());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800244 }
245
246 @Test
247 public void testFocusability() {
Louis Chang149d5c82019-12-30 09:47:39 +0800248 final ActivityStack stack = mRootWindowContainer.getDefaultDisplay().createStack(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800249 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
250 final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
251 .setStack(stack).build();
252
Evan Roskye84ef9e2020-01-09 17:28:19 -0800253 // Created stacks are focusable by default.
Evan Rosky226de132020-01-03 18:00:29 -0800254 assertTrue(stack.isTopActivityFocusable());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800255 assertTrue(activity.isFocusable());
256
Evan Roskye84ef9e2020-01-09 17:28:19 -0800257 // If the stack is made unfocusable, its activities should inherit that.
258 stack.setFocusable(false);
Evan Rosky226de132020-01-03 18:00:29 -0800259 assertFalse(stack.isTopActivityFocusable());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800260 assertFalse(activity.isFocusable());
261
Louis Chang149d5c82019-12-30 09:47:39 +0800262 final ActivityStack pinnedStack = mRootWindowContainer.getDefaultDisplay().createStack(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800263 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
264 final ActivityRecord pinnedActivity = new ActivityBuilder(mService).setCreateTask(true)
265 .setStack(pinnedStack).build();
266
267 // We should not be focusable when in pinned mode
Evan Rosky226de132020-01-03 18:00:29 -0800268 assertFalse(pinnedStack.isTopActivityFocusable());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800269 assertFalse(pinnedActivity.isFocusable());
270
271 // Add flag forcing focusability.
272 pinnedActivity.info.flags |= FLAG_ALWAYS_FOCUSABLE;
273
274 // We should not be focusable when in pinned mode
Evan Rosky226de132020-01-03 18:00:29 -0800275 assertTrue(pinnedStack.isTopActivityFocusable());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800276 assertTrue(pinnedActivity.isFocusable());
277
278 // Without the overridding activity, stack should not be focusable.
Louis Changcdec0802019-11-11 11:45:07 +0800279 pinnedStack.removeChild(pinnedActivity.getTask(), "testFocusability");
Evan Rosky226de132020-01-03 18:00:29 -0800280 assertFalse(pinnedStack.isTopActivityFocusable());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800281 }
282
283 /**
284 * Verify that split-screen primary stack will be chosen if activity is launched that targets
285 * split-screen secondary, but a matching existing instance is found on top of split-screen
286 * primary stack.
287 */
288 @Test
289 public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() {
290 // Create primary split-screen stack with a task and an activity.
Louis Chang149d5c82019-12-30 09:47:39 +0800291 final ActivityStack primaryStack = mRootWindowContainer.getDefaultDisplay()
Wale Ogunwaled32da472018-11-16 07:19:28 -0800292 .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
293 true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800294 final Task task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800295 final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
296
297 // Find a launch stack for the top activity in split-screen primary, while requesting
298 // split-screen secondary.
299 final ActivityOptions options = ActivityOptions.makeBasic();
300 options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
301 final ActivityStack result =
Louis Chang149d5c82019-12-30 09:47:39 +0800302 mRootWindowContainer.getLaunchStack(r, options, task, true /* onTop */);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800303
304 // Assert that the primary stack is returned.
305 assertEquals(primaryStack, result);
306 }
307
308 /**
Wale Ogunwaled32da472018-11-16 07:19:28 -0800309 * Verify that home stack would be moved to front when the top activity is Recents.
310 */
311 @Test
312 public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
313 // Create stack/task on default display.
Louis Chang149d5c82019-12-30 09:47:39 +0800314 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
315 final ActivityStack targetStack = new StackBuilder(mRootWindowContainer)
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700316 .setOnTop(false)
317 .build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900318 final Task targetTask = targetStack.getBottomMostTask();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800319
320 // Create Recents on top of the display.
Louis Chang149d5c82019-12-30 09:47:39 +0800321 final ActivityStack stack = new StackBuilder(mRootWindowContainer).setActivityType(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800322 ACTIVITY_TYPE_RECENTS).build();
323
324 final String reason = "findTaskToMoveToFront";
325 mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
326 false);
327
328 verify(display).moveHomeStackToFront(contains(reason));
329 }
330
331 /**
332 * Verify that home stack won't be moved to front if the top activity on other display is
333 * Recents.
334 */
335 @Test
336 public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() {
337 // Create stack/task on default display.
Louis Chang149d5c82019-12-30 09:47:39 +0800338 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800339 final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
340 ACTIVITY_TYPE_STANDARD, false /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800341 final Task targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800342
343 // Create Recents on secondary display.
Louis Chang677921f2019-12-06 16:44:24 +0800344 final TestDisplayContent secondDisplay = addNewDisplayContentAt(
345 DisplayContent.POSITION_TOP);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800346 final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
347 ACTIVITY_TYPE_RECENTS, true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800348 final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800349 new ActivityBuilder(mService).setTask(task).build();
350
351 final String reason = "findTaskToMoveToFront";
352 mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
353 false);
354
355 verify(display, never()).moveHomeStackToFront(contains(reason));
356 }
357
358 /**
359 * Verify if a stack is not at the topmost position, it should be able to resume its activity if
360 * the stack is the top focused.
361 */
362 @Test
363 public void testResumeActivityWhenNonTopmostStackIsTopFocused() {
364 // Create a stack at bottom.
Louis Chang149d5c82019-12-30 09:47:39 +0800365 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800366 final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
367 ACTIVITY_TYPE_STANDARD, false /* onTop */));
Louis Changcdec0802019-11-11 11:45:07 +0800368 final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800369 final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
Louis Chang2453d062019-11-19 22:30:48 +0800370 display.positionStackAtBottom(targetStack);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800371
372 // Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it
373 // is the current top focused stack.
374 assertFalse(targetStack.isTopStackOnDisplay());
Louis Chang149d5c82019-12-30 09:47:39 +0800375 doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800376
377 // Use the stack as target to resume.
Louis Chang149d5c82019-12-30 09:47:39 +0800378 mRootWindowContainer.resumeFocusedStacksTopActivities(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800379 targetStack, activity, null /* targetOptions */);
380
381 // Verify the target stack should resume its activity.
382 verify(targetStack, times(1)).resumeTopActivityUncheckedLocked(
383 eq(activity), eq(null /* targetOptions */));
384 }
385
386 /**
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700387 * Verify that home activity will be started on a display even if another display has a
388 * focusable activity.
389 */
390 @Test
391 public void testResumeFocusedStacksStartsHomeActivity_NoActivities() {
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -0700392 mFullscreenStack.removeIfPossible();
Wale Ogunwale734b8962020-01-21 12:17:42 -0800393 mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY).getRootHomeTask()
Louis Chang677921f2019-12-06 16:44:24 +0800394 .removeIfPossible();
Louis Chang149d5c82019-12-30 09:47:39 +0800395 mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY)
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700396 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
397
Louis Chang149d5c82019-12-30 09:47:39 +0800398 doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), anyInt());
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700399
400 mService.setBooted(true);
401
402 // Trigger resume on all displays
Louis Chang149d5c82019-12-30 09:47:39 +0800403 mRootWindowContainer.resumeFocusedStacksTopActivities();
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700404
405 // Verify that home activity was started on the default display
Louis Chang149d5c82019-12-30 09:47:39 +0800406 verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(DEFAULT_DISPLAY));
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700407 }
408
409 /**
410 * Verify that home activity will be started on a display even if another display has a
411 * focusable activity.
412 */
413 @Test
414 public void testResumeFocusedStacksStartsHomeActivity_ActivityOnSecondaryScreen() {
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -0700415 mFullscreenStack.removeIfPossible();
Wale Ogunwale734b8962020-01-21 12:17:42 -0800416 mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY).getRootHomeTask()
Louis Chang677921f2019-12-06 16:44:24 +0800417 .removeIfPossible();
Louis Chang149d5c82019-12-30 09:47:39 +0800418 mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY)
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700419 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
420
421 // Create an activity on secondary display.
Louis Chang677921f2019-12-06 16:44:24 +0800422 final TestDisplayContent secondDisplay = addNewDisplayContentAt(
423 DisplayContent.POSITION_TOP);
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700424 final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
425 ACTIVITY_TYPE_STANDARD, true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800426 final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700427 new ActivityBuilder(mService).setTask(task).build();
428
Louis Chang149d5c82019-12-30 09:47:39 +0800429 doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), anyInt());
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700430
431 mService.setBooted(true);
432
433 // Trigger resume on all displays
Louis Chang149d5c82019-12-30 09:47:39 +0800434 mRootWindowContainer.resumeFocusedStacksTopActivities();
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700435
436 // Verify that home activity was started on the default display
Louis Chang149d5c82019-12-30 09:47:39 +0800437 verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(DEFAULT_DISPLAY));
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700438 }
439
440 /**
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200441 * Verify that a lingering transition is being executed in case the activity to be resumed is
442 * already resumed
443 */
444 @Test
445 public void testResumeActivityLingeringTransition() {
446 // Create a stack at top.
Louis Chang149d5c82019-12-30 09:47:39 +0800447 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200448 final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
449 ACTIVITY_TYPE_STANDARD, false /* onTop */));
Louis Changcdec0802019-11-11 11:45:07 +0800450 final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200451 final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
452 activity.setState(ActivityState.RESUMED, "test");
453
454 // Assume the stack is at the topmost position
455 assertTrue(targetStack.isTopStackOnDisplay());
456
457 // Use the stack as target to resume.
Louis Chang149d5c82019-12-30 09:47:39 +0800458 mRootWindowContainer.resumeFocusedStacksTopActivities();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200459
460 // Verify the lingering app transition is being executed because it's already resumed
461 verify(targetStack, times(1)).executeAppTransition(any());
462 }
463
464 @Test
465 public void testResumeActivityLingeringTransition_notExecuted() {
466 // Create a stack at bottom.
Louis Chang149d5c82019-12-30 09:47:39 +0800467 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200468 final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
469 ACTIVITY_TYPE_STANDARD, false /* onTop */));
Louis Changcdec0802019-11-11 11:45:07 +0800470 final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200471 final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
472 activity.setState(ActivityState.RESUMED, "test");
Louis Chang2453d062019-11-19 22:30:48 +0800473 display.positionStackAtBottom(targetStack);
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200474
475 // Assume the stack is at the topmost position
476 assertFalse(targetStack.isTopStackOnDisplay());
Louis Chang149d5c82019-12-30 09:47:39 +0800477 doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200478
479 // Use the stack as target to resume.
Louis Chang149d5c82019-12-30 09:47:39 +0800480 mRootWindowContainer.resumeFocusedStacksTopActivities();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200481
482 // Verify the lingering app transition is being executed because it's already resumed
483 verify(targetStack, never()).executeAppTransition(any());
484 }
485
486 /**
Wale Ogunwaled32da472018-11-16 07:19:28 -0800487 * Tests that home activities can be started on the displays that supports system decorations.
488 */
Chilun2afb94e2018-12-25 20:42:45 +0800489 @Test
490 public void testStartHomeOnAllDisplays() {
Chilun939b05c2020-02-19 14:50:59 +0800491 mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
Chilun59954982019-05-23 14:50:48 +0800492 mockResolveSecondaryHomeActivity();
Riddle Hsuff9e8282019-04-24 23:55:11 +0800493
Wale Ogunwaled32da472018-11-16 07:19:28 -0800494 // Create secondary displays.
Louis Chang677921f2019-12-06 16:44:24 +0800495 final TestDisplayContent secondDisplay =
496 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700497 .setSystemDecorations(true).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800498
Louis Chang149d5c82019-12-30 09:47:39 +0800499 doReturn(true).when(mRootWindowContainer)
Wale Ogunwaled32da472018-11-16 07:19:28 -0800500 .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
Louis Chang149d5c82019-12-30 09:47:39 +0800501 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800502 any(), anyInt(), anyBoolean());
503
Louis Chang149d5c82019-12-30 09:47:39 +0800504 mRootWindowContainer.startHomeOnAllDisplays(0, "testStartHome");
Wale Ogunwaled32da472018-11-16 07:19:28 -0800505
Louis Chang149d5c82019-12-30 09:47:39 +0800506 assertTrue(mRootWindowContainer.getDefaultDisplay().getTopStack().isActivityTypeHome());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800507 assertNotNull(secondDisplay.getTopStack());
508 assertTrue(secondDisplay.getTopStack().isActivityTypeHome());
509 }
510
511 /**
512 * Tests that home activities won't be started before booting when display added.
513 */
514 @Test
515 public void testNotStartHomeBeforeBoot() {
516 final int displayId = 1;
517 final boolean isBooting = mService.mAmInternal.isBooting();
518 final boolean isBooted = mService.mAmInternal.isBooted();
519 try {
520 mService.mAmInternal.setBooting(false);
521 mService.mAmInternal.setBooted(false);
Louis Chang149d5c82019-12-30 09:47:39 +0800522 mRootWindowContainer.onDisplayAdded(displayId);
523 verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800524 } finally {
525 mService.mAmInternal.setBooting(isBooting);
526 mService.mAmInternal.setBooted(isBooted);
527 }
528 }
529
530 /**
531 * Tests whether home can be started if being instrumented.
532 */
533 @Test
534 public void testCanStartHomeWhenInstrumented() {
535 final ActivityInfo info = new ActivityInfo();
536 info.applicationInfo = new ApplicationInfo();
537 final WindowProcessController app = mock(WindowProcessController.class);
538 doReturn(app).when(mService).getProcessController(any(), anyInt());
539
540 // Can not start home if we don't want to start home while home is being instrumented.
541 doReturn(true).when(app).isInstrumenting();
Louis Chang149d5c82019-12-30 09:47:39 +0800542 assertFalse(mRootWindowContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800543 false /* allowInstrumenting*/));
544
545 // Can start home for other cases.
Louis Chang149d5c82019-12-30 09:47:39 +0800546 assertTrue(mRootWindowContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800547 true /* allowInstrumenting*/));
548
549 doReturn(false).when(app).isInstrumenting();
Louis Chang149d5c82019-12-30 09:47:39 +0800550 assertTrue(mRootWindowContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800551 false /* allowInstrumenting*/));
Louis Chang149d5c82019-12-30 09:47:39 +0800552 assertTrue(mRootWindowContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800553 true /* allowInstrumenting*/));
554 }
Chilun2ef71f72018-11-16 17:57:15 +0800555
556 /**
Chilun85ebc0d2019-04-15 16:00:53 +0800557 * Tests that secondary home activity should not be resolved if device is still locked.
558 */
559 @Test
560 public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() {
561 // Create secondary displays.
Louis Chang677921f2019-12-06 16:44:24 +0800562 final TestDisplayContent secondDisplay =
563 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700564 .setSystemDecorations(true).build();
Chilun85ebc0d2019-04-15 16:00:53 +0800565
Chilun85ebc0d2019-04-15 16:00:53 +0800566 // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false.
Louis Chang149d5c82019-12-30 09:47:39 +0800567 final int currentUser = mRootWindowContainer.mCurrentUser;
568 mRootWindowContainer.mCurrentUser = -1;
Chilun85ebc0d2019-04-15 16:00:53 +0800569
Louis Chang149d5c82019-12-30 09:47:39 +0800570 mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
Chilun85ebc0d2019-04-15 16:00:53 +0800571 secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */);
572
573 try {
Louis Chang149d5c82019-12-30 09:47:39 +0800574 verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(),
Chilun85ebc0d2019-04-15 16:00:53 +0800575 anyInt());
576 } finally {
Louis Chang149d5c82019-12-30 09:47:39 +0800577 mRootWindowContainer.mCurrentUser = currentUser;
Chilun85ebc0d2019-04-15 16:00:53 +0800578 }
579 }
580
581 /**
582 * Tests that secondary home activity should not be resolved if display does not support system
583 * decorations.
584 */
585 @Test
586 public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() {
587 // Create secondary displays.
Louis Chang677921f2019-12-06 16:44:24 +0800588 final TestDisplayContent secondDisplay =
589 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700590 .setSystemDecorations(false).build();
Chilun85ebc0d2019-04-15 16:00:53 +0800591
Louis Chang149d5c82019-12-30 09:47:39 +0800592 mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
Chilun85ebc0d2019-04-15 16:00:53 +0800593 secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */);
594
Louis Chang149d5c82019-12-30 09:47:39 +0800595 verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), anyInt());
Chilun85ebc0d2019-04-15 16:00:53 +0800596 }
597
598 /**
Riddle Hsuff9e8282019-04-24 23:55:11 +0800599 * Tests that when starting {@link #ResolverActivity} for home, it should use the standard
600 * activity type (in a new stack) so the order of back stack won't be broken.
601 */
602 @Test
603 public void testStartResolverActivityForHome() {
604 final ActivityInfo info = new ActivityInfo();
605 info.applicationInfo = new ApplicationInfo();
606 info.applicationInfo.packageName = "android";
607 info.name = ResolverActivity.class.getName();
Louis Chang149d5c82019-12-30 09:47:39 +0800608 doReturn(info).when(mRootWindowContainer).resolveHomeActivity(anyInt(), any());
Riddle Hsuff9e8282019-04-24 23:55:11 +0800609
Louis Chang149d5c82019-12-30 09:47:39 +0800610 mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "test", DEFAULT_DISPLAY);
611 final ActivityRecord resolverActivity = mRootWindowContainer.topRunningActivity();
Riddle Hsuff9e8282019-04-24 23:55:11 +0800612
613 assertEquals(info, resolverActivity.info);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800614 assertEquals(ACTIVITY_TYPE_STANDARD, resolverActivity.getRootTask().getActivityType());
Riddle Hsuff9e8282019-04-24 23:55:11 +0800615 }
616
617 /**
Chilun939b05c2020-02-19 14:50:59 +0800618 * Tests that secondary home should be selected if primary home not set.
Chilun2ef71f72018-11-16 17:57:15 +0800619 */
620 @Test
Chilun939b05c2020-02-19 14:50:59 +0800621 public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSet() {
622 // Setup: primary home not set.
623 final Intent primaryHomeIntent = mService.getHomeIntent();
624 final ActivityInfo aInfoPrimary = new ActivityInfo();
625 aInfoPrimary.name = ResolverActivity.class.getName();
626 doReturn(aInfoPrimary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
627 refEq(primaryHomeIntent));
628 // Setup: set secondary home.
629 mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */);
Chilun2ef71f72018-11-16 17:57:15 +0800630
Chilun939b05c2020-02-19 14:50:59 +0800631 // Run the test.
Louis Chang149d5c82019-12-30 09:47:39 +0800632 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
Chilun2ef71f72018-11-16 17:57:15 +0800633 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
Chilun939b05c2020-02-19 14:50:59 +0800634 final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
635 assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
636 assertEquals(aInfoSecondary.applicationInfo.packageName,
637 resolvedInfo.first.applicationInfo.packageName);
Chilun2ef71f72018-11-16 17:57:15 +0800638 }
639
640 /**
Keun young Park340546a2019-05-06 16:27:44 -0700641 * Tests that the default secondary home activity is always picked when it is in forced by
642 * config_useSystemProvidedLauncherForSecondary.
643 */
644 @Test
Chilun939b05c2020-02-19 14:50:59 +0800645 public void testResolveSecondaryHomeActivityForced() {
646 // SetUp: set primary home.
647 mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
648 // SetUp: set secondary home and force it.
649 mockResolveHomeActivity(false /* primaryHome */, true /* forceSystemProvided */);
650 final Intent secondaryHomeIntent =
651 mService.getSecondaryHomeIntent(null /* preferredPackage */);
Chilun2ef71f72018-11-16 17:57:15 +0800652 final List<ResolveInfo> resolutions = new ArrayList<>();
Chilun939b05c2020-02-19 14:50:59 +0800653 final ResolveInfo resolveInfo = new ResolveInfo();
654 final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
655 resolveInfo.activityInfo = aInfoSecondary;
656 resolutions.add(resolveInfo);
657 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(),
Chilun2ef71f72018-11-16 17:57:15 +0800658 refEq(secondaryHomeIntent));
Chilun939b05c2020-02-19 14:50:59 +0800659 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
660 any(), anyInt(), anyBoolean());
Chilun2ef71f72018-11-16 17:57:15 +0800661
Chilun939b05c2020-02-19 14:50:59 +0800662 // Run the test.
Louis Chang149d5c82019-12-30 09:47:39 +0800663 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
Chilun2ef71f72018-11-16 17:57:15 +0800664 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
Chilun939b05c2020-02-19 14:50:59 +0800665 assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
666 assertEquals(aInfoSecondary.applicationInfo.packageName,
667 resolvedInfo.first.applicationInfo.packageName);
Chilun2ef71f72018-11-16 17:57:15 +0800668 }
669
670 /**
Chilun939b05c2020-02-19 14:50:59 +0800671 * Tests that secondary home should be selected if primary home not support secondary displays
672 * or there is no matched activity in the same package as selected primary home.
Chilun2ef71f72018-11-16 17:57:15 +0800673 */
674 @Test
Chilun939b05c2020-02-19 14:50:59 +0800675 public void testResolveSecondaryHomeActivityWhenPrimaryHomeNotSupportMultiDisplay() {
676 // Setup: there is no matched activity in the same package as selected primary home.
677 mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
678 final List<ResolveInfo> resolutions = new ArrayList<>();
679 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
680 // Setup: set secondary home.
681 mockResolveHomeActivity(false /* primaryHome */, false /* forceSystemProvided */);
Chilun2ef71f72018-11-16 17:57:15 +0800682
Chilun939b05c2020-02-19 14:50:59 +0800683 // Run the test.
684 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
685 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
686 final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/);
687 assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
688 assertEquals(aInfoSecondary.applicationInfo.packageName,
689 resolvedInfo.first.applicationInfo.packageName);
690 }
691 /**
692 * Tests that primary home activity should be selected if it already support secondary displays.
693 */
694 @Test
695 public void testResolveSecondaryHomeActivityWhenPrimaryHomeSupportMultiDisplay() {
696 // SetUp: set primary home.
697 mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
698 // SetUp: put primary home info on 2nd item
Chilun2ef71f72018-11-16 17:57:15 +0800699 final List<ResolveInfo> resolutions = new ArrayList<>();
700 final ResolveInfo infoFake1 = new ResolveInfo();
701 infoFake1.activityInfo = new ActivityInfo();
702 infoFake1.activityInfo.name = "fakeActivity1";
703 infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
704 infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
705 final ResolveInfo infoFake2 = new ResolveInfo();
Chilun939b05c2020-02-19 14:50:59 +0800706 final ActivityInfo aInfoPrimary = getFakeHomeActivityInfo(true /* primaryHome */);
707 infoFake2.activityInfo = aInfoPrimary;
Chilun2ef71f72018-11-16 17:57:15 +0800708 resolutions.add(infoFake1);
709 resolutions.add(infoFake2);
Louis Chang149d5c82019-12-30 09:47:39 +0800710 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
Chilun2ef71f72018-11-16 17:57:15 +0800711
Louis Chang149d5c82019-12-30 09:47:39 +0800712 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
Chilun2ef71f72018-11-16 17:57:15 +0800713 any(), anyInt(), anyBoolean());
714
Chilun939b05c2020-02-19 14:50:59 +0800715 // Run the test.
Louis Chang149d5c82019-12-30 09:47:39 +0800716 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
Chilun2ef71f72018-11-16 17:57:15 +0800717 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
Chilun939b05c2020-02-19 14:50:59 +0800718 assertEquals(aInfoPrimary.name, resolvedInfo.first.name);
719 assertEquals(aInfoPrimary.applicationInfo.packageName,
Chilun2ef71f72018-11-16 17:57:15 +0800720 resolvedInfo.first.applicationInfo.packageName);
Chilun2ef71f72018-11-16 17:57:15 +0800721 }
722
723 /**
724 * Tests that the first one that matches should be selected if there are multiple activities.
725 */
726 @Test
727 public void testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay() {
Chilun939b05c2020-02-19 14:50:59 +0800728 // SetUp: set primary home.
729 mockResolveHomeActivity(true /* primaryHome */, false /* forceSystemProvided */);
730 // Setup: prepare two eligible activity info.
Chilun2ef71f72018-11-16 17:57:15 +0800731 final List<ResolveInfo> resolutions = new ArrayList<>();
732 final ResolveInfo infoFake1 = new ResolveInfo();
733 infoFake1.activityInfo = new ActivityInfo();
734 infoFake1.activityInfo.name = "fakeActivity1";
735 infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
736 infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
737 final ResolveInfo infoFake2 = new ResolveInfo();
738 infoFake2.activityInfo = new ActivityInfo();
739 infoFake2.activityInfo.name = "fakeActivity2";
740 infoFake2.activityInfo.applicationInfo = new ApplicationInfo();
741 infoFake2.activityInfo.applicationInfo.packageName = "fakePackage2";
742 resolutions.add(infoFake1);
743 resolutions.add(infoFake2);
Louis Chang149d5c82019-12-30 09:47:39 +0800744 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
Chilun2ef71f72018-11-16 17:57:15 +0800745
Louis Chang149d5c82019-12-30 09:47:39 +0800746 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
Chilun2ef71f72018-11-16 17:57:15 +0800747 any(), anyInt(), anyBoolean());
748
Chilun939b05c2020-02-19 14:50:59 +0800749 // Use the first one of matched activities in the same package as selected primary home.
Louis Chang149d5c82019-12-30 09:47:39 +0800750 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
Chilun2ef71f72018-11-16 17:57:15 +0800751 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
752
753 assertEquals(infoFake1.activityInfo.applicationInfo.packageName,
754 resolvedInfo.first.applicationInfo.packageName);
755 assertEquals(infoFake1.activityInfo.name, resolvedInfo.first.name);
756 }
Riddle Hsuff9e8282019-04-24 23:55:11 +0800757
758 /**
Louis Chang149d5c82019-12-30 09:47:39 +0800759 * Test that {@link RootWindowContainer#getLaunchStack} with the real caller id will get the
lumarkf65e02d2019-09-14 19:25:21 +0800760 * expected stack when requesting the activity launch on the secondary display.
761 */
762 @Test
763 public void testGetLaunchStackWithRealCallerId() {
764 // Create a non-system owned virtual display.
Louis Chang677921f2019-12-06 16:44:24 +0800765 final TestDisplayContent secondaryDisplay =
766 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700767 .setType(TYPE_VIRTUAL).setOwnerUid(100).build();
lumarkf65e02d2019-09-14 19:25:21 +0800768
769 // Create an activity with specify the original launch pid / uid.
770 final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200)
771 .setLaunchedFromUid(200).build();
772
773 // Simulate ActivityStarter to find a launch stack for requesting the activity to launch
774 // on the secondary display with realCallerId.
775 final ActivityOptions options = ActivityOptions.makeBasic();
776 options.setLaunchDisplayId(secondaryDisplay.mDisplayId);
777 options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
778 doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId,
779 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info);
Louis Chang149d5c82019-12-30 09:47:39 +0800780 final ActivityStack result = mRootWindowContainer.getLaunchStack(r, options,
lumarkf65e02d2019-09-14 19:25:21 +0800781 null /* task */, true /* onTop */, null, 300 /* test realCallerPid */,
782 300 /* test realCallerUid */);
783
784 // Assert that the stack is returned as expected.
785 assertNotNull(result);
786 assertEquals("The display ID of the stack should same as secondary display ",
Wale Ogunwale0b3d2922019-12-30 08:55:07 -0800787 secondaryDisplay.mDisplayId, result.getDisplayId());
lumarkf65e02d2019-09-14 19:25:21 +0800788 }
789
Darryl L Johnson3388bd22019-12-19 17:38:41 -0800790 @Test
791 public void testSwitchUser_missingHomeRootTask() {
792 doReturn(mFullscreenStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
793
794 DisplayContent defaultDisplay = mRootWindowContainer.getDefaultDisplay();
795 ActivityStack homeStack = defaultDisplay.getRootHomeTask();
796 if (homeStack != null) {
797 homeStack.removeImmediately();
798 }
799 assertNull(defaultDisplay.getRootHomeTask());
800
801 int currentUser = mRootWindowContainer.mCurrentUser;
802 int otherUser = currentUser + 1;
803
804 mRootWindowContainer.switchUser(otherUser, null);
805
806 assertNotNull(defaultDisplay.getRootHomeTask());
807 assertEquals(defaultDisplay.getTopStack(), defaultDisplay.getRootHomeTask());
808 }
809
lumarkf65e02d2019-09-14 19:25:21 +0800810 /**
Louis Chang149d5c82019-12-30 09:47:39 +0800811 * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
Chilun939b05c2020-02-19 14:50:59 +0800812 * info for test cases.
813 *
814 * @param primaryHome Indicate to use primary home intent as parameter, otherwise, use
815 * secondary home intent.
816 * @param forceSystemProvided Indicate to force using system provided home activity.
Riddle Hsuff9e8282019-04-24 23:55:11 +0800817 */
Chilun939b05c2020-02-19 14:50:59 +0800818 private void mockResolveHomeActivity(boolean primaryHome, boolean forceSystemProvided) {
819 ActivityInfo targetActivityInfo = getFakeHomeActivityInfo(primaryHome);
820 Intent targetIntent;
821 if (primaryHome) {
822 targetIntent = mService.getHomeIntent();
823 } else {
824 Resources resources = mContext.getResources();
825 spyOn(resources);
826 doReturn(targetActivityInfo.applicationInfo.packageName).when(resources).getString(
827 com.android.internal.R.string.config_secondaryHomePackage);
828 doReturn(forceSystemProvided).when(resources).getBoolean(
829 com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
830 targetIntent = mService.getSecondaryHomeIntent(null /* preferredPackage */);
831 }
832 doReturn(targetActivityInfo).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
833 refEq(targetIntent));
Riddle Hsuff9e8282019-04-24 23:55:11 +0800834 }
Chilun59954982019-05-23 14:50:48 +0800835
836 /**
Louis Chang149d5c82019-12-30 09:47:39 +0800837 * Mock {@link RootWindowContainer#resolveSecondaryHomeActivity} for returning consistent
Chilun939b05c2020-02-19 14:50:59 +0800838 * activity info for test cases.
Chilun59954982019-05-23 14:50:48 +0800839 */
840 private void mockResolveSecondaryHomeActivity() {
841 final Intent secondaryHomeIntent = mService
842 .getSecondaryHomeIntent(null /* preferredPackage */);
Chilun939b05c2020-02-19 14:50:59 +0800843 final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false);
Louis Chang149d5c82019-12-30 09:47:39 +0800844 doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer)
Chilun59954982019-05-23 14:50:48 +0800845 .resolveSecondaryHomeActivity(anyInt(), anyInt());
846 }
Chilun939b05c2020-02-19 14:50:59 +0800847
848 private ActivityInfo getFakeHomeActivityInfo(boolean primaryHome) {
849 final ActivityInfo aInfo = new ActivityInfo();
850 aInfo.name = primaryHome ? "fakeHomeActivity" : "fakeSecondaryHomeActivity";
851 aInfo.applicationInfo = new ApplicationInfo();
852 aInfo.applicationInfo.packageName =
853 primaryHome ? "fakeHomePackage" : "fakeSecondaryHomePackage";
854 return aInfo;
855 }
Wale Ogunwaled32da472018-11-16 07:19:28 -0800856}