blob: 60f1ae26f5dd35cef9ab5fe59859956ce4caeb34 [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;
Riddle Hsub70b36d2018-09-11 21:20:02 +080036import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
Brett Chabota26eda92018-07-23 13:08:30 -070037import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
Riddle Hsub70b36d2018-09-11 21:20:02 +080038import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
Brett Chabota26eda92018-07-23 13:08:30 -070039
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090040import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
41import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
42import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
43import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
44import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
45import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
46import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
47import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
48import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Wale Ogunwale59507092018-10-29 09:00:30 -070049import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
50import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
51import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
Brett Chabota26eda92018-07-23 13:08:30 -070052
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090053import static com.google.common.truth.Truth.assertThat;
54
Brett Chabota26eda92018-07-23 13:08:30 -070055import static org.junit.Assert.assertEquals;
Riddle Hsub70b36d2018-09-11 21:20:02 +080056import static org.mockito.ArgumentMatchers.any;
57import static org.mockito.ArgumentMatchers.anyBoolean;
58import static org.mockito.ArgumentMatchers.anyInt;
59import static org.mockito.ArgumentMatchers.anyObject;
60import static org.mockito.ArgumentMatchers.eq;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070061
Bryce Lee93e7f792017-10-25 15:54:55 -070062import android.app.ActivityOptions;
63import android.app.IApplicationThread;
Michal Karpinski302dcec2019-02-01 11:48:25 +000064import android.app.admin.DevicePolicyManager;
Riddle Hsub70b36d2018-09-11 21:20:02 +080065import android.content.ComponentName;
Bryce Lee93e7f792017-10-25 15:54:55 -070066import android.content.Intent;
67import android.content.pm.ActivityInfo;
Bryce Leead5b8322018-03-08 14:28:52 -080068import android.content.pm.ActivityInfo.WindowLayout;
Bryce Lee93e7f792017-10-25 15:54:55 -070069import android.content.pm.ApplicationInfo;
70import android.content.pm.IPackageManager;
Philip P. Moltmann6c644e62018-07-18 15:41:24 -070071import android.content.pm.PackageManagerInternal;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070072import android.graphics.Rect;
Bryce Lee93e7f792017-10-25 15:54:55 -070073import android.os.IBinder;
Michal Karpinski8596ded2018-11-14 14:43:48 +000074import android.os.Process;
Bryce Lee93e7f792017-10-25 15:54:55 -070075import android.os.RemoteException;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070076import android.platform.test.annotations.Presubmit;
Bryce Lee93e7f792017-10-25 15:54:55 -070077import android.service.voice.IVoiceInteractionSession;
Bryce Leead5b8322018-03-08 14:28:52 -080078import android.view.Gravity;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070079
Brett Chabota26eda92018-07-23 13:08:30 -070080import androidx.test.filters.SmallTest;
Brett Chabota26eda92018-07-23 13:08:30 -070081
Wale Ogunwale59507092018-10-29 09:00:30 -070082import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
83import com.android.server.wm.TaskRecord.TaskRecordFactory;
Bryce Lee93e7f792017-10-25 15:54:55 -070084
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090085import org.junit.Before;
Brett Chabota26eda92018-07-23 13:08:30 -070086import org.junit.Test;
Bryce Lee2b8e0372018-04-05 17:01:37 -070087
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070088/**
Bryce Leed3624e12017-11-30 08:51:45 -080089 * Tests for the {@link ActivityStarter} class.
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070090 *
91 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090092 * atest WmTests:ActivityStarterTests
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070093 */
94@SmallTest
95@Presubmit
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070096public class ActivityStarterTests extends ActivityTestsBase {
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070097 private ActivityStarter mStarter;
Bryce Leed3624e12017-11-30 08:51:45 -080098 private ActivityStartController mController;
Michal Karpinski201bc0c2018-07-20 15:32:00 +010099 private ActivityMetricsLogger mActivityMetricsLogger;
Bryce Lee93e7f792017-10-25 15:54:55 -0700100
101 private static final int PRECONDITION_NO_CALLER_APP = 1;
102 private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
103 private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2;
104 private static final int PRECONDITION_SOURCE_PRESENT = 1 << 3;
105 private static final int PRECONDITION_REQUEST_CODE = 1 << 4;
106 private static final int PRECONDITION_SOURCE_VOICE_SESSION = 1 << 5;
107 private static final int PRECONDITION_NO_VOICE_SESSION_SUPPORT = 1 << 6;
108 private static final int PRECONDITION_DIFFERENT_UID = 1 << 7;
109 private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8;
110 private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9;
111 private static final int PRECONDITION_DISALLOW_APP_SWITCHING = 1 << 10;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700112
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100113 private static final int FAKE_CALLING_UID = 666;
114 private static final int FAKE_REAL_CALLING_UID = 667;
115 private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
Michal Karpinski8596ded2018-11-14 14:43:48 +0000116 private static final int UNIMPORTANT_UID = 12345;
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000117 private static final int UNIMPORTANT_UID2 = 12346;
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100118
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900119 @Before
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700120 public void setUp() throws Exception {
Bryce Leed3624e12017-11-30 08:51:45 -0800121 mController = mock(ActivityStartController.class);
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100122 mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
123 clearInvocations(mActivityMetricsLogger);
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700124 mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
Bryce Leed3624e12017-11-30 08:51:45 -0800125 mock(ActivityStartInterceptor.class));
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700126 }
127
128 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900129 public void testUpdateLaunchBounds() {
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700130 // When in a non-resizeable stack, the task bounds should be updated.
Bryce Lee18d51592017-10-25 10:22:19 -0700131 final TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
Wale Ogunwaled32da472018-11-16 07:19:28 -0800132 .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
Bryce Lee18d51592017-10-25 10:22:19 -0700133 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
134 .build();
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700135 final Rect bounds = new Rect(10, 10, 100, 100);
136
137 mStarter.updateBounds(task, bounds);
Evan Roskydfe3da72018-10-26 17:21:06 -0700138 assertEquals(bounds, task.getRequestedOverrideBounds());
139 assertEquals(new Rect(), task.getStack().getRequestedOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700140
141 // When in a resizeable stack, the stack bounds should be updated as well.
Bryce Lee18d51592017-10-25 10:22:19 -0700142 final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
Wale Ogunwaled32da472018-11-16 07:19:28 -0800143 .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
Bryce Lee18d51592017-10-25 10:22:19 -0700144 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
145 .build();
Yunfan Chen279f5582018-12-12 15:24:50 -0800146 assertThat((Object) task2.getStack()).isInstanceOf(ActivityStack.class);
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700147 mStarter.updateBounds(task2, bounds);
148
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700149 verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId),
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700150 eq(bounds), anyBoolean(), anyBoolean(), anyBoolean(), anyInt());
151
152 // In the case of no animation, the stack and task bounds should be set immediately.
153 if (!ANIMATE) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700154 assertEquals(bounds, task2.getStack().getRequestedOverrideBounds());
155 assertEquals(bounds, task2.getRequestedOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700156 } else {
Evan Roskydfe3da72018-10-26 17:21:06 -0700157 assertEquals(new Rect(), task2.getRequestedOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700158 }
159 }
Bryce Lee93e7f792017-10-25 15:54:55 -0700160
161 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900162 public void testStartActivityPreconditions() {
Bryce Lee93e7f792017-10-25 15:54:55 -0700163 verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED);
164 verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT,
165 START_INTENT_NOT_RESOLVED);
166 verifyStartActivityPreconditions(PRECONDITION_NO_ACTIVITY_INFO, START_CLASS_NOT_FOUND);
167 verifyStartActivityPreconditions(PRECONDITION_SOURCE_PRESENT | PRECONDITION_REQUEST_CODE,
168 Intent.FLAG_ACTIVITY_FORWARD_RESULT, START_FORWARD_AND_REQUEST_CONFLICT);
169 verifyStartActivityPreconditions(
170 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
171 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID,
172 START_NOT_VOICE_COMPATIBLE);
173 verifyStartActivityPreconditions(
174 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
175 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID
176 | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION,
177 START_NOT_VOICE_COMPATIBLE);
178 verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED);
179 verifyStartActivityPreconditions(PRECONDITION_DISALLOW_APP_SWITCHING,
180 START_SWITCHES_CANCELED);
181 }
182
183 private static boolean containsConditions(int preconditions, int mask) {
184 return (preconditions & mask) == mask;
185 }
186
187 private void verifyStartActivityPreconditions(int preconditions, int expectedResult) {
188 verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
189 }
190
191 /**
192 * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
193 * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
194 * and the launch flags specified in the intent. The method constructs a call to
Bryce Lee4c9a5972017-12-01 22:14:24 -0800195 * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
196 * the expected. It is important to note that the method also checks side effects of the start,
197 * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
Bryce Lee93e7f792017-10-25 15:54:55 -0700198 * @param preconditions A bitmask representing the preconditions for the launch
199 * @param launchFlags The launch flags to be provided by the launch {@link Intent}.
200 * @param expectedResult The expected result from the launch.
201 */
202 private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
203 int expectedResult) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700204 final ActivityTaskManagerService service = mService;
Bryce Lee93e7f792017-10-25 15:54:55 -0700205 final IPackageManager packageManager = mock(IPackageManager.class);
Bryce Leed3624e12017-11-30 08:51:45 -0800206 final ActivityStartController controller = mock(ActivityStartController.class);
Bryce Lee93e7f792017-10-25 15:54:55 -0700207
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700208 final ActivityStarter starter = new ActivityStarter(controller, service,
Bryce Leed3624e12017-11-30 08:51:45 -0800209 service.mStackSupervisor, mock(ActivityStartInterceptor.class));
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700210 prepareStarter(launchFlags);
Bryce Lee93e7f792017-10-25 15:54:55 -0700211 final IApplicationThread caller = mock(IApplicationThread.class);
212
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700213 final WindowProcessController wpc =
214 containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
215 ? null : new WindowProcessController(
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900216 service, mock(ApplicationInfo.class), null, 0, -1, null, null);
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700217 doReturn(wpc).when(service).getProcessController(anyObject());
Bryce Lee93e7f792017-10-25 15:54:55 -0700218
219 final Intent intent = new Intent();
220 intent.setFlags(launchFlags);
221
222 final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO)
223 ? null : new ActivityInfo();
224
Bryce Lee93e7f792017-10-25 15:54:55 -0700225 IVoiceInteractionSession voiceSession =
226 containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
227 ? mock(IVoiceInteractionSession.class) : null;
228
229 // Create source token
230 final ActivityBuilder builder = new ActivityBuilder(service).setTask(
231 new TaskBuilder(service.mStackSupervisor).setVoiceSession(voiceSession).build());
232
Bryce Leefbd263b42018-03-07 10:33:55 -0800233 if (aInfo != null) {
234 aInfo.applicationInfo = new ApplicationInfo();
Bryce Leead5b8322018-03-08 14:28:52 -0800235 aInfo.applicationInfo.packageName =
236 ActivityBuilder.getDefaultComponent().getPackageName();
Bryce Leefbd263b42018-03-07 10:33:55 -0800237 }
238
Bryce Lee93e7f792017-10-25 15:54:55 -0700239 // Offset uid by one from {@link ActivityInfo} to simulate different uids.
240 if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) {
241 builder.setUid(aInfo.applicationInfo.uid + 1);
242 }
243
244 final ActivityRecord source = builder.build();
245
246 if (!containsConditions(preconditions, PRECONDITION_NO_INTENT_COMPONENT)) {
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800247 intent.setComponent(source.mActivityComponent);
Bryce Lee93e7f792017-10-25 15:54:55 -0700248 }
249
250 if (containsConditions(preconditions, PRECONDITION_DISALLOW_APP_SWITCHING)) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700251 doReturn(false).when(service).checkAppSwitchAllowedLocked(
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700252 anyInt(), anyInt(), anyInt(), anyInt(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700253 }
254
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900255 if (containsConditions(preconditions, PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
Bryce Lee93e7f792017-10-25 15:54:55 -0700256 doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission(
Jorim Jaggi4d8d32c2018-01-19 15:57:41 +0100257 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700258 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700259 }
260
261 try {
262 if (containsConditions(preconditions,
263 PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION)) {
264 doAnswer((inv) -> {
265 throw new RemoteException();
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800266 }).when(packageManager).activitySupportsIntent(
267 eq(source.mActivityComponent), eq(intent), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700268 } else {
269 doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT))
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800270 .when(packageManager).activitySupportsIntent(eq(source.mActivityComponent),
Bryce Lee93e7f792017-10-25 15:54:55 -0700271 eq(intent), any());
272 }
273 } catch (RemoteException e) {
274 }
275
276 final IBinder resultTo = containsConditions(preconditions, PRECONDITION_SOURCE_PRESENT)
277 || containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
278 ? source.appToken : null;
279
280 final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE)
281 ? 1 : 0;
282
Bryce Lee4c9a5972017-12-01 22:14:24 -0800283 final int result = starter.setCaller(caller)
284 .setIntent(intent)
285 .setActivityInfo(aInfo)
286 .setResultTo(resultTo)
287 .setRequestCode(requestCode)
288 .setReason("testLaunchActivityPermissionDenied")
289 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700290
291 // In some cases the expected result internally is different than the published result. We
292 // must use ActivityStarter#getExternalResult to translate.
293 assertEquals(ActivityStarter.getExternalResult(expectedResult), result);
294
295 // Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
296 if (expectedResult != START_SUCCESS) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700297 final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
Bryce Lee4c9a5972017-12-01 22:14:24 -0800298 mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
Bryce Lee93e7f792017-10-25 15:54:55 -0700299 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Bryce Lee4c9a5972017-12-01 22:14:24 -0800300
301 final int optionResult = optionStarter.setCaller(caller)
302 .setIntent(intent)
303 .setActivityInfo(aInfo)
304 .setResultTo(resultTo)
305 .setRequestCode(requestCode)
306 .setReason("testLaunchActivityPermissionDenied")
Jorim Jaggi4d8d32c2018-01-19 15:57:41 +0100307 .setActivityOptions(new SafeActivityOptions(options))
Bryce Lee4c9a5972017-12-01 22:14:24 -0800308 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700309 verify(options, times(1)).abort();
310 }
311 }
Bryce Leeb802ea12017-11-15 21:25:03 -0800312
Riddle Hsub70b36d2018-09-11 21:20:02 +0800313 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) {
314 return prepareStarter(launchFlags, true /* mockGetLaunchStack */);
315 }
316
317 /**
318 * Creates a {@link ActivityStarter} with default parameters and necessary mocks.
319 *
320 * @param launchFlags The intent flags to launch activity.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800321 * @param mockGetLaunchStack Whether to mock {@link RootActivityContainer#getLaunchStack} for
Riddle Hsub70b36d2018-09-11 21:20:02 +0800322 * always launching to the testing stack. Set to false when allowing
323 * the activity can be launched to any stack that is decided by real
324 * implementation.
325 * @return A {@link ActivityStarter} with default setup.
326 */
327 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
328 boolean mockGetLaunchStack) {
Bryce Leead5b8322018-03-08 14:28:52 -0800329 // always allow test to start activity.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800330 doReturn(true).when(mSupervisor).checkStartAnyActivityPermission(
Bryce Leead5b8322018-03-08 14:28:52 -0800331 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700332 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800333
334 // instrument the stack and task used.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800335 final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack(
Bryce Lee2b8e0372018-04-05 17:01:37 -0700336 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800337 final TaskRecord task = new TaskBuilder(mSupervisor)
Bryce Lee2b8e0372018-04-05 17:01:37 -0700338 .setCreateStack(false)
339 .build();
Bryce Leead5b8322018-03-08 14:28:52 -0800340
Bryce Leead5b8322018-03-08 14:28:52 -0800341 // use factory that only returns spy task.
342 final TaskRecordFactory factory = mock(TaskRecordFactory.class);
343 TaskRecord.setTaskRecordFactory(factory);
344
345 // return task when created.
346 doReturn(task).when(factory).create(any(), anyInt(), any(), any(), any(), any());
347
Riddle Hsub70b36d2018-09-11 21:20:02 +0800348 if (mockGetLaunchStack) {
349 // Direct starter to use spy stack.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800350 doReturn(stack).when(mRootActivityContainer)
Riddle Hsub70b36d2018-09-11 21:20:02 +0800351 .getLaunchStack(any(), any(), any(), anyBoolean());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800352 doReturn(stack).when(mRootActivityContainer)
Garfield Tan20d9e2f2018-11-16 15:42:29 -0800353 .getLaunchStack(any(), any(), any(), anyBoolean(), any());
Riddle Hsub70b36d2018-09-11 21:20:02 +0800354 }
Bryce Leead5b8322018-03-08 14:28:52 -0800355
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700356 // Set up mock package manager internal and make sure no unmocked methods are called
357 PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class,
358 invocation -> {
359 throw new RuntimeException("Not stubbed");
360 });
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700361 doReturn(mockPackageManager).when(mService).getPackageManagerInternalLocked();
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700362
363 // Never review permissions
364 doReturn(false).when(mockPackageManager).isPermissionsReviewRequired(any(), anyInt());
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700365 doNothing().when(mockPackageManager).grantEphemeralAccess(
366 anyInt(), any(), anyInt(), anyInt());
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700367
Bryce Lee32e09ef2018-03-19 15:29:49 -0700368 final Intent intent = new Intent();
369 intent.addFlags(launchFlags);
370 intent.setComponent(ActivityBuilder.getDefaultComponent());
371
372 final ActivityInfo info = new ActivityInfo();
373
374 info.applicationInfo = new ApplicationInfo();
375 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
376
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700377 return new ActivityStarter(mController, mService,
Bryce Lee32e09ef2018-03-19 15:29:49 -0700378 mService.mStackSupervisor, mock(ActivityStartInterceptor.class))
379 .setIntent(intent)
380 .setActivityInfo(info);
Bryce Leead5b8322018-03-08 14:28:52 -0800381 }
382
383 /**
384 * Ensures that values specified at launch time are passed to {@link LaunchParamsModifier}
385 * when we are laying out a new task.
386 */
387 @Test
388 public void testCreateTaskLayout() {
389 // modifier for validating passed values.
390 final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
391 mService.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
392
393 // add custom values to activity info to make unique.
394 final ActivityInfo info = new ActivityInfo();
395 final Rect launchBounds = new Rect(0, 0, 20, 30);
Bryce Leead5b8322018-03-08 14:28:52 -0800396
397 final WindowLayout windowLayout =
398 new WindowLayout(10, .5f, 20, 1.0f, Gravity.NO_GRAVITY, 1, 1);
399
400 info.windowLayout = windowLayout;
401 info.applicationInfo = new ApplicationInfo();
402 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
403
404 // create starter.
Bryce Lee32e09ef2018-03-19 15:29:49 -0700405 final ActivityStarter optionStarter = prepareStarter(0 /* launchFlags */);
Bryce Leead5b8322018-03-08 14:28:52 -0800406
407 final ActivityOptions options = ActivityOptions.makeBasic();
408 options.setLaunchBounds(launchBounds);
409
410 // run starter.
411 optionStarter
Bryce Leead5b8322018-03-08 14:28:52 -0800412 .setReason("testCreateTaskLayout")
413 .setActivityInfo(info)
414 .setActivityOptions(new SafeActivityOptions(options))
415 .execute();
416
Louis Chang6fb1e842018-12-03 16:07:50 +0800417 // verify that values are passed to the modifier. Values are passed thrice -- two for
Garfield Tan706dbcb2018-10-15 11:33:02 -0700418 // setting initial state, another when task is created.
Louis Chang6fb1e842018-12-03 16:07:50 +0800419 verify(modifier, times(3)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
420 anyInt(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800421 }
Bryce Lee32e09ef2018-03-19 15:29:49 -0700422
423 /**
424 * This test ensures that if the intent is being delivered to a
425 */
426 @Test
427 public void testSplitScreenDeliverToTop() {
428 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
429
430 final ActivityRecord focusActivity = new ActivityBuilder(mService)
431 .setCreateTask(true)
432 .build();
433
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800434 focusActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700435
436 final ActivityRecord reusableActivity = new ActivityBuilder(mService)
437 .setCreateTask(true)
438 .build();
439
440 // Create reusable activity after entering split-screen so that it is the top secondary
441 // stack.
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800442 reusableActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700443
444 // Set focus back to primary.
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800445 final ActivityStack focusStack = focusActivity.getActivityStack();
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700446 focusStack.moveToFront("testSplitScreenDeliverToTop");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700447
Wale Ogunwaled32da472018-11-16 07:19:28 -0800448 doReturn(reusableActivity).when(mRootActivityContainer).findTask(any(), anyInt());
Bryce Lee32e09ef2018-03-19 15:29:49 -0700449
450 final int result = starter.setReason("testSplitScreenDeliverToTop").execute();
451
452 // Ensure result is delivering intent to top.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900453 assertEquals(START_DELIVERED_TO_TOP, result);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700454 }
455
456 /**
457 * This test ensures that if the intent is being delivered to a split-screen unfocused task
458 * reports it is brought to front instead of delivering to top.
459 */
460 @Test
461 public void testSplitScreenTaskToFront() {
462 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
463
464 // Create reusable activity here first. Setting the windowing mode of the primary stack
465 // will move the existing standard full screen stack to secondary, putting this one on the
466 // bottom.
467 final ActivityRecord reusableActivity = new ActivityBuilder(mService)
468 .setCreateTask(true)
469 .build();
470
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800471 reusableActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700472
473 final ActivityRecord focusActivity = new ActivityBuilder(mService)
474 .setCreateTask(true)
475 .build();
476
477 // Enter split-screen. Primary stack should have focus.
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800478 focusActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700479
Wale Ogunwaled32da472018-11-16 07:19:28 -0800480 doReturn(reusableActivity).when(mRootActivityContainer).findTask(any(), anyInt());
Bryce Lee32e09ef2018-03-19 15:29:49 -0700481
482 final int result = starter.setReason("testSplitScreenMoveToFront").execute();
483
484 // Ensure result is moving task to front.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900485 assertEquals(START_TASK_TO_FRONT, result);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700486 }
Bryce Lee2b8e0372018-04-05 17:01:37 -0700487
488 /**
489 * Tests activity is cleaned up properly in a task mode violation.
490 */
491 @Test
492 public void testTaskModeViolation() {
Wale Ogunwaled32da472018-11-16 07:19:28 -0800493 final ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700494 ((TestActivityDisplay) display).removeAllTasks();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700495 assertNoTasks(display);
496
497 final ActivityStarter starter = prepareStarter(0);
498
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700499 final LockTaskController lockTaskController = mService.getLockTaskController();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700500 doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
501
502 final int result = starter.setReason("testTaskModeViolation").execute();
503
504 assertEquals(START_RETURN_LOCK_TASK_MODE_VIOLATION, result);
505 assertNoTasks(display);
506 }
507
508 private void assertNoTasks(ActivityDisplay display) {
509 for (int i = display.getChildCount() - 1; i >= 0; --i) {
510 final ActivityStack stack = display.getChildAt(i);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900511 assertThat(stack.getAllTasks()).isEmpty();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700512 }
513 }
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100514
515 /**
516 * This test ensures that activity starts are not being logged when the logging is disabled.
517 */
518 @Test
519 public void testActivityStartsLogging_noLoggingWhenDisabled() {
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700520 doReturn(false).when(mService).isActivityStartsLoggingEnabled();
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100521 doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
522
523 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK);
524 starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute();
525
526 // verify logging wasn't done
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000527 verify(mActivityMetricsLogger, never()).logAbortedBgActivityStart(any(), any(), anyInt(),
528 any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100529 }
530
531 /**
532 * This test ensures that activity starts are being logged when the logging is enabled.
533 */
534 @Test
535 public void testActivityStartsLogging_logsWhenEnabled() {
536 // note: conveniently this package doesn't have any activity visible
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700537 doReturn(true).when(mService).isActivityStartsLoggingEnabled();
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100538 doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
539
540 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
541 .setCallingUid(FAKE_CALLING_UID)
542 .setRealCallingUid(FAKE_REAL_CALLING_UID)
543 .setCallingPackage(FAKE_CALLING_PACKAGE)
544 .setOriginatingPendingIntent(null);
545
546 starter.setReason("testActivityStartsLogging_logsWhenEnabled").execute();
547
548 // verify the above activity start was logged
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000549 verify(mActivityMetricsLogger, times(1)).logAbortedBgActivityStart(any(), any(),
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100550 eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(),
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000551 eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), eq(false));
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100552 }
Riddle Hsub70b36d2018-09-11 21:20:02 +0800553
554 /**
Michal Karpinski8596ded2018-11-14 14:43:48 +0000555 * This test ensures that unsupported usecases aren't aborted when background starts are
556 * allowed.
557 */
558 @Test
559 public void testBackgroundActivityStartsAllowed_noStartsAborted() {
560 doReturn(true).when(mService).isBackgroundActivityStartsEnabled();
561
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000562 runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
563 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
564 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000565 false, false, false, false, false);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000566 }
567
568 /**
569 * This test ensures that unsupported usecases are aborted when background starts are
570 * disallowed.
571 */
572 @Test
573 public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
574 doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
575
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000576 runAndVerifyBackgroundActivityStartsSubtest(
577 "disallowed_unsupportedUsecase_aborted", true,
578 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
579 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000580 false, false, false, false, false);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000581 }
582
583 /**
584 * This test ensures that supported usecases aren't aborted when background starts are
585 * disallowed.
586 * The scenarios each have only one condidion that makes them supported.
587 */
588 @Test
589 public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
590 doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
591
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000592 runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
593 Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
594 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000595 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000596 runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
597 Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
598 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000599 false, false, false, false, false);
Michal Karpinskib416f472019-01-24 14:34:28 +0000600 runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false,
601 Process.NFC_UID, false, PROCESS_STATE_TOP + 1,
602 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000603 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000604 runAndVerifyBackgroundActivityStartsSubtest(
605 "disallowed_callingUidHasVisibleWindow_notAborted", false,
606 UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
607 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000608 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000609 runAndVerifyBackgroundActivityStartsSubtest(
610 "disallowed_callingUidProcessStateTop_notAborted", false,
611 UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
612 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000613 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000614 runAndVerifyBackgroundActivityStartsSubtest(
615 "disallowed_realCallingUidHasVisibleWindow_notAborted", false,
616 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
617 UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000618 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000619 runAndVerifyBackgroundActivityStartsSubtest(
620 "disallowed_realCallingUidProcessStateTop_notAborted", false,
621 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
622 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000623 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000624 runAndVerifyBackgroundActivityStartsSubtest(
625 "disallowed_hasForegroundActivities_notAborted", false,
626 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
627 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000628 true, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000629 runAndVerifyBackgroundActivityStartsSubtest(
630 "disallowed_callerIsRecents_notAborted", false,
631 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
632 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000633 false, true, false, false, false);
Michal Karpinskiac116df2018-12-10 17:51:42 +0000634 runAndVerifyBackgroundActivityStartsSubtest(
635 "disallowed_callerIsWhitelisted_notAborted", false,
636 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
637 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000638 false, false, true, false, false);
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000639 runAndVerifyBackgroundActivityStartsSubtest(
640 "disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted",
641 false,
642 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
643 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000644 false, false, false, true, false);
645 runAndVerifyBackgroundActivityStartsSubtest(
646 "disallowed_callingPackageIsDeviceOwner_notAborted", false,
647 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
648 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
649 false, false, false, false, true);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000650 }
651
652 private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000653 int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
654 int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
Michal Karpinskiac116df2018-12-10 17:51:42 +0000655 boolean hasForegroundActivities, boolean callerIsRecents,
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000656 boolean callerIsTempWhitelisted,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000657 boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
658 boolean isCallingPackageDeviceOwner) {
Michal Karpinski8596ded2018-11-14 14:43:48 +0000659 // window visibility
Michal Karpinskia606a292019-01-12 17:29:52 +0000660 doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
661 .isAnyNonToastWindowVisibleForUid(callingUid);
662 doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
663 .isAnyNonToastWindowVisibleForUid(realCallingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000664 // process importance
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000665 doReturn(callingUidProcState).when(mService).getUidStateLocked(callingUid);
666 doReturn(realCallingUidProcState).when(mService).getUidStateLocked(realCallingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000667 // foreground activities
668 final IApplicationThread caller = mock(IApplicationThread.class);
669 final ApplicationInfo ai = new ApplicationInfo();
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000670 ai.uid = callingUid;
Michal Karpinski8596ded2018-11-14 14:43:48 +0000671 final WindowProcessController callerApp =
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000672 new WindowProcessController(mService, ai, null, callingUid, -1, null, null);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000673 callerApp.setHasForegroundActivities(hasForegroundActivities);
674 doReturn(callerApp).when(mService).getProcessController(caller);
Michal Karpinski82bb5902018-11-28 15:52:52 +0000675 // caller is recents
676 RecentTasks recentTasks = mock(RecentTasks.class);
677 mService.mStackSupervisor.setRecentTasks(recentTasks);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000678 doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
Michal Karpinskiac116df2018-12-10 17:51:42 +0000679 // caller is temp whitelisted
680 callerApp.setAllowBackgroundActivityStarts(callerIsTempWhitelisted);
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000681 // caller is instrumenting with background activity starts privileges
Michal Karpinski4bc56492019-01-31 12:07:33 +0000682 callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000683 callerIsInstrumentingWithBackgroundActivityStartPrivileges);
Michal Karpinski302dcec2019-02-01 11:48:25 +0000684 // caller is device owner
685 DevicePolicyManager dpmMock = mService.getDevicePolicyManager();
686 doReturn(isCallingPackageDeviceOwner).when(dpmMock).isDeviceOwnerApp(any());
Michal Karpinski8596ded2018-11-14 14:43:48 +0000687
688 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000689 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
690 .setCaller(caller)
691 .setCallingUid(callingUid)
692 .setRealCallingUid(realCallingUid)
693 .setActivityOptions(new SafeActivityOptions(options));
Michal Karpinski8596ded2018-11-14 14:43:48 +0000694
695 final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();
696
697 assertEquals(ActivityStarter.getExternalResult(
698 shouldHaveAborted ? START_ABORTED : START_SUCCESS), result);
699 verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
700 }
701
702 /**
Riddle Hsub70b36d2018-09-11 21:20:02 +0800703 * This test ensures that when starting an existing single task activity on secondary display
704 * which is not the top focused display, it should deliver new intent to the activity and not
705 * create a new stack.
706 */
707 @Test
708 public void testDeliverIntentToTopActivityOfNonTopDisplay() {
709 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
710 false /* mockGetLaunchStack */);
711
712 // Create a secondary display at bottom.
Riddle Hsufd4a0502018-10-16 01:05:16 +0800713 final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800714 mRootActivityContainer.addChild(secondaryDisplay, POSITION_BOTTOM);
Riddle Hsub70b36d2018-09-11 21:20:02 +0800715 final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
716 ACTIVITY_TYPE_STANDARD, true /* onTop */);
717
718 // Create an activity record on the top of secondary display.
Riddle Hsufd4a0502018-10-16 01:05:16 +0800719 final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
Riddle Hsub70b36d2018-09-11 21:20:02 +0800720
721 // Put an activity on default display as the top focused activity.
722 new ActivityBuilder(mService).setCreateTask(true).build();
723
724 // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
725 // on secondary display.
726 final ActivityOptions options = ActivityOptions.makeBasic()
727 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
728 final int result = starter.setReason("testDeliverIntentToTopActivityOfNonTopDisplay")
729 .setIntent(topActivityOnSecondaryDisplay.intent)
730 .setActivityOptions(options.toBundle())
731 .execute();
732
733 // Ensure result is delivering intent to top.
734 assertEquals(START_DELIVERED_TO_TOP, result);
735
736 // Ensure secondary display only creates one stack.
737 verify(secondaryDisplay, times(1)).createStack(anyInt(), anyInt(), anyBoolean());
738 }
739
740 /**
Riddle Hsufd4a0502018-10-16 01:05:16 +0800741 * This test ensures that when starting an existing non-top single task activity on secondary
742 * display which is the top focused display, it should bring the task to front without creating
743 * unused stack.
744 */
745 @Test
746 public void testBringTaskToFrontOnSecondaryDisplay() {
747 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
748 false /* mockGetLaunchStack */);
749
750 // Create a secondary display with an activity.
751 final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800752 mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP);
Riddle Hsufd4a0502018-10-16 01:05:16 +0800753 final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
754 secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
755 ACTIVITY_TYPE_STANDARD, false /* onTop */));
756
757 // Create another activity on top of the secondary display.
758 final ActivityStack topStack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
759 ACTIVITY_TYPE_STANDARD, true /* onTop */);
760 final TaskRecord topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
761 new ActivityBuilder(mService).setTask(topTask).build();
762
763 // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
764 final ActivityOptions options = ActivityOptions.makeBasic()
765 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
766 final int result = starter.setReason("testBringTaskToFrontOnSecondaryDisplay")
767 .setIntent(singleTaskActivity.intent)
768 .setActivityOptions(options.toBundle())
769 .execute();
770
771 // Ensure result is moving existing task to front.
772 assertEquals(START_TASK_TO_FRONT, result);
773
774 // Ensure secondary display only creates two stacks.
775 verify(secondaryDisplay, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
776 }
777
778 private ActivityRecord createSingleTaskActivityOn(ActivityStack stack) {
779 final ComponentName componentName = ComponentName.createRelative(
780 DEFAULT_COMPONENT_PACKAGE_NAME,
781 DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
782 final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
783 .setComponent(componentName)
784 .setStack(stack)
785 .build();
786 return new ActivityBuilder(mService)
787 .setComponent(componentName)
788 .setLaunchMode(LAUNCH_SINGLE_TASK)
789 .setTask(taskRecord)
790 .build();
791 }
792
793 /**
Riddle Hsub70b36d2018-09-11 21:20:02 +0800794 * This test ensures that a reused top activity in the top focused stack is able to be
795 * reparented to another display.
796 */
797 @Test
798 public void testReparentTopFocusedActivityToSecondaryDisplay() {
799 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
800 false /* mockGetLaunchStack */);
801
802 // Create a secondary display at bottom.
803 final TestActivityDisplay secondaryDisplay = addNewActivityDisplayAt(POSITION_BOTTOM);
804 secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
805 true /* onTop */);
806
807 // Put an activity on default display as the top focused activity.
808 final ActivityRecord topActivity = new ActivityBuilder(mService)
809 .setCreateTask(true)
810 .setLaunchMode(LAUNCH_SINGLE_TASK)
811 .build();
812
813 // Start activity with the same intent as {@code topActivity} on secondary display.
814 final ActivityOptions options = ActivityOptions.makeBasic()
815 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
816 starter.setReason("testReparentTopFocusedActivityToSecondaryDisplay")
817 .setIntent(topActivity.intent)
818 .setActivityOptions(options.toBundle())
819 .execute();
820
821 // Ensure the activity is moved to secondary display.
822 assertEquals(secondaryDisplay, topActivity.getDisplay());
823 }
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700824}