blob: 18e842f3e694fa106099f01d69a61ac3eaa12eaf [file] [log] [blame]
Bryce Lee4e4a3ec2017-09-27 08:25:03 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.am;
18
Bryce Lee93e7f792017-10-25 15:54:55 -070019import static android.app.ActivityManager.START_ABORTED;
20import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
Bryce Lee32e09ef2018-03-19 15:29:49 -070021import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
Bryce Lee93e7f792017-10-25 15:54:55 -070022import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
Bryce Lee32e09ef2018-03-19 15:29:49 -070023import static android.app.ActivityManager.START_INTENT_NOT_RESOLVED;
Bryce Lee93e7f792017-10-25 15:54:55 -070024import static android.app.ActivityManager.START_NOT_VOICE_COMPATIBLE;
Bryce Lee32e09ef2018-03-19 15:29:49 -070025import static android.app.ActivityManager.START_PERMISSION_DENIED;
Bryce Lee2b8e0372018-04-05 17:01:37 -070026import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
Bryce Lee93e7f792017-10-25 15:54:55 -070027import static android.app.ActivityManager.START_SUCCESS;
28import static android.app.ActivityManager.START_SWITCHES_CANCELED;
Bryce Lee32e09ef2018-03-19 15:29:49 -070029import static android.app.ActivityManager.START_TASK_TO_FRONT;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070030import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
31import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
32import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Bryce Lee32e09ef2018-03-19 15:29:49 -070033import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
34import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070035
Bryce Lee93e7f792017-10-25 15:54:55 -070036import android.app.ActivityOptions;
37import android.app.IApplicationThread;
Bryce Lee2b8e0372018-04-05 17:01:37 -070038import android.content.ComponentName;
Bryce Lee93e7f792017-10-25 15:54:55 -070039import android.content.Intent;
40import android.content.pm.ActivityInfo;
Bryce Leead5b8322018-03-08 14:28:52 -080041import android.content.pm.ActivityInfo.WindowLayout;
Bryce Lee93e7f792017-10-25 15:54:55 -070042import android.content.pm.ApplicationInfo;
43import android.content.pm.IPackageManager;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070044import android.graphics.Rect;
Bryce Lee93e7f792017-10-25 15:54:55 -070045import android.os.IBinder;
46import android.os.RemoteException;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070047import android.platform.test.annotations.Presubmit;
Bryce Lee93e7f792017-10-25 15:54:55 -070048import android.service.voice.IVoiceInteractionSession;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070049import android.support.test.filters.SmallTest;
50import android.support.test.runner.AndroidJUnit4;
Bryce Leead5b8322018-03-08 14:28:52 -080051import android.view.Gravity;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070052
53import org.junit.runner.RunWith;
54import org.junit.Test;
55
Bryce Lee32e09ef2018-03-19 15:29:49 -070056import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070057import static com.android.server.am.ActivityManagerService.ANIMATE;
58
59import static org.junit.Assert.assertEquals;
60import static org.junit.Assert.assertTrue;
61import static org.mockito.Mockito.any;
62import static org.mockito.Mockito.anyBoolean;
63import static org.mockito.Mockito.anyInt;
Bryce Lee93e7f792017-10-25 15:54:55 -070064import static org.mockito.Mockito.anyObject;
65import static org.mockito.Mockito.doAnswer;
Bryce Leead5b8322018-03-08 14:28:52 -080066import static org.mockito.Mockito.doNothing;
Bryce Lee93e7f792017-10-25 15:54:55 -070067import static org.mockito.Mockito.doReturn;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070068import static org.mockito.Mockito.eq;
Bryce Lee93e7f792017-10-25 15:54:55 -070069import static org.mockito.Mockito.mock;
70import static org.mockito.Mockito.spy;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070071import static org.mockito.Mockito.verify;
72import static org.mockito.Mockito.times;
73
Bryce Lee93e7f792017-10-25 15:54:55 -070074import com.android.internal.os.BatteryStatsImpl;
Bryce Leedaa91e42017-12-06 14:13:01 -080075import com.android.server.am.ActivityStarter.Factory;
Bryce Leead5b8322018-03-08 14:28:52 -080076import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
77import com.android.server.am.TaskRecord.TaskRecordFactory;
Bryce Lee93e7f792017-10-25 15:54:55 -070078
Bryce Lee2b8e0372018-04-05 17:01:37 -070079import java.util.ArrayList;
80
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070081/**
Bryce Leed3624e12017-11-30 08:51:45 -080082 * Tests for the {@link ActivityStarter} class.
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070083 *
84 * Build/Install/Run:
Bryce Leed3624e12017-11-30 08:51:45 -080085 * atest FrameworksServicesTests:ActivityStarterTests
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070086 */
87@SmallTest
88@Presubmit
89@RunWith(AndroidJUnit4.class)
90public class ActivityStarterTests extends ActivityTestsBase {
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070091 private ActivityManagerService mService;
92 private ActivityStarter mStarter;
Bryce Leed3624e12017-11-30 08:51:45 -080093 private ActivityStartController mController;
Bryce Lee93e7f792017-10-25 15:54:55 -070094
95 private static final int PRECONDITION_NO_CALLER_APP = 1;
96 private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
97 private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2;
98 private static final int PRECONDITION_SOURCE_PRESENT = 1 << 3;
99 private static final int PRECONDITION_REQUEST_CODE = 1 << 4;
100 private static final int PRECONDITION_SOURCE_VOICE_SESSION = 1 << 5;
101 private static final int PRECONDITION_NO_VOICE_SESSION_SUPPORT = 1 << 6;
102 private static final int PRECONDITION_DIFFERENT_UID = 1 << 7;
103 private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8;
104 private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9;
105 private static final int PRECONDITION_DISALLOW_APP_SWITCHING = 1 << 10;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700106
107 @Override
108 public void setUp() throws Exception {
109 super.setUp();
110 mService = createActivityManagerService();
Bryce Leed3624e12017-11-30 08:51:45 -0800111 mController = mock(ActivityStartController.class);
112 mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
113 mock(ActivityStartInterceptor.class));
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700114 }
115
116 @Test
117 public void testUpdateLaunchBounds() throws Exception {
118 // When in a non-resizeable stack, the task bounds should be updated.
Bryce Lee18d51592017-10-25 10:22:19 -0700119 final TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
120 .setStack(mService.mStackSupervisor.getDefaultDisplay().createStack(
121 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
122 .build();
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700123 final Rect bounds = new Rect(10, 10, 100, 100);
124
125 mStarter.updateBounds(task, bounds);
Bryce Leef3c6a472017-11-14 14:53:06 -0800126 assertEquals(task.getOverrideBounds(), bounds);
127 assertEquals(new Rect(), task.getStack().getOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700128
129 // When in a resizeable stack, the stack bounds should be updated as well.
Bryce Lee18d51592017-10-25 10:22:19 -0700130 final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
131 .setStack(mService.mStackSupervisor.getDefaultDisplay().createStack(
132 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
133 .build();
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700134 assertTrue(task2.getStack() instanceof PinnedActivityStack);
135 mStarter.updateBounds(task2, bounds);
136
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700137 verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId),
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700138 eq(bounds), anyBoolean(), anyBoolean(), anyBoolean(), anyInt());
139
140 // In the case of no animation, the stack and task bounds should be set immediately.
141 if (!ANIMATE) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800142 assertEquals(task2.getStack().getOverrideBounds(), bounds);
143 assertEquals(task2.getOverrideBounds(), bounds);
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700144 } else {
Bryce Leef3c6a472017-11-14 14:53:06 -0800145 assertEquals(task2.getOverrideBounds(), new Rect());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700146 }
147 }
Bryce Lee93e7f792017-10-25 15:54:55 -0700148
149 @Test
150 public void testStartActivityPreconditions() throws Exception {
151 verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED);
152 verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT,
153 START_INTENT_NOT_RESOLVED);
154 verifyStartActivityPreconditions(PRECONDITION_NO_ACTIVITY_INFO, START_CLASS_NOT_FOUND);
155 verifyStartActivityPreconditions(PRECONDITION_SOURCE_PRESENT | PRECONDITION_REQUEST_CODE,
156 Intent.FLAG_ACTIVITY_FORWARD_RESULT, START_FORWARD_AND_REQUEST_CONFLICT);
157 verifyStartActivityPreconditions(
158 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
159 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID,
160 START_NOT_VOICE_COMPATIBLE);
161 verifyStartActivityPreconditions(
162 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
163 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID
164 | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION,
165 START_NOT_VOICE_COMPATIBLE);
166 verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED);
167 verifyStartActivityPreconditions(PRECONDITION_DISALLOW_APP_SWITCHING,
168 START_SWITCHES_CANCELED);
169 }
170
171 private static boolean containsConditions(int preconditions, int mask) {
172 return (preconditions & mask) == mask;
173 }
174
175 private void verifyStartActivityPreconditions(int preconditions, int expectedResult) {
176 verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
177 }
178
179 /**
180 * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
181 * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
182 * and the launch flags specified in the intent. The method constructs a call to
Bryce Lee4c9a5972017-12-01 22:14:24 -0800183 * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
184 * the expected. It is important to note that the method also checks side effects of the start,
185 * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
Bryce Lee93e7f792017-10-25 15:54:55 -0700186 * @param preconditions A bitmask representing the preconditions for the launch
187 * @param launchFlags The launch flags to be provided by the launch {@link Intent}.
188 * @param expectedResult The expected result from the launch.
189 */
190 private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
191 int expectedResult) {
192 final ActivityManagerService service = createActivityManagerService();
193 final IPackageManager packageManager = mock(IPackageManager.class);
Bryce Leed3624e12017-11-30 08:51:45 -0800194 final ActivityStartController controller = mock(ActivityStartController.class);
Bryce Lee93e7f792017-10-25 15:54:55 -0700195
Bryce Leed3624e12017-11-30 08:51:45 -0800196 final ActivityStarter starter = new ActivityStarter(controller, service,
197 service.mStackSupervisor, mock(ActivityStartInterceptor.class));
Bryce Lee93e7f792017-10-25 15:54:55 -0700198 final IApplicationThread caller = mock(IApplicationThread.class);
199
200 // If no caller app, return {@code null} {@link ProcessRecord}.
201 final ProcessRecord record = containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
Dianne Hackborne9d9b4b2018-03-28 13:51:46 -0700202 ? null : new ProcessRecord(null, mock(BatteryStatsImpl.class),
Bryce Lee93e7f792017-10-25 15:54:55 -0700203 mock(ApplicationInfo.class), null, 0);
204
205 doReturn(record).when(service).getRecordForAppLocked(anyObject());
206
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)) {
235 intent.setComponent(source.realActivity);
236 }
237
238 if (containsConditions(preconditions, PRECONDITION_DISALLOW_APP_SWITCHING)) {
239 doReturn(false).when(service).checkAppSwitchAllowedLocked(anyInt(), anyInt(), anyInt(),
240 anyInt(), any());
241 }
242
243 if (containsConditions(preconditions,PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
244 doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission(
Jorim Jaggi4d8d32c2018-01-19 15:57:41 +0100245 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
246 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();
254 }).when(packageManager).activitySupportsIntent(eq(source.realActivity), eq(intent),
255 any());
256 } else {
257 doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT))
258 .when(packageManager).activitySupportsIntent(eq(source.realActivity),
259 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) {
Bryce Lee4c9a5972017-12-01 22:14:24 -0800285 final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
286 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
Bryce Lee32e09ef2018-03-19 15:29:49 -0700301 private ActivityStarter prepareStarter(int launchFlags) {
Bryce Leead5b8322018-03-08 14:28:52 -0800302 // always allow test to start activity.
303 doReturn(true).when(mService.mStackSupervisor).checkStartAnyActivityPermission(
304 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
305 anyBoolean(), any(), any(), any());
306
307 // instrument the stack and task used.
Bryce Lee2b8e0372018-04-05 17:01:37 -0700308 final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack(
309 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
310 final TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
311 .setCreateStack(false)
312 .build();
Bryce Leead5b8322018-03-08 14:28:52 -0800313
314 // supervisor needs a focused stack.
Bryce Lee2b8e0372018-04-05 17:01:37 -0700315 mService.mStackSupervisor.mFocusedStack = stack;
Bryce Leead5b8322018-03-08 14:28:52 -0800316
317 // use factory that only returns spy task.
318 final TaskRecordFactory factory = mock(TaskRecordFactory.class);
319 TaskRecord.setTaskRecordFactory(factory);
320
321 // return task when created.
322 doReturn(task).when(factory).create(any(), anyInt(), any(), any(), any(), any());
323
324 // direct starter to use spy stack.
325 doReturn(stack).when(mService.mStackSupervisor)
326 .getLaunchStack(any(), any(), any(), anyBoolean());
327 doReturn(stack).when(mService.mStackSupervisor)
328 .getLaunchStack(any(), any(), any(), anyBoolean(), anyInt());
329
Bryce Lee32e09ef2018-03-19 15:29:49 -0700330 final Intent intent = new Intent();
331 intent.addFlags(launchFlags);
332 intent.setComponent(ActivityBuilder.getDefaultComponent());
333
334 final ActivityInfo info = new ActivityInfo();
335
336 info.applicationInfo = new ApplicationInfo();
337 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
338
Bryce Leead5b8322018-03-08 14:28:52 -0800339 return new ActivityStarter(mController, mService,
Bryce Lee32e09ef2018-03-19 15:29:49 -0700340 mService.mStackSupervisor, mock(ActivityStartInterceptor.class))
341 .setIntent(intent)
342 .setActivityInfo(info);
Bryce Leead5b8322018-03-08 14:28:52 -0800343 }
344
345 /**
346 * Ensures that values specified at launch time are passed to {@link LaunchParamsModifier}
347 * when we are laying out a new task.
348 */
349 @Test
350 public void testCreateTaskLayout() {
351 // modifier for validating passed values.
352 final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
353 mService.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
354
355 // add custom values to activity info to make unique.
356 final ActivityInfo info = new ActivityInfo();
357 final Rect launchBounds = new Rect(0, 0, 20, 30);
Bryce Leead5b8322018-03-08 14:28:52 -0800358
359 final WindowLayout windowLayout =
360 new WindowLayout(10, .5f, 20, 1.0f, Gravity.NO_GRAVITY, 1, 1);
361
362 info.windowLayout = windowLayout;
363 info.applicationInfo = new ApplicationInfo();
364 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
365
366 // create starter.
Bryce Lee32e09ef2018-03-19 15:29:49 -0700367 final ActivityStarter optionStarter = prepareStarter(0 /* launchFlags */);
Bryce Leead5b8322018-03-08 14:28:52 -0800368
369 final ActivityOptions options = ActivityOptions.makeBasic();
370 options.setLaunchBounds(launchBounds);
371
372 // run starter.
373 optionStarter
Bryce Leead5b8322018-03-08 14:28:52 -0800374 .setReason("testCreateTaskLayout")
375 .setActivityInfo(info)
376 .setActivityOptions(new SafeActivityOptions(options))
377 .execute();
378
379 // verify that values are passed to the modifier.
380 verify(modifier, times(1)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
381 any(), any());
382 }
Bryce Lee32e09ef2018-03-19 15:29:49 -0700383
384 /**
385 * This test ensures that if the intent is being delivered to a
386 */
387 @Test
388 public void testSplitScreenDeliverToTop() {
389 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
390
391 final ActivityRecord focusActivity = new ActivityBuilder(mService)
392 .setCreateTask(true)
393 .build();
394
395 focusActivity.getStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
396
397 final ActivityRecord reusableActivity = new ActivityBuilder(mService)
398 .setCreateTask(true)
399 .build();
400
401 // Create reusable activity after entering split-screen so that it is the top secondary
402 // stack.
403 reusableActivity.getStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
404
405 // Set focus back to primary.
406 mService.mStackSupervisor.setFocusStackUnchecked("testSplitScreenDeliverToTop",
407 focusActivity.getStack());
408
409 doReturn(reusableActivity).when(mService.mStackSupervisor).findTaskLocked(any(), anyInt());
410
411 final int result = starter.setReason("testSplitScreenDeliverToTop").execute();
412
413 // Ensure result is delivering intent to top.
414 assertEquals(result, START_DELIVERED_TO_TOP);
415 }
416
417 /**
418 * This test ensures that if the intent is being delivered to a split-screen unfocused task
419 * reports it is brought to front instead of delivering to top.
420 */
421 @Test
422 public void testSplitScreenTaskToFront() {
423 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
424
425 // Create reusable activity here first. Setting the windowing mode of the primary stack
426 // will move the existing standard full screen stack to secondary, putting this one on the
427 // bottom.
428 final ActivityRecord reusableActivity = new ActivityBuilder(mService)
429 .setCreateTask(true)
430 .build();
431
432 reusableActivity.getStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
433
434 final ActivityRecord focusActivity = new ActivityBuilder(mService)
435 .setCreateTask(true)
436 .build();
437
438 // Enter split-screen. Primary stack should have focus.
439 focusActivity.getStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
440
441 doReturn(reusableActivity).when(mService.mStackSupervisor).findTaskLocked(any(), anyInt());
442
443 final int result = starter.setReason("testSplitScreenMoveToFront").execute();
444
445 // Ensure result is moving task to front.
446 assertEquals(result, START_TASK_TO_FRONT);
447 }
Bryce Lee2b8e0372018-04-05 17:01:37 -0700448
449 /**
450 * Tests activity is cleaned up properly in a task mode violation.
451 */
452 @Test
453 public void testTaskModeViolation() {
454 final ActivityDisplay display = mService.mStackSupervisor.getDefaultDisplay();
455 assertNoTasks(display);
456
457 final ActivityStarter starter = prepareStarter(0);
458
459 final LockTaskController lockTaskController = mService.getLockTaskController();
460 doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
461
462 final int result = starter.setReason("testTaskModeViolation").execute();
463
464 assertEquals(START_RETURN_LOCK_TASK_MODE_VIOLATION, result);
465 assertNoTasks(display);
466 }
467
468 private void assertNoTasks(ActivityDisplay display) {
469 for (int i = display.getChildCount() - 1; i >= 0; --i) {
470 final ActivityStack stack = display.getChildAt(i);
471 assertTrue(stack.getAllTasks().isEmpty());
472 }
473 }
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700474}