blob: 02d1f9b43e9135f01ee3d131bc8a8fa7b50b7f96 [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;
Diego Vela671c0072020-03-25 09:39:26 -070052import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
Louis Chang677921f2019-12-06 16:44:24 +080053import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
54import static com.android.server.wm.WindowContainer.POSITION_TOP;
Brett Chabota26eda92018-07-23 13:08:30 -070055
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090056import static com.google.common.truth.Truth.assertThat;
57
Brett Chabota26eda92018-07-23 13:08:30 -070058import static org.junit.Assert.assertEquals;
Wale Ogunwale85fb19a2019-12-05 10:41:05 +090059import static org.junit.Assert.assertFalse;
Diego Vela671c0072020-03-25 09:39:26 -070060import static org.junit.Assert.assertTrue;
Riddle Hsub70b36d2018-09-11 21:20:02 +080061import static org.mockito.ArgumentMatchers.any;
62import static org.mockito.ArgumentMatchers.anyBoolean;
63import static org.mockito.ArgumentMatchers.anyInt;
Wale Ogunwaleda8b8272018-11-29 19:37:37 -080064import static org.mockito.ArgumentMatchers.anyString;
Riddle Hsub70b36d2018-09-11 21:20:02 +080065import static org.mockito.ArgumentMatchers.eq;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070066
Bryce Lee93e7f792017-10-25 15:54:55 -070067import android.app.ActivityOptions;
68import android.app.IApplicationThread;
Riddle Hsub70b36d2018-09-11 21:20:02 +080069import android.content.ComponentName;
Bryce Lee93e7f792017-10-25 15:54:55 -070070import android.content.Intent;
71import android.content.pm.ActivityInfo;
Bryce Leead5b8322018-03-08 14:28:52 -080072import android.content.pm.ActivityInfo.WindowLayout;
Bryce Lee93e7f792017-10-25 15:54:55 -070073import android.content.pm.ApplicationInfo;
74import android.content.pm.IPackageManager;
Philip P. Moltmann6c644e62018-07-18 15:41:24 -070075import android.content.pm.PackageManagerInternal;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070076import android.graphics.Rect;
Bryce Lee93e7f792017-10-25 15:54:55 -070077import android.os.IBinder;
Michal Karpinski8596ded2018-11-14 14:43:48 +000078import android.os.Process;
Bryce Lee93e7f792017-10-25 15:54:55 -070079import android.os.RemoteException;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070080import android.platform.test.annotations.Presubmit;
Bryce Lee93e7f792017-10-25 15:54:55 -070081import android.service.voice.IVoiceInteractionSession;
Bryce Leead5b8322018-03-08 14:28:52 -080082import android.view.Gravity;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070083
Brett Chabota26eda92018-07-23 13:08:30 -070084import androidx.test.filters.SmallTest;
Brett Chabota26eda92018-07-23 13:08:30 -070085
Wale Ogunwale59507092018-10-29 09:00:30 -070086import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
Garfield Tane3d37b52019-07-23 12:43:05 -070087import com.android.server.wm.utils.MockTracker;
Bryce Lee93e7f792017-10-25 15:54:55 -070088
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090089import org.junit.Before;
Brett Chabota26eda92018-07-23 13:08:30 -070090import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +080091import org.junit.runner.RunWith;
Bryce Lee2b8e0372018-04-05 17:01:37 -070092
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070093/**
Bryce Leed3624e12017-11-30 08:51:45 -080094 * Tests for the {@link ActivityStarter} class.
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070095 *
96 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090097 * atest WmTests:ActivityStarterTests
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070098 */
99@SmallTest
100@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +0800101@RunWith(WindowTestRunner.class)
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700102public class ActivityStarterTests extends ActivityTestsBase {
Bryce 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);
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700130 }
131
132 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900133 public void testStartActivityPreconditions() {
Bryce Lee93e7f792017-10-25 15:54:55 -0700134 verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED);
135 verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT,
136 START_INTENT_NOT_RESOLVED);
137 verifyStartActivityPreconditions(PRECONDITION_NO_ACTIVITY_INFO, START_CLASS_NOT_FOUND);
138 verifyStartActivityPreconditions(PRECONDITION_SOURCE_PRESENT | PRECONDITION_REQUEST_CODE,
139 Intent.FLAG_ACTIVITY_FORWARD_RESULT, START_FORWARD_AND_REQUEST_CONFLICT);
140 verifyStartActivityPreconditions(
141 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
142 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID,
143 START_NOT_VOICE_COMPATIBLE);
144 verifyStartActivityPreconditions(
145 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
146 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID
147 | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION,
148 START_NOT_VOICE_COMPATIBLE);
149 verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED);
150 verifyStartActivityPreconditions(PRECONDITION_DISALLOW_APP_SWITCHING,
151 START_SWITCHES_CANCELED);
152 }
153
154 private static boolean containsConditions(int preconditions, int mask) {
155 return (preconditions & mask) == mask;
156 }
157
158 private void verifyStartActivityPreconditions(int preconditions, int expectedResult) {
159 verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
160 }
161
Garfield Tane3d37b52019-07-23 12:43:05 -0700162 private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
163 int expectedResult) {
164 // We track mocks created here because this is used in a single test
165 // (testStartActivityPreconditions) as a specific case, and mocks created inside it won't be
166 // used for other cases. To avoid extensive memory usage, we clean up all used mocks after
167 // each case. This is necessary because usually we only clean up mocks after a test
168 // finishes, but this test creates too many mocks that the intermediate memory usage can be
169 // ~0.8 GiB and thus very susceptible to OutOfMemoryException.
170 try (MockTracker tracker = new MockTracker()) {
171 verifyStartActivityPreconditionsUntracked(preconditions, launchFlags, expectedResult);
172 }
173 }
174
Bryce Lee93e7f792017-10-25 15:54:55 -0700175 /**
176 * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
177 * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
178 * and the launch flags specified in the intent. The method constructs a call to
Bryce Lee4c9a5972017-12-01 22:14:24 -0800179 * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
180 * the expected. It is important to note that the method also checks side effects of the start,
181 * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
Diego Vela671c0072020-03-25 09:39:26 -0700182 *
Bryce Lee93e7f792017-10-25 15:54:55 -0700183 * @param preconditions A bitmask representing the preconditions for the launch
184 * @param launchFlags The launch flags to be provided by the launch {@link Intent}.
185 * @param expectedResult The expected result from the launch.
186 */
Garfield Tane3d37b52019-07-23 12:43:05 -0700187 private void verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags,
Bryce Lee93e7f792017-10-25 15:54:55 -0700188 int expectedResult) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700189 final ActivityTaskManagerService service = mService;
Bryce Lee93e7f792017-10-25 15:54:55 -0700190 final IPackageManager packageManager = mock(IPackageManager.class);
Bryce Leed3624e12017-11-30 08:51:45 -0800191 final ActivityStartController controller = mock(ActivityStartController.class);
Bryce Lee93e7f792017-10-25 15:54:55 -0700192
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700193 final ActivityStarter starter = new ActivityStarter(controller, service,
Bryce Leed3624e12017-11-30 08:51:45 -0800194 service.mStackSupervisor, mock(ActivityStartInterceptor.class));
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700195 prepareStarter(launchFlags);
Bryce Lee93e7f792017-10-25 15:54:55 -0700196 final IApplicationThread caller = mock(IApplicationThread.class);
Darryl L Johnson15192d32020-01-15 15:31:42 -0800197 final WindowProcessListener listener = mock(WindowProcessListener.class);
Bryce Lee93e7f792017-10-25 15:54:55 -0700198
Darryl L Johnsona0982222020-02-18 18:21:51 -0800199 final ApplicationInfo ai = new ApplicationInfo();
200 ai.packageName = "com.android.test.package";
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700201 final WindowProcessController wpc =
202 containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
Darryl L Johnsona0982222020-02-18 18:21:51 -0800203 ? null : new WindowProcessController(service, ai, null, 0, -1, null, listener);
Diego Vela671c0072020-03-25 09:39:26 -0700204 doReturn(wpc).when(service).getProcessController(any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700205
206 final Intent intent = new Intent();
207 intent.setFlags(launchFlags);
208
209 final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO)
210 ? null : new ActivityInfo();
211
Bryce Lee93e7f792017-10-25 15:54:55 -0700212 IVoiceInteractionSession voiceSession =
213 containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
214 ? mock(IVoiceInteractionSession.class) : null;
215
216 // Create source token
217 final ActivityBuilder builder = new ActivityBuilder(service).setTask(
218 new TaskBuilder(service.mStackSupervisor).setVoiceSession(voiceSession).build());
219
Bryce Leefbd263b42018-03-07 10:33:55 -0800220 if (aInfo != null) {
221 aInfo.applicationInfo = new ApplicationInfo();
Bryce Leead5b8322018-03-08 14:28:52 -0800222 aInfo.applicationInfo.packageName =
223 ActivityBuilder.getDefaultComponent().getPackageName();
Bryce Leefbd263b42018-03-07 10:33:55 -0800224 }
225
Bryce Lee93e7f792017-10-25 15:54:55 -0700226 // Offset uid by one from {@link ActivityInfo} to simulate different uids.
227 if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) {
228 builder.setUid(aInfo.applicationInfo.uid + 1);
229 }
230
231 final ActivityRecord source = builder.build();
232
233 if (!containsConditions(preconditions, PRECONDITION_NO_INTENT_COMPONENT)) {
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800234 intent.setComponent(source.mActivityComponent);
Bryce Lee93e7f792017-10-25 15:54:55 -0700235 }
236
237 if (containsConditions(preconditions, PRECONDITION_DISALLOW_APP_SWITCHING)) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700238 doReturn(false).when(service).checkAppSwitchAllowedLocked(
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700239 anyInt(), anyInt(), anyInt(), anyInt(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700240 }
241
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900242 if (containsConditions(preconditions, PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
Bryce Lee93e7f792017-10-25 15:54:55 -0700243 doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission(
Philip P. Moltmannee295092020-02-10 08:46:26 -0800244 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700245 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700246 }
247
248 try {
249 if (containsConditions(preconditions,
250 PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION)) {
251 doAnswer((inv) -> {
252 throw new RemoteException();
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800253 }).when(packageManager).activitySupportsIntent(
254 eq(source.mActivityComponent), eq(intent), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700255 } else {
256 doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT))
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800257 .when(packageManager).activitySupportsIntent(eq(source.mActivityComponent),
Bryce Lee93e7f792017-10-25 15:54:55 -0700258 eq(intent), any());
259 }
260 } catch (RemoteException e) {
261 }
262
263 final IBinder resultTo = containsConditions(preconditions, PRECONDITION_SOURCE_PRESENT)
264 || containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
265 ? source.appToken : null;
266
267 final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE)
268 ? 1 : 0;
269
Bryce Lee4c9a5972017-12-01 22:14:24 -0800270 final int result = starter.setCaller(caller)
271 .setIntent(intent)
272 .setActivityInfo(aInfo)
273 .setResultTo(resultTo)
274 .setRequestCode(requestCode)
275 .setReason("testLaunchActivityPermissionDenied")
276 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700277
278 // In some cases the expected result internally is different than the published result. We
279 // must use ActivityStarter#getExternalResult to translate.
280 assertEquals(ActivityStarter.getExternalResult(expectedResult), result);
281
282 // Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
283 if (expectedResult != START_SUCCESS) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700284 final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
Bryce Lee4c9a5972017-12-01 22:14:24 -0800285 mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
Bryce Lee93e7f792017-10-25 15:54:55 -0700286 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Bryce Lee4c9a5972017-12-01 22:14:24 -0800287
288 final int optionResult = optionStarter.setCaller(caller)
289 .setIntent(intent)
290 .setActivityInfo(aInfo)
291 .setResultTo(resultTo)
292 .setRequestCode(requestCode)
293 .setReason("testLaunchActivityPermissionDenied")
Jorim Jaggi4d8d32c2018-01-19 15:57:41 +0100294 .setActivityOptions(new SafeActivityOptions(options))
Bryce Lee4c9a5972017-12-01 22:14:24 -0800295 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700296 verify(options, times(1)).abort();
297 }
298 }
Bryce Leeb802ea12017-11-15 21:25:03 -0800299
Riddle Hsub70b36d2018-09-11 21:20:02 +0800300 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) {
301 return prepareStarter(launchFlags, true /* mockGetLaunchStack */);
302 }
303
304 /**
305 * Creates a {@link ActivityStarter} with default parameters and necessary mocks.
306 *
307 * @param launchFlags The intent flags to launch activity.
Louis Chang149d5c82019-12-30 09:47:39 +0800308 * @param mockGetLaunchStack Whether to mock {@link RootWindowContainer#getLaunchStack} for
Riddle Hsub70b36d2018-09-11 21:20:02 +0800309 * always launching to the testing stack. Set to false when allowing
310 * the activity can be launched to any stack that is decided by real
311 * implementation.
312 * @return A {@link ActivityStarter} with default setup.
313 */
314 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
315 boolean mockGetLaunchStack) {
Bryce Leead5b8322018-03-08 14:28:52 -0800316 // always allow test to start activity.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800317 doReturn(true).when(mSupervisor).checkStartAnyActivityPermission(
Philip P. Moltmannee295092020-02-10 08:46:26 -0800318 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700319 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800320
Riddle Hsub70b36d2018-09-11 21:20:02 +0800321 if (mockGetLaunchStack) {
Riddle Hsuff9e8282019-04-24 23:55:11 +0800322 // Instrument the stack and task used.
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700323 final ActivityStack stack = mRootWindowContainer.getDefaultTaskDisplayArea()
324 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
325 true /* onTop */);
Riddle Hsuff9e8282019-04-24 23:55:11 +0800326
Riddle Hsub70b36d2018-09-11 21:20:02 +0800327 // Direct starter to use spy stack.
Louis Chang149d5c82019-12-30 09:47:39 +0800328 doReturn(stack).when(mRootWindowContainer)
Riddle Hsub70b36d2018-09-11 21:20:02 +0800329 .getLaunchStack(any(), any(), any(), anyBoolean());
Louis Chang149d5c82019-12-30 09:47:39 +0800330 doReturn(stack).when(mRootWindowContainer)
lumarkf65e02d2019-09-14 19:25:21 +0800331 .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
Riddle Hsub70b36d2018-09-11 21:20:02 +0800332 }
Bryce Leead5b8322018-03-08 14:28:52 -0800333
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700334 // Set up mock package manager internal and make sure no unmocked methods are called
Louis Chang54fbb052019-10-16 17:10:17 +0800335 mMockPackageManager = mock(PackageManagerInternal.class,
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700336 invocation -> {
337 throw new RuntimeException("Not stubbed");
338 });
Louis Chang54fbb052019-10-16 17:10:17 +0800339 doReturn(mMockPackageManager).when(mService).getPackageManagerInternalLocked();
340 doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
341 doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyInt(), anyInt(),
Patrick Baumann2fa1c952020-01-28 09:41:22 -0800342 anyInt(), anyBoolean(), anyInt());
Darryl L Johnsona0982222020-02-18 18:21:51 -0800343 doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent();
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700344
345 // Never review permissions
Louis Chang54fbb052019-10-16 17:10:17 +0800346 doReturn(false).when(mMockPackageManager).isPermissionsReviewRequired(any(), anyInt());
347 doNothing().when(mMockPackageManager).grantImplicitAccess(
Patrick Baumann710d7202020-01-09 15:02:14 -0800348 anyInt(), any(), anyInt(), anyInt(), anyBoolean());
Louis Chang54fbb052019-10-16 17:10:17 +0800349 doNothing().when(mMockPackageManager).notifyPackageUse(anyString(), anyInt());
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700350
Bryce Lee32e09ef2018-03-19 15:29:49 -0700351 final Intent intent = new Intent();
352 intent.addFlags(launchFlags);
353 intent.setComponent(ActivityBuilder.getDefaultComponent());
354
355 final ActivityInfo info = new ActivityInfo();
356
357 info.applicationInfo = new ApplicationInfo();
358 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
359
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700360 return new ActivityStarter(mController, mService,
Bryce Lee32e09ef2018-03-19 15:29:49 -0700361 mService.mStackSupervisor, mock(ActivityStartInterceptor.class))
362 .setIntent(intent)
363 .setActivityInfo(info);
Bryce Leead5b8322018-03-08 14:28:52 -0800364 }
365
366 /**
367 * Ensures that values specified at launch time are passed to {@link LaunchParamsModifier}
368 * when we are laying out a new task.
369 */
370 @Test
371 public void testCreateTaskLayout() {
372 // modifier for validating passed values.
373 final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
374 mService.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
375
376 // add custom values to activity info to make unique.
377 final ActivityInfo info = new ActivityInfo();
378 final Rect launchBounds = new Rect(0, 0, 20, 30);
Bryce Leead5b8322018-03-08 14:28:52 -0800379
380 final WindowLayout windowLayout =
381 new WindowLayout(10, .5f, 20, 1.0f, Gravity.NO_GRAVITY, 1, 1);
382
383 info.windowLayout = windowLayout;
384 info.applicationInfo = new ApplicationInfo();
385 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
386
387 // create starter.
Bryce Lee32e09ef2018-03-19 15:29:49 -0700388 final ActivityStarter optionStarter = prepareStarter(0 /* launchFlags */);
Bryce Leead5b8322018-03-08 14:28:52 -0800389
390 final ActivityOptions options = ActivityOptions.makeBasic();
391 options.setLaunchBounds(launchBounds);
392
393 // run starter.
394 optionStarter
Bryce Leead5b8322018-03-08 14:28:52 -0800395 .setReason("testCreateTaskLayout")
396 .setActivityInfo(info)
397 .setActivityOptions(new SafeActivityOptions(options))
398 .execute();
399
Louis Chang6fb1e842018-12-03 16:07:50 +0800400 // verify that values are passed to the modifier. Values are passed thrice -- two for
Garfield Tan706dbcb2018-10-15 11:33:02 -0700401 // setting initial state, another when task is created.
Louis Chang6fb1e842018-12-03 16:07:50 +0800402 verify(modifier, times(3)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
403 anyInt(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800404 }
Bryce Lee32e09ef2018-03-19 15:29:49 -0700405
406 /**
Louis Chang38430df2020-01-02 17:14:59 +0800407 * This test ensures that if the intent is being delivered to a split-screen unfocused task
408 * while it already on top, reports it as delivering to top.
Bryce Lee32e09ef2018-03-19 15:29:49 -0700409 */
410 @Test
411 public void testSplitScreenDeliverToTop() {
Louis Chang38430df2020-01-02 17:14:59 +0800412 final ActivityStarter starter = prepareStarter(
413 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
414 final ActivityRecord splitPrimaryFocusActivity =
415 new ActivityBuilder(mService).setCreateTask(true).build();
416 final ActivityRecord splitSecondReusableActivity =
417 new ActivityBuilder(mService).setCreateTask(true).build();
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800418 splitPrimaryFocusActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800419 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800420 splitSecondReusableActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800421 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700422
423 // Set focus back to primary.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800424 splitPrimaryFocusActivity.getRootTask().moveToFront("testSplitScreenDeliverToTop");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700425
Louis Chang38430df2020-01-02 17:14:59 +0800426 // Start activity and delivered new intent.
427 starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
Andrii Kulian1cfcae82020-04-10 12:44:38 -0700428 doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), any());
Bryce Lee32e09ef2018-03-19 15:29:49 -0700429 final int result = starter.setReason("testSplitScreenDeliverToTop").execute();
430
431 // Ensure result is delivering intent to top.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900432 assertEquals(START_DELIVERED_TO_TOP, result);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700433 }
434
435 /**
436 * This test ensures that if the intent is being delivered to a split-screen unfocused task
437 * reports it is brought to front instead of delivering to top.
438 */
439 @Test
440 public void testSplitScreenTaskToFront() {
Louis Chang38430df2020-01-02 17:14:59 +0800441 final ActivityStarter starter = prepareStarter(
442 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
443 final ActivityRecord splitSecondReusableActivity =
444 new ActivityBuilder(mService).setCreateTask(true).build();
445 final ActivityRecord splitSecondTopActivity =
446 new ActivityBuilder(mService).setCreateTask(true).build();
447 final ActivityRecord splitPrimaryFocusActivity =
448 new ActivityBuilder(mService).setCreateTask(true).build();
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800449 splitPrimaryFocusActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800450 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800451 splitSecondReusableActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800452 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800453 splitSecondTopActivity.getRootTask()
Louis Chang38430df2020-01-02 17:14:59 +0800454 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700455
Louis Chang38430df2020-01-02 17:14:59 +0800456 // Make it on top of split-screen-secondary.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800457 splitSecondTopActivity.getRootTask().moveToFront("testSplitScreenTaskToFront");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700458
Louis Chang38430df2020-01-02 17:14:59 +0800459 // Let primary stack has focus.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800460 splitPrimaryFocusActivity.getRootTask().moveToFront("testSplitScreenTaskToFront");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700461
Louis Chang38430df2020-01-02 17:14:59 +0800462 // Start activity and delivered new intent.
463 starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
Andrii Kulian1cfcae82020-04-10 12:44:38 -0700464 doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), any());
Bryce Lee32e09ef2018-03-19 15:29:49 -0700465 final int result = starter.setReason("testSplitScreenMoveToFront").execute();
466
467 // Ensure result is moving task to front.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900468 assertEquals(START_TASK_TO_FRONT, result);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700469 }
Bryce Lee2b8e0372018-04-05 17:01:37 -0700470
471 /**
472 * Tests activity is cleaned up properly in a task mode violation.
473 */
474 @Test
475 public void testTaskModeViolation() {
Louis Chang149d5c82019-12-30 09:47:39 +0800476 final DisplayContent display = mService.mRootWindowContainer.getDefaultDisplay();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700477 display.removeAllTasks();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700478 assertNoTasks(display);
479
480 final ActivityStarter starter = prepareStarter(0);
481
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700482 final LockTaskController lockTaskController = mService.getLockTaskController();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700483 doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
484
485 final int result = starter.setReason("testTaskModeViolation").execute();
486
487 assertEquals(START_RETURN_LOCK_TASK_MODE_VIOLATION, result);
488 assertNoTasks(display);
489 }
490
Louis Chang677921f2019-12-06 16:44:24 +0800491 private void assertNoTasks(DisplayContent display) {
Andrii Kulianf9df4a82020-03-31 12:09:27 -0700492 for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
493 final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
494 for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
495 final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
496 assertFalse(stack.hasChild());
497 }
Bryce Lee2b8e0372018-04-05 17:01:37 -0700498 }
499 }
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100500
501 /**
502 * This test ensures that activity starts are not being logged when the logging is disabled.
503 */
504 @Test
505 public void testActivityStartsLogging_noLoggingWhenDisabled() {
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700506 doReturn(false).when(mService).isActivityStartsLoggingEnabled();
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100507 doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
508
509 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK);
510 starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute();
511
512 // verify logging wasn't done
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000513 verify(mActivityMetricsLogger, never()).logAbortedBgActivityStart(any(), any(), anyInt(),
514 any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100515 }
516
517 /**
518 * This test ensures that activity starts are being logged when the logging is enabled.
519 */
520 @Test
521 public void testActivityStartsLogging_logsWhenEnabled() {
522 // note: conveniently this package doesn't have any activity visible
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700523 doReturn(true).when(mService).isActivityStartsLoggingEnabled();
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100524 doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
525
526 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
527 .setCallingUid(FAKE_CALLING_UID)
528 .setRealCallingUid(FAKE_REAL_CALLING_UID)
529 .setCallingPackage(FAKE_CALLING_PACKAGE)
530 .setOriginatingPendingIntent(null);
531
532 starter.setReason("testActivityStartsLogging_logsWhenEnabled").execute();
533
534 // verify the above activity start was logged
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000535 verify(mActivityMetricsLogger, times(1)).logAbortedBgActivityStart(any(), any(),
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100536 eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(),
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000537 eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), eq(false));
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100538 }
Riddle Hsub70b36d2018-09-11 21:20:02 +0800539
540 /**
Michal Karpinski8596ded2018-11-14 14:43:48 +0000541 * This test ensures that unsupported usecases aren't aborted when background starts are
542 * allowed.
543 */
544 @Test
545 public void testBackgroundActivityStartsAllowed_noStartsAborted() {
546 doReturn(true).when(mService).isBackgroundActivityStartsEnabled();
547
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000548 runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
549 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
550 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100551 false, false, false, false, false);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000552 }
553
554 /**
555 * This test ensures that unsupported usecases are aborted when background starts are
556 * disallowed.
557 */
558 @Test
559 public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
560 doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
561
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000562 runAndVerifyBackgroundActivityStartsSubtest(
563 "disallowed_unsupportedUsecase_aborted", true,
564 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
565 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100566 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100567 runAndVerifyBackgroundActivityStartsSubtest(
568 "disallowed_callingUidProcessStateTop_aborted", true,
569 UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
570 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100571 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100572 runAndVerifyBackgroundActivityStartsSubtest(
573 "disallowed_realCallingUidProcessStateTop_aborted", true,
574 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
575 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
Alan Stokes9e245762019-05-21 14:54:28 +0100576 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100577 runAndVerifyBackgroundActivityStartsSubtest(
578 "disallowed_hasForegroundActivities_aborted", true,
579 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
580 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100581 true, false, false, false, false);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000582 }
583
584 /**
585 * This test ensures that supported usecases aren't aborted when background starts are
586 * disallowed.
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100587 * The scenarios each have only one condition that makes them supported.
Michal Karpinski8596ded2018-11-14 14:43:48 +0000588 */
589 @Test
590 public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
591 doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
592
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000593 runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
594 Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
595 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100596 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000597 runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
598 Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
599 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100600 false, false, false, false, false);
Michal Karpinskib416f472019-01-24 14:34:28 +0000601 runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false,
602 Process.NFC_UID, false, PROCESS_STATE_TOP + 1,
603 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100604 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000605 runAndVerifyBackgroundActivityStartsSubtest(
606 "disallowed_callingUidHasVisibleWindow_notAborted", false,
607 UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
608 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100609 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000610 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000611 "disallowed_realCallingUidHasVisibleWindow_notAborted", false,
612 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
613 UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100614 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000615 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000616 "disallowed_callerIsRecents_notAborted", false,
617 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
618 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100619 false, true, false, false, false);
Michal Karpinskiac116df2018-12-10 17:51:42 +0000620 runAndVerifyBackgroundActivityStartsSubtest(
621 "disallowed_callerIsWhitelisted_notAborted", false,
622 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
623 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100624 false, false, true, false, false);
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000625 runAndVerifyBackgroundActivityStartsSubtest(
626 "disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted",
627 false,
628 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
629 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100630 false, false, false, true, false);
Michal Karpinski302dcec2019-02-01 11:48:25 +0000631 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski4026cae2019-02-12 11:51:47 +0000632 "disallowed_callingPackageNameIsDeviceOwner_notAborted", false,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000633 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
634 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100635 false, false, false, false, true);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000636 }
637
638 private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000639 int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
640 int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
Michal Karpinskiac116df2018-12-10 17:51:42 +0000641 boolean hasForegroundActivities, boolean callerIsRecents,
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000642 boolean callerIsTempWhitelisted,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000643 boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
Alan Stokes9e245762019-05-21 14:54:28 +0100644 boolean isCallingUidDeviceOwner) {
Michal Karpinski8596ded2018-11-14 14:43:48 +0000645 // window visibility
Michal Karpinskia606a292019-01-12 17:29:52 +0000646 doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
647 .isAnyNonToastWindowVisibleForUid(callingUid);
648 doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
649 .isAnyNonToastWindowVisibleForUid(realCallingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000650 // process importance
Riddle Hsua0536432019-02-16 00:38:59 +0800651 doReturn(callingUidProcState).when(mService).getUidState(callingUid);
652 doReturn(realCallingUidProcState).when(mService).getUidState(realCallingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000653 // foreground activities
654 final IApplicationThread caller = mock(IApplicationThread.class);
Darryl L Johnson15192d32020-01-15 15:31:42 -0800655 final WindowProcessListener listener = mock(WindowProcessListener.class);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000656 final ApplicationInfo ai = new ApplicationInfo();
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000657 ai.uid = callingUid;
Darryl L Johnsona0982222020-02-18 18:21:51 -0800658 ai.packageName = "com.android.test.package";
Michal Karpinski8596ded2018-11-14 14:43:48 +0000659 final WindowProcessController callerApp =
Darryl L Johnson15192d32020-01-15 15:31:42 -0800660 new WindowProcessController(mService, ai, null, callingUid, -1, null, listener);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000661 callerApp.setHasForegroundActivities(hasForegroundActivities);
662 doReturn(callerApp).when(mService).getProcessController(caller);
Michal Karpinski82bb5902018-11-28 15:52:52 +0000663 // caller is recents
664 RecentTasks recentTasks = mock(RecentTasks.class);
665 mService.mStackSupervisor.setRecentTasks(recentTasks);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000666 doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
Michal Karpinskiac116df2018-12-10 17:51:42 +0000667 // caller is temp whitelisted
668 callerApp.setAllowBackgroundActivityStarts(callerIsTempWhitelisted);
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000669 // caller is instrumenting with background activity starts privileges
Michal Karpinski4bc56492019-01-31 12:07:33 +0000670 callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000671 callerIsInstrumentingWithBackgroundActivityStartPrivileges);
Ricky Wai96f5c352019-04-10 18:40:17 +0100672 // callingUid is the device owner
673 doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000674
675 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700676 ActivityRecord[] outActivity = new ActivityRecord[1];
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000677 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
Michal Karpinski666631b2019-02-26 16:59:11 +0000678 .setCallingPackage("com.whatever.dude")
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000679 .setCaller(caller)
680 .setCallingUid(callingUid)
681 .setRealCallingUid(realCallingUid)
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700682 .setActivityOptions(new SafeActivityOptions(options))
683 .setOutActivity(outActivity);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000684
685 final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();
686
687 assertEquals(ActivityStarter.getExternalResult(
688 shouldHaveAborted ? START_ABORTED : START_SUCCESS), result);
689 verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700690
691 final ActivityRecord startedActivity = outActivity[0];
Louis Changcdec0802019-11-11 11:45:07 +0800692 if (startedActivity != null && startedActivity.getTask() != null) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700693 // Remove the activity so it doesn't interfere with with subsequent activity launch
694 // tests from this method.
Louis Changcdec0802019-11-11 11:45:07 +0800695 startedActivity.getTask().removeChild(startedActivity);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700696 }
Michal Karpinski8596ded2018-11-14 14:43:48 +0000697 }
698
699 /**
Riddle Hsu273e9992019-04-29 22:40:59 +0800700 * This test ensures that {@link ActivityStarter#setTargetStackAndMoveToFrontIfNeeded} will
701 * move the existing task to front if the current focused stack doesn't have running task.
702 */
703 @Test
704 public void testBringTaskToFrontWhenFocusedStackIsFinising() {
705 // Put 2 tasks in the same stack (simulate the behavior of home stack).
706 final ActivityRecord activity = new ActivityBuilder(mService)
707 .setCreateTask(true).build();
708 new ActivityBuilder(mService)
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800709 .setStack(activity.getRootTask())
Riddle Hsu273e9992019-04-29 22:40:59 +0800710 .setCreateTask(true).build();
711
712 // Create a top finishing activity.
713 final ActivityRecord finishingTopActivity = new ActivityBuilder(mService)
714 .setCreateTask(true).build();
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800715 finishingTopActivity.getRootTask().moveToFront("finishingTopActivity");
Riddle Hsu273e9992019-04-29 22:40:59 +0800716
Louis Chang149d5c82019-12-30 09:47:39 +0800717 assertEquals(finishingTopActivity, mRootWindowContainer.topRunningActivity());
Riddle Hsu273e9992019-04-29 22:40:59 +0800718 finishingTopActivity.finishing = true;
719
720 // Launch the bottom task of the target stack.
721 prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetLaunchStack */)
722 .setReason("testBringTaskToFrontWhenTopStackIsFinising")
723 .setIntent(activity.intent)
724 .execute();
725 // The hierarchies of the activity should move to front.
Louis Chang149d5c82019-12-30 09:47:39 +0800726 assertEquals(activity, mRootWindowContainer.topRunningActivity());
Riddle Hsu273e9992019-04-29 22:40:59 +0800727 }
728
729 /**
Riddle Hsub70b36d2018-09-11 21:20:02 +0800730 * This test ensures that when starting an existing single task activity on secondary display
731 * which is not the top focused display, it should deliver new intent to the activity and not
732 * create a new stack.
733 */
734 @Test
735 public void testDeliverIntentToTopActivityOfNonTopDisplay() {
736 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
737 false /* mockGetLaunchStack */);
738
739 // Create a secondary display at bottom.
Louis Chang677921f2019-12-06 16:44:24 +0800740 final TestDisplayContent secondaryDisplay =
741 new TestDisplayContent.Builder(mService, 1000, 1500)
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700742 .setPosition(POSITION_BOTTOM).build();
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700743 final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
Andrii Kulian86d676c2020-03-27 19:34:54 -0700744 final ActivityStack stack = secondaryTaskContainer.createStack(
745 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Riddle Hsub70b36d2018-09-11 21:20:02 +0800746
747 // Create an activity record on the top of secondary display.
Riddle Hsufd4a0502018-10-16 01:05:16 +0800748 final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
Riddle Hsub70b36d2018-09-11 21:20:02 +0800749
750 // Put an activity on default display as the top focused activity.
751 new ActivityBuilder(mService).setCreateTask(true).build();
752
753 // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
754 // on secondary display.
755 final ActivityOptions options = ActivityOptions.makeBasic()
756 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
757 final int result = starter.setReason("testDeliverIntentToTopActivityOfNonTopDisplay")
758 .setIntent(topActivityOnSecondaryDisplay.intent)
759 .setActivityOptions(options.toBundle())
760 .execute();
761
762 // Ensure result is delivering intent to top.
763 assertEquals(START_DELIVERED_TO_TOP, result);
764
765 // Ensure secondary display only creates one stack.
Andrii Kulian86d676c2020-03-27 19:34:54 -0700766 verify(secondaryTaskContainer, times(1)).createStack(anyInt(), anyInt(), anyBoolean());
Riddle Hsub70b36d2018-09-11 21:20:02 +0800767 }
768
769 /**
Riddle Hsufd4a0502018-10-16 01:05:16 +0800770 * This test ensures that when starting an existing non-top single task activity on secondary
771 * display which is the top focused display, it should bring the task to front without creating
772 * unused stack.
773 */
774 @Test
775 public void testBringTaskToFrontOnSecondaryDisplay() {
776 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
777 false /* mockGetLaunchStack */);
778
779 // Create a secondary display with an activity.
Louis Chang677921f2019-12-06 16:44:24 +0800780 final TestDisplayContent secondaryDisplay =
781 new TestDisplayContent.Builder(mService, 1000, 1500).build();
Louis Chang149d5c82019-12-30 09:47:39 +0800782 mRootWindowContainer.positionChildAt(POSITION_TOP, secondaryDisplay,
Louis Chang3ff72a82019-12-17 12:12:59 +0800783 false /* includingParents */);
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700784 final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
Riddle Hsufd4a0502018-10-16 01:05:16 +0800785 final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
Andrii Kulian86d676c2020-03-27 19:34:54 -0700786 secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN,
Riddle Hsufd4a0502018-10-16 01:05:16 +0800787 ACTIVITY_TYPE_STANDARD, false /* onTop */));
788
789 // Create another activity on top of the secondary display.
Andrii Kulian86d676c2020-03-27 19:34:54 -0700790 final ActivityStack topStack = secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN,
Riddle Hsufd4a0502018-10-16 01:05:16 +0800791 ACTIVITY_TYPE_STANDARD, true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800792 final Task topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
Riddle Hsufd4a0502018-10-16 01:05:16 +0800793 new ActivityBuilder(mService).setTask(topTask).build();
794
795 // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
796 final ActivityOptions options = ActivityOptions.makeBasic()
797 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
798 final int result = starter.setReason("testBringTaskToFrontOnSecondaryDisplay")
799 .setIntent(singleTaskActivity.intent)
800 .setActivityOptions(options.toBundle())
801 .execute();
802
803 // Ensure result is moving existing task to front.
804 assertEquals(START_TASK_TO_FRONT, result);
805
806 // Ensure secondary display only creates two stacks.
Andrii Kulian86d676c2020-03-27 19:34:54 -0700807 verify(secondaryTaskContainer, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
Riddle Hsufd4a0502018-10-16 01:05:16 +0800808 }
809
Evan Rosky8d1c24e2020-04-23 09:21:16 -0700810 @Test
811 public void testWasVisibleInRestartAttempt() {
812 final ActivityStarter starter = prepareStarter(
813 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
814 final ActivityRecord reusableActivity =
815 new ActivityBuilder(mService).setCreateTask(true).build();
816 final ActivityRecord topActivity =
817 new ActivityBuilder(mService).setCreateTask(true).build();
818
819 // Make sure topActivity is on top
820 topActivity.getRootTask().moveToFront("testWasVisibleInRestartAttempt");
821 reusableActivity.setVisible(false);
822
823 final TaskChangeNotificationController taskChangeNotifier =
824 mService.getTaskChangeNotificationController();
825 spyOn(taskChangeNotifier);
826
827 Task task = topActivity.getTask();
828 starter.postStartActivityProcessing(
829 task.getTopNonFinishingActivity(), START_DELIVERED_TO_TOP, task.getStack());
830
831 verify(taskChangeNotifier).notifyActivityRestartAttempt(
832 any(), anyBoolean(), anyBoolean(), anyBoolean());
833 verify(taskChangeNotifier).notifyActivityRestartAttempt(
834 any(), anyBoolean(), anyBoolean(), eq(true));
835
836 Task task2 = reusableActivity.getTask();
837 starter.postStartActivityProcessing(
838 task2.getTopNonFinishingActivity(), START_TASK_TO_FRONT, task.getStack());
839 verify(taskChangeNotifier, times(2)).notifyActivityRestartAttempt(
840 any(), anyBoolean(), anyBoolean(), anyBoolean());
841 verify(taskChangeNotifier).notifyActivityRestartAttempt(
842 any(), anyBoolean(), anyBoolean(), eq(false));
843 }
844
Riddle Hsufd4a0502018-10-16 01:05:16 +0800845 private ActivityRecord createSingleTaskActivityOn(ActivityStack stack) {
846 final ComponentName componentName = ComponentName.createRelative(
847 DEFAULT_COMPONENT_PACKAGE_NAME,
848 DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
Louis Changcdec0802019-11-11 11:45:07 +0800849 final Task task = new TaskBuilder(mSupervisor)
Riddle Hsufd4a0502018-10-16 01:05:16 +0800850 .setComponent(componentName)
851 .setStack(stack)
852 .build();
853 return new ActivityBuilder(mService)
854 .setComponent(componentName)
855 .setLaunchMode(LAUNCH_SINGLE_TASK)
Louis Changcdec0802019-11-11 11:45:07 +0800856 .setTask(task)
Riddle Hsufd4a0502018-10-16 01:05:16 +0800857 .build();
858 }
859
860 /**
Riddle Hsub70b36d2018-09-11 21:20:02 +0800861 * This test ensures that a reused top activity in the top focused stack is able to be
862 * reparented to another display.
863 */
864 @Test
865 public void testReparentTopFocusedActivityToSecondaryDisplay() {
866 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
867 false /* mockGetLaunchStack */);
868
869 // Create a secondary display at bottom.
Louis Chang677921f2019-12-06 16:44:24 +0800870 final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM);
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700871 final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
Andrii Kulian86d676c2020-03-27 19:34:54 -0700872 secondaryTaskContainer.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
Riddle Hsub70b36d2018-09-11 21:20:02 +0800873 true /* onTop */);
874
875 // Put an activity on default display as the top focused activity.
876 final ActivityRecord topActivity = new ActivityBuilder(mService)
877 .setCreateTask(true)
878 .setLaunchMode(LAUNCH_SINGLE_TASK)
879 .build();
880
881 // Start activity with the same intent as {@code topActivity} on secondary display.
882 final ActivityOptions options = ActivityOptions.makeBasic()
883 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
884 starter.setReason("testReparentTopFocusedActivityToSecondaryDisplay")
885 .setIntent(topActivity.intent)
886 .setActivityOptions(options.toBundle())
887 .execute();
888
889 // Ensure the activity is moved to secondary display.
890 assertEquals(secondaryDisplay, topActivity.getDisplay());
891 }
Winson Chunge219ae12019-07-18 13:43:23 -0700892
893 /**
894 * This test ensures that starting an activity with the freeze-task-list activity option will
895 * actually freeze the task list
896 */
897 @Test
898 public void testFreezeTaskListActivityOption() {
899 RecentTasks recentTasks = mock(RecentTasks.class);
900 mService.mStackSupervisor.setRecentTasks(recentTasks);
901 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
902
903 final ActivityStarter starter = prepareStarter(0 /* flags */);
904 final ActivityOptions options = ActivityOptions.makeBasic();
905 options.setFreezeRecentTasksReordering();
906
907 starter.setReason("testFreezeTaskListActivityOption")
908 .setActivityOptions(new SafeActivityOptions(options))
909 .execute();
910
911 verify(recentTasks, times(1)).setFreezeTaskListReordering();
912 verify(recentTasks, times(0)).resetFreezeTaskListReorderingOnTimeout();
913 }
914
915 /**
916 * This test ensures that if we froze the task list as a part of starting an activity that fails
917 * to start, that we also reset the task list.
918 */
919 @Test
920 public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() {
921 RecentTasks recentTasks = mock(RecentTasks.class);
922 mService.mStackSupervisor.setRecentTasks(recentTasks);
923 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
924
925 final ActivityStarter starter = prepareStarter(0 /* flags */);
926 final ActivityOptions options = ActivityOptions.makeBasic();
927 options.setFreezeRecentTasksReordering();
928
929 starter.setReason("testFreezeTaskListActivityOptionFailedStart")
930 .setActivityOptions(new SafeActivityOptions(options))
931 .execute();
932
933 // Simulate a failed start
Winson Chunge789ff62020-02-24 14:40:23 -0800934 starter.postStartActivityProcessing(null, START_CANCELED, null);
Winson Chunge219ae12019-07-18 13:43:23 -0700935
936 verify(recentTasks, times(1)).setFreezeTaskListReordering();
937 verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
938 }
Louis Chang54fbb052019-10-16 17:10:17 +0800939
940 @Test
941 public void testNoActivityInfo() {
942 final ActivityStarter starter = prepareStarter(0 /* flags */);
943 spyOn(starter.mRequest);
944
945 final Intent intent = new Intent();
946 intent.setComponent(ActivityBuilder.getDefaultComponent());
947 starter.setReason("testNoActivityInfo").setIntent(intent)
948 .setActivityInfo(null).execute();
949 verify(starter.mRequest).resolveActivity(any());
950 }
951
952 @Test
953 public void testResolveEphemeralInstaller() {
954 final ActivityStarter starter = prepareStarter(0 /* flags */);
955 final Intent intent = new Intent();
956 intent.setComponent(ActivityBuilder.getDefaultComponent());
957
958 doReturn(true).when(mMockPackageManager).isInstantAppInstallerComponent(any());
959 starter.setIntent(intent).mRequest.resolveActivity(mService.mStackSupervisor);
960
961 // Make sure the client intent won't be modified.
962 assertThat(intent.getComponent()).isNotNull();
963 assertThat(starter.getIntent().getComponent()).isNull();
964 }
965
966 @Test
967 public void testNotAllowIntentWithFd() {
968 final ActivityStarter starter = prepareStarter(0 /* flags */);
969 final Intent intent = spy(new Intent());
970 intent.setComponent(ActivityBuilder.getDefaultComponent());
971 doReturn(true).when(intent).hasFileDescriptors();
972
973 boolean exceptionCaught = false;
974 try {
975 starter.setIntent(intent).execute();
976 } catch (IllegalArgumentException ex) {
977 exceptionCaught = true;
978 }
979 assertThat(exceptionCaught).isTrue();
980 }
Louis Chang07b13002019-11-27 22:08:37 +0800981
982 @Test
983 public void testRecycleTaskFromAnotherUser() {
984 final ActivityStarter starter = prepareStarter(0 /* flags */);
985 starter.mStartActivity = new ActivityBuilder(mService).build();
986 final Task task = new TaskBuilder(mService.mStackSupervisor)
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700987 .setStack(mService.mRootWindowContainer.getDefaultTaskDisplayArea().createStack(
Louis Chang07b13002019-11-27 22:08:37 +0800988 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
989 .setUserId(10)
990 .build();
991
992 final int result = starter.recycleTask(task, null, null);
993 assertThat(result == START_SUCCESS).isTrue();
994 assertThat(starter.mAddingToTask).isTrue();
995 }
Louis Chang38430df2020-01-02 17:14:59 +0800996
997 @Test
998 public void testTargetStackInSplitScreen() {
999 final ActivityStarter starter =
1000 prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetLaunchStack */);
1001 final ActivityRecord top = new ActivityBuilder(mService).setCreateTask(true).build();
1002 final ActivityOptions options = ActivityOptions.makeBasic();
1003 final ActivityRecord[] outActivity = new ActivityRecord[1];
1004
1005 // Activity must not land on split-screen stack if currently not in split-screen mode.
1006 starter.setActivityOptions(options.toBundle())
1007 .setReason("testWindowingModeOptionsLaunchAdjacent")
1008 .setOutActivity(outActivity).execute();
1009 assertThat(outActivity[0].inSplitScreenWindowingMode()).isFalse();
1010
1011 // Move activity to split-screen-primary stack and make sure it has the focus.
Evan Roskyaf9f27c2020-02-18 18:58:35 +00001012 TestSplitOrganizer splitOrg = new TestSplitOrganizer(mService, top.getDisplayId());
Louis Changa009c762020-02-26 11:21:31 +08001013 top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM);
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -08001014 top.getRootTask().moveToFront("testWindowingModeOptionsLaunchAdjacent");
Louis Chang38430df2020-01-02 17:14:59 +08001015
1016 // Activity must landed on split-screen-secondary when launch adjacent.
1017 starter.setActivityOptions(options.toBundle())
1018 .setReason("testWindowingModeOptionsLaunchAdjacent")
1019 .setOutActivity(outActivity).execute();
1020 assertThat(outActivity[0].inSplitScreenSecondaryWindowingMode()).isTrue();
1021 }
Winson Chungf45dd9f2019-10-11 15:07:47 -07001022
1023 @Test
1024 public void testActivityStart_expectAddedToRecentTask() {
1025 RecentTasks recentTasks = mock(RecentTasks.class);
1026 mService.mStackSupervisor.setRecentTasks(recentTasks);
1027 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
1028
1029 final ActivityStarter starter = prepareStarter(0 /* flags */);
1030
1031 starter.setReason("testAddToTaskListOnActivityStart")
1032 .execute();
1033
1034 verify(recentTasks, times(1)).add(any());
1035 }
Diego Vela671c0072020-03-25 09:39:26 -07001036
1037 @Test
1038 public void testStartActivityInner_allSplitScreenPrimaryActivitiesVisible() {
1039 // Given
1040 final ActivityStarter starter = prepareStarter(0, false);
1041
1042 starter.setReason("testAllSplitScreenPrimaryActivitiesAreResumed");
1043
1044 final ActivityRecord targetRecord = new ActivityBuilder(mService).build();
1045 targetRecord.setFocusable(false);
1046 targetRecord.setVisibility(false);
1047 final ActivityRecord sourceRecord = new ActivityBuilder(mService).build();
1048
1049 final ActivityStack stack = spy(
1050 mRootWindowContainer.getDefaultTaskDisplayArea()
1051 .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
1052 /* onTop */true));
1053
1054 stack.addChild(targetRecord);
1055
1056 doReturn(stack).when(mRootWindowContainer)
1057 .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
1058
1059 starter.mStartActivity = new ActivityBuilder(mService).build();
1060
1061 // When
1062 starter.startActivityInner(
1063 /* r */targetRecord,
1064 /* sourceRecord */ sourceRecord,
1065 /* voiceSession */null,
1066 /* voiceInteractor */ null,
1067 /* startFlags */ 0,
1068 /* doResume */true,
1069 /* options */null,
1070 /* inTask */null,
1071 /* restrictedBgActivity */false);
1072
1073 // Then
1074 verify(stack).ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
1075 verify(targetRecord).makeVisibleIfNeeded(null, true);
1076 assertTrue(targetRecord.mVisibleRequested);
1077 }
Wale Ogunwale44f036f2017-09-29 05:09:09 -07001078}