blob: fa182d68d91763e5a10349c4ae9f330a516ae76a [file] [log] [blame]
Bryce Lee4e4a3ec2017-09-27 08:25:03 -07001/*
Wale Ogunwale59507092018-10-29 09:00:30 -07002 * Copyright (C) 2018 The Android Open Source Project
Bryce Lee4e4a3ec2017-09-27 08:25:03 -07003 *
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
Wale Ogunwale59507092018-10-29 09:00:30 -070014 * limitations under the License
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070015 */
16
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070018
Michal Karpinski8596ded2018-11-14 14:43:48 +000019import static android.app.ActivityManager.PROCESS_STATE_TOP;
Bryce Lee93e7f792017-10-25 15:54:55 -070020import static android.app.ActivityManager.START_ABORTED;
21import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
Bryce Lee32e09ef2018-03-19 15:29:49 -070022import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
Bryce Lee93e7f792017-10-25 15:54:55 -070023import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
Bryce Lee32e09ef2018-03-19 15:29:49 -070024import static android.app.ActivityManager.START_INTENT_NOT_RESOLVED;
Bryce Lee93e7f792017-10-25 15:54:55 -070025import static android.app.ActivityManager.START_NOT_VOICE_COMPATIBLE;
Bryce Lee32e09ef2018-03-19 15:29:49 -070026import static android.app.ActivityManager.START_PERMISSION_DENIED;
Bryce Lee2b8e0372018-04-05 17:01:37 -070027import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
Bryce Lee93e7f792017-10-25 15:54:55 -070028import static android.app.ActivityManager.START_SUCCESS;
29import static android.app.ActivityManager.START_SWITCHES_CANCELED;
Bryce Lee32e09ef2018-03-19 15:29:49 -070030import static android.app.ActivityManager.START_TASK_TO_FRONT;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070031import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
32import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
33import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Bryce Lee32e09ef2018-03-19 15:29:49 -070034import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
35import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Louis Chang38430df2020-01-02 17:14:59 +080036import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
Riddle Hsub70b36d2018-09-11 21:20:02 +080037import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
Brett Chabota26eda92018-07-23 13:08:30 -070038import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
Louis Chang38430df2020-01-02 17:14:59 +080039import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
Riddle Hsub70b36d2018-09-11 21:20:02 +080040import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
Brett Chabota26eda92018-07-23 13:08:30 -070041
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090042import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
43import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
44import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
45import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
46import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
47import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
48import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
Louis Chang54fbb052019-10-16 17:10:17 +080049import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090050import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
51import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Wale Ogunwale59507092018-10-29 09:00:30 -070052import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
Louis Chang677921f2019-12-06 16:44:24 +080053import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
54import static com.android.server.wm.WindowContainer.POSITION_TOP;
Brett Chabota26eda92018-07-23 13:08:30 -070055
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090056import static com.google.common.truth.Truth.assertThat;
57
Brett Chabota26eda92018-07-23 13:08:30 -070058import static org.junit.Assert.assertEquals;
Wale Ogunwale85fb19a2019-12-05 10:41:05 +090059import static org.junit.Assert.assertFalse;
Riddle Hsub70b36d2018-09-11 21:20:02 +080060import static org.mockito.ArgumentMatchers.any;
61import static org.mockito.ArgumentMatchers.anyBoolean;
62import static org.mockito.ArgumentMatchers.anyInt;
63import static org.mockito.ArgumentMatchers.anyObject;
Wale Ogunwaleda8b8272018-11-29 19:37:37 -080064import static org.mockito.ArgumentMatchers.anyString;
Riddle Hsub70b36d2018-09-11 21:20:02 +080065import static org.mockito.ArgumentMatchers.eq;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070066
Bryce Lee93e7f792017-10-25 15:54:55 -070067import android.app.ActivityOptions;
68import android.app.IApplicationThread;
Riddle Hsub70b36d2018-09-11 21:20:02 +080069import android.content.ComponentName;
Bryce Lee93e7f792017-10-25 15:54:55 -070070import android.content.Intent;
71import android.content.pm.ActivityInfo;
Bryce Leead5b8322018-03-08 14:28:52 -080072import android.content.pm.ActivityInfo.WindowLayout;
Bryce Lee93e7f792017-10-25 15:54:55 -070073import android.content.pm.ApplicationInfo;
74import android.content.pm.IPackageManager;
Philip P. Moltmann6c644e62018-07-18 15:41:24 -070075import android.content.pm.PackageManagerInternal;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070076import android.graphics.Rect;
Bryce Lee93e7f792017-10-25 15:54:55 -070077import android.os.IBinder;
Michal Karpinski8596ded2018-11-14 14:43:48 +000078import android.os.Process;
Bryce Lee93e7f792017-10-25 15:54:55 -070079import android.os.RemoteException;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070080import android.platform.test.annotations.Presubmit;
Bryce Lee93e7f792017-10-25 15:54:55 -070081import android.service.voice.IVoiceInteractionSession;
Bryce Leead5b8322018-03-08 14:28:52 -080082import android.view.Gravity;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070083
Brett Chabota26eda92018-07-23 13:08:30 -070084import androidx.test.filters.SmallTest;
Brett Chabota26eda92018-07-23 13:08:30 -070085
Wale Ogunwale59507092018-10-29 09:00:30 -070086import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
Garfield Tane3d37b52019-07-23 12:43:05 -070087import com.android.server.wm.utils.MockTracker;
Bryce Lee93e7f792017-10-25 15:54:55 -070088
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090089import org.junit.Before;
Brett Chabota26eda92018-07-23 13:08:30 -070090import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +080091import org.junit.runner.RunWith;
Bryce Lee2b8e0372018-04-05 17:01:37 -070092
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070093/**
Bryce Leed3624e12017-11-30 08:51:45 -080094 * Tests for the {@link ActivityStarter} class.
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070095 *
96 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090097 * atest WmTests:ActivityStarterTests
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070098 */
99@SmallTest
100@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +0800101@RunWith(WindowTestRunner.class)
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700102public class ActivityStarterTests extends ActivityTestsBase {
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700103 private ActivityStarter mStarter;
Bryce Leed3624e12017-11-30 08:51:45 -0800104 private ActivityStartController mController;
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100105 private ActivityMetricsLogger mActivityMetricsLogger;
Louis Chang54fbb052019-10-16 17:10:17 +0800106 private PackageManagerInternal mMockPackageManager;
Bryce Lee93e7f792017-10-25 15:54:55 -0700107
108 private static final int PRECONDITION_NO_CALLER_APP = 1;
109 private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
110 private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2;
111 private static final int PRECONDITION_SOURCE_PRESENT = 1 << 3;
112 private static final int PRECONDITION_REQUEST_CODE = 1 << 4;
113 private static final int PRECONDITION_SOURCE_VOICE_SESSION = 1 << 5;
114 private static final int PRECONDITION_NO_VOICE_SESSION_SUPPORT = 1 << 6;
115 private static final int PRECONDITION_DIFFERENT_UID = 1 << 7;
116 private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8;
117 private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9;
118 private static final int PRECONDITION_DISALLOW_APP_SWITCHING = 1 << 10;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700119
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100120 private static final int FAKE_CALLING_UID = 666;
121 private static final int FAKE_REAL_CALLING_UID = 667;
122 private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
Michal Karpinski8596ded2018-11-14 14:43:48 +0000123 private static final int UNIMPORTANT_UID = 12345;
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000124 private static final int UNIMPORTANT_UID2 = 12346;
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100125
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900126 @Before
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700127 public void setUp() throws Exception {
Bryce Leed3624e12017-11-30 08:51:45 -0800128 mController = mock(ActivityStartController.class);
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100129 mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
130 clearInvocations(mActivityMetricsLogger);
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700131 mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
Bryce Leed3624e12017-11-30 08:51:45 -0800132 mock(ActivityStartInterceptor.class));
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700133 }
134
135 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900136 public void testUpdateLaunchBounds() {
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700137 // When in a non-resizeable stack, the task bounds should be updated.
Louis Changcdec0802019-11-11 11:45:07 +0800138 final Task task = new TaskBuilder(mService.mStackSupervisor)
Louis Chang149d5c82019-12-30 09:47:39 +0800139 .setStack(mService.mRootWindowContainer.getDefaultDisplay().createStack(
Bryce Lee18d51592017-10-25 10:22:19 -0700140 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
141 .build();
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700142 final Rect bounds = new Rect(10, 10, 100, 100);
143
144 mStarter.updateBounds(task, bounds);
Evan Roskydfe3da72018-10-26 17:21:06 -0700145 assertEquals(bounds, task.getRequestedOverrideBounds());
146 assertEquals(new Rect(), task.getStack().getRequestedOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700147
148 // When in a resizeable stack, the stack bounds should be updated as well.
Louis Changcdec0802019-11-11 11:45:07 +0800149 final Task task2 = new TaskBuilder(mService.mStackSupervisor)
Louis Chang149d5c82019-12-30 09:47:39 +0800150 .setStack(mService.mRootWindowContainer.getDefaultDisplay().createStack(
Bryce Lee18d51592017-10-25 10:22:19 -0700151 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
152 .build();
Yunfan Chen279f5582018-12-12 15:24:50 -0800153 assertThat((Object) task2.getStack()).isInstanceOf(ActivityStack.class);
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700154 mStarter.updateBounds(task2, bounds);
155
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800156 verify(mService, times(1)).animateResizePinnedStack(eq(task2.getRootTaskId()),
Evan Roskydbe2ce52019-07-18 11:13:17 -0700157 eq(bounds), anyInt());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700158
159 // In the case of no animation, the stack and task bounds should be set immediately.
160 if (!ANIMATE) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700161 assertEquals(bounds, task2.getStack().getRequestedOverrideBounds());
162 assertEquals(bounds, task2.getRequestedOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700163 } else {
Evan Roskydfe3da72018-10-26 17:21:06 -0700164 assertEquals(new Rect(), task2.getRequestedOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700165 }
166 }
Bryce Lee93e7f792017-10-25 15:54:55 -0700167
168 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900169 public void testStartActivityPreconditions() {
Bryce Lee93e7f792017-10-25 15:54:55 -0700170 verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED);
171 verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT,
172 START_INTENT_NOT_RESOLVED);
173 verifyStartActivityPreconditions(PRECONDITION_NO_ACTIVITY_INFO, START_CLASS_NOT_FOUND);
174 verifyStartActivityPreconditions(PRECONDITION_SOURCE_PRESENT | PRECONDITION_REQUEST_CODE,
175 Intent.FLAG_ACTIVITY_FORWARD_RESULT, START_FORWARD_AND_REQUEST_CONFLICT);
176 verifyStartActivityPreconditions(
177 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
178 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID,
179 START_NOT_VOICE_COMPATIBLE);
180 verifyStartActivityPreconditions(
181 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
182 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID
183 | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION,
184 START_NOT_VOICE_COMPATIBLE);
185 verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED);
186 verifyStartActivityPreconditions(PRECONDITION_DISALLOW_APP_SWITCHING,
187 START_SWITCHES_CANCELED);
188 }
189
190 private static boolean containsConditions(int preconditions, int mask) {
191 return (preconditions & mask) == mask;
192 }
193
194 private void verifyStartActivityPreconditions(int preconditions, int expectedResult) {
195 verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
196 }
197
Garfield Tane3d37b52019-07-23 12:43:05 -0700198 private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
199 int expectedResult) {
200 // We track mocks created here because this is used in a single test
201 // (testStartActivityPreconditions) as a specific case, and mocks created inside it won't be
202 // used for other cases. To avoid extensive memory usage, we clean up all used mocks after
203 // each case. This is necessary because usually we only clean up mocks after a test
204 // finishes, but this test creates too many mocks that the intermediate memory usage can be
205 // ~0.8 GiB and thus very susceptible to OutOfMemoryException.
206 try (MockTracker tracker = new MockTracker()) {
207 verifyStartActivityPreconditionsUntracked(preconditions, launchFlags, expectedResult);
208 }
209 }
210
Bryce Lee93e7f792017-10-25 15:54:55 -0700211 /**
212 * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
213 * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
214 * and the launch flags specified in the intent. The method constructs a call to
Bryce Lee4c9a5972017-12-01 22:14:24 -0800215 * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
216 * the expected. It is important to note that the method also checks side effects of the start,
217 * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
Bryce Lee93e7f792017-10-25 15:54:55 -0700218 * @param preconditions A bitmask representing the preconditions for the launch
219 * @param launchFlags The launch flags to be provided by the launch {@link Intent}.
220 * @param expectedResult The expected result from the launch.
221 */
Garfield Tane3d37b52019-07-23 12:43:05 -0700222 private void verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags,
Bryce Lee93e7f792017-10-25 15:54:55 -0700223 int expectedResult) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700224 final ActivityTaskManagerService service = mService;
Bryce Lee93e7f792017-10-25 15:54:55 -0700225 final IPackageManager packageManager = mock(IPackageManager.class);
Bryce Leed3624e12017-11-30 08:51:45 -0800226 final ActivityStartController controller = mock(ActivityStartController.class);
Bryce Lee93e7f792017-10-25 15:54:55 -0700227
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700228 final ActivityStarter starter = new ActivityStarter(controller, service,
Bryce Leed3624e12017-11-30 08:51:45 -0800229 service.mStackSupervisor, mock(ActivityStartInterceptor.class));
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700230 prepareStarter(launchFlags);
Bryce Lee93e7f792017-10-25 15:54:55 -0700231 final IApplicationThread caller = mock(IApplicationThread.class);
Darryl L Johnson15192d32020-01-15 15:31:42 -0800232 final WindowProcessListener listener = mock(WindowProcessListener.class);
Bryce Lee93e7f792017-10-25 15:54:55 -0700233
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700234 final WindowProcessController wpc =
235 containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
236 ? null : new WindowProcessController(
Darryl L Johnson15192d32020-01-15 15:31:42 -0800237 service, mock(ApplicationInfo.class), null, 0, -1, null, listener);
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700238 doReturn(wpc).when(service).getProcessController(anyObject());
Bryce Lee93e7f792017-10-25 15:54:55 -0700239
240 final Intent intent = new Intent();
241 intent.setFlags(launchFlags);
242
243 final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO)
244 ? null : new ActivityInfo();
245
Bryce Lee93e7f792017-10-25 15:54:55 -0700246 IVoiceInteractionSession voiceSession =
247 containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
248 ? mock(IVoiceInteractionSession.class) : null;
249
250 // Create source token
251 final ActivityBuilder builder = new ActivityBuilder(service).setTask(
252 new TaskBuilder(service.mStackSupervisor).setVoiceSession(voiceSession).build());
253
Bryce Leefbd263b42018-03-07 10:33:55 -0800254 if (aInfo != null) {
255 aInfo.applicationInfo = new ApplicationInfo();
Bryce Leead5b8322018-03-08 14:28:52 -0800256 aInfo.applicationInfo.packageName =
257 ActivityBuilder.getDefaultComponent().getPackageName();
Bryce Leefbd263b42018-03-07 10:33:55 -0800258 }
259
Bryce Lee93e7f792017-10-25 15:54:55 -0700260 // Offset uid by one from {@link ActivityInfo} to simulate different uids.
261 if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) {
262 builder.setUid(aInfo.applicationInfo.uid + 1);
263 }
264
265 final ActivityRecord source = builder.build();
266
267 if (!containsConditions(preconditions, PRECONDITION_NO_INTENT_COMPONENT)) {
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800268 intent.setComponent(source.mActivityComponent);
Bryce Lee93e7f792017-10-25 15:54:55 -0700269 }
270
271 if (containsConditions(preconditions, PRECONDITION_DISALLOW_APP_SWITCHING)) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700272 doReturn(false).when(service).checkAppSwitchAllowedLocked(
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700273 anyInt(), anyInt(), anyInt(), anyInt(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700274 }
275
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900276 if (containsConditions(preconditions, PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
Bryce Lee93e7f792017-10-25 15:54:55 -0700277 doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission(
Philip P. Moltmannee295092020-02-10 08:46:26 -0800278 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700279 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700280 }
281
282 try {
283 if (containsConditions(preconditions,
284 PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION)) {
285 doAnswer((inv) -> {
286 throw new RemoteException();
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800287 }).when(packageManager).activitySupportsIntent(
288 eq(source.mActivityComponent), eq(intent), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700289 } else {
290 doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT))
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800291 .when(packageManager).activitySupportsIntent(eq(source.mActivityComponent),
Bryce Lee93e7f792017-10-25 15:54:55 -0700292 eq(intent), any());
293 }
294 } catch (RemoteException e) {
295 }
296
297 final IBinder resultTo = containsConditions(preconditions, PRECONDITION_SOURCE_PRESENT)
298 || containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
299 ? source.appToken : null;
300
301 final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE)
302 ? 1 : 0;
303
Bryce Lee4c9a5972017-12-01 22:14:24 -0800304 final int result = starter.setCaller(caller)
305 .setIntent(intent)
306 .setActivityInfo(aInfo)
307 .setResultTo(resultTo)
308 .setRequestCode(requestCode)
309 .setReason("testLaunchActivityPermissionDenied")
310 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700311
312 // In some cases the expected result internally is different than the published result. We
313 // must use ActivityStarter#getExternalResult to translate.
314 assertEquals(ActivityStarter.getExternalResult(expectedResult), result);
315
316 // Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
317 if (expectedResult != START_SUCCESS) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700318 final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
Bryce Lee4c9a5972017-12-01 22:14:24 -0800319 mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
Bryce Lee93e7f792017-10-25 15:54:55 -0700320 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Bryce Lee4c9a5972017-12-01 22:14:24 -0800321
322 final int optionResult = optionStarter.setCaller(caller)
323 .setIntent(intent)
324 .setActivityInfo(aInfo)
325 .setResultTo(resultTo)
326 .setRequestCode(requestCode)
327 .setReason("testLaunchActivityPermissionDenied")
Jorim Jaggi4d8d32c2018-01-19 15:57:41 +0100328 .setActivityOptions(new SafeActivityOptions(options))
Bryce Lee4c9a5972017-12-01 22:14:24 -0800329 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700330 verify(options, times(1)).abort();
331 }
332 }
Bryce Leeb802ea12017-11-15 21:25:03 -0800333
Riddle Hsub70b36d2018-09-11 21:20:02 +0800334 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) {
335 return prepareStarter(launchFlags, true /* mockGetLaunchStack */);
336 }
337
338 /**
339 * Creates a {@link ActivityStarter} with default parameters and necessary mocks.
340 *
341 * @param launchFlags The intent flags to launch activity.
Louis Chang149d5c82019-12-30 09:47:39 +0800342 * @param mockGetLaunchStack Whether to mock {@link RootWindowContainer#getLaunchStack} for
Riddle Hsub70b36d2018-09-11 21:20:02 +0800343 * always launching to the testing stack. Set to false when allowing
344 * the activity can be launched to any stack that is decided by real
345 * implementation.
346 * @return A {@link ActivityStarter} with default setup.
347 */
348 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
349 boolean mockGetLaunchStack) {
Bryce Leead5b8322018-03-08 14:28:52 -0800350 // always allow test to start activity.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800351 doReturn(true).when(mSupervisor).checkStartAnyActivityPermission(
Philip P. Moltmannee295092020-02-10 08:46:26 -0800352 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700353 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800354
Riddle Hsub70b36d2018-09-11 21:20:02 +0800355 if (mockGetLaunchStack) {
Riddle Hsuff9e8282019-04-24 23:55:11 +0800356 // Instrument the stack and task used.
Louis Chang149d5c82019-12-30 09:47:39 +0800357 final ActivityStack stack = mRootWindowContainer.getDefaultDisplay().createStack(
Riddle Hsuff9e8282019-04-24 23:55:11 +0800358 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
359
Riddle Hsub70b36d2018-09-11 21:20:02 +0800360 // Direct starter to use spy stack.
Louis Chang149d5c82019-12-30 09:47:39 +0800361 doReturn(stack).when(mRootWindowContainer)
Riddle Hsub70b36d2018-09-11 21:20:02 +0800362 .getLaunchStack(any(), any(), any(), anyBoolean());
Louis Chang149d5c82019-12-30 09:47:39 +0800363 doReturn(stack).when(mRootWindowContainer)
lumarkf65e02d2019-09-14 19:25:21 +0800364 .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
Riddle Hsub70b36d2018-09-11 21:20:02 +0800365 }
Bryce Leead5b8322018-03-08 14:28:52 -0800366
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700367 // Set up mock package manager internal and make sure no unmocked methods are called
Louis Chang54fbb052019-10-16 17:10:17 +0800368 mMockPackageManager = mock(PackageManagerInternal.class,
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700369 invocation -> {
370 throw new RuntimeException("Not stubbed");
371 });
Louis Chang54fbb052019-10-16 17:10:17 +0800372 doReturn(mMockPackageManager).when(mService).getPackageManagerInternalLocked();
373 doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
374 doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyInt(), anyInt(),
375 anyBoolean(), anyInt());
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700376
377 // Never review permissions
Louis Chang54fbb052019-10-16 17:10:17 +0800378 doReturn(false).when(mMockPackageManager).isPermissionsReviewRequired(any(), anyInt());
379 doNothing().when(mMockPackageManager).grantImplicitAccess(
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700380 anyInt(), any(), anyInt(), anyInt());
Louis Chang54fbb052019-10-16 17:10:17 +0800381 doNothing().when(mMockPackageManager).notifyPackageUse(anyString(), anyInt());
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700382
Bryce Lee32e09ef2018-03-19 15:29:49 -0700383 final Intent intent = new Intent();
384 intent.addFlags(launchFlags);
385 intent.setComponent(ActivityBuilder.getDefaultComponent());
386
387 final ActivityInfo info = new ActivityInfo();
388
389 info.applicationInfo = new ApplicationInfo();
390 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
391
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700392 return new ActivityStarter(mController, mService,
Bryce Lee32e09ef2018-03-19 15:29:49 -0700393 mService.mStackSupervisor, mock(ActivityStartInterceptor.class))
394 .setIntent(intent)
395 .setActivityInfo(info);
Bryce Leead5b8322018-03-08 14:28:52 -0800396 }
397
398 /**
399 * Ensures that values specified at launch time are passed to {@link LaunchParamsModifier}
400 * when we are laying out a new task.
401 */
402 @Test
403 public void testCreateTaskLayout() {
404 // modifier for validating passed values.
405 final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
406 mService.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
407
408 // add custom values to activity info to make unique.
409 final ActivityInfo info = new ActivityInfo();
410 final Rect launchBounds = new Rect(0, 0, 20, 30);
Bryce Leead5b8322018-03-08 14:28:52 -0800411
412 final WindowLayout windowLayout =
413 new WindowLayout(10, .5f, 20, 1.0f, Gravity.NO_GRAVITY, 1, 1);
414
415 info.windowLayout = windowLayout;
416 info.applicationInfo = new ApplicationInfo();
417 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
418
419 // create starter.
Bryce Lee32e09ef2018-03-19 15:29:49 -0700420 final ActivityStarter optionStarter = prepareStarter(0 /* launchFlags */);
Bryce Leead5b8322018-03-08 14:28:52 -0800421
422 final ActivityOptions options = ActivityOptions.makeBasic();
423 options.setLaunchBounds(launchBounds);
424
425 // run starter.
426 optionStarter
Bryce Leead5b8322018-03-08 14:28:52 -0800427 .setReason("testCreateTaskLayout")
428 .setActivityInfo(info)
429 .setActivityOptions(new SafeActivityOptions(options))
430 .execute();
431
Louis Chang6fb1e842018-12-03 16:07:50 +0800432 // verify that values are passed to the modifier. Values are passed thrice -- two for
Garfield Tan706dbcb2018-10-15 11:33:02 -0700433 // setting initial state, another when task is created.
Louis Chang6fb1e842018-12-03 16:07:50 +0800434 verify(modifier, times(3)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
435 anyInt(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800436 }
Bryce Lee32e09ef2018-03-19 15:29:49 -0700437
438 /**
Louis Chang38430df2020-01-02 17:14:59 +0800439 * This test ensures that if the intent is being delivered to a split-screen unfocused task
440 * while it already on top, reports it as delivering to top.
Bryce Lee32e09ef2018-03-19 15:29:49 -0700441 */
442 @Test
443 public void testSplitScreenDeliverToTop() {
Louis Chang38430df2020-01-02 17:14:59 +0800444 final ActivityStarter starter = prepareStarter(
445 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
446 final ActivityRecord splitPrimaryFocusActivity =
447 new ActivityBuilder(mService).setCreateTask(true).build();
448 final ActivityRecord splitSecondReusableActivity =
449 new ActivityBuilder(mService).setCreateTask(true).build();
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800450 splitPrimaryFocusActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800451 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800452 splitSecondReusableActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800453 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700454
455 // Set focus back to primary.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800456 splitPrimaryFocusActivity.getRootTask().moveToFront("testSplitScreenDeliverToTop");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700457
Louis Chang38430df2020-01-02 17:14:59 +0800458 // Start activity and delivered new intent.
459 starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
460 doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), anyInt());
Bryce Lee32e09ef2018-03-19 15:29:49 -0700461 final int result = starter.setReason("testSplitScreenDeliverToTop").execute();
462
463 // Ensure result is delivering intent to top.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900464 assertEquals(START_DELIVERED_TO_TOP, result);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700465 }
466
467 /**
468 * This test ensures that if the intent is being delivered to a split-screen unfocused task
469 * reports it is brought to front instead of delivering to top.
470 */
471 @Test
472 public void testSplitScreenTaskToFront() {
Louis Chang38430df2020-01-02 17:14:59 +0800473 final ActivityStarter starter = prepareStarter(
474 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
475 final ActivityRecord splitSecondReusableActivity =
476 new ActivityBuilder(mService).setCreateTask(true).build();
477 final ActivityRecord splitSecondTopActivity =
478 new ActivityBuilder(mService).setCreateTask(true).build();
479 final ActivityRecord splitPrimaryFocusActivity =
480 new ActivityBuilder(mService).setCreateTask(true).build();
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800481 splitPrimaryFocusActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800482 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800483 splitSecondReusableActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800484 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800485 splitSecondTopActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800486 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700487
Louis Chang38430df2020-01-02 17:14:59 +0800488 // Make it on top of split-screen-secondary.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800489 splitSecondTopActivity.getRootTask().moveToFront("testSplitScreenTaskToFront");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700490
Louis Chang38430df2020-01-02 17:14:59 +0800491 // Let primary stack has focus.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800492 splitPrimaryFocusActivity.getRootTask().moveToFront("testSplitScreenTaskToFront");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700493
Louis Chang38430df2020-01-02 17:14:59 +0800494 // Start activity and delivered new intent.
495 starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
496 doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), anyInt());
Bryce Lee32e09ef2018-03-19 15:29:49 -0700497 final int result = starter.setReason("testSplitScreenMoveToFront").execute();
498
499 // Ensure result is moving task to front.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900500 assertEquals(START_TASK_TO_FRONT, result);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700501 }
Bryce Lee2b8e0372018-04-05 17:01:37 -0700502
503 /**
504 * Tests activity is cleaned up properly in a task mode violation.
505 */
506 @Test
507 public void testTaskModeViolation() {
Louis Chang149d5c82019-12-30 09:47:39 +0800508 final DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700509 display.removeAllTasks();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700510 assertNoTasks(display);
511
512 final ActivityStarter starter = prepareStarter(0);
513
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700514 final LockTaskController lockTaskController = mService.getLockTaskController();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700515 doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
516
517 final int result = starter.setReason("testTaskModeViolation").execute();
518
519 assertEquals(START_RETURN_LOCK_TASK_MODE_VIOLATION, result);
520 assertNoTasks(display);
521 }
522
Louis Chang677921f2019-12-06 16:44:24 +0800523 private void assertNoTasks(DisplayContent display) {
Louis Chang2453d062019-11-19 22:30:48 +0800524 for (int i = display.getStackCount() - 1; i >= 0; --i) {
525 final ActivityStack stack = display.getStackAt(i);
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900526 assertFalse(stack.hasChild());
Bryce Lee2b8e0372018-04-05 17:01:37 -0700527 }
528 }
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100529
530 /**
531 * This test ensures that activity starts are not being logged when the logging is disabled.
532 */
533 @Test
534 public void testActivityStartsLogging_noLoggingWhenDisabled() {
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700535 doReturn(false).when(mService).isActivityStartsLoggingEnabled();
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100536 doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
537
538 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK);
539 starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute();
540
541 // verify logging wasn't done
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000542 verify(mActivityMetricsLogger, never()).logAbortedBgActivityStart(any(), any(), anyInt(),
543 any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100544 }
545
546 /**
547 * This test ensures that activity starts are being logged when the logging is enabled.
548 */
549 @Test
550 public void testActivityStartsLogging_logsWhenEnabled() {
551 // note: conveniently this package doesn't have any activity visible
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700552 doReturn(true).when(mService).isActivityStartsLoggingEnabled();
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100553 doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
554
555 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
556 .setCallingUid(FAKE_CALLING_UID)
557 .setRealCallingUid(FAKE_REAL_CALLING_UID)
558 .setCallingPackage(FAKE_CALLING_PACKAGE)
559 .setOriginatingPendingIntent(null);
560
561 starter.setReason("testActivityStartsLogging_logsWhenEnabled").execute();
562
563 // verify the above activity start was logged
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000564 verify(mActivityMetricsLogger, times(1)).logAbortedBgActivityStart(any(), any(),
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100565 eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(),
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000566 eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), eq(false));
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100567 }
Riddle Hsub70b36d2018-09-11 21:20:02 +0800568
569 /**
Michal Karpinski8596ded2018-11-14 14:43:48 +0000570 * This test ensures that unsupported usecases aren't aborted when background starts are
571 * allowed.
572 */
573 @Test
574 public void testBackgroundActivityStartsAllowed_noStartsAborted() {
575 doReturn(true).when(mService).isBackgroundActivityStartsEnabled();
576
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000577 runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
578 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
579 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100580 false, false, false, false, false);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000581 }
582
583 /**
584 * This test ensures that unsupported usecases are aborted when background starts are
585 * disallowed.
586 */
587 @Test
588 public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
589 doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
590
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000591 runAndVerifyBackgroundActivityStartsSubtest(
592 "disallowed_unsupportedUsecase_aborted", true,
593 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
594 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100595 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100596 runAndVerifyBackgroundActivityStartsSubtest(
597 "disallowed_callingUidProcessStateTop_aborted", true,
598 UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
599 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100600 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100601 runAndVerifyBackgroundActivityStartsSubtest(
602 "disallowed_realCallingUidProcessStateTop_aborted", true,
603 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
604 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
Alan Stokes9e245762019-05-21 14:54:28 +0100605 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100606 runAndVerifyBackgroundActivityStartsSubtest(
607 "disallowed_hasForegroundActivities_aborted", true,
608 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
609 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100610 true, false, false, false, false);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000611 }
612
613 /**
614 * This test ensures that supported usecases aren't aborted when background starts are
615 * disallowed.
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100616 * The scenarios each have only one condition that makes them supported.
Michal Karpinski8596ded2018-11-14 14:43:48 +0000617 */
618 @Test
619 public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
620 doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
621
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000622 runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
623 Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
624 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100625 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000626 runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
627 Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
628 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100629 false, false, false, false, false);
Michal Karpinskib416f472019-01-24 14:34:28 +0000630 runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false,
631 Process.NFC_UID, false, PROCESS_STATE_TOP + 1,
632 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100633 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000634 runAndVerifyBackgroundActivityStartsSubtest(
635 "disallowed_callingUidHasVisibleWindow_notAborted", false,
636 UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
637 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100638 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000639 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000640 "disallowed_realCallingUidHasVisibleWindow_notAborted", false,
641 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
642 UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100643 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000644 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000645 "disallowed_callerIsRecents_notAborted", false,
646 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
647 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100648 false, true, false, false, false);
Michal Karpinskiac116df2018-12-10 17:51:42 +0000649 runAndVerifyBackgroundActivityStartsSubtest(
650 "disallowed_callerIsWhitelisted_notAborted", false,
651 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
652 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100653 false, false, true, false, false);
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000654 runAndVerifyBackgroundActivityStartsSubtest(
655 "disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted",
656 false,
657 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
658 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100659 false, false, false, true, false);
Michal Karpinski302dcec2019-02-01 11:48:25 +0000660 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski4026cae2019-02-12 11:51:47 +0000661 "disallowed_callingPackageNameIsDeviceOwner_notAborted", false,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000662 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
663 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100664 false, false, false, false, true);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000665 }
666
667 private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000668 int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
669 int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
Michal Karpinskiac116df2018-12-10 17:51:42 +0000670 boolean hasForegroundActivities, boolean callerIsRecents,
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000671 boolean callerIsTempWhitelisted,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000672 boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
Alan Stokes9e245762019-05-21 14:54:28 +0100673 boolean isCallingUidDeviceOwner) {
Michal Karpinski8596ded2018-11-14 14:43:48 +0000674 // window visibility
Michal Karpinskia606a292019-01-12 17:29:52 +0000675 doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
676 .isAnyNonToastWindowVisibleForUid(callingUid);
677 doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
678 .isAnyNonToastWindowVisibleForUid(realCallingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000679 // process importance
Riddle Hsua0536432019-02-16 00:38:59 +0800680 doReturn(callingUidProcState).when(mService).getUidState(callingUid);
681 doReturn(realCallingUidProcState).when(mService).getUidState(realCallingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000682 // foreground activities
683 final IApplicationThread caller = mock(IApplicationThread.class);
Darryl L Johnson15192d32020-01-15 15:31:42 -0800684 final WindowProcessListener listener = mock(WindowProcessListener.class);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000685 final ApplicationInfo ai = new ApplicationInfo();
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000686 ai.uid = callingUid;
Michal Karpinski8596ded2018-11-14 14:43:48 +0000687 final WindowProcessController callerApp =
Darryl L Johnson15192d32020-01-15 15:31:42 -0800688 new WindowProcessController(mService, ai, null, callingUid, -1, null, listener);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000689 callerApp.setHasForegroundActivities(hasForegroundActivities);
690 doReturn(callerApp).when(mService).getProcessController(caller);
Michal Karpinski82bb5902018-11-28 15:52:52 +0000691 // caller is recents
692 RecentTasks recentTasks = mock(RecentTasks.class);
693 mService.mStackSupervisor.setRecentTasks(recentTasks);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000694 doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
Michal Karpinskiac116df2018-12-10 17:51:42 +0000695 // caller is temp whitelisted
696 callerApp.setAllowBackgroundActivityStarts(callerIsTempWhitelisted);
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000697 // caller is instrumenting with background activity starts privileges
Michal Karpinski4bc56492019-01-31 12:07:33 +0000698 callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000699 callerIsInstrumentingWithBackgroundActivityStartPrivileges);
Ricky Wai96f5c352019-04-10 18:40:17 +0100700 // callingUid is the device owner
701 doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000702
703 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700704 ActivityRecord[] outActivity = new ActivityRecord[1];
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000705 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
Michal Karpinski666631b2019-02-26 16:59:11 +0000706 .setCallingPackage("com.whatever.dude")
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000707 .setCaller(caller)
708 .setCallingUid(callingUid)
709 .setRealCallingUid(realCallingUid)
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700710 .setActivityOptions(new SafeActivityOptions(options))
711 .setOutActivity(outActivity);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000712
713 final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();
714
715 assertEquals(ActivityStarter.getExternalResult(
716 shouldHaveAborted ? START_ABORTED : START_SUCCESS), result);
717 verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700718
719 final ActivityRecord startedActivity = outActivity[0];
Louis Changcdec0802019-11-11 11:45:07 +0800720 if (startedActivity != null && startedActivity.getTask() != null) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700721 // Remove the activity so it doesn't interfere with with subsequent activity launch
722 // tests from this method.
Louis Changcdec0802019-11-11 11:45:07 +0800723 startedActivity.getTask().removeChild(startedActivity);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700724 }
Michal Karpinski8596ded2018-11-14 14:43:48 +0000725 }
726
727 /**
Riddle Hsu273e9992019-04-29 22:40:59 +0800728 * This test ensures that {@link ActivityStarter#setTargetStackAndMoveToFrontIfNeeded} will
729 * move the existing task to front if the current focused stack doesn't have running task.
730 */
731 @Test
732 public void testBringTaskToFrontWhenFocusedStackIsFinising() {
733 // Put 2 tasks in the same stack (simulate the behavior of home stack).
734 final ActivityRecord activity = new ActivityBuilder(mService)
735 .setCreateTask(true).build();
736 new ActivityBuilder(mService)
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800737 .setStack(activity.getRootTask())
Riddle Hsu273e9992019-04-29 22:40:59 +0800738 .setCreateTask(true).build();
739
740 // Create a top finishing activity.
741 final ActivityRecord finishingTopActivity = new ActivityBuilder(mService)
742 .setCreateTask(true).build();
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800743 finishingTopActivity.getRootTask().moveToFront("finishingTopActivity");
Riddle Hsu273e9992019-04-29 22:40:59 +0800744
Louis Chang149d5c82019-12-30 09:47:39 +0800745 assertEquals(finishingTopActivity, mRootWindowContainer.topRunningActivity());
Riddle Hsu273e9992019-04-29 22:40:59 +0800746 finishingTopActivity.finishing = true;
747
748 // Launch the bottom task of the target stack.
749 prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetLaunchStack */)
750 .setReason("testBringTaskToFrontWhenTopStackIsFinising")
751 .setIntent(activity.intent)
752 .execute();
753 // The hierarchies of the activity should move to front.
Louis Chang149d5c82019-12-30 09:47:39 +0800754 assertEquals(activity, mRootWindowContainer.topRunningActivity());
Riddle Hsu273e9992019-04-29 22:40:59 +0800755 }
756
757 /**
Riddle Hsub70b36d2018-09-11 21:20:02 +0800758 * This test ensures that when starting an existing single task activity on secondary display
759 * which is not the top focused display, it should deliver new intent to the activity and not
760 * create a new stack.
761 */
762 @Test
763 public void testDeliverIntentToTopActivityOfNonTopDisplay() {
764 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
765 false /* mockGetLaunchStack */);
766
767 // Create a secondary display at bottom.
Louis Chang677921f2019-12-06 16:44:24 +0800768 final TestDisplayContent secondaryDisplay =
769 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700770 .setPosition(POSITION_BOTTOM).build();
Riddle Hsub70b36d2018-09-11 21:20:02 +0800771 final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
772 ACTIVITY_TYPE_STANDARD, true /* onTop */);
773
774 // Create an activity record on the top of secondary display.
Riddle Hsufd4a0502018-10-16 01:05:16 +0800775 final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
Riddle Hsub70b36d2018-09-11 21:20:02 +0800776
777 // Put an activity on default display as the top focused activity.
778 new ActivityBuilder(mService).setCreateTask(true).build();
779
780 // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
781 // on secondary display.
782 final ActivityOptions options = ActivityOptions.makeBasic()
783 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
784 final int result = starter.setReason("testDeliverIntentToTopActivityOfNonTopDisplay")
785 .setIntent(topActivityOnSecondaryDisplay.intent)
786 .setActivityOptions(options.toBundle())
787 .execute();
788
789 // Ensure result is delivering intent to top.
790 assertEquals(START_DELIVERED_TO_TOP, result);
791
792 // Ensure secondary display only creates one stack.
793 verify(secondaryDisplay, times(1)).createStack(anyInt(), anyInt(), anyBoolean());
794 }
795
796 /**
Riddle Hsufd4a0502018-10-16 01:05:16 +0800797 * This test ensures that when starting an existing non-top single task activity on secondary
798 * display which is the top focused display, it should bring the task to front without creating
799 * unused stack.
800 */
801 @Test
802 public void testBringTaskToFrontOnSecondaryDisplay() {
803 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
804 false /* mockGetLaunchStack */);
805
806 // Create a secondary display with an activity.
Louis Chang677921f2019-12-06 16:44:24 +0800807 final TestDisplayContent secondaryDisplay =
808 new TestDisplayContent.Builder(mService, 1000, 1500).build();
Louis Chang149d5c82019-12-30 09:47:39 +0800809 mRootWindowContainer.positionChildAt(POSITION_TOP, secondaryDisplay,
Louis Chang3ff72a82019-12-17 12:12:59 +0800810 false /* includingParents */);
Riddle Hsufd4a0502018-10-16 01:05:16 +0800811 final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
812 secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
813 ACTIVITY_TYPE_STANDARD, false /* onTop */));
814
815 // Create another activity on top of the secondary display.
816 final ActivityStack topStack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
817 ACTIVITY_TYPE_STANDARD, true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800818 final Task topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
Riddle Hsufd4a0502018-10-16 01:05:16 +0800819 new ActivityBuilder(mService).setTask(topTask).build();
820
821 // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
822 final ActivityOptions options = ActivityOptions.makeBasic()
823 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
824 final int result = starter.setReason("testBringTaskToFrontOnSecondaryDisplay")
825 .setIntent(singleTaskActivity.intent)
826 .setActivityOptions(options.toBundle())
827 .execute();
828
829 // Ensure result is moving existing task to front.
830 assertEquals(START_TASK_TO_FRONT, result);
831
832 // Ensure secondary display only creates two stacks.
833 verify(secondaryDisplay, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
834 }
835
836 private ActivityRecord createSingleTaskActivityOn(ActivityStack stack) {
837 final ComponentName componentName = ComponentName.createRelative(
838 DEFAULT_COMPONENT_PACKAGE_NAME,
839 DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
Louis Changcdec0802019-11-11 11:45:07 +0800840 final Task task = new TaskBuilder(mSupervisor)
Riddle Hsufd4a0502018-10-16 01:05:16 +0800841 .setComponent(componentName)
842 .setStack(stack)
843 .build();
844 return new ActivityBuilder(mService)
845 .setComponent(componentName)
846 .setLaunchMode(LAUNCH_SINGLE_TASK)
Louis Changcdec0802019-11-11 11:45:07 +0800847 .setTask(task)
Riddle Hsufd4a0502018-10-16 01:05:16 +0800848 .build();
849 }
850
851 /**
Riddle Hsub70b36d2018-09-11 21:20:02 +0800852 * This test ensures that a reused top activity in the top focused stack is able to be
853 * reparented to another display.
854 */
855 @Test
856 public void testReparentTopFocusedActivityToSecondaryDisplay() {
857 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
858 false /* mockGetLaunchStack */);
859
860 // Create a secondary display at bottom.
Louis Chang677921f2019-12-06 16:44:24 +0800861 final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM);
Riddle Hsub70b36d2018-09-11 21:20:02 +0800862 secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
863 true /* onTop */);
864
865 // Put an activity on default display as the top focused activity.
866 final ActivityRecord topActivity = new ActivityBuilder(mService)
867 .setCreateTask(true)
868 .setLaunchMode(LAUNCH_SINGLE_TASK)
869 .build();
870
871 // Start activity with the same intent as {@code topActivity} on secondary display.
872 final ActivityOptions options = ActivityOptions.makeBasic()
873 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
874 starter.setReason("testReparentTopFocusedActivityToSecondaryDisplay")
875 .setIntent(topActivity.intent)
876 .setActivityOptions(options.toBundle())
877 .execute();
878
879 // Ensure the activity is moved to secondary display.
880 assertEquals(secondaryDisplay, topActivity.getDisplay());
881 }
Winson Chunge219ae12019-07-18 13:43:23 -0700882
883 /**
884 * This test ensures that starting an activity with the freeze-task-list activity option will
885 * actually freeze the task list
886 */
887 @Test
888 public void testFreezeTaskListActivityOption() {
889 RecentTasks recentTasks = mock(RecentTasks.class);
890 mService.mStackSupervisor.setRecentTasks(recentTasks);
891 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
892
893 final ActivityStarter starter = prepareStarter(0 /* flags */);
894 final ActivityOptions options = ActivityOptions.makeBasic();
895 options.setFreezeRecentTasksReordering();
896
897 starter.setReason("testFreezeTaskListActivityOption")
898 .setActivityOptions(new SafeActivityOptions(options))
899 .execute();
900
901 verify(recentTasks, times(1)).setFreezeTaskListReordering();
902 verify(recentTasks, times(0)).resetFreezeTaskListReorderingOnTimeout();
903 }
904
905 /**
906 * This test ensures that if we froze the task list as a part of starting an activity that fails
907 * to start, that we also reset the task list.
908 */
909 @Test
910 public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() {
911 RecentTasks recentTasks = mock(RecentTasks.class);
912 mService.mStackSupervisor.setRecentTasks(recentTasks);
913 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
914
915 final ActivityStarter starter = prepareStarter(0 /* flags */);
916 final ActivityOptions options = ActivityOptions.makeBasic();
917 options.setFreezeRecentTasksReordering();
918
919 starter.setReason("testFreezeTaskListActivityOptionFailedStart")
920 .setActivityOptions(new SafeActivityOptions(options))
921 .execute();
922
923 // Simulate a failed start
924 starter.postStartActivityProcessing(null, START_ABORTED, null);
925
926 verify(recentTasks, times(1)).setFreezeTaskListReordering();
927 verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
928 }
Louis Chang54fbb052019-10-16 17:10:17 +0800929
930 @Test
931 public void testNoActivityInfo() {
932 final ActivityStarter starter = prepareStarter(0 /* flags */);
933 spyOn(starter.mRequest);
934
935 final Intent intent = new Intent();
936 intent.setComponent(ActivityBuilder.getDefaultComponent());
937 starter.setReason("testNoActivityInfo").setIntent(intent)
938 .setActivityInfo(null).execute();
939 verify(starter.mRequest).resolveActivity(any());
940 }
941
942 @Test
943 public void testResolveEphemeralInstaller() {
944 final ActivityStarter starter = prepareStarter(0 /* flags */);
945 final Intent intent = new Intent();
946 intent.setComponent(ActivityBuilder.getDefaultComponent());
947
948 doReturn(true).when(mMockPackageManager).isInstantAppInstallerComponent(any());
949 starter.setIntent(intent).mRequest.resolveActivity(mService.mStackSupervisor);
950
951 // Make sure the client intent won't be modified.
952 assertThat(intent.getComponent()).isNotNull();
953 assertThat(starter.getIntent().getComponent()).isNull();
954 }
955
956 @Test
957 public void testNotAllowIntentWithFd() {
958 final ActivityStarter starter = prepareStarter(0 /* flags */);
959 final Intent intent = spy(new Intent());
960 intent.setComponent(ActivityBuilder.getDefaultComponent());
961 doReturn(true).when(intent).hasFileDescriptors();
962
963 boolean exceptionCaught = false;
964 try {
965 starter.setIntent(intent).execute();
966 } catch (IllegalArgumentException ex) {
967 exceptionCaught = true;
968 }
969 assertThat(exceptionCaught).isTrue();
970 }
Louis Chang07b13002019-11-27 22:08:37 +0800971
972 @Test
973 public void testRecycleTaskFromAnotherUser() {
974 final ActivityStarter starter = prepareStarter(0 /* flags */);
975 starter.mStartActivity = new ActivityBuilder(mService).build();
976 final Task task = new TaskBuilder(mService.mStackSupervisor)
Louis Chang149d5c82019-12-30 09:47:39 +0800977 .setStack(mService.mRootWindowContainer.getDefaultDisplay().createStack(
Louis Chang07b13002019-11-27 22:08:37 +0800978 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
979 .setUserId(10)
980 .build();
981
982 final int result = starter.recycleTask(task, null, null);
983 assertThat(result == START_SUCCESS).isTrue();
984 assertThat(starter.mAddingToTask).isTrue();
985 }
Louis Chang38430df2020-01-02 17:14:59 +0800986
987 @Test
988 public void testTargetStackInSplitScreen() {
989 final ActivityStarter starter =
990 prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetLaunchStack */);
991 final ActivityRecord top = new ActivityBuilder(mService).setCreateTask(true).build();
992 final ActivityOptions options = ActivityOptions.makeBasic();
993 final ActivityRecord[] outActivity = new ActivityRecord[1];
994
995 // Activity must not land on split-screen stack if currently not in split-screen mode.
996 starter.setActivityOptions(options.toBundle())
997 .setReason("testWindowingModeOptionsLaunchAdjacent")
998 .setOutActivity(outActivity).execute();
999 assertThat(outActivity[0].inSplitScreenWindowingMode()).isFalse();
1000
1001 // Move activity to split-screen-primary stack and make sure it has the focus.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -08001002 top.getRootTask().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
1003 top.getRootTask().moveToFront("testWindowingModeOptionsLaunchAdjacent");
Louis Chang38430df2020-01-02 17:14:59 +08001004
1005 // Activity must landed on split-screen-secondary when launch adjacent.
1006 starter.setActivityOptions(options.toBundle())
1007 .setReason("testWindowingModeOptionsLaunchAdjacent")
1008 .setOutActivity(outActivity).execute();
1009 assertThat(outActivity[0].inSplitScreenSecondaryWindowingMode()).isTrue();
1010 }
Winson Chungf45dd9f2019-10-11 15:07:47 -07001011
1012 @Test
1013 public void testActivityStart_expectAddedToRecentTask() {
1014 RecentTasks recentTasks = mock(RecentTasks.class);
1015 mService.mStackSupervisor.setRecentTasks(recentTasks);
1016 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
1017
1018 final ActivityStarter starter = prepareStarter(0 /* flags */);
1019
1020 starter.setReason("testAddToTaskListOnActivityStart")
1021 .execute();
1022
1023 verify(recentTasks, times(1)).add(any());
1024 }
Wale Ogunwale44f036f2017-09-29 05:09:09 -07001025}