blob: 19a3e4a17c206bf4c87db43fe49c4c82c85a0526 [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;
Andrii Kulian6a6c4f12018-07-16 21:23:33 -070058import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070059
60import static org.junit.Assert.assertEquals;
61import static org.junit.Assert.assertTrue;
62import static org.mockito.Mockito.any;
63import static org.mockito.Mockito.anyBoolean;
64import static org.mockito.Mockito.anyInt;
Bryce Lee93e7f792017-10-25 15:54:55 -070065import static org.mockito.Mockito.anyObject;
66import static org.mockito.Mockito.doAnswer;
Bryce Leead5b8322018-03-08 14:28:52 -080067import static org.mockito.Mockito.doNothing;
Bryce Lee93e7f792017-10-25 15:54:55 -070068import static org.mockito.Mockito.doReturn;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070069import static org.mockito.Mockito.eq;
Bryce Lee93e7f792017-10-25 15:54:55 -070070import static org.mockito.Mockito.mock;
71import static org.mockito.Mockito.spy;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070072import static org.mockito.Mockito.verify;
73import static org.mockito.Mockito.times;
74
Bryce Lee93e7f792017-10-25 15:54:55 -070075import com.android.internal.os.BatteryStatsImpl;
Bryce Leedaa91e42017-12-06 14:13:01 -080076import com.android.server.am.ActivityStarter.Factory;
Bryce Leead5b8322018-03-08 14:28:52 -080077import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
78import com.android.server.am.TaskRecord.TaskRecordFactory;
Bryce Lee93e7f792017-10-25 15:54:55 -070079
Bryce Lee2b8e0372018-04-05 17:01:37 -070080import java.util.ArrayList;
Andrii Kulian6a6c4f12018-07-16 21:23:33 -070081import java.util.List;
Bryce Lee2b8e0372018-04-05 17:01:37 -070082
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070083/**
Bryce Leed3624e12017-11-30 08:51:45 -080084 * Tests for the {@link ActivityStarter} class.
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070085 *
86 * Build/Install/Run:
Bryce Leed3624e12017-11-30 08:51:45 -080087 * atest FrameworksServicesTests:ActivityStarterTests
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070088 */
89@SmallTest
90@Presubmit
91@RunWith(AndroidJUnit4.class)
92public class ActivityStarterTests extends ActivityTestsBase {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -070093 private ActivityTaskManagerService mService;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070094 private ActivityStarter mStarter;
Bryce Leed3624e12017-11-30 08:51:45 -080095 private ActivityStartController mController;
Bryce Lee93e7f792017-10-25 15:54:55 -070096
97 private static final int PRECONDITION_NO_CALLER_APP = 1;
98 private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
99 private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2;
100 private static final int PRECONDITION_SOURCE_PRESENT = 1 << 3;
101 private static final int PRECONDITION_REQUEST_CODE = 1 << 4;
102 private static final int PRECONDITION_SOURCE_VOICE_SESSION = 1 << 5;
103 private static final int PRECONDITION_NO_VOICE_SESSION_SUPPORT = 1 << 6;
104 private static final int PRECONDITION_DIFFERENT_UID = 1 << 7;
105 private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8;
106 private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9;
107 private static final int PRECONDITION_DISALLOW_APP_SWITCHING = 1 << 10;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700108
109 @Override
110 public void setUp() throws Exception {
111 super.setUp();
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700112 mService = createActivityTaskManagerService();
Bryce Leed3624e12017-11-30 08:51:45 -0800113 mController = mock(ActivityStartController.class);
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700114 mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
Bryce Leed3624e12017-11-30 08:51:45 -0800115 mock(ActivityStartInterceptor.class));
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700116 }
117
118 @Test
119 public void testUpdateLaunchBounds() throws Exception {
120 // When in a non-resizeable stack, the task bounds should be updated.
Bryce Lee18d51592017-10-25 10:22:19 -0700121 final TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
122 .setStack(mService.mStackSupervisor.getDefaultDisplay().createStack(
123 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
124 .build();
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700125 final Rect bounds = new Rect(10, 10, 100, 100);
126
127 mStarter.updateBounds(task, bounds);
Bryce Leef3c6a472017-11-14 14:53:06 -0800128 assertEquals(task.getOverrideBounds(), bounds);
129 assertEquals(new Rect(), task.getStack().getOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700130
131 // When in a resizeable stack, the stack bounds should be updated as well.
Bryce Lee18d51592017-10-25 10:22:19 -0700132 final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
133 .setStack(mService.mStackSupervisor.getDefaultDisplay().createStack(
134 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
135 .build();
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700136 assertTrue(task2.getStack() instanceof PinnedActivityStack);
137 mStarter.updateBounds(task2, bounds);
138
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700139 verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId),
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700140 eq(bounds), anyBoolean(), anyBoolean(), anyBoolean(), anyInt());
141
142 // In the case of no animation, the stack and task bounds should be set immediately.
143 if (!ANIMATE) {
Bryce Leef3c6a472017-11-14 14:53:06 -0800144 assertEquals(task2.getStack().getOverrideBounds(), bounds);
145 assertEquals(task2.getOverrideBounds(), bounds);
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700146 } else {
Bryce Leef3c6a472017-11-14 14:53:06 -0800147 assertEquals(task2.getOverrideBounds(), new Rect());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700148 }
149 }
Bryce Lee93e7f792017-10-25 15:54:55 -0700150
151 @Test
152 public void testStartActivityPreconditions() throws Exception {
153 verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED);
154 verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT,
155 START_INTENT_NOT_RESOLVED);
156 verifyStartActivityPreconditions(PRECONDITION_NO_ACTIVITY_INFO, START_CLASS_NOT_FOUND);
157 verifyStartActivityPreconditions(PRECONDITION_SOURCE_PRESENT | PRECONDITION_REQUEST_CODE,
158 Intent.FLAG_ACTIVITY_FORWARD_RESULT, START_FORWARD_AND_REQUEST_CONFLICT);
159 verifyStartActivityPreconditions(
160 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
161 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID,
162 START_NOT_VOICE_COMPATIBLE);
163 verifyStartActivityPreconditions(
164 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
165 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID
166 | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION,
167 START_NOT_VOICE_COMPATIBLE);
168 verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED);
169 verifyStartActivityPreconditions(PRECONDITION_DISALLOW_APP_SWITCHING,
170 START_SWITCHES_CANCELED);
171 }
172
173 private static boolean containsConditions(int preconditions, int mask) {
174 return (preconditions & mask) == mask;
175 }
176
177 private void verifyStartActivityPreconditions(int preconditions, int expectedResult) {
178 verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
179 }
180
181 /**
182 * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
183 * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
184 * and the launch flags specified in the intent. The method constructs a call to
Bryce Lee4c9a5972017-12-01 22:14:24 -0800185 * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
186 * the expected. It is important to note that the method also checks side effects of the start,
187 * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
Bryce Lee93e7f792017-10-25 15:54:55 -0700188 * @param preconditions A bitmask representing the preconditions for the launch
189 * @param launchFlags The launch flags to be provided by the launch {@link Intent}.
190 * @param expectedResult The expected result from the launch.
191 */
192 private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
193 int expectedResult) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700194 final ActivityTaskManagerService service = mService;
Bryce Lee93e7f792017-10-25 15:54:55 -0700195 final IPackageManager packageManager = mock(IPackageManager.class);
Bryce Leed3624e12017-11-30 08:51:45 -0800196 final ActivityStartController controller = mock(ActivityStartController.class);
Bryce Lee93e7f792017-10-25 15:54:55 -0700197
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700198 final ActivityStarter starter = new ActivityStarter(controller, service,
Bryce Leed3624e12017-11-30 08:51:45 -0800199 service.mStackSupervisor, mock(ActivityStartInterceptor.class));
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700200 prepareStarter(launchFlags);
Bryce Lee93e7f792017-10-25 15:54:55 -0700201 final IApplicationThread caller = mock(IApplicationThread.class);
202
203 // If no caller app, return {@code null} {@link ProcessRecord}.
204 final ProcessRecord record = containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700205 ? null : new ProcessRecord(service.mAm, mock(BatteryStatsImpl.class),
Bryce Lee93e7f792017-10-25 15:54:55 -0700206 mock(ApplicationInfo.class), null, 0);
207
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700208 doReturn(record).when(service.mAm).getRecordForAppLocked(anyObject());
Bryce Lee93e7f792017-10-25 15:54:55 -0700209
210 final Intent intent = new Intent();
211 intent.setFlags(launchFlags);
212
213 final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO)
214 ? null : new ActivityInfo();
215
Bryce Lee93e7f792017-10-25 15:54:55 -0700216 IVoiceInteractionSession voiceSession =
217 containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
218 ? mock(IVoiceInteractionSession.class) : null;
219
220 // Create source token
221 final ActivityBuilder builder = new ActivityBuilder(service).setTask(
222 new TaskBuilder(service.mStackSupervisor).setVoiceSession(voiceSession).build());
223
Bryce Leefbd263b42018-03-07 10:33:55 -0800224 if (aInfo != null) {
225 aInfo.applicationInfo = new ApplicationInfo();
Bryce Leead5b8322018-03-08 14:28:52 -0800226 aInfo.applicationInfo.packageName =
227 ActivityBuilder.getDefaultComponent().getPackageName();
Bryce Leefbd263b42018-03-07 10:33:55 -0800228 }
229
Bryce Lee93e7f792017-10-25 15:54:55 -0700230 // Offset uid by one from {@link ActivityInfo} to simulate different uids.
231 if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) {
232 builder.setUid(aInfo.applicationInfo.uid + 1);
233 }
234
235 final ActivityRecord source = builder.build();
236
237 if (!containsConditions(preconditions, PRECONDITION_NO_INTENT_COMPONENT)) {
238 intent.setComponent(source.realActivity);
239 }
240
241 if (containsConditions(preconditions, PRECONDITION_DISALLOW_APP_SWITCHING)) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700242 doReturn(false).when(service).checkAppSwitchAllowedLocked(
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700243 anyInt(), anyInt(), anyInt(), anyInt(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700244 }
245
246 if (containsConditions(preconditions,PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
247 doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission(
Jorim Jaggi4d8d32c2018-01-19 15:57:41 +0100248 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700249 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700250 }
251
252 try {
253 if (containsConditions(preconditions,
254 PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION)) {
255 doAnswer((inv) -> {
256 throw new RemoteException();
257 }).when(packageManager).activitySupportsIntent(eq(source.realActivity), eq(intent),
258 any());
259 } else {
260 doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT))
261 .when(packageManager).activitySupportsIntent(eq(source.realActivity),
262 eq(intent), any());
263 }
264 } catch (RemoteException e) {
265 }
266
267 final IBinder resultTo = containsConditions(preconditions, PRECONDITION_SOURCE_PRESENT)
268 || containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
269 ? source.appToken : null;
270
271 final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE)
272 ? 1 : 0;
273
Bryce Lee4c9a5972017-12-01 22:14:24 -0800274 final int result = starter.setCaller(caller)
275 .setIntent(intent)
276 .setActivityInfo(aInfo)
277 .setResultTo(resultTo)
278 .setRequestCode(requestCode)
279 .setReason("testLaunchActivityPermissionDenied")
280 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700281
282 // In some cases the expected result internally is different than the published result. We
283 // must use ActivityStarter#getExternalResult to translate.
284 assertEquals(ActivityStarter.getExternalResult(expectedResult), result);
285
286 // Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
287 if (expectedResult != START_SUCCESS) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700288 final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
Bryce Lee4c9a5972017-12-01 22:14:24 -0800289 mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
Bryce Lee93e7f792017-10-25 15:54:55 -0700290 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Bryce Lee4c9a5972017-12-01 22:14:24 -0800291
292 final int optionResult = optionStarter.setCaller(caller)
293 .setIntent(intent)
294 .setActivityInfo(aInfo)
295 .setResultTo(resultTo)
296 .setRequestCode(requestCode)
297 .setReason("testLaunchActivityPermissionDenied")
Jorim Jaggi4d8d32c2018-01-19 15:57:41 +0100298 .setActivityOptions(new SafeActivityOptions(options))
Bryce Lee4c9a5972017-12-01 22:14:24 -0800299 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700300 verify(options, times(1)).abort();
301 }
302 }
Bryce Leeb802ea12017-11-15 21:25:03 -0800303
Bryce Lee32e09ef2018-03-19 15:29:49 -0700304 private ActivityStarter prepareStarter(int launchFlags) {
Bryce Leead5b8322018-03-08 14:28:52 -0800305 // always allow test to start activity.
306 doReturn(true).when(mService.mStackSupervisor).checkStartAnyActivityPermission(
307 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700308 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800309
310 // instrument the stack and task used.
Bryce Lee2b8e0372018-04-05 17:01:37 -0700311 final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack(
312 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
313 final TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
314 .setCreateStack(false)
315 .build();
Bryce Leead5b8322018-03-08 14:28:52 -0800316
Bryce Leead5b8322018-03-08 14:28:52 -0800317 // 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
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700339 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.
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700406 final ActivityStack focusStack = focusActivity.getStack();
407 focusStack.moveToFront("testSplitScreenDeliverToTop");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700408
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();
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700455 ((TestActivityDisplay) display).removeAllTasks();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700456 assertNoTasks(display);
457
458 final ActivityStarter starter = prepareStarter(0);
459
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700460 final LockTaskController lockTaskController = mService.getLockTaskController();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700461 doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
462
463 final int result = starter.setReason("testTaskModeViolation").execute();
464
465 assertEquals(START_RETURN_LOCK_TASK_MODE_VIOLATION, result);
466 assertNoTasks(display);
467 }
468
469 private void assertNoTasks(ActivityDisplay display) {
470 for (int i = display.getChildCount() - 1; i >= 0; --i) {
471 final ActivityStack stack = display.getChildAt(i);
472 assertTrue(stack.getAllTasks().isEmpty());
473 }
474 }
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700475}