blob: 9f092835b8d301c086732b159a3091c4e98a3a1d [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.ComponentName;
56import android.content.Intent;
Wale Ogunwaled32da472018-11-16 07:19:28 -080057import android.content.pm.ActivityInfo;
58import android.content.pm.ApplicationInfo;
Chilun2ef71f72018-11-16 17:57:15 +080059import android.content.pm.ResolveInfo;
Keun young Park340546a2019-05-06 16:27:44 -070060import android.content.res.Resources;
Wale Ogunwaled32da472018-11-16 07:19:28 -080061import android.graphics.Rect;
Wale Ogunwaled32da472018-11-16 07:19:28 -080062import android.platform.test.annotations.Presubmit;
Chilun2ef71f72018-11-16 17:57:15 +080063import android.util.Pair;
64
Wale Ogunwaled32da472018-11-16 07:19:28 -080065import androidx.test.filters.MediumTest;
Chilun2ef71f72018-11-16 17:57:15 +080066
67import com.android.internal.app.ResolverActivity;
Jorim Jaggia5cf6802019-04-26 19:43:11 +020068import com.android.server.wm.ActivityStack.ActivityState;
Chilun2ef71f72018-11-16 17:57:15 +080069
Wale Ogunwaled32da472018-11-16 07:19:28 -080070import org.junit.Before;
71import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +080072import org.junit.runner.RunWith;
Wale Ogunwaled32da472018-11-16 07:19:28 -080073
74import java.util.ArrayList;
Garfield Tan26835f02019-02-07 14:38:38 -080075import java.util.Arrays;
Chilun2ef71f72018-11-16 17:57:15 +080076import java.util.List;
Wale Ogunwalea38654f2019-11-17 20:37:15 -080077import java.util.function.Consumer;
Wale Ogunwaled32da472018-11-16 07:19:28 -080078
79/**
Louis Chang149d5c82019-12-30 09:47:39 +080080 * Tests for the {@link RootWindowContainer} class.
Wale Ogunwaled32da472018-11-16 07:19:28 -080081 *
82 * Build/Install/Run:
Riddle Hsuff9e8282019-04-24 23:55:11 +080083 * atest WmTests:RootActivityContainerTests
Wale Ogunwaled32da472018-11-16 07:19:28 -080084 */
85@MediumTest
86@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +080087@RunWith(WindowTestRunner.class)
Wale Ogunwaled32da472018-11-16 07:19:28 -080088public class RootActivityContainerTests extends ActivityTestsBase {
89 private ActivityStack mFullscreenStack;
90
91 @Before
92 public void setUp() throws Exception {
Louis Chang149d5c82019-12-30 09:47:39 +080093 mFullscreenStack = mRootWindowContainer.getDefaultDisplay().createStack(
Wale Ogunwaled32da472018-11-16 07:19:28 -080094 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Louis Chang3ff72a82019-12-17 12:12:59 +080095 doNothing().when(mService).updateSleepIfNeededLocked();
Wale Ogunwaled32da472018-11-16 07:19:28 -080096 }
97
98 /**
99 * This test ensures that we do not try to restore a task based off an invalid task id. We
100 * should expect {@code null} to be returned in this case.
101 */
102 @Test
103 public void testRestoringInvalidTask() {
Louis Chang149d5c82019-12-30 09:47:39 +0800104 mRootWindowContainer.getDefaultDisplay().removeAllTasks();
105 Task task = mRootWindowContainer.anyTaskForId(0 /*taskId*/,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800106 MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
107 assertNull(task);
108 }
109
110 /**
111 * This test ensures that an existing task in the pinned stack is moved to the fullscreen
112 * activity stack when a new task is added.
113 */
114 @Test
115 public void testReplacingTaskInPinnedStack() {
116 final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
117 .setStack(mFullscreenStack).build();
Louis Changcdec0802019-11-11 11:45:07 +0800118 final Task task = firstActivity.getTask();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800119
Ben Lin6db8fb22019-10-18 16:03:44 -0700120 final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(task)
Wale Ogunwaled32da472018-11-16 07:19:28 -0800121 .setStack(mFullscreenStack).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800122
123 mFullscreenStack.moveToFront("testReplacingTaskInPinnedStack");
124
125 // Ensure full screen stack has both tasks.
Ben Lin6db8fb22019-10-18 16:03:44 -0700126 ensureStackPlacement(mFullscreenStack, firstActivity, secondActivity);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800127
128 // Move first activity to pinned stack.
129 final Rect sourceBounds = new Rect();
Louis Chang149d5c82019-12-30 09:47:39 +0800130 mRootWindowContainer.moveActivityToPinnedStack(firstActivity, sourceBounds,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800131 0f /*aspectRatio*/, "initialMove");
132
Louis Chang677921f2019-12-06 16:44:24 +0800133 final DisplayContent display = mFullscreenStack.getDisplay();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800134 ActivityStack pinnedStack = display.getPinnedStack();
135 // Ensure a task has moved over.
Ben Lin6db8fb22019-10-18 16:03:44 -0700136 ensureStackPlacement(pinnedStack, firstActivity);
137 ensureStackPlacement(mFullscreenStack, secondActivity);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800138
139 // Move second activity to pinned stack.
Louis Chang149d5c82019-12-30 09:47:39 +0800140 mRootWindowContainer.moveActivityToPinnedStack(secondActivity, sourceBounds,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800141 0f /*aspectRatio*/, "secondMove");
142
143 // Need to get stacks again as a new instance might have been created.
144 pinnedStack = display.getPinnedStack();
145 mFullscreenStack = display.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
146 // Ensure stacks have swapped tasks.
Ben Lin6db8fb22019-10-18 16:03:44 -0700147 ensureStackPlacement(pinnedStack, secondActivity);
148 ensureStackPlacement(mFullscreenStack, firstActivity);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800149 }
150
Ben Lin6db8fb22019-10-18 16:03:44 -0700151 private static void ensureStackPlacement(ActivityStack stack, ActivityRecord... activities) {
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900152 final Task task = stack.getBottomMostTask();
Ben Lin6db8fb22019-10-18 16:03:44 -0700153 final ArrayList<ActivityRecord> stackActivities = new ArrayList<>();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800154
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800155 task.forAllActivities((Consumer<ActivityRecord>) stackActivities::add, false);
Ben Lin6db8fb22019-10-18 16:03:44 -0700156
157 assertEquals("Expecting " + Arrays.deepToString(activities) + " got " + stackActivities,
158 stackActivities.size(), activities != null ? activities.length : 0);
159
160 if (activities == null) {
Wale Ogunwaled32da472018-11-16 07:19:28 -0800161 return;
162 }
163
Ben Lin6db8fb22019-10-18 16:03:44 -0700164 for (ActivityRecord activity : activities) {
165 assertTrue(stackActivities.contains(activity));
Wale Ogunwaled32da472018-11-16 07:19:28 -0800166 }
167 }
168
169 @Test
170 public void testApplySleepTokens() {
Louis Chang149d5c82019-12-30 09:47:39 +0800171 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800172 final KeyguardController keyguard = mSupervisor.getKeyguardController();
Louis Chang149d5c82019-12-30 09:47:39 +0800173 final ActivityStack stack = new StackBuilder(mRootWindowContainer)
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -0700174 .setCreateActivity(false)
175 .setDisplay(display)
176 .setOnTop(false)
177 .build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800178
179 // Make sure we wake and resume in the case the display is turning on and the keyguard is
180 // not showing.
181 verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
182 false /* displayShouldSleep */, true /* isFocusedStack */,
183 false /* keyguardShowing */, true /* expectWakeFromSleep */,
184 true /* expectResumeTopActivity */);
185
186 // Make sure we wake and don't resume when the display is turning on and the keyguard is
187 // showing.
188 verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
189 false /* displayShouldSleep */, true /* isFocusedStack */,
190 true /* keyguardShowing */, true /* expectWakeFromSleep */,
191 false /* expectResumeTopActivity */);
192
193 // Make sure we wake and don't resume when the display is turning on and the keyguard is
194 // not showing as unfocused.
195 verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
196 false /* displayShouldSleep */, false /* isFocusedStack */,
197 false /* keyguardShowing */, true /* expectWakeFromSleep */,
198 false /* expectResumeTopActivity */);
199
200 // Should not do anything if the display state hasn't changed.
201 verifySleepTokenBehavior(display, keyguard, stack, false /*displaySleeping*/,
202 false /* displayShouldSleep */, true /* isFocusedStack */,
203 false /* keyguardShowing */, false /* expectWakeFromSleep */,
204 false /* expectResumeTopActivity */);
205 }
206
Louis Chang677921f2019-12-06 16:44:24 +0800207 private void verifySleepTokenBehavior(DisplayContent display, KeyguardController keyguard,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800208 ActivityStack stack, boolean displaySleeping, boolean displayShouldSleep,
209 boolean isFocusedStack, boolean keyguardShowing, boolean expectWakeFromSleep,
210 boolean expectResumeTopActivity) {
211 reset(stack);
212
213 doReturn(displayShouldSleep).when(display).shouldSleep();
214 doReturn(displaySleeping).when(display).isSleeping();
215 doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt());
216
217 doReturn(isFocusedStack).when(stack).isFocusedStackOnDisplay();
218 doReturn(isFocusedStack ? stack : null).when(display).getFocusedStack();
Louis Chang149d5c82019-12-30 09:47:39 +0800219 mRootWindowContainer.applySleepTokens(true);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800220 verify(stack, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked();
221 verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked(
222 null /* target */, null /* targetOptions */);
223 }
224
225 /**
226 * Verifies that removal of activity with task and stack is done correctly.
227 */
228 @Test
229 public void testRemovingStackOnAppCrash() {
Louis Chang149d5c82019-12-30 09:47:39 +0800230 final DisplayContent defaultDisplay = mRootWindowContainer.getDefaultDisplay();
Louis Chang2453d062019-11-19 22:30:48 +0800231 final int originalStackCount = defaultDisplay.getStackCount();
Louis Chang149d5c82019-12-30 09:47:39 +0800232 final ActivityStack stack = mRootWindowContainer.getDefaultDisplay().createStack(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800233 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
234 final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
235 .setStack(stack).build();
236
Louis Chang2453d062019-11-19 22:30:48 +0800237 assertEquals(originalStackCount + 1, defaultDisplay.getStackCount());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800238
239 // Let's pretend that the app has crashed.
240 firstActivity.app.setThread(null);
Louis Chang149d5c82019-12-30 09:47:39 +0800241 mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test");
Wale Ogunwaled32da472018-11-16 07:19:28 -0800242
243 // Verify that the stack was removed.
Louis Chang2453d062019-11-19 22:30:48 +0800244 assertEquals(originalStackCount, defaultDisplay.getStackCount());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800245 }
246
247 @Test
248 public void testFocusability() {
Louis Chang149d5c82019-12-30 09:47:39 +0800249 final ActivityStack stack = mRootWindowContainer.getDefaultDisplay().createStack(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800250 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
251 final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
252 .setStack(stack).build();
253
254 // Under split screen primary we should be focusable when not minimized
Louis Chang149d5c82019-12-30 09:47:39 +0800255 mRootWindowContainer.setDockedStackMinimized(false);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800256 assertTrue(stack.isFocusable());
257 assertTrue(activity.isFocusable());
258
259 // Under split screen primary we should not be focusable when minimized
Louis Chang149d5c82019-12-30 09:47:39 +0800260 mRootWindowContainer.setDockedStackMinimized(true);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800261 assertFalse(stack.isFocusable());
262 assertFalse(activity.isFocusable());
263
Louis Chang149d5c82019-12-30 09:47:39 +0800264 final ActivityStack pinnedStack = mRootWindowContainer.getDefaultDisplay().createStack(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800265 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
266 final ActivityRecord pinnedActivity = new ActivityBuilder(mService).setCreateTask(true)
267 .setStack(pinnedStack).build();
268
269 // We should not be focusable when in pinned mode
270 assertFalse(pinnedStack.isFocusable());
271 assertFalse(pinnedActivity.isFocusable());
272
273 // Add flag forcing focusability.
274 pinnedActivity.info.flags |= FLAG_ALWAYS_FOCUSABLE;
275
276 // We should not be focusable when in pinned mode
277 assertTrue(pinnedStack.isFocusable());
278 assertTrue(pinnedActivity.isFocusable());
279
280 // Without the overridding activity, stack should not be focusable.
Louis Changcdec0802019-11-11 11:45:07 +0800281 pinnedStack.removeChild(pinnedActivity.getTask(), "testFocusability");
Wale Ogunwaled32da472018-11-16 07:19:28 -0800282 assertFalse(pinnedStack.isFocusable());
283 }
284
285 /**
286 * Verify that split-screen primary stack will be chosen if activity is launched that targets
287 * split-screen secondary, but a matching existing instance is found on top of split-screen
288 * primary stack.
289 */
290 @Test
291 public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() {
292 // Create primary split-screen stack with a task and an activity.
Louis Chang149d5c82019-12-30 09:47:39 +0800293 final ActivityStack primaryStack = mRootWindowContainer.getDefaultDisplay()
Wale Ogunwaled32da472018-11-16 07:19:28 -0800294 .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
295 true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800296 final Task task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800297 final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
298
299 // Find a launch stack for the top activity in split-screen primary, while requesting
300 // split-screen secondary.
301 final ActivityOptions options = ActivityOptions.makeBasic();
302 options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
303 final ActivityStack result =
Louis Chang149d5c82019-12-30 09:47:39 +0800304 mRootWindowContainer.getLaunchStack(r, options, task, true /* onTop */);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800305
306 // Assert that the primary stack is returned.
307 assertEquals(primaryStack, result);
308 }
309
310 /**
311 * Verify split-screen primary stack & task can resized by
312 * {@link android.app.IActivityTaskManager#resizeDockedStack} as expect.
313 */
314 @Test
315 public void testResizeDockedStackForSplitScreenPrimary() {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700316 final Rect taskSize = new Rect(0, 0, 1000, 1000);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800317 final Rect stackSize = new Rect(0, 0, 300, 300);
318
319 // Create primary split-screen stack with a task.
Louis Chang149d5c82019-12-30 09:47:39 +0800320 final ActivityStack primaryStack = new StackBuilder(mRootWindowContainer)
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700321 .setActivityType(ACTIVITY_TYPE_STANDARD)
322 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
323 .setOnTop(true)
324 .build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900325 final Task task = primaryStack.getTopMostTask();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800326
327 // Resize dock stack.
328 mService.resizeDockedStack(stackSize, taskSize, null, null, null);
329
330 // Verify dock stack & its task bounds if is equal as resized result.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700331 assertEquals(stackSize, primaryStack.getBounds());
332 assertEquals(taskSize, task.getBounds());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800333 }
334
335 /**
336 * Verify that home stack would be moved to front when the top activity is Recents.
337 */
338 @Test
339 public void testFindTaskToMoveToFrontWhenRecentsOnTop() {
340 // Create stack/task on default display.
Louis Chang149d5c82019-12-30 09:47:39 +0800341 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
342 final ActivityStack targetStack = new StackBuilder(mRootWindowContainer)
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700343 .setOnTop(false)
344 .build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900345 final Task targetTask = targetStack.getBottomMostTask();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800346
347 // Create Recents on top of the display.
Louis Chang149d5c82019-12-30 09:47:39 +0800348 final ActivityStack stack = new StackBuilder(mRootWindowContainer).setActivityType(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800349 ACTIVITY_TYPE_RECENTS).build();
350
351 final String reason = "findTaskToMoveToFront";
352 mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
353 false);
354
355 verify(display).moveHomeStackToFront(contains(reason));
356 }
357
358 /**
359 * Verify that home stack won't be moved to front if the top activity on other display is
360 * Recents.
361 */
362 @Test
363 public void testFindTaskToMoveToFrontWhenRecentsOnOtherDisplay() {
364 // Create stack/task on default display.
Louis Chang149d5c82019-12-30 09:47:39 +0800365 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800366 final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
367 ACTIVITY_TYPE_STANDARD, false /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800368 final Task targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800369
370 // Create Recents on secondary display.
Louis Chang677921f2019-12-06 16:44:24 +0800371 final TestDisplayContent secondDisplay = addNewDisplayContentAt(
372 DisplayContent.POSITION_TOP);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800373 final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
374 ACTIVITY_TYPE_RECENTS, true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800375 final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800376 new ActivityBuilder(mService).setTask(task).build();
377
378 final String reason = "findTaskToMoveToFront";
379 mSupervisor.findTaskToMoveToFront(targetTask, 0, ActivityOptions.makeBasic(), reason,
380 false);
381
382 verify(display, never()).moveHomeStackToFront(contains(reason));
383 }
384
385 /**
386 * Verify if a stack is not at the topmost position, it should be able to resume its activity if
387 * the stack is the top focused.
388 */
389 @Test
390 public void testResumeActivityWhenNonTopmostStackIsTopFocused() {
391 // Create a stack at bottom.
Louis Chang149d5c82019-12-30 09:47:39 +0800392 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800393 final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
394 ACTIVITY_TYPE_STANDARD, false /* onTop */));
Louis Changcdec0802019-11-11 11:45:07 +0800395 final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800396 final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
Louis Chang2453d062019-11-19 22:30:48 +0800397 display.positionStackAtBottom(targetStack);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800398
399 // Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it
400 // is the current top focused stack.
401 assertFalse(targetStack.isTopStackOnDisplay());
Louis Chang149d5c82019-12-30 09:47:39 +0800402 doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800403
404 // Use the stack as target to resume.
Louis Chang149d5c82019-12-30 09:47:39 +0800405 mRootWindowContainer.resumeFocusedStacksTopActivities(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800406 targetStack, activity, null /* targetOptions */);
407
408 // Verify the target stack should resume its activity.
409 verify(targetStack, times(1)).resumeTopActivityUncheckedLocked(
410 eq(activity), eq(null /* targetOptions */));
411 }
412
413 /**
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700414 * Verify that home activity will be started on a display even if another display has a
415 * focusable activity.
416 */
417 @Test
418 public void testResumeFocusedStacksStartsHomeActivity_NoActivities() {
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -0700419 mFullscreenStack.removeIfPossible();
Louis Chang149d5c82019-12-30 09:47:39 +0800420 mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY).getHomeStack()
Louis Chang677921f2019-12-06 16:44:24 +0800421 .removeIfPossible();
Louis Chang149d5c82019-12-30 09:47:39 +0800422 mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY)
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700423 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
424
Louis Chang149d5c82019-12-30 09:47:39 +0800425 doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), anyInt());
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700426
427 mService.setBooted(true);
428
429 // Trigger resume on all displays
Louis Chang149d5c82019-12-30 09:47:39 +0800430 mRootWindowContainer.resumeFocusedStacksTopActivities();
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700431
432 // Verify that home activity was started on the default display
Louis Chang149d5c82019-12-30 09:47:39 +0800433 verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(DEFAULT_DISPLAY));
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700434 }
435
436 /**
437 * Verify that home activity will be started on a display even if another display has a
438 * focusable activity.
439 */
440 @Test
441 public void testResumeFocusedStacksStartsHomeActivity_ActivityOnSecondaryScreen() {
Wale Ogunwalebebd8cd2019-10-28 15:53:31 -0700442 mFullscreenStack.removeIfPossible();
Louis Chang149d5c82019-12-30 09:47:39 +0800443 mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY).getHomeStack()
Louis Chang677921f2019-12-06 16:44:24 +0800444 .removeIfPossible();
Louis Chang149d5c82019-12-30 09:47:39 +0800445 mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY)
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700446 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
447
448 // Create an activity on secondary display.
Louis Chang677921f2019-12-06 16:44:24 +0800449 final TestDisplayContent secondDisplay = addNewDisplayContentAt(
450 DisplayContent.POSITION_TOP);
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700451 final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
452 ACTIVITY_TYPE_STANDARD, true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800453 final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700454 new ActivityBuilder(mService).setTask(task).build();
455
Louis Chang149d5c82019-12-30 09:47:39 +0800456 doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), anyInt());
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700457
458 mService.setBooted(true);
459
460 // Trigger resume on all displays
Louis Chang149d5c82019-12-30 09:47:39 +0800461 mRootWindowContainer.resumeFocusedStacksTopActivities();
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700462
463 // Verify that home activity was started on the default display
Louis Chang149d5c82019-12-30 09:47:39 +0800464 verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(DEFAULT_DISPLAY));
Andrii Kulian3ff5a0b2019-05-16 13:18:04 -0700465 }
466
467 /**
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200468 * Verify that a lingering transition is being executed in case the activity to be resumed is
469 * already resumed
470 */
471 @Test
472 public void testResumeActivityLingeringTransition() {
473 // Create a stack at top.
Louis Chang149d5c82019-12-30 09:47:39 +0800474 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200475 final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
476 ACTIVITY_TYPE_STANDARD, false /* onTop */));
Louis Changcdec0802019-11-11 11:45:07 +0800477 final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200478 final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
479 activity.setState(ActivityState.RESUMED, "test");
480
481 // Assume the stack is at the topmost position
482 assertTrue(targetStack.isTopStackOnDisplay());
483
484 // Use the stack as target to resume.
Louis Chang149d5c82019-12-30 09:47:39 +0800485 mRootWindowContainer.resumeFocusedStacksTopActivities();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200486
487 // Verify the lingering app transition is being executed because it's already resumed
488 verify(targetStack, times(1)).executeAppTransition(any());
489 }
490
491 @Test
492 public void testResumeActivityLingeringTransition_notExecuted() {
493 // Create a stack at bottom.
Louis Chang149d5c82019-12-30 09:47:39 +0800494 final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200495 final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
496 ACTIVITY_TYPE_STANDARD, false /* onTop */));
Louis Changcdec0802019-11-11 11:45:07 +0800497 final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200498 final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
499 activity.setState(ActivityState.RESUMED, "test");
Louis Chang2453d062019-11-19 22:30:48 +0800500 display.positionStackAtBottom(targetStack);
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200501
502 // Assume the stack is at the topmost position
503 assertFalse(targetStack.isTopStackOnDisplay());
Louis Chang149d5c82019-12-30 09:47:39 +0800504 doReturn(targetStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200505
506 // Use the stack as target to resume.
Louis Chang149d5c82019-12-30 09:47:39 +0800507 mRootWindowContainer.resumeFocusedStacksTopActivities();
Jorim Jaggia5cf6802019-04-26 19:43:11 +0200508
509 // Verify the lingering app transition is being executed because it's already resumed
510 verify(targetStack, never()).executeAppTransition(any());
511 }
512
513 /**
Wale Ogunwaled32da472018-11-16 07:19:28 -0800514 * Tests that home activities can be started on the displays that supports system decorations.
515 */
Chilun2afb94e2018-12-25 20:42:45 +0800516 @Test
517 public void testStartHomeOnAllDisplays() {
Riddle Hsuff9e8282019-04-24 23:55:11 +0800518 mockResolveHomeActivity();
Chilun59954982019-05-23 14:50:48 +0800519 mockResolveSecondaryHomeActivity();
Riddle Hsuff9e8282019-04-24 23:55:11 +0800520
Wale Ogunwaled32da472018-11-16 07:19:28 -0800521 // Create secondary displays.
Louis Chang677921f2019-12-06 16:44:24 +0800522 final TestDisplayContent secondDisplay =
523 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700524 .setSystemDecorations(true).build();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800525
Louis Chang149d5c82019-12-30 09:47:39 +0800526 doReturn(true).when(mRootWindowContainer)
Wale Ogunwaled32da472018-11-16 07:19:28 -0800527 .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean());
Louis Chang149d5c82019-12-30 09:47:39 +0800528 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
Wale Ogunwaled32da472018-11-16 07:19:28 -0800529 any(), anyInt(), anyBoolean());
530
Louis Chang149d5c82019-12-30 09:47:39 +0800531 mRootWindowContainer.startHomeOnAllDisplays(0, "testStartHome");
Wale Ogunwaled32da472018-11-16 07:19:28 -0800532
Louis Chang149d5c82019-12-30 09:47:39 +0800533 assertTrue(mRootWindowContainer.getDefaultDisplay().getTopStack().isActivityTypeHome());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800534 assertNotNull(secondDisplay.getTopStack());
535 assertTrue(secondDisplay.getTopStack().isActivityTypeHome());
536 }
537
538 /**
539 * Tests that home activities won't be started before booting when display added.
540 */
541 @Test
542 public void testNotStartHomeBeforeBoot() {
543 final int displayId = 1;
544 final boolean isBooting = mService.mAmInternal.isBooting();
545 final boolean isBooted = mService.mAmInternal.isBooted();
546 try {
547 mService.mAmInternal.setBooting(false);
548 mService.mAmInternal.setBooted(false);
Louis Chang149d5c82019-12-30 09:47:39 +0800549 mRootWindowContainer.onDisplayAdded(displayId);
550 verify(mRootWindowContainer, never()).startHomeOnDisplay(anyInt(), any(), anyInt());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800551 } finally {
552 mService.mAmInternal.setBooting(isBooting);
553 mService.mAmInternal.setBooted(isBooted);
554 }
555 }
556
557 /**
558 * Tests whether home can be started if being instrumented.
559 */
560 @Test
561 public void testCanStartHomeWhenInstrumented() {
562 final ActivityInfo info = new ActivityInfo();
563 info.applicationInfo = new ApplicationInfo();
564 final WindowProcessController app = mock(WindowProcessController.class);
565 doReturn(app).when(mService).getProcessController(any(), anyInt());
566
567 // Can not start home if we don't want to start home while home is being instrumented.
568 doReturn(true).when(app).isInstrumenting();
Louis Chang149d5c82019-12-30 09:47:39 +0800569 assertFalse(mRootWindowContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800570 false /* allowInstrumenting*/));
571
572 // Can start home for other cases.
Louis Chang149d5c82019-12-30 09:47:39 +0800573 assertTrue(mRootWindowContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800574 true /* allowInstrumenting*/));
575
576 doReturn(false).when(app).isInstrumenting();
Louis Chang149d5c82019-12-30 09:47:39 +0800577 assertTrue(mRootWindowContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800578 false /* allowInstrumenting*/));
Louis Chang149d5c82019-12-30 09:47:39 +0800579 assertTrue(mRootWindowContainer.canStartHomeOnDisplay(info, DEFAULT_DISPLAY,
Wale Ogunwaled32da472018-11-16 07:19:28 -0800580 true /* allowInstrumenting*/));
581 }
Chilun2ef71f72018-11-16 17:57:15 +0800582
583 /**
Chilun85ebc0d2019-04-15 16:00:53 +0800584 * Tests that secondary home activity should not be resolved if device is still locked.
585 */
586 @Test
587 public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() {
588 // Create secondary displays.
Louis Chang677921f2019-12-06 16:44:24 +0800589 final TestDisplayContent secondDisplay =
590 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700591 .setSystemDecorations(true).build();
Chilun85ebc0d2019-04-15 16:00:53 +0800592
Chilun85ebc0d2019-04-15 16:00:53 +0800593 // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false.
Louis Chang149d5c82019-12-30 09:47:39 +0800594 final int currentUser = mRootWindowContainer.mCurrentUser;
595 mRootWindowContainer.mCurrentUser = -1;
Chilun85ebc0d2019-04-15 16:00:53 +0800596
Louis Chang149d5c82019-12-30 09:47:39 +0800597 mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
Chilun85ebc0d2019-04-15 16:00:53 +0800598 secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */);
599
600 try {
Louis Chang149d5c82019-12-30 09:47:39 +0800601 verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(),
Chilun85ebc0d2019-04-15 16:00:53 +0800602 anyInt());
603 } finally {
Louis Chang149d5c82019-12-30 09:47:39 +0800604 mRootWindowContainer.mCurrentUser = currentUser;
Chilun85ebc0d2019-04-15 16:00:53 +0800605 }
606 }
607
608 /**
609 * Tests that secondary home activity should not be resolved if display does not support system
610 * decorations.
611 */
612 @Test
613 public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() {
614 // Create secondary displays.
Louis Chang677921f2019-12-06 16:44:24 +0800615 final TestDisplayContent secondDisplay =
616 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700617 .setSystemDecorations(false).build();
Chilun85ebc0d2019-04-15 16:00:53 +0800618
Louis Chang149d5c82019-12-30 09:47:39 +0800619 mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome",
Chilun85ebc0d2019-04-15 16:00:53 +0800620 secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */);
621
Louis Chang149d5c82019-12-30 09:47:39 +0800622 verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), anyInt());
Chilun85ebc0d2019-04-15 16:00:53 +0800623 }
624
625 /**
Riddle Hsuff9e8282019-04-24 23:55:11 +0800626 * Tests that when starting {@link #ResolverActivity} for home, it should use the standard
627 * activity type (in a new stack) so the order of back stack won't be broken.
628 */
629 @Test
630 public void testStartResolverActivityForHome() {
631 final ActivityInfo info = new ActivityInfo();
632 info.applicationInfo = new ApplicationInfo();
633 info.applicationInfo.packageName = "android";
634 info.name = ResolverActivity.class.getName();
Louis Chang149d5c82019-12-30 09:47:39 +0800635 doReturn(info).when(mRootWindowContainer).resolveHomeActivity(anyInt(), any());
Riddle Hsuff9e8282019-04-24 23:55:11 +0800636
Louis Chang149d5c82019-12-30 09:47:39 +0800637 mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "test", DEFAULT_DISPLAY);
638 final ActivityRecord resolverActivity = mRootWindowContainer.topRunningActivity();
Riddle Hsuff9e8282019-04-24 23:55:11 +0800639
640 assertEquals(info, resolverActivity.info);
641 assertEquals(ACTIVITY_TYPE_STANDARD, resolverActivity.getActivityStack().getActivityType());
642 }
643
644 /**
Chilun2ef71f72018-11-16 17:57:15 +0800645 * Tests that secondary home should be selected if default home not set.
646 */
647 @Test
648 public void testResolveSecondaryHomeActivityWhenDefaultHomeNotSet() {
649 final Intent defaultHomeIntent = mService.getHomeIntent();
650 final ActivityInfo aInfoDefault = new ActivityInfo();
651 aInfoDefault.name = ResolverActivity.class.getName();
Louis Chang149d5c82019-12-30 09:47:39 +0800652 doReturn(aInfoDefault).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
Chilun2ef71f72018-11-16 17:57:15 +0800653 refEq(defaultHomeIntent));
654
655 final String secondaryHomeComponent = mService.mContext.getResources().getString(
656 com.android.internal.R.string.config_secondaryHomeComponent);
657 final ComponentName comp = ComponentName.unflattenFromString(secondaryHomeComponent);
658 final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
659 final ActivityInfo aInfoSecondary = new ActivityInfo();
660 aInfoSecondary.name = comp.getClassName();
Louis Chang149d5c82019-12-30 09:47:39 +0800661 doReturn(aInfoSecondary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
Chilun2ef71f72018-11-16 17:57:15 +0800662 refEq(secondaryHomeIntent));
663
664 // Should fallback to secondary home if default home not set.
Louis Chang149d5c82019-12-30 09:47:39 +0800665 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
Chilun2ef71f72018-11-16 17:57:15 +0800666 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
667
668 assertEquals(comp.getClassName(), resolvedInfo.first.name);
669 }
670
671 /**
Keun young Park340546a2019-05-06 16:27:44 -0700672 * Tests that the default secondary home activity is always picked when it is in forced by
673 * config_useSystemProvidedLauncherForSecondary.
674 */
675 @Test
676 public void testResolveSecondaryHomeActivityForced() throws Exception {
677 Resources resources = mContext.getResources();
678 spyOn(resources);
679 try {
680 // setUp: set secondary launcher and force it.
681 final String defaultSecondaryHome =
682 "com.android.test/com.android.test.TestDefaultSecondaryHome";
683 final ComponentName secondaryComp = ComponentName.unflattenFromString(
684 defaultSecondaryHome);
685 doReturn(defaultSecondaryHome).when(resources).getString(
686 com.android.internal.R.string.config_secondaryHomeComponent);
687 doReturn(true).when(resources).getBoolean(
688 com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
689 final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
690 assertEquals(secondaryComp, secondaryHomeIntent.getComponent());
691 final ActivityInfo aInfoSecondary = new ActivityInfo();
692 aInfoSecondary.name = secondaryComp.getClassName();
693 aInfoSecondary.applicationInfo = new ApplicationInfo();
694 aInfoSecondary.applicationInfo.packageName = secondaryComp.getPackageName();
Louis Chang149d5c82019-12-30 09:47:39 +0800695 doReturn(aInfoSecondary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
Keun young Park340546a2019-05-06 16:27:44 -0700696 refEq(secondaryHomeIntent));
697 final Intent homeIntent = mService.getHomeIntent();
698 final ActivityInfo aInfoDefault = new ActivityInfo();
699 aInfoDefault.name = "fakeHomeActivity";
700 aInfoDefault.applicationInfo = new ApplicationInfo();
701 aInfoDefault.applicationInfo.packageName = "fakeHomePackage";
Louis Chang149d5c82019-12-30 09:47:39 +0800702 doReturn(aInfoDefault).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
Keun young Park340546a2019-05-06 16:27:44 -0700703 refEq(homeIntent));
704 // Let resolveActivities call to validate both main launcher and second launcher so that
705 // resolveActivities call does not work as enabler for secondary.
706 final List<ResolveInfo> resolutions1 = new ArrayList<>();
707 final ResolveInfo resolveInfo1 = new ResolveInfo();
708 resolveInfo1.activityInfo = new ActivityInfo();
709 resolveInfo1.activityInfo.name = aInfoDefault.name;
710 resolveInfo1.activityInfo.applicationInfo = aInfoDefault.applicationInfo;
711 resolutions1.add(resolveInfo1);
Louis Chang149d5c82019-12-30 09:47:39 +0800712 doReturn(resolutions1).when(mRootWindowContainer).resolveActivities(anyInt(),
Keun young Park340546a2019-05-06 16:27:44 -0700713 refEq(homeIntent));
714 final List<ResolveInfo> resolutions2 = new ArrayList<>();
715 final ResolveInfo resolveInfo2 = new ResolveInfo();
716 resolveInfo2.activityInfo = new ActivityInfo();
717 resolveInfo2.activityInfo.name = aInfoSecondary.name;
718 resolveInfo2.activityInfo.applicationInfo = aInfoSecondary.applicationInfo;
719 resolutions2.add(resolveInfo2);
Louis Chang149d5c82019-12-30 09:47:39 +0800720 doReturn(resolutions2).when(mRootWindowContainer).resolveActivities(anyInt(),
Keun young Park340546a2019-05-06 16:27:44 -0700721 refEq(secondaryHomeIntent));
Louis Chang149d5c82019-12-30 09:47:39 +0800722 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
Keun young Park340546a2019-05-06 16:27:44 -0700723 any(), anyInt(), anyBoolean());
724
725 // Run the test
Louis Chang149d5c82019-12-30 09:47:39 +0800726 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
Keun young Park340546a2019-05-06 16:27:44 -0700727 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
728 assertEquals(secondaryComp.getClassName(), resolvedInfo.first.name);
729 assertEquals(secondaryComp.getPackageName(),
730 resolvedInfo.first.applicationInfo.packageName);
731 assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
732 } finally {
733 // tearDown
734 reset(resources);
735 }
736 }
737
738 /**
Chilun2ef71f72018-11-16 17:57:15 +0800739 * Tests that secondary home should be selected if default home not support secondary displays
740 * or there is no matched activity in the same package as selected default home.
741 */
742 @Test
743 public void testResolveSecondaryHomeActivityWhenDefaultHomeNotSupportMultiDisplay() {
Riddle Hsuff9e8282019-04-24 23:55:11 +0800744 mockResolveHomeActivity();
Chilun2ef71f72018-11-16 17:57:15 +0800745
746 final List<ResolveInfo> resolutions = new ArrayList<>();
Louis Chang149d5c82019-12-30 09:47:39 +0800747 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
Chilun2ef71f72018-11-16 17:57:15 +0800748
749 final String secondaryHomeComponent = mService.mContext.getResources().getString(
750 com.android.internal.R.string.config_secondaryHomeComponent);
751 final ComponentName comp = ComponentName.unflattenFromString(secondaryHomeComponent);
752 final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
753 final ActivityInfo aInfoSecondary = new ActivityInfo();
754 aInfoSecondary.name = comp.getClassName();
Louis Chang149d5c82019-12-30 09:47:39 +0800755 doReturn(aInfoSecondary).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
Chilun2ef71f72018-11-16 17:57:15 +0800756 refEq(secondaryHomeIntent));
757
758 // Should fallback to secondary home if selected default home not support secondary displays
759 // or there is no matched activity in the same package as selected default home.
Louis Chang149d5c82019-12-30 09:47:39 +0800760 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
Chilun2ef71f72018-11-16 17:57:15 +0800761 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
762
763 assertEquals(comp.getClassName(), resolvedInfo.first.name);
764 }
765
766 /**
767 * Tests that default home activity should be selected if it already support secondary displays.
768 */
769 @Test
770 public void testResolveSecondaryHomeActivityWhenDefaultHomeSupportMultiDisplay() {
Riddle Hsuff9e8282019-04-24 23:55:11 +0800771 final ActivityInfo aInfoDefault = mockResolveHomeActivity();
Chilun2ef71f72018-11-16 17:57:15 +0800772
773 final List<ResolveInfo> resolutions = new ArrayList<>();
774 final ResolveInfo infoFake1 = new ResolveInfo();
775 infoFake1.activityInfo = new ActivityInfo();
776 infoFake1.activityInfo.name = "fakeActivity1";
777 infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
778 infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
779 final ResolveInfo infoFake2 = new ResolveInfo();
780 infoFake2.activityInfo = aInfoDefault;
781 resolutions.add(infoFake1);
782 resolutions.add(infoFake2);
Louis Chang149d5c82019-12-30 09:47:39 +0800783 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
Chilun2ef71f72018-11-16 17:57:15 +0800784
Louis Chang149d5c82019-12-30 09:47:39 +0800785 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
Chilun2ef71f72018-11-16 17:57:15 +0800786 any(), anyInt(), anyBoolean());
787
788 // Use default home activity if it support secondary displays.
Louis Chang149d5c82019-12-30 09:47:39 +0800789 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
Chilun2ef71f72018-11-16 17:57:15 +0800790 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
791
792 assertEquals(aInfoDefault.applicationInfo.packageName,
793 resolvedInfo.first.applicationInfo.packageName);
794 assertEquals(aInfoDefault.name, resolvedInfo.first.name);
795 }
796
797 /**
798 * Tests that the first one that matches should be selected if there are multiple activities.
799 */
800 @Test
801 public void testResolveSecondaryHomeActivityWhenOtherActivitySupportMultiDisplay() {
Riddle Hsuff9e8282019-04-24 23:55:11 +0800802 mockResolveHomeActivity();
Chilun2ef71f72018-11-16 17:57:15 +0800803
804 final List<ResolveInfo> resolutions = new ArrayList<>();
805 final ResolveInfo infoFake1 = new ResolveInfo();
806 infoFake1.activityInfo = new ActivityInfo();
807 infoFake1.activityInfo.name = "fakeActivity1";
808 infoFake1.activityInfo.applicationInfo = new ApplicationInfo();
809 infoFake1.activityInfo.applicationInfo.packageName = "fakePackage1";
810 final ResolveInfo infoFake2 = new ResolveInfo();
811 infoFake2.activityInfo = new ActivityInfo();
812 infoFake2.activityInfo.name = "fakeActivity2";
813 infoFake2.activityInfo.applicationInfo = new ApplicationInfo();
814 infoFake2.activityInfo.applicationInfo.packageName = "fakePackage2";
815 resolutions.add(infoFake1);
816 resolutions.add(infoFake2);
Louis Chang149d5c82019-12-30 09:47:39 +0800817 doReturn(resolutions).when(mRootWindowContainer).resolveActivities(anyInt(), any());
Chilun2ef71f72018-11-16 17:57:15 +0800818
Louis Chang149d5c82019-12-30 09:47:39 +0800819 doReturn(true).when(mRootWindowContainer).canStartHomeOnDisplay(
Chilun2ef71f72018-11-16 17:57:15 +0800820 any(), anyInt(), anyBoolean());
821
822 // Use the first one of matched activities in the same package as selected default home.
Louis Chang149d5c82019-12-30 09:47:39 +0800823 final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer
Chilun2ef71f72018-11-16 17:57:15 +0800824 .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
825
826 assertEquals(infoFake1.activityInfo.applicationInfo.packageName,
827 resolvedInfo.first.applicationInfo.packageName);
828 assertEquals(infoFake1.activityInfo.name, resolvedInfo.first.name);
829 }
Riddle Hsuff9e8282019-04-24 23:55:11 +0800830
831 /**
Louis Chang149d5c82019-12-30 09:47:39 +0800832 * Test that {@link RootWindowContainer#getLaunchStack} with the real caller id will get the
lumarkf65e02d2019-09-14 19:25:21 +0800833 * expected stack when requesting the activity launch on the secondary display.
834 */
835 @Test
836 public void testGetLaunchStackWithRealCallerId() {
837 // Create a non-system owned virtual display.
Louis Chang677921f2019-12-06 16:44:24 +0800838 final TestDisplayContent secondaryDisplay =
839 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700840 .setType(TYPE_VIRTUAL).setOwnerUid(100).build();
lumarkf65e02d2019-09-14 19:25:21 +0800841
842 // Create an activity with specify the original launch pid / uid.
843 final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200)
844 .setLaunchedFromUid(200).build();
845
846 // Simulate ActivityStarter to find a launch stack for requesting the activity to launch
847 // on the secondary display with realCallerId.
848 final ActivityOptions options = ActivityOptions.makeBasic();
849 options.setLaunchDisplayId(secondaryDisplay.mDisplayId);
850 options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
851 doReturn(true).when(mSupervisor).canPlaceEntityOnDisplay(secondaryDisplay.mDisplayId,
852 300 /* test realCallerPid */, 300 /* test realCallerUid */, r.info);
Louis Chang149d5c82019-12-30 09:47:39 +0800853 final ActivityStack result = mRootWindowContainer.getLaunchStack(r, options,
lumarkf65e02d2019-09-14 19:25:21 +0800854 null /* task */, true /* onTop */, null, 300 /* test realCallerPid */,
855 300 /* test realCallerUid */);
856
857 // Assert that the stack is returned as expected.
858 assertNotNull(result);
859 assertEquals("The display ID of the stack should same as secondary display ",
860 secondaryDisplay.mDisplayId, result.mDisplayId);
861 }
862
863 /**
Louis Chang149d5c82019-12-30 09:47:39 +0800864 * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
Riddle Hsuff9e8282019-04-24 23:55:11 +0800865 * info for test cases (the original implementation will resolve from the real package manager).
866 */
867 private ActivityInfo mockResolveHomeActivity() {
868 final Intent homeIntent = mService.getHomeIntent();
869 final ActivityInfo aInfoDefault = new ActivityInfo();
870 aInfoDefault.name = "fakeHomeActivity";
871 aInfoDefault.applicationInfo = new ApplicationInfo();
872 aInfoDefault.applicationInfo.packageName = "fakeHomePackage";
Louis Chang149d5c82019-12-30 09:47:39 +0800873 doReturn(aInfoDefault).when(mRootWindowContainer).resolveHomeActivity(anyInt(),
Riddle Hsuff9e8282019-04-24 23:55:11 +0800874 refEq(homeIntent));
875 return aInfoDefault;
876 }
Chilun59954982019-05-23 14:50:48 +0800877
878 /**
Louis Chang149d5c82019-12-30 09:47:39 +0800879 * Mock {@link RootWindowContainer#resolveSecondaryHomeActivity} for returning consistent
Chilun59954982019-05-23 14:50:48 +0800880 * activity info for test cases (the original implementation will resolve from the real package
881 * manager).
882 */
883 private void mockResolveSecondaryHomeActivity() {
884 final Intent secondaryHomeIntent = mService
885 .getSecondaryHomeIntent(null /* preferredPackage */);
886 final ActivityInfo aInfoSecondary = new ActivityInfo();
887 aInfoSecondary.name = "fakeSecondaryHomeActivity";
888 aInfoSecondary.applicationInfo = new ApplicationInfo();
889 aInfoSecondary.applicationInfo.packageName = "fakeSecondaryHomePackage";
Louis Chang149d5c82019-12-30 09:47:39 +0800890 doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer)
Chilun59954982019-05-23 14:50:48 +0800891 .resolveSecondaryHomeActivity(anyInt(), anyInt());
892 }
Wale Ogunwaled32da472018-11-16 07:19:28 -0800893}