blob: edc9756d6d0e4da8f364c8d7b251060418d5f9ed [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;
Winson Chunge789ff62020-02-24 14:40:23 -080021import static android.app.ActivityManager.START_CANCELED;
Bryce Lee93e7f792017-10-25 15:54:55 -070022import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
Bryce Lee32e09ef2018-03-19 15:29:49 -070023import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
Bryce Lee93e7f792017-10-25 15:54:55 -070024import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
Bryce Lee32e09ef2018-03-19 15:29:49 -070025import static android.app.ActivityManager.START_INTENT_NOT_RESOLVED;
Bryce Lee93e7f792017-10-25 15:54:55 -070026import static android.app.ActivityManager.START_NOT_VOICE_COMPATIBLE;
Bryce Lee32e09ef2018-03-19 15:29:49 -070027import static android.app.ActivityManager.START_PERMISSION_DENIED;
Bryce Lee2b8e0372018-04-05 17:01:37 -070028import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
Bryce Lee93e7f792017-10-25 15:54:55 -070029import static android.app.ActivityManager.START_SUCCESS;
30import static android.app.ActivityManager.START_SWITCHES_CANCELED;
Bryce Lee32e09ef2018-03-19 15:29:49 -070031import static android.app.ActivityManager.START_TASK_TO_FRONT;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070032import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
33import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
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;
Louis Chang677921f2019-12-06 16:44:24 +080052import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
53import static com.android.server.wm.WindowContainer.POSITION_TOP;
Brett Chabota26eda92018-07-23 13:08:30 -070054
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090055import static com.google.common.truth.Truth.assertThat;
56
Brett Chabota26eda92018-07-23 13:08:30 -070057import static org.junit.Assert.assertEquals;
Wale Ogunwale85fb19a2019-12-05 10:41:05 +090058import static org.junit.Assert.assertFalse;
Riddle Hsub70b36d2018-09-11 21:20:02 +080059import static org.mockito.ArgumentMatchers.any;
60import static org.mockito.ArgumentMatchers.anyBoolean;
61import static org.mockito.ArgumentMatchers.anyInt;
Diego Vela25cbe9d2020-05-14 01:06:02 +000062import static org.mockito.ArgumentMatchers.anyObject;
Wale Ogunwaleda8b8272018-11-29 19:37:37 -080063import static org.mockito.ArgumentMatchers.anyString;
Riddle Hsub70b36d2018-09-11 21:20:02 +080064import static org.mockito.ArgumentMatchers.eq;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070065
Bryce Lee93e7f792017-10-25 15:54:55 -070066import android.app.ActivityOptions;
67import android.app.IApplicationThread;
Riddle Hsub70b36d2018-09-11 21:20:02 +080068import android.content.ComponentName;
Bryce Lee93e7f792017-10-25 15:54:55 -070069import android.content.Intent;
70import android.content.pm.ActivityInfo;
Bryce Leead5b8322018-03-08 14:28:52 -080071import android.content.pm.ActivityInfo.WindowLayout;
Bryce Lee93e7f792017-10-25 15:54:55 -070072import android.content.pm.ApplicationInfo;
73import android.content.pm.IPackageManager;
Philip P. Moltmann6c644e62018-07-18 15:41:24 -070074import android.content.pm.PackageManagerInternal;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070075import android.graphics.Rect;
Bryce Lee93e7f792017-10-25 15:54:55 -070076import android.os.IBinder;
Michal Karpinski8596ded2018-11-14 14:43:48 +000077import android.os.Process;
Bryce Lee93e7f792017-10-25 15:54:55 -070078import android.os.RemoteException;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070079import android.platform.test.annotations.Presubmit;
Bryce Lee93e7f792017-10-25 15:54:55 -070080import android.service.voice.IVoiceInteractionSession;
Bryce Leead5b8322018-03-08 14:28:52 -080081import android.view.Gravity;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070082
Brett Chabota26eda92018-07-23 13:08:30 -070083import androidx.test.filters.SmallTest;
Brett Chabota26eda92018-07-23 13:08:30 -070084
Wale Ogunwale59507092018-10-29 09:00:30 -070085import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
Garfield Tane3d37b52019-07-23 12:43:05 -070086import com.android.server.wm.utils.MockTracker;
Bryce Lee93e7f792017-10-25 15:54:55 -070087
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090088import org.junit.Before;
Brett Chabota26eda92018-07-23 13:08:30 -070089import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +080090import org.junit.runner.RunWith;
Bryce Lee2b8e0372018-04-05 17:01:37 -070091
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070092/**
Bryce Leed3624e12017-11-30 08:51:45 -080093 * Tests for the {@link ActivityStarter} class.
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070094 *
95 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090096 * atest WmTests:ActivityStarterTests
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070097 */
98@SmallTest
99@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +0800100@RunWith(WindowTestRunner.class)
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700101public class ActivityStarterTests extends ActivityTestsBase {
Diego Vela25cbe9d2020-05-14 01:06:02 +0000102 private ActivityStarter mStarter;
Bryce Leed3624e12017-11-30 08:51:45 -0800103 private ActivityStartController mController;
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100104 private ActivityMetricsLogger mActivityMetricsLogger;
Louis Chang54fbb052019-10-16 17:10:17 +0800105 private PackageManagerInternal mMockPackageManager;
Bryce Lee93e7f792017-10-25 15:54:55 -0700106
107 private static final int PRECONDITION_NO_CALLER_APP = 1;
108 private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
109 private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2;
110 private static final int PRECONDITION_SOURCE_PRESENT = 1 << 3;
111 private static final int PRECONDITION_REQUEST_CODE = 1 << 4;
112 private static final int PRECONDITION_SOURCE_VOICE_SESSION = 1 << 5;
113 private static final int PRECONDITION_NO_VOICE_SESSION_SUPPORT = 1 << 6;
114 private static final int PRECONDITION_DIFFERENT_UID = 1 << 7;
115 private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8;
116 private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9;
117 private static final int PRECONDITION_DISALLOW_APP_SWITCHING = 1 << 10;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700118
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100119 private static final int FAKE_CALLING_UID = 666;
120 private static final int FAKE_REAL_CALLING_UID = 667;
121 private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
Michal Karpinski8596ded2018-11-14 14:43:48 +0000122 private static final int UNIMPORTANT_UID = 12345;
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000123 private static final int UNIMPORTANT_UID2 = 12346;
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100124
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900125 @Before
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700126 public void setUp() throws Exception {
Bryce Leed3624e12017-11-30 08:51:45 -0800127 mController = mock(ActivityStartController.class);
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100128 mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
129 clearInvocations(mActivityMetricsLogger);
Diego Vela25cbe9d2020-05-14 01:06:02 +0000130 mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
131 mock(ActivityStartInterceptor.class));
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700132 }
133
134 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900135 public void testStartActivityPreconditions() {
Bryce Lee93e7f792017-10-25 15:54:55 -0700136 verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED);
137 verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT,
138 START_INTENT_NOT_RESOLVED);
139 verifyStartActivityPreconditions(PRECONDITION_NO_ACTIVITY_INFO, START_CLASS_NOT_FOUND);
140 verifyStartActivityPreconditions(PRECONDITION_SOURCE_PRESENT | PRECONDITION_REQUEST_CODE,
141 Intent.FLAG_ACTIVITY_FORWARD_RESULT, START_FORWARD_AND_REQUEST_CONFLICT);
142 verifyStartActivityPreconditions(
143 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
144 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID,
145 START_NOT_VOICE_COMPATIBLE);
146 verifyStartActivityPreconditions(
147 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
148 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID
149 | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION,
150 START_NOT_VOICE_COMPATIBLE);
151 verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED);
152 verifyStartActivityPreconditions(PRECONDITION_DISALLOW_APP_SWITCHING,
153 START_SWITCHES_CANCELED);
154 }
155
156 private static boolean containsConditions(int preconditions, int mask) {
157 return (preconditions & mask) == mask;
158 }
159
160 private void verifyStartActivityPreconditions(int preconditions, int expectedResult) {
161 verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
162 }
163
Garfield Tane3d37b52019-07-23 12:43:05 -0700164 private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
165 int expectedResult) {
166 // We track mocks created here because this is used in a single test
167 // (testStartActivityPreconditions) as a specific case, and mocks created inside it won't be
168 // used for other cases. To avoid extensive memory usage, we clean up all used mocks after
169 // each case. This is necessary because usually we only clean up mocks after a test
170 // finishes, but this test creates too many mocks that the intermediate memory usage can be
171 // ~0.8 GiB and thus very susceptible to OutOfMemoryException.
172 try (MockTracker tracker = new MockTracker()) {
173 verifyStartActivityPreconditionsUntracked(preconditions, launchFlags, expectedResult);
174 }
175 }
176
Bryce Lee93e7f792017-10-25 15:54:55 -0700177 /**
178 * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
179 * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
180 * and the launch flags specified in the intent. The method constructs a call to
Bryce Lee4c9a5972017-12-01 22:14:24 -0800181 * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
182 * the expected. It is important to note that the method also checks side effects of the start,
183 * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
Bryce Lee93e7f792017-10-25 15:54:55 -0700184 * @param preconditions A bitmask representing the preconditions for the launch
185 * @param launchFlags The launch flags to be provided by the launch {@link Intent}.
186 * @param expectedResult The expected result from the launch.
187 */
Garfield Tane3d37b52019-07-23 12:43:05 -0700188 private void verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags,
Bryce Lee93e7f792017-10-25 15:54:55 -0700189 int expectedResult) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700190 final ActivityTaskManagerService service = mService;
Bryce Lee93e7f792017-10-25 15:54:55 -0700191 final IPackageManager packageManager = mock(IPackageManager.class);
Bryce Leed3624e12017-11-30 08:51:45 -0800192 final ActivityStartController controller = mock(ActivityStartController.class);
Bryce Lee93e7f792017-10-25 15:54:55 -0700193
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700194 final ActivityStarter starter = new ActivityStarter(controller, service,
Bryce Leed3624e12017-11-30 08:51:45 -0800195 service.mStackSupervisor, mock(ActivityStartInterceptor.class));
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700196 prepareStarter(launchFlags);
Bryce Lee93e7f792017-10-25 15:54:55 -0700197 final IApplicationThread caller = mock(IApplicationThread.class);
Darryl L Johnson15192d32020-01-15 15:31:42 -0800198 final WindowProcessListener listener = mock(WindowProcessListener.class);
Bryce Lee93e7f792017-10-25 15:54:55 -0700199
Darryl L Johnsona0982222020-02-18 18:21:51 -0800200 final ApplicationInfo ai = new ApplicationInfo();
201 ai.packageName = "com.android.test.package";
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700202 final WindowProcessController wpc =
203 containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
Darryl L Johnsona0982222020-02-18 18:21:51 -0800204 ? null : new WindowProcessController(service, ai, null, 0, -1, null, listener);
Diego Vela25cbe9d2020-05-14 01:06:02 +0000205 doReturn(wpc).when(service).getProcessController(anyObject());
Bryce Lee93e7f792017-10-25 15:54:55 -0700206
207 final Intent intent = new Intent();
208 intent.setFlags(launchFlags);
209
210 final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO)
211 ? null : new ActivityInfo();
212
Bryce Lee93e7f792017-10-25 15:54:55 -0700213 IVoiceInteractionSession voiceSession =
214 containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
215 ? mock(IVoiceInteractionSession.class) : null;
216
217 // Create source token
218 final ActivityBuilder builder = new ActivityBuilder(service).setTask(
219 new TaskBuilder(service.mStackSupervisor).setVoiceSession(voiceSession).build());
220
Bryce Leefbd263b42018-03-07 10:33:55 -0800221 if (aInfo != null) {
222 aInfo.applicationInfo = new ApplicationInfo();
Bryce Leead5b8322018-03-08 14:28:52 -0800223 aInfo.applicationInfo.packageName =
224 ActivityBuilder.getDefaultComponent().getPackageName();
Bryce Leefbd263b42018-03-07 10:33:55 -0800225 }
226
Bryce Lee93e7f792017-10-25 15:54:55 -0700227 // Offset uid by one from {@link ActivityInfo} to simulate different uids.
228 if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) {
229 builder.setUid(aInfo.applicationInfo.uid + 1);
230 }
231
232 final ActivityRecord source = builder.build();
233
234 if (!containsConditions(preconditions, PRECONDITION_NO_INTENT_COMPONENT)) {
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800235 intent.setComponent(source.mActivityComponent);
Bryce Lee93e7f792017-10-25 15:54:55 -0700236 }
237
238 if (containsConditions(preconditions, PRECONDITION_DISALLOW_APP_SWITCHING)) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700239 doReturn(false).when(service).checkAppSwitchAllowedLocked(
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700240 anyInt(), anyInt(), anyInt(), anyInt(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700241 }
242
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900243 if (containsConditions(preconditions, PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
Bryce Lee93e7f792017-10-25 15:54:55 -0700244 doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission(
Philip P. Moltmannee295092020-02-10 08:46:26 -0800245 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700246 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700247 }
248
249 try {
250 if (containsConditions(preconditions,
251 PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION)) {
252 doAnswer((inv) -> {
253 throw new RemoteException();
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800254 }).when(packageManager).activitySupportsIntent(
255 eq(source.mActivityComponent), eq(intent), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700256 } else {
257 doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT))
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800258 .when(packageManager).activitySupportsIntent(eq(source.mActivityComponent),
Bryce Lee93e7f792017-10-25 15:54:55 -0700259 eq(intent), any());
260 }
261 } catch (RemoteException e) {
262 }
263
264 final IBinder resultTo = containsConditions(preconditions, PRECONDITION_SOURCE_PRESENT)
265 || containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
266 ? source.appToken : null;
267
268 final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE)
269 ? 1 : 0;
270
Bryce Lee4c9a5972017-12-01 22:14:24 -0800271 final int result = starter.setCaller(caller)
272 .setIntent(intent)
273 .setActivityInfo(aInfo)
274 .setResultTo(resultTo)
275 .setRequestCode(requestCode)
276 .setReason("testLaunchActivityPermissionDenied")
277 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700278
279 // In some cases the expected result internally is different than the published result. We
280 // must use ActivityStarter#getExternalResult to translate.
281 assertEquals(ActivityStarter.getExternalResult(expectedResult), result);
282
283 // Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
284 if (expectedResult != START_SUCCESS) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700285 final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
Bryce Lee4c9a5972017-12-01 22:14:24 -0800286 mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
Bryce Lee93e7f792017-10-25 15:54:55 -0700287 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Bryce Lee4c9a5972017-12-01 22:14:24 -0800288
289 final int optionResult = optionStarter.setCaller(caller)
290 .setIntent(intent)
291 .setActivityInfo(aInfo)
292 .setResultTo(resultTo)
293 .setRequestCode(requestCode)
294 .setReason("testLaunchActivityPermissionDenied")
Jorim Jaggi4d8d32c2018-01-19 15:57:41 +0100295 .setActivityOptions(new SafeActivityOptions(options))
Bryce Lee4c9a5972017-12-01 22:14:24 -0800296 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700297 verify(options, times(1)).abort();
298 }
299 }
Bryce Leeb802ea12017-11-15 21:25:03 -0800300
Riddle Hsub70b36d2018-09-11 21:20:02 +0800301 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) {
302 return prepareStarter(launchFlags, true /* mockGetLaunchStack */);
303 }
304
305 /**
306 * Creates a {@link ActivityStarter} with default parameters and necessary mocks.
307 *
308 * @param launchFlags The intent flags to launch activity.
Louis Chang149d5c82019-12-30 09:47:39 +0800309 * @param mockGetLaunchStack Whether to mock {@link RootWindowContainer#getLaunchStack} for
Riddle Hsub70b36d2018-09-11 21:20:02 +0800310 * always launching to the testing stack. Set to false when allowing
311 * the activity can be launched to any stack that is decided by real
312 * implementation.
313 * @return A {@link ActivityStarter} with default setup.
314 */
315 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
316 boolean mockGetLaunchStack) {
Bryce Leead5b8322018-03-08 14:28:52 -0800317 // always allow test to start activity.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800318 doReturn(true).when(mSupervisor).checkStartAnyActivityPermission(
Philip P. Moltmannee295092020-02-10 08:46:26 -0800319 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700320 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800321
Riddle Hsub70b36d2018-09-11 21:20:02 +0800322 if (mockGetLaunchStack) {
Riddle Hsuff9e8282019-04-24 23:55:11 +0800323 // Instrument the stack and task used.
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700324 final ActivityStack stack = mRootWindowContainer.getDefaultTaskDisplayArea()
325 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
326 true /* onTop */);
Riddle Hsuff9e8282019-04-24 23:55:11 +0800327
Riddle Hsub70b36d2018-09-11 21:20:02 +0800328 // Direct starter to use spy stack.
Louis Chang149d5c82019-12-30 09:47:39 +0800329 doReturn(stack).when(mRootWindowContainer)
Riddle Hsub70b36d2018-09-11 21:20:02 +0800330 .getLaunchStack(any(), any(), any(), anyBoolean());
Louis Chang149d5c82019-12-30 09:47:39 +0800331 doReturn(stack).when(mRootWindowContainer)
lumarkf65e02d2019-09-14 19:25:21 +0800332 .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
Riddle Hsub70b36d2018-09-11 21:20:02 +0800333 }
Bryce Leead5b8322018-03-08 14:28:52 -0800334
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700335 // Set up mock package manager internal and make sure no unmocked methods are called
Louis Chang54fbb052019-10-16 17:10:17 +0800336 mMockPackageManager = mock(PackageManagerInternal.class,
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700337 invocation -> {
338 throw new RuntimeException("Not stubbed");
339 });
Louis Chang54fbb052019-10-16 17:10:17 +0800340 doReturn(mMockPackageManager).when(mService).getPackageManagerInternalLocked();
341 doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
342 doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyInt(), anyInt(),
Patrick Baumann2fa1c952020-01-28 09:41:22 -0800343 anyInt(), anyBoolean(), anyInt());
Darryl L Johnsona0982222020-02-18 18:21:51 -0800344 doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent();
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700345
346 // Never review permissions
Louis Chang54fbb052019-10-16 17:10:17 +0800347 doReturn(false).when(mMockPackageManager).isPermissionsReviewRequired(any(), anyInt());
348 doNothing().when(mMockPackageManager).grantImplicitAccess(
Patrick Baumann710d7202020-01-09 15:02:14 -0800349 anyInt(), any(), anyInt(), anyInt(), anyBoolean());
Louis Chang54fbb052019-10-16 17:10:17 +0800350 doNothing().when(mMockPackageManager).notifyPackageUse(anyString(), anyInt());
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700351
Bryce Lee32e09ef2018-03-19 15:29:49 -0700352 final Intent intent = new Intent();
353 intent.addFlags(launchFlags);
354 intent.setComponent(ActivityBuilder.getDefaultComponent());
355
356 final ActivityInfo info = new ActivityInfo();
357
358 info.applicationInfo = new ApplicationInfo();
359 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
360
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700361 return new ActivityStarter(mController, mService,
Bryce Lee32e09ef2018-03-19 15:29:49 -0700362 mService.mStackSupervisor, mock(ActivityStartInterceptor.class))
363 .setIntent(intent)
364 .setActivityInfo(info);
Bryce Leead5b8322018-03-08 14:28:52 -0800365 }
366
367 /**
368 * Ensures that values specified at launch time are passed to {@link LaunchParamsModifier}
369 * when we are laying out a new task.
370 */
371 @Test
372 public void testCreateTaskLayout() {
373 // modifier for validating passed values.
374 final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
375 mService.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
376
377 // add custom values to activity info to make unique.
378 final ActivityInfo info = new ActivityInfo();
379 final Rect launchBounds = new Rect(0, 0, 20, 30);
Bryce Leead5b8322018-03-08 14:28:52 -0800380
381 final WindowLayout windowLayout =
382 new WindowLayout(10, .5f, 20, 1.0f, Gravity.NO_GRAVITY, 1, 1);
383
384 info.windowLayout = windowLayout;
385 info.applicationInfo = new ApplicationInfo();
386 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
387
388 // create starter.
Bryce Lee32e09ef2018-03-19 15:29:49 -0700389 final ActivityStarter optionStarter = prepareStarter(0 /* launchFlags */);
Bryce Leead5b8322018-03-08 14:28:52 -0800390
391 final ActivityOptions options = ActivityOptions.makeBasic();
392 options.setLaunchBounds(launchBounds);
393
394 // run starter.
395 optionStarter
Bryce Leead5b8322018-03-08 14:28:52 -0800396 .setReason("testCreateTaskLayout")
397 .setActivityInfo(info)
398 .setActivityOptions(new SafeActivityOptions(options))
399 .execute();
400
Louis Chang6fb1e842018-12-03 16:07:50 +0800401 // verify that values are passed to the modifier. Values are passed thrice -- two for
Garfield Tan706dbcb2018-10-15 11:33:02 -0700402 // setting initial state, another when task is created.
Louis Chang6fb1e842018-12-03 16:07:50 +0800403 verify(modifier, times(3)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
404 anyInt(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800405 }
Bryce Lee32e09ef2018-03-19 15:29:49 -0700406
407 /**
Louis Chang38430df2020-01-02 17:14:59 +0800408 * This test ensures that if the intent is being delivered to a split-screen unfocused task
409 * while it already on top, reports it as delivering to top.
Bryce Lee32e09ef2018-03-19 15:29:49 -0700410 */
411 @Test
412 public void testSplitScreenDeliverToTop() {
Louis Chang38430df2020-01-02 17:14:59 +0800413 final ActivityStarter starter = prepareStarter(
414 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
415 final ActivityRecord splitPrimaryFocusActivity =
416 new ActivityBuilder(mService).setCreateTask(true).build();
417 final ActivityRecord splitSecondReusableActivity =
418 new ActivityBuilder(mService).setCreateTask(true).build();
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800419 splitPrimaryFocusActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800420 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800421 splitSecondReusableActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800422 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700423
424 // Set focus back to primary.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800425 splitPrimaryFocusActivity.getRootTask().moveToFront("testSplitScreenDeliverToTop");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700426
Louis Chang38430df2020-01-02 17:14:59 +0800427 // Start activity and delivered new intent.
428 starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
Andrii Kulian1cfcae82020-04-10 12:44:38 -0700429 doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), any());
Bryce Lee32e09ef2018-03-19 15:29:49 -0700430 final int result = starter.setReason("testSplitScreenDeliverToTop").execute();
431
432 // Ensure result is delivering intent to top.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900433 assertEquals(START_DELIVERED_TO_TOP, result);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700434 }
435
436 /**
437 * This test ensures that if the intent is being delivered to a split-screen unfocused task
438 * reports it is brought to front instead of delivering to top.
439 */
440 @Test
441 public void testSplitScreenTaskToFront() {
Louis Chang38430df2020-01-02 17:14:59 +0800442 final ActivityStarter starter = prepareStarter(
443 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
444 final ActivityRecord splitSecondReusableActivity =
445 new ActivityBuilder(mService).setCreateTask(true).build();
446 final ActivityRecord splitSecondTopActivity =
447 new ActivityBuilder(mService).setCreateTask(true).build();
448 final ActivityRecord splitPrimaryFocusActivity =
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);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800454 splitSecondTopActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800455 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700456
Louis Chang38430df2020-01-02 17:14:59 +0800457 // Make it on top of split-screen-secondary.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800458 splitSecondTopActivity.getRootTask().moveToFront("testSplitScreenTaskToFront");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700459
Louis Chang38430df2020-01-02 17:14:59 +0800460 // Let primary stack has focus.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800461 splitPrimaryFocusActivity.getRootTask().moveToFront("testSplitScreenTaskToFront");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700462
Louis Chang38430df2020-01-02 17:14:59 +0800463 // Start activity and delivered new intent.
464 starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
Andrii Kulian1cfcae82020-04-10 12:44:38 -0700465 doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), any());
Bryce Lee32e09ef2018-03-19 15:29:49 -0700466 final int result = starter.setReason("testSplitScreenMoveToFront").execute();
467
468 // Ensure result is moving task to front.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900469 assertEquals(START_TASK_TO_FRONT, result);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700470 }
Bryce Lee2b8e0372018-04-05 17:01:37 -0700471
472 /**
473 * Tests activity is cleaned up properly in a task mode violation.
474 */
475 @Test
476 public void testTaskModeViolation() {
Louis Chang149d5c82019-12-30 09:47:39 +0800477 final DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700478 display.removeAllTasks();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700479 assertNoTasks(display);
480
481 final ActivityStarter starter = prepareStarter(0);
482
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700483 final LockTaskController lockTaskController = mService.getLockTaskController();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700484 doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
485
486 final int result = starter.setReason("testTaskModeViolation").execute();
487
488 assertEquals(START_RETURN_LOCK_TASK_MODE_VIOLATION, result);
489 assertNoTasks(display);
490 }
491
Louis Chang677921f2019-12-06 16:44:24 +0800492 private void assertNoTasks(DisplayContent display) {
Andrii Kulianf9df4a82020-03-31 12:09:27 -0700493 for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
494 final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
495 for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
496 final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
497 assertFalse(stack.hasChild());
498 }
Bryce Lee2b8e0372018-04-05 17:01:37 -0700499 }
500 }
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100501
502 /**
503 * This test ensures that activity starts are not being logged when the logging is disabled.
504 */
505 @Test
506 public void testActivityStartsLogging_noLoggingWhenDisabled() {
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700507 doReturn(false).when(mService).isActivityStartsLoggingEnabled();
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100508 doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
509
510 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK);
511 starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute();
512
513 // verify logging wasn't done
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000514 verify(mActivityMetricsLogger, never()).logAbortedBgActivityStart(any(), any(), anyInt(),
515 any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100516 }
517
518 /**
519 * This test ensures that activity starts are being logged when the logging is enabled.
520 */
521 @Test
522 public void testActivityStartsLogging_logsWhenEnabled() {
523 // note: conveniently this package doesn't have any activity visible
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700524 doReturn(true).when(mService).isActivityStartsLoggingEnabled();
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100525 doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
526
527 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
528 .setCallingUid(FAKE_CALLING_UID)
529 .setRealCallingUid(FAKE_REAL_CALLING_UID)
530 .setCallingPackage(FAKE_CALLING_PACKAGE)
531 .setOriginatingPendingIntent(null);
532
533 starter.setReason("testActivityStartsLogging_logsWhenEnabled").execute();
534
535 // verify the above activity start was logged
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000536 verify(mActivityMetricsLogger, times(1)).logAbortedBgActivityStart(any(), any(),
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100537 eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(),
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000538 eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), eq(false));
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100539 }
Riddle Hsub70b36d2018-09-11 21:20:02 +0800540
541 /**
Michal Karpinski8596ded2018-11-14 14:43:48 +0000542 * This test ensures that unsupported usecases aren't aborted when background starts are
543 * allowed.
544 */
545 @Test
546 public void testBackgroundActivityStartsAllowed_noStartsAborted() {
547 doReturn(true).when(mService).isBackgroundActivityStartsEnabled();
548
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000549 runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
550 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
551 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100552 false, false, false, false, false);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000553 }
554
555 /**
556 * This test ensures that unsupported usecases are aborted when background starts are
557 * disallowed.
558 */
559 @Test
560 public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
561 doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
562
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000563 runAndVerifyBackgroundActivityStartsSubtest(
564 "disallowed_unsupportedUsecase_aborted", true,
565 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
566 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100567 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100568 runAndVerifyBackgroundActivityStartsSubtest(
569 "disallowed_callingUidProcessStateTop_aborted", true,
570 UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
571 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100572 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100573 runAndVerifyBackgroundActivityStartsSubtest(
574 "disallowed_realCallingUidProcessStateTop_aborted", true,
575 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
576 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
Alan Stokes9e245762019-05-21 14:54:28 +0100577 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100578 runAndVerifyBackgroundActivityStartsSubtest(
579 "disallowed_hasForegroundActivities_aborted", true,
580 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
581 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100582 true, false, false, false, false);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000583 }
584
585 /**
586 * This test ensures that supported usecases aren't aborted when background starts are
587 * disallowed.
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100588 * The scenarios each have only one condition that makes them supported.
Michal Karpinski8596ded2018-11-14 14:43:48 +0000589 */
590 @Test
591 public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
592 doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
593
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000594 runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
595 Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
596 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100597 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000598 runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
599 Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
600 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100601 false, false, false, false, false);
Michal Karpinskib416f472019-01-24 14:34:28 +0000602 runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false,
603 Process.NFC_UID, false, PROCESS_STATE_TOP + 1,
604 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100605 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000606 runAndVerifyBackgroundActivityStartsSubtest(
607 "disallowed_callingUidHasVisibleWindow_notAborted", false,
608 UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
609 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100610 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000611 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000612 "disallowed_realCallingUidHasVisibleWindow_notAborted", false,
613 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
614 UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100615 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000616 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000617 "disallowed_callerIsRecents_notAborted", false,
618 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
619 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100620 false, true, false, false, false);
Michal Karpinskiac116df2018-12-10 17:51:42 +0000621 runAndVerifyBackgroundActivityStartsSubtest(
622 "disallowed_callerIsWhitelisted_notAborted", false,
623 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
624 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100625 false, false, true, false, false);
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000626 runAndVerifyBackgroundActivityStartsSubtest(
627 "disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted",
628 false,
629 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
630 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100631 false, false, false, true, false);
Michal Karpinski302dcec2019-02-01 11:48:25 +0000632 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski4026cae2019-02-12 11:51:47 +0000633 "disallowed_callingPackageNameIsDeviceOwner_notAborted", false,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000634 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
635 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100636 false, false, false, false, true);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000637 }
638
639 private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000640 int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
641 int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
Michal Karpinskiac116df2018-12-10 17:51:42 +0000642 boolean hasForegroundActivities, boolean callerIsRecents,
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000643 boolean callerIsTempWhitelisted,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000644 boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
Alan Stokes9e245762019-05-21 14:54:28 +0100645 boolean isCallingUidDeviceOwner) {
Michal Karpinski8596ded2018-11-14 14:43:48 +0000646 // window visibility
Michal Karpinskia606a292019-01-12 17:29:52 +0000647 doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
648 .isAnyNonToastWindowVisibleForUid(callingUid);
649 doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
650 .isAnyNonToastWindowVisibleForUid(realCallingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000651 // process importance
Riddle Hsua0536432019-02-16 00:38:59 +0800652 doReturn(callingUidProcState).when(mService).getUidState(callingUid);
653 doReturn(realCallingUidProcState).when(mService).getUidState(realCallingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000654 // foreground activities
655 final IApplicationThread caller = mock(IApplicationThread.class);
Darryl L Johnson15192d32020-01-15 15:31:42 -0800656 final WindowProcessListener listener = mock(WindowProcessListener.class);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000657 final ApplicationInfo ai = new ApplicationInfo();
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000658 ai.uid = callingUid;
Darryl L Johnsona0982222020-02-18 18:21:51 -0800659 ai.packageName = "com.android.test.package";
Michal Karpinski8596ded2018-11-14 14:43:48 +0000660 final WindowProcessController callerApp =
Darryl L Johnson15192d32020-01-15 15:31:42 -0800661 new WindowProcessController(mService, ai, null, callingUid, -1, null, listener);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000662 callerApp.setHasForegroundActivities(hasForegroundActivities);
663 doReturn(callerApp).when(mService).getProcessController(caller);
Michal Karpinski82bb5902018-11-28 15:52:52 +0000664 // caller is recents
665 RecentTasks recentTasks = mock(RecentTasks.class);
666 mService.mStackSupervisor.setRecentTasks(recentTasks);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000667 doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
Michal Karpinskiac116df2018-12-10 17:51:42 +0000668 // caller is temp whitelisted
669 callerApp.setAllowBackgroundActivityStarts(callerIsTempWhitelisted);
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000670 // caller is instrumenting with background activity starts privileges
Michal Karpinski4bc56492019-01-31 12:07:33 +0000671 callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000672 callerIsInstrumentingWithBackgroundActivityStartPrivileges);
Ricky Wai96f5c352019-04-10 18:40:17 +0100673 // callingUid is the device owner
674 doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000675
676 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700677 ActivityRecord[] outActivity = new ActivityRecord[1];
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000678 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
Michal Karpinski666631b2019-02-26 16:59:11 +0000679 .setCallingPackage("com.whatever.dude")
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000680 .setCaller(caller)
681 .setCallingUid(callingUid)
682 .setRealCallingUid(realCallingUid)
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700683 .setActivityOptions(new SafeActivityOptions(options))
684 .setOutActivity(outActivity);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000685
686 final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();
687
688 assertEquals(ActivityStarter.getExternalResult(
689 shouldHaveAborted ? START_ABORTED : START_SUCCESS), result);
690 verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700691
692 final ActivityRecord startedActivity = outActivity[0];
Louis Changcdec0802019-11-11 11:45:07 +0800693 if (startedActivity != null && startedActivity.getTask() != null) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700694 // Remove the activity so it doesn't interfere with with subsequent activity launch
695 // tests from this method.
Louis Changcdec0802019-11-11 11:45:07 +0800696 startedActivity.getTask().removeChild(startedActivity);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700697 }
Michal Karpinski8596ded2018-11-14 14:43:48 +0000698 }
699
700 /**
Riddle Hsu273e9992019-04-29 22:40:59 +0800701 * This test ensures that {@link ActivityStarter#setTargetStackAndMoveToFrontIfNeeded} will
702 * move the existing task to front if the current focused stack doesn't have running task.
703 */
704 @Test
705 public void testBringTaskToFrontWhenFocusedStackIsFinising() {
706 // Put 2 tasks in the same stack (simulate the behavior of home stack).
707 final ActivityRecord activity = new ActivityBuilder(mService)
708 .setCreateTask(true).build();
709 new ActivityBuilder(mService)
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800710 .setStack(activity.getRootTask())
Riddle Hsu273e9992019-04-29 22:40:59 +0800711 .setCreateTask(true).build();
712
713 // Create a top finishing activity.
714 final ActivityRecord finishingTopActivity = new ActivityBuilder(mService)
715 .setCreateTask(true).build();
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800716 finishingTopActivity.getRootTask().moveToFront("finishingTopActivity");
Riddle Hsu273e9992019-04-29 22:40:59 +0800717
Louis Chang149d5c82019-12-30 09:47:39 +0800718 assertEquals(finishingTopActivity, mRootWindowContainer.topRunningActivity());
Riddle Hsu273e9992019-04-29 22:40:59 +0800719 finishingTopActivity.finishing = true;
720
721 // Launch the bottom task of the target stack.
722 prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetLaunchStack */)
723 .setReason("testBringTaskToFrontWhenTopStackIsFinising")
724 .setIntent(activity.intent)
725 .execute();
726 // The hierarchies of the activity should move to front.
Louis Chang149d5c82019-12-30 09:47:39 +0800727 assertEquals(activity, mRootWindowContainer.topRunningActivity());
Riddle Hsu273e9992019-04-29 22:40:59 +0800728 }
729
730 /**
Riddle Hsub70b36d2018-09-11 21:20:02 +0800731 * This test ensures that when starting an existing single task activity on secondary display
732 * which is not the top focused display, it should deliver new intent to the activity and not
733 * create a new stack.
734 */
735 @Test
736 public void testDeliverIntentToTopActivityOfNonTopDisplay() {
737 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
738 false /* mockGetLaunchStack */);
739
740 // Create a secondary display at bottom.
Louis Chang677921f2019-12-06 16:44:24 +0800741 final TestDisplayContent secondaryDisplay =
742 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700743 .setPosition(POSITION_BOTTOM).build();
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700744 final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
Andrii Kulian86d676c2020-03-27 19:34:54 -0700745 final ActivityStack stack = secondaryTaskContainer.createStack(
746 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Riddle Hsub70b36d2018-09-11 21:20:02 +0800747
748 // Create an activity record on the top of secondary display.
Riddle Hsufd4a0502018-10-16 01:05:16 +0800749 final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
Riddle Hsub70b36d2018-09-11 21:20:02 +0800750
751 // Put an activity on default display as the top focused activity.
752 new ActivityBuilder(mService).setCreateTask(true).build();
753
754 // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
755 // on secondary display.
756 final ActivityOptions options = ActivityOptions.makeBasic()
757 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
758 final int result = starter.setReason("testDeliverIntentToTopActivityOfNonTopDisplay")
759 .setIntent(topActivityOnSecondaryDisplay.intent)
760 .setActivityOptions(options.toBundle())
761 .execute();
762
763 // Ensure result is delivering intent to top.
764 assertEquals(START_DELIVERED_TO_TOP, result);
765
766 // Ensure secondary display only creates one stack.
Andrii Kulian86d676c2020-03-27 19:34:54 -0700767 verify(secondaryTaskContainer, times(1)).createStack(anyInt(), anyInt(), anyBoolean());
Riddle Hsub70b36d2018-09-11 21:20:02 +0800768 }
769
770 /**
Riddle Hsufd4a0502018-10-16 01:05:16 +0800771 * This test ensures that when starting an existing non-top single task activity on secondary
772 * display which is the top focused display, it should bring the task to front without creating
773 * unused stack.
774 */
775 @Test
776 public void testBringTaskToFrontOnSecondaryDisplay() {
777 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
778 false /* mockGetLaunchStack */);
779
780 // Create a secondary display with an activity.
Louis Chang677921f2019-12-06 16:44:24 +0800781 final TestDisplayContent secondaryDisplay =
782 new TestDisplayContent.Builder(mService, 1000, 1500).build();
Louis Chang149d5c82019-12-30 09:47:39 +0800783 mRootWindowContainer.positionChildAt(POSITION_TOP, secondaryDisplay,
Louis Chang3ff72a82019-12-17 12:12:59 +0800784 false /* includingParents */);
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700785 final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
Riddle Hsufd4a0502018-10-16 01:05:16 +0800786 final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
Andrii Kulian86d676c2020-03-27 19:34:54 -0700787 secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN,
Riddle Hsufd4a0502018-10-16 01:05:16 +0800788 ACTIVITY_TYPE_STANDARD, false /* onTop */));
789
790 // Create another activity on top of the secondary display.
Andrii Kulian86d676c2020-03-27 19:34:54 -0700791 final ActivityStack topStack = secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN,
Riddle Hsufd4a0502018-10-16 01:05:16 +0800792 ACTIVITY_TYPE_STANDARD, true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800793 final Task topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
Riddle Hsufd4a0502018-10-16 01:05:16 +0800794 new ActivityBuilder(mService).setTask(topTask).build();
795
796 // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
797 final ActivityOptions options = ActivityOptions.makeBasic()
798 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
799 final int result = starter.setReason("testBringTaskToFrontOnSecondaryDisplay")
800 .setIntent(singleTaskActivity.intent)
801 .setActivityOptions(options.toBundle())
802 .execute();
803
804 // Ensure result is moving existing task to front.
805 assertEquals(START_TASK_TO_FRONT, result);
806
807 // Ensure secondary display only creates two stacks.
Andrii Kulian86d676c2020-03-27 19:34:54 -0700808 verify(secondaryTaskContainer, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
Riddle Hsufd4a0502018-10-16 01:05:16 +0800809 }
810
Evan Rosky8d1c24e2020-04-23 09:21:16 -0700811 @Test
812 public void testWasVisibleInRestartAttempt() {
813 final ActivityStarter starter = prepareStarter(
814 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
815 final ActivityRecord reusableActivity =
816 new ActivityBuilder(mService).setCreateTask(true).build();
817 final ActivityRecord topActivity =
818 new ActivityBuilder(mService).setCreateTask(true).build();
819
820 // Make sure topActivity is on top
821 topActivity.getRootTask().moveToFront("testWasVisibleInRestartAttempt");
822 reusableActivity.setVisible(false);
823
824 final TaskChangeNotificationController taskChangeNotifier =
825 mService.getTaskChangeNotificationController();
826 spyOn(taskChangeNotifier);
827
828 Task task = topActivity.getTask();
829 starter.postStartActivityProcessing(
830 task.getTopNonFinishingActivity(), START_DELIVERED_TO_TOP, task.getStack());
831
832 verify(taskChangeNotifier).notifyActivityRestartAttempt(
833 any(), anyBoolean(), anyBoolean(), anyBoolean());
834 verify(taskChangeNotifier).notifyActivityRestartAttempt(
835 any(), anyBoolean(), anyBoolean(), eq(true));
836
837 Task task2 = reusableActivity.getTask();
838 starter.postStartActivityProcessing(
839 task2.getTopNonFinishingActivity(), START_TASK_TO_FRONT, task.getStack());
840 verify(taskChangeNotifier, times(2)).notifyActivityRestartAttempt(
841 any(), anyBoolean(), anyBoolean(), anyBoolean());
842 verify(taskChangeNotifier).notifyActivityRestartAttempt(
843 any(), anyBoolean(), anyBoolean(), eq(false));
844 }
845
Riddle Hsufd4a0502018-10-16 01:05:16 +0800846 private ActivityRecord createSingleTaskActivityOn(ActivityStack stack) {
847 final ComponentName componentName = ComponentName.createRelative(
848 DEFAULT_COMPONENT_PACKAGE_NAME,
849 DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
Louis Changcdec0802019-11-11 11:45:07 +0800850 final Task task = new TaskBuilder(mSupervisor)
Riddle Hsufd4a0502018-10-16 01:05:16 +0800851 .setComponent(componentName)
852 .setStack(stack)
853 .build();
854 return new ActivityBuilder(mService)
855 .setComponent(componentName)
856 .setLaunchMode(LAUNCH_SINGLE_TASK)
Louis Changcdec0802019-11-11 11:45:07 +0800857 .setTask(task)
Riddle Hsufd4a0502018-10-16 01:05:16 +0800858 .build();
859 }
860
861 /**
Riddle Hsub70b36d2018-09-11 21:20:02 +0800862 * This test ensures that a reused top activity in the top focused stack is able to be
863 * reparented to another display.
864 */
865 @Test
866 public void testReparentTopFocusedActivityToSecondaryDisplay() {
867 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
868 false /* mockGetLaunchStack */);
869
870 // Create a secondary display at bottom.
Louis Chang677921f2019-12-06 16:44:24 +0800871 final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM);
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700872 final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
Andrii Kulian86d676c2020-03-27 19:34:54 -0700873 secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
Riddle Hsub70b36d2018-09-11 21:20:02 +0800874 true /* onTop */);
875
876 // Put an activity on default display as the top focused activity.
877 final ActivityRecord topActivity = new ActivityBuilder(mService)
878 .setCreateTask(true)
879 .setLaunchMode(LAUNCH_SINGLE_TASK)
880 .build();
881
882 // Start activity with the same intent as {@code topActivity} on secondary display.
883 final ActivityOptions options = ActivityOptions.makeBasic()
884 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
885 starter.setReason("testReparentTopFocusedActivityToSecondaryDisplay")
886 .setIntent(topActivity.intent)
887 .setActivityOptions(options.toBundle())
888 .execute();
889
890 // Ensure the activity is moved to secondary display.
891 assertEquals(secondaryDisplay, topActivity.getDisplay());
892 }
Winson Chunge219ae12019-07-18 13:43:23 -0700893
894 /**
895 * This test ensures that starting an activity with the freeze-task-list activity option will
896 * actually freeze the task list
897 */
898 @Test
899 public void testFreezeTaskListActivityOption() {
900 RecentTasks recentTasks = mock(RecentTasks.class);
901 mService.mStackSupervisor.setRecentTasks(recentTasks);
902 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
903
904 final ActivityStarter starter = prepareStarter(0 /* flags */);
905 final ActivityOptions options = ActivityOptions.makeBasic();
906 options.setFreezeRecentTasksReordering();
907
908 starter.setReason("testFreezeTaskListActivityOption")
909 .setActivityOptions(new SafeActivityOptions(options))
910 .execute();
911
912 verify(recentTasks, times(1)).setFreezeTaskListReordering();
913 verify(recentTasks, times(0)).resetFreezeTaskListReorderingOnTimeout();
914 }
915
916 /**
917 * This test ensures that if we froze the task list as a part of starting an activity that fails
918 * to start, that we also reset the task list.
919 */
920 @Test
921 public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() {
922 RecentTasks recentTasks = mock(RecentTasks.class);
923 mService.mStackSupervisor.setRecentTasks(recentTasks);
924 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
925
926 final ActivityStarter starter = prepareStarter(0 /* flags */);
927 final ActivityOptions options = ActivityOptions.makeBasic();
928 options.setFreezeRecentTasksReordering();
929
930 starter.setReason("testFreezeTaskListActivityOptionFailedStart")
931 .setActivityOptions(new SafeActivityOptions(options))
932 .execute();
933
934 // Simulate a failed start
Winson Chunge789ff62020-02-24 14:40:23 -0800935 starter.postStartActivityProcessing(null, START_CANCELED, null);
Winson Chunge219ae12019-07-18 13:43:23 -0700936
937 verify(recentTasks, times(1)).setFreezeTaskListReordering();
938 verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
939 }
Louis Chang54fbb052019-10-16 17:10:17 +0800940
941 @Test
942 public void testNoActivityInfo() {
943 final ActivityStarter starter = prepareStarter(0 /* flags */);
944 spyOn(starter.mRequest);
945
946 final Intent intent = new Intent();
947 intent.setComponent(ActivityBuilder.getDefaultComponent());
948 starter.setReason("testNoActivityInfo").setIntent(intent)
949 .setActivityInfo(null).execute();
950 verify(starter.mRequest).resolveActivity(any());
951 }
952
953 @Test
954 public void testResolveEphemeralInstaller() {
955 final ActivityStarter starter = prepareStarter(0 /* flags */);
956 final Intent intent = new Intent();
957 intent.setComponent(ActivityBuilder.getDefaultComponent());
958
959 doReturn(true).when(mMockPackageManager).isInstantAppInstallerComponent(any());
960 starter.setIntent(intent).mRequest.resolveActivity(mService.mStackSupervisor);
961
962 // Make sure the client intent won't be modified.
963 assertThat(intent.getComponent()).isNotNull();
964 assertThat(starter.getIntent().getComponent()).isNull();
965 }
966
967 @Test
968 public void testNotAllowIntentWithFd() {
969 final ActivityStarter starter = prepareStarter(0 /* flags */);
970 final Intent intent = spy(new Intent());
971 intent.setComponent(ActivityBuilder.getDefaultComponent());
972 doReturn(true).when(intent).hasFileDescriptors();
973
974 boolean exceptionCaught = false;
975 try {
976 starter.setIntent(intent).execute();
977 } catch (IllegalArgumentException ex) {
978 exceptionCaught = true;
979 }
980 assertThat(exceptionCaught).isTrue();
981 }
Louis Chang07b13002019-11-27 22:08:37 +0800982
983 @Test
984 public void testRecycleTaskFromAnotherUser() {
985 final ActivityStarter starter = prepareStarter(0 /* flags */);
986 starter.mStartActivity = new ActivityBuilder(mService).build();
987 final Task task = new TaskBuilder(mService.mStackSupervisor)
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700988 .setStack(mService.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
Louis Chang07b13002019-11-27 22:08:37 +0800989 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
990 .setUserId(10)
991 .build();
992
993 final int result = starter.recycleTask(task, null, null);
994 assertThat(result == START_SUCCESS).isTrue();
995 assertThat(starter.mAddingToTask).isTrue();
996 }
Louis Chang38430df2020-01-02 17:14:59 +0800997
998 @Test
999 public void testTargetStackInSplitScreen() {
1000 final ActivityStarter starter =
1001 prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetLaunchStack */);
1002 final ActivityRecord top = new ActivityBuilder(mService).setCreateTask(true).build();
1003 final ActivityOptions options = ActivityOptions.makeBasic();
1004 final ActivityRecord[] outActivity = new ActivityRecord[1];
1005
1006 // Activity must not land on split-screen stack if currently not in split-screen mode.
1007 starter.setActivityOptions(options.toBundle())
1008 .setReason("testWindowingModeOptionsLaunchAdjacent")
1009 .setOutActivity(outActivity).execute();
1010 assertThat(outActivity[0].inSplitScreenWindowingMode()).isFalse();
1011
1012 // Move activity to split-screen-primary stack and make sure it has the focus.
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001013 TestSplitOrganizer splitOrg = new TestSplitOrganizer(mService, top.getDisplayId());
Louis Changa009c762020-02-26 11:21:31 +08001014 top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -08001015 top.getRootTask().moveToFront("testWindowingModeOptionsLaunchAdjacent");
Louis Chang38430df2020-01-02 17:14:59 +08001016
1017 // Activity must landed on split-screen-secondary when launch adjacent.
1018 starter.setActivityOptions(options.toBundle())
1019 .setReason("testWindowingModeOptionsLaunchAdjacent")
1020 .setOutActivity(outActivity).execute();
1021 assertThat(outActivity[0].inSplitScreenSecondaryWindowingMode()).isTrue();
1022 }
Winson Chungf45dd9f2019-10-11 15:07:47 -07001023
1024 @Test
1025 public void testActivityStart_expectAddedToRecentTask() {
1026 RecentTasks recentTasks = mock(RecentTasks.class);
1027 mService.mStackSupervisor.setRecentTasks(recentTasks);
1028 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
1029
1030 final ActivityStarter starter = prepareStarter(0 /* flags */);
1031
1032 starter.setReason("testAddToTaskListOnActivityStart")
1033 .execute();
1034
1035 verify(recentTasks, times(1)).add(any());
1036 }
Wale Ogunwale44f036f2017-09-29 05:09:09 -07001037}