1 /*
2  * Copyright (C) 2018 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 
17 package com.android.server.wm;
18 
19 import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
20 import static android.app.Activity.RESULT_CANCELED;
21 import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
22 import static android.app.ActivityManager.PROCESS_STATE_TOP;
23 import static android.app.ActivityManager.START_ABORTED;
24 import static android.app.ActivityManager.START_CANCELED;
25 import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
26 import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
27 import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
28 import static android.app.ActivityManager.START_INTENT_NOT_RESOLVED;
29 import static android.app.ActivityManager.START_NOT_VOICE_COMPATIBLE;
30 import static android.app.ActivityManager.START_PERMISSION_DENIED;
31 import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
32 import static android.app.ActivityManager.START_SUCCESS;
33 import static android.app.ActivityManager.START_TASK_TO_FRONT;
34 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
35 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
36 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
37 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
38 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
39 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
40 import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
41 import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
42 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
43 import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
44 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
45 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
46 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
47 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
48 import static android.os.Process.SYSTEM_UID;
49 
50 import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
51 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
52 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
53 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
54 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
55 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
56 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
57 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
58 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
59 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
60 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
61 import static com.android.server.wm.ActivityStarter.canEmbedActivity;
62 import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
63 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
64 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
65 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
66 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
67 import static com.android.server.wm.WindowContainer.POSITION_TOP;
68 import static com.android.server.wm.WindowTestsBase.ActivityBuilder.DEFAULT_FAKE_UID;
69 
70 import static com.google.common.truth.Truth.assertThat;
71 
72 import static org.junit.Assert.assertEquals;
73 import static org.junit.Assert.assertFalse;
74 import static org.junit.Assert.assertNotEquals;
75 import static org.junit.Assert.assertNotNull;
76 import static org.junit.Assert.assertNull;
77 import static org.junit.Assert.assertTrue;
78 import static org.mockito.ArgumentMatchers.any;
79 import static org.mockito.ArgumentMatchers.anyBoolean;
80 import static org.mockito.ArgumentMatchers.anyInt;
81 import static org.mockito.ArgumentMatchers.anyLong;
82 import static org.mockito.ArgumentMatchers.anyObject;
83 import static org.mockito.ArgumentMatchers.anyString;
84 import static org.mockito.ArgumentMatchers.eq;
85 import static org.mockito.ArgumentMatchers.notNull;
86 
87 import android.app.ActivityOptions;
88 import android.app.AppOpsManager;
89 import android.app.BackgroundStartPrivileges;
90 import android.app.IApplicationThread;
91 import android.app.PictureInPictureParams;
92 import android.content.ComponentName;
93 import android.content.Intent;
94 import android.content.pm.ActivityInfo;
95 import android.content.pm.ActivityInfo.WindowLayout;
96 import android.content.pm.ApplicationInfo;
97 import android.content.pm.IPackageManager;
98 import android.content.pm.PackageManagerInternal;
99 import android.content.pm.SigningDetails;
100 import android.graphics.Rect;
101 import android.os.Binder;
102 import android.os.IBinder;
103 import android.os.Process;
104 import android.os.RemoteException;
105 import android.os.UserHandle;
106 import android.platform.test.annotations.Presubmit;
107 import android.provider.DeviceConfig;
108 import android.service.voice.IVoiceInteractionSession;
109 import android.util.Pair;
110 import android.util.Size;
111 import android.view.Gravity;
112 import android.view.RemoteAnimationAdapter;
113 import android.window.TaskFragmentOrganizerToken;
114 
115 import androidx.test.filters.SmallTest;
116 
117 import com.android.compatibility.common.util.DeviceConfigStateHelper;
118 import com.android.internal.util.FrameworkStatsLog;
119 import com.android.server.am.PendingIntentRecord;
120 import com.android.server.pm.pkg.AndroidPackage;
121 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
122 import com.android.server.wm.utils.MockTracker;
123 
124 import org.junit.After;
125 import org.junit.Before;
126 import org.junit.Ignore;
127 import org.junit.Test;
128 import org.junit.runner.RunWith;
129 import org.mockito.MockitoSession;
130 import org.mockito.quality.Strictness;
131 
132 import java.util.Arrays;
133 import java.util.HashSet;
134 import java.util.Set;
135 
136 /**
137  * Tests for the {@link ActivityStarter} class.
138  *
139  * Build/Install/Run:
140  *  atest WmTests:ActivityStarterTests
141  */
142 @SmallTest
143 @Presubmit
144 @RunWith(WindowTestRunner.class)
145 public class ActivityStarterTests extends WindowTestsBase {
146 
147     private static final int PRECONDITION_NO_CALLER_APP = 1;
148     private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
149     private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2;
150     private static final int PRECONDITION_SOURCE_PRESENT = 1 << 3;
151     private static final int PRECONDITION_REQUEST_CODE = 1 << 4;
152     private static final int PRECONDITION_SOURCE_VOICE_SESSION = 1 << 5;
153     private static final int PRECONDITION_NO_VOICE_SESSION_SUPPORT = 1 << 6;
154     private static final int PRECONDITION_DIFFERENT_UID = 1 << 7;
155     private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8;
156     private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9;
157     private static final int FAKE_CALLING_UID = 666;
158     private static final int FAKE_REAL_CALLING_UID = 667;
159     private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
160     private static final int UNIMPORTANT_UID = 12345;
161     private static final int UNIMPORTANT_UID2 = 12346;
162     private static final int SDK_SANDBOX_UID = Process.toSdkSandboxUid(UNIMPORTANT_UID);
163     private static final int SECONDARY_USER_SDK_SANDBOX_UID =
164             UserHandle.getUid(10, SDK_SANDBOX_UID);
165     private static final int CURRENT_IME_UID = 12347;
166 
167     protected final DeviceConfigStateHelper mDeviceConfig = new DeviceConfigStateHelper(
168             DeviceConfig.NAMESPACE_WINDOW_MANAGER);
169 
170     private ActivityStartController mController;
171     private ActivityMetricsLogger mActivityMetricsLogger;
172     private PackageManagerInternal mMockPackageManager;
173     private AppOpsManager mAppOpsManager;
174 
175     @Before
setUp()176     public void setUp() throws Exception {
177         mController = mock(ActivityStartController.class);
178         BackgroundActivityStartController balController =
179                 new BackgroundActivityStartController(mAtm, mSupervisor);
180         doReturn(balController).when(mController).getBackgroundActivityLaunchController();
181         mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
182         clearInvocations(mActivityMetricsLogger);
183         mAppOpsManager = mAtm.getAppOpsManager();
184         doReturn(AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).checkOpNoThrow(
185                 eq(AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION),
186                 anyInt(), any());
187     }
188 
189     @After
tearDown()190     public void tearDown() throws Exception {
191         mDeviceConfig.close();
192     }
193 
194     @Test
testStartActivityPreconditions()195     public void testStartActivityPreconditions() {
196         verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED);
197         verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT,
198                 START_INTENT_NOT_RESOLVED);
199         verifyStartActivityPreconditions(PRECONDITION_NO_ACTIVITY_INFO, START_CLASS_NOT_FOUND);
200         verifyStartActivityPreconditions(PRECONDITION_SOURCE_PRESENT | PRECONDITION_REQUEST_CODE,
201                 Intent.FLAG_ACTIVITY_FORWARD_RESULT, START_FORWARD_AND_REQUEST_CONFLICT);
202         verifyStartActivityPreconditions(
203                 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
204                         | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID,
205                 START_NOT_VOICE_COMPATIBLE);
206         verifyStartActivityPreconditions(
207                 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
208                         | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID
209                         | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION,
210                 START_NOT_VOICE_COMPATIBLE);
211         verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED);
212     }
213 
containsConditions(int preconditions, int mask)214     private static boolean containsConditions(int preconditions, int mask) {
215         return (preconditions & mask) == mask;
216     }
217 
verifyStartActivityPreconditions(int preconditions, int expectedResult)218     private void verifyStartActivityPreconditions(int preconditions, int expectedResult) {
219         verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
220     }
221 
verifyStartActivityPreconditions(int preconditions, int launchFlags, int expectedResult)222     private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
223             int expectedResult) {
224         // We track mocks created here because this is used in a single test
225         // (testStartActivityPreconditions) as a specific case, and mocks created inside it won't be
226         // used for other cases. To avoid extensive memory usage, we clean up all used mocks after
227         // each case. This is necessary because usually we only clean up mocks after a test
228         // finishes, but this test creates too many mocks that the intermediate memory usage can be
229         // ~0.8 GiB and thus very susceptible to OutOfMemoryException.
230         try (MockTracker tracker = new MockTracker()) {
231             verifyStartActivityPreconditionsUntracked(preconditions, launchFlags, expectedResult);
232         }
233     }
234 
235     /**
236      * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
237      * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
238      * and the launch flags specified in the intent. The method constructs a call to
239      * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
240      * the expected. It is important to note that the method also checks side effects of the start,
241      * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
242      *
243      * @param preconditions A bitmask representing the preconditions for the launch
244      * @param launchFlags The launch flags to be provided by the launch {@link Intent}.
245      * @param expectedResult The expected result from the launch.
246      */
verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags, int expectedResult)247     private void verifyStartActivityPreconditionsUntracked(int preconditions, int launchFlags,
248             int expectedResult) {
249         final ActivityTaskManagerService service = mAtm;
250         final IPackageManager packageManager = mock(IPackageManager.class);
251 
252         final ActivityStarter starter =
253                 new ActivityStarter(
254                         mController,
255                         service,
256                         service.mTaskSupervisor,
257                         mock(ActivityStartInterceptor.class));
258         prepareStarter(launchFlags);
259         final IApplicationThread caller = mock(IApplicationThread.class);
260         final WindowProcessListener listener = mock(WindowProcessListener.class);
261 
262         final ApplicationInfo ai = new ApplicationInfo();
263         ai.packageName = "com.android.test.package";
264         final WindowProcessController wpc =
265                 containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
266                         ? null
267                         : new WindowProcessController(service, ai, null, 0, -1, null, listener);
268         doReturn(wpc).when(service).getProcessController(any());
269 
270         final Intent intent = new Intent();
271         intent.setFlags(launchFlags);
272 
273         final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO)
274                 ?  null : new ActivityInfo();
275 
276         IVoiceInteractionSession voiceSession =
277                 containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
278                         ? mock(IVoiceInteractionSession.class) : null;
279 
280         // Create source token
281         final ActivityBuilder builder = new ActivityBuilder(service).setTask(
282                 new TaskBuilder(service.mTaskSupervisor)
283                         .setVoiceSession(voiceSession)
284                         .setCreateParentTask(true)
285                         .build());
286 
287         if (aInfo != null) {
288             aInfo.applicationInfo = new ApplicationInfo();
289             aInfo.applicationInfo.packageName =
290                     ActivityBuilder.getDefaultComponent().getPackageName();
291         }
292 
293         // Offset uid by one from {@link ActivityInfo} to simulate different uids.
294         if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) {
295             builder.setUid(aInfo.applicationInfo.uid + 1);
296         }
297 
298         final ActivityRecord source = builder.build();
299 
300         if (!containsConditions(preconditions, PRECONDITION_NO_INTENT_COMPONENT)) {
301             intent.setComponent(source.mActivityComponent);
302         }
303 
304         if (containsConditions(preconditions, PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
305             doReturn(false).when(service.mTaskSupervisor).checkStartAnyActivityPermission(
306                     any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
307                     anyBoolean(), anyBoolean(), any(), any(), any());
308         }
309 
310         try {
311             if (containsConditions(preconditions,
312                     PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION)) {
313                 doAnswer((inv) -> {
314                     throw new RemoteException();
315                 }).when(packageManager).activitySupportsIntentAsUser(
316                         eq(source.mActivityComponent), eq(intent), any(), anyInt());
317             } else {
318                 doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT))
319                         .when(packageManager).activitySupportsIntentAsUser(
320                                 eq(source.mActivityComponent), eq(intent), any(), anyInt());
321             }
322         } catch (RemoteException e) {
323         }
324 
325         final IBinder resultTo = containsConditions(preconditions, PRECONDITION_SOURCE_PRESENT)
326                 || containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
327                 ? source.token : null;
328 
329         final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE)
330                 ? 1 : 0;
331 
332         final int result = starter.setCaller(caller)
333                 .setIntent(intent)
334                 .setActivityInfo(aInfo)
335                 .setResultTo(resultTo)
336                 .setRequestCode(requestCode)
337                 .setReason("testLaunchActivityPermissionDenied")
338                 .execute();
339 
340         // In some cases the expected result internally is different than the published result. We
341         // must use ActivityStarter#getExternalResult to translate.
342         assertEquals(ActivityStarter.getExternalResult(expectedResult), result);
343 
344         // Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
345         if (expectedResult != START_SUCCESS) {
346             final ActivityStarter optionStarter = new ActivityStarter(mController, mAtm,
347                     mAtm.mTaskSupervisor, mock(ActivityStartInterceptor.class));
348             final ActivityOptions options = spy(ActivityOptions.makeBasic());
349 
350             final int optionResult = optionStarter.setCaller(caller)
351                     .setIntent(intent)
352                     .setActivityInfo(aInfo)
353                     .setResultTo(resultTo)
354                     .setRequestCode(requestCode)
355                     .setReason("testLaunchActivityPermissionDenied")
356                     .setActivityOptions(new SafeActivityOptions(options))
357                     .execute();
358             verify(options, times(1)).abort();
359         }
360     }
361 
prepareStarter(@ntent.Flags int launchFlags)362     private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) {
363         return prepareStarter(launchFlags, true /* mockGetRootTask */, LAUNCH_MULTIPLE);
364     }
365 
prepareStarter(@ntent.Flags int launchFlags, boolean mockGetRootTask)366     private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
367             boolean mockGetRootTask) {
368         return prepareStarter(launchFlags, mockGetRootTask, LAUNCH_MULTIPLE);
369     }
370 
setupImeWindow()371     private void setupImeWindow() {
372         final WindowState imeWindow = createWindow(null, W_INPUT_METHOD,
373                 "mImeWindow", CURRENT_IME_UID);
374         mDisplayContent.mInputMethodWindow = imeWindow;
375     }
376 
377     /**
378      * Creates a {@link ActivityStarter} with default parameters and necessary mocks.
379      *
380      * @param launchFlags The intent flags to launch activity.
381      * @param mockGetRootTask Whether to mock {@link RootWindowContainer#getOrCreateRootTask} for
382      *                           always launching to the testing stack. Set to false when allowing
383      *                           the activity can be launched to any stack that is decided by real
384      *                           implementation.
385      * @return A {@link ActivityStarter} with default setup.
386      */
prepareStarter(@ntent.Flags int launchFlags, boolean mockGetRootTask, int launchMode)387     private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
388             boolean mockGetRootTask, int launchMode) {
389         // always allow test to start activity.
390         doReturn(true).when(mSupervisor).checkStartAnyActivityPermission(
391                 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(),
392                 anyBoolean(), anyBoolean(), any(), any(), any());
393 
394         if (mockGetRootTask) {
395             // Instrument the stack and task used.
396             final Task stack = mRootWindowContainer.getDefaultTaskDisplayArea()
397                     .createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
398                             true /* onTop */);
399 
400             // Direct starter to use spy stack.
401             doReturn(stack).when(mRootWindowContainer)
402                     .getOrCreateRootTask(any(), any(), any(), anyBoolean());
403             doReturn(stack).when(mRootWindowContainer).getOrCreateRootTask(any(), any(), any(),
404                     any(), anyBoolean(), any(), anyInt());
405         }
406 
407         // Set up mock package manager internal and make sure no unmocked methods are called
408         mMockPackageManager = mock(PackageManagerInternal.class,
409                 invocation -> {
410                     throw new RuntimeException("Not stubbed");
411                 });
412         doReturn(null).when(mMockPackageManager).getDefaultHomeActivity(anyInt());
413         doReturn(mMockPackageManager).when(mAtm).getPackageManagerInternalLocked();
414         doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
415         doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyLong(), anyLong(),
416                 anyInt(), anyBoolean(), anyInt());
417         doReturn(null).when(mMockPackageManager).resolveIntentExported(any(), any(),
418                 anyLong(), anyLong(), anyInt(), anyBoolean(), anyInt(), anyInt());
419         doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent();
420 
421         // Never review permissions
422         doReturn(false).when(mMockPackageManager).isPermissionsReviewRequired(any(), anyInt());
423         doNothing().when(mMockPackageManager).grantImplicitAccess(
424                 anyInt(), any(), anyInt(), anyInt(), anyBoolean());
425         doNothing().when(mMockPackageManager).notifyPackageUse(anyString(), anyInt());
426 
427         final Intent intent = new Intent();
428         intent.addFlags(launchFlags);
429         intent.setComponent(ActivityBuilder.getDefaultComponent());
430 
431         final ActivityInfo info = new ActivityInfo();
432 
433         info.applicationInfo = new ApplicationInfo();
434         info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
435         info.launchMode = launchMode;
436 
437         return new ActivityStarter(mController, mAtm,
438                 mAtm.mTaskSupervisor, mock(ActivityStartInterceptor.class))
439                 .setIntent(intent)
440                 .setActivityInfo(info);
441     }
442 
443     /**
444      * Ensures that values specified at launch time are passed to {@link LaunchParamsModifier}
445      * when we are laying out a new task.
446      */
447     @Test
testCreateTaskLayout()448     public void testCreateTaskLayout() {
449         // modifier for validating passed values.
450         final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
451         mAtm.mTaskSupervisor.getLaunchParamsController().registerModifier(modifier);
452 
453         // add custom values to activity info to make unique.
454         final ActivityInfo info = new ActivityInfo();
455         final Rect launchBounds = new Rect(0, 0, 20, 30);
456 
457         final WindowLayout windowLayout =
458                 new WindowLayout(10, .5f, 20, 1.0f, Gravity.NO_GRAVITY, 1, 1);
459 
460         info.windowLayout = windowLayout;
461         info.applicationInfo = new ApplicationInfo();
462         info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
463 
464         // create starter.
465         final ActivityStarter optionStarter = prepareStarter(0 /* launchFlags */);
466 
467         final ActivityOptions options = ActivityOptions.makeBasic();
468         options.setLaunchBounds(launchBounds);
469 
470         // run starter.
471         optionStarter
472                 .setReason("testCreateTaskLayout")
473                 .setActivityInfo(info)
474                 .setActivityOptions(new SafeActivityOptions(options))
475                 .execute();
476 
477         // verify that values are passed to the modifier. Values are passed thrice -- two for
478         // setting initial state, another when task is created.
479         verify(modifier, times(3)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
480                 any(), anyInt(), any(), any());
481     }
482 
483     /**
484      * This test ensures that if the intent is being delivered to a split-screen unfocused task
485      * while it already on top, reports it as delivering to top.
486      */
487     @Test
testSplitScreenDeliverToTop()488     public void testSplitScreenDeliverToTop() {
489         final ActivityStarter starter = prepareStarter(
490                 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP,
491                 false /* mockGetRootTask */);
492         final Pair<ActivityRecord, ActivityRecord> activities = createActivitiesInSplit();
493         final ActivityRecord splitPrimaryFocusActivity = activities.first;
494         final ActivityRecord splitSecondReusableActivity = activities.second;
495 
496         // Set focus back to primary.
497         splitPrimaryFocusActivity.moveFocusableActivityToTop("testSplitScreenDeliverToTop");
498 
499         // Start activity and delivered new intent.
500         starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
501         doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), any());
502         final int result = starter.setReason("testSplitScreenDeliverToTop").execute();
503 
504         // Ensure result is delivering intent to top.
505         assertEquals(START_DELIVERED_TO_TOP, result);
506     }
507 
508     /**
509      * This test ensures that if the intent is being delivered to a split-screen unfocused task
510      * reports it is brought to front instead of delivering to top.
511      */
512     @Test
testSplitScreenTaskToFront()513     public void testSplitScreenTaskToFront() {
514         final ActivityStarter starter = prepareStarter(
515                 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
516         final Pair<ActivityRecord, ActivityRecord> activities = createActivitiesInSplit();
517         final ActivityRecord splitPrimaryFocusActivity = activities.first;
518         final ActivityRecord splitSecondReusableActivity = activities.second;
519         final ActivityRecord splitSecondTopActivity = new ActivityBuilder(mAtm).setCreateTask(true)
520                 .setParentTask(splitSecondReusableActivity.getRootTask()).build();
521         assertTrue(splitSecondTopActivity.inMultiWindowMode());
522 
523         // Let primary stack has focus.
524         splitPrimaryFocusActivity.moveFocusableActivityToTop("testSplitScreenTaskToFront");
525 
526         // Start activity and delivered new intent.
527         starter.getIntent().setComponent(splitSecondReusableActivity.mActivityComponent);
528         doReturn(splitSecondReusableActivity).when(mRootWindowContainer).findTask(any(), any());
529         final int result = starter.setReason("testSplitScreenMoveToFront").execute();
530 
531         // Ensure result is moving task to front.
532         assertEquals(START_TASK_TO_FRONT, result);
533     }
534 
535     /** Returns 2 activities. The first is in primary and the second is in secondary. */
createActivitiesInSplit()536     private Pair<ActivityRecord, ActivityRecord> createActivitiesInSplit() {
537         final TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm);
538         // The fullscreen windowing mode activity will be moved to split-secondary by
539         // TestSplitOrganizer when a split-primary task appears.
540         final ActivityRecord splitPrimaryActivity = new TaskBuilder(mSupervisor)
541                 .setParentTask(splitOrg.mPrimary)
542                 .setCreateActivity(true)
543                 .build()
544                 .getTopMostActivity();
545         final ActivityRecord splitSecondActivity = new TaskBuilder(mSupervisor)
546                 .setParentTask(splitOrg.mSecondary)
547                 .setCreateActivity(true)
548                 .build()
549                 .getTopMostActivity();
550 
551         splitPrimaryActivity.setVisibleRequested(true);
552         splitSecondActivity.setVisibleRequested(true);
553 
554         assertEquals(splitOrg.mPrimary, splitPrimaryActivity.getRootTask());
555         assertEquals(splitOrg.mSecondary, splitSecondActivity.getRootTask());
556         return Pair.create(splitPrimaryActivity, splitSecondActivity);
557     }
558 
559     @Test
testMoveVisibleTaskToFront()560     public void testMoveVisibleTaskToFront() {
561         final ActivityRecord activity = new TaskBuilder(mSupervisor)
562                 .setCreateActivity(true).build().getTopMostActivity();
563         final ActivityRecord translucentActivity = new TaskBuilder(mSupervisor)
564                 .setCreateActivity(true).build().getTopMostActivity();
565         assertTrue(activity.isVisibleRequested());
566 
567         final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
568                 false /* mockGetRootTask */);
569         starter.getIntent().setComponent(activity.mActivityComponent);
570         final int result = starter.setReason("testMoveVisibleTaskToFront").execute();
571 
572         assertEquals(START_TASK_TO_FRONT, result);
573         assertEquals(1, activity.compareTo(translucentActivity));
574     }
575 
576     /**
577      * Tests activity is cleaned up properly in a task mode violation.
578      */
579     @Test
testTaskModeViolation()580     public void testTaskModeViolation() {
581         final DisplayContent display = mAtm.mRootWindowContainer.getDefaultDisplay();
582         display.removeAllTasks();
583         assertNoTasks(display);
584 
585         final ActivityStarter starter = prepareStarter(0);
586 
587         final LockTaskController lockTaskController = mAtm.getLockTaskController();
588         doReturn(true).when(lockTaskController).isNewTaskLockTaskModeViolation(any());
589 
590         final int result = starter.setReason("testTaskModeViolation").execute();
591 
592         assertEquals(START_RETURN_LOCK_TASK_MODE_VIOLATION, result);
593         assertNoTasks(display);
594     }
595 
assertNoTasks(DisplayContent display)596     private void assertNoTasks(DisplayContent display) {
597         display.forAllRootTasks(rootTask -> {
598             assertFalse(rootTask.hasChild());
599         });
600     }
601 
602     /**
603      * This test ensures that activity starts are not being logged when the logging is disabled.
604      */
605     @Test
testActivityStartsLogging_noLoggingWhenDisabled()606     public void testActivityStartsLogging_noLoggingWhenDisabled() {
607         doReturn(false).when(mAtm).isActivityStartsLoggingEnabled();
608         doReturn(mActivityMetricsLogger).when(mAtm.mTaskSupervisor).getActivityMetricsLogger();
609 
610         ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK);
611         starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute();
612 
613         // verify logging wasn't done
614         verify(mActivityMetricsLogger, never()).logAbortedBgActivityStart(any(), any(), anyInt(),
615                 any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
616     }
617 
618     /**
619      * This test ensures that activity starts are being logged when the logging is enabled.
620      */
621     @Test
testActivityStartsLogging_logsWhenEnabled()622     public void testActivityStartsLogging_logsWhenEnabled() {
623         // note: conveniently this package doesn't have any activity visible
624         doReturn(true).when(mAtm).isActivityStartsLoggingEnabled();
625         doReturn(mActivityMetricsLogger).when(mAtm.mTaskSupervisor).getActivityMetricsLogger();
626 
627         ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
628                 .setCallingUid(FAKE_CALLING_UID)
629                 .setRealCallingUid(FAKE_REAL_CALLING_UID)
630                 .setCallingPackage(FAKE_CALLING_PACKAGE)
631                 .setOriginatingPendingIntent(null);
632 
633         starter.setReason("testActivityStartsLogging_logsWhenEnabled").execute();
634 
635         // verify the above activity start was logged
636         verify(mActivityMetricsLogger, times(1)).logAbortedBgActivityStart(any(), any(),
637                 eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(),
638                 eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), eq(false));
639     }
640 
641     /**
642      * This test ensures that unsupported usecases aren't aborted when background starts are
643      * allowed.
644      */
645     @Test
testBackgroundActivityStartsAllowed_noStartsAborted()646     public void testBackgroundActivityStartsAllowed_noStartsAborted() {
647         doReturn(true).when(mAtm).isBackgroundActivityStartsEnabled();
648         runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
649                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
650                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
651                 false, false, false, false, false, false, false, false);
652     }
653 
654     /**
655      * This test ensures that unsupported usecases are aborted when background starts are
656      * disallowed.
657      */
658     @Test
testBackgroundActivityStartsDisallowed_unsupportedUsecaseAborted()659     public void testBackgroundActivityStartsDisallowed_unsupportedUsecaseAborted() {
660         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
661         runAndVerifyBackgroundActivityStartsSubtest(
662                 "disallowed_unsupportedUsecase_aborted", true,
663                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
664                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
665                 false, false, false, false, false, false, false, false);
666     }
667 
668     /**
669      * This test ensures that unsupported usecases are aborted when background starts are
670      * disallowed.
671      */
672     @Test
testBackgroundActivityStartsDisallowed_callingUidProcessStateTopAborted()673     public void testBackgroundActivityStartsDisallowed_callingUidProcessStateTopAborted() {
674         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
675         runAndVerifyBackgroundActivityStartsSubtest(
676                 "disallowed_callingUidProcessStateTop_aborted", true,
677                 UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
678                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
679                 false, false, false, false, false, false, false, false);
680     }
681 
682     /**
683      * This test ensures that unsupported usecases are aborted when background starts are
684      * disallowed.
685      */
686     @Test
testBackgroundActivityStartsDisallowed_realCallingUidProcessStateTopAborted()687     public void testBackgroundActivityStartsDisallowed_realCallingUidProcessStateTopAborted() {
688         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
689         runAndVerifyBackgroundActivityStartsSubtest(
690                 "disallowed_realCallingUidProcessStateTop_aborted", true,
691                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
692                 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
693                 false, false, false, false, false, false, false, false);
694     }
695 
696     /**
697      * This test ensures that unsupported usecases are aborted when background starts are
698      * disallowed.
699      */
700     @Test
testBackgroundActivityStartsDisallowed_hasForegroundActivitiesAborted()701     public void testBackgroundActivityStartsDisallowed_hasForegroundActivitiesAborted() {
702         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
703         runAndVerifyBackgroundActivityStartsSubtest(
704                 "disallowed_hasForegroundActivities_aborted", true,
705                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
706                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
707                 true, false, false, false, false, false, false, false);
708     }
709 
710     /**
711      * This test ensures that unsupported usecases are aborted when background starts are
712      * disallowed.
713      */
714     @Test
testBackgroundActivityStartsDisallowed_pinnedSingleInstanceAborted()715     public void testBackgroundActivityStartsDisallowed_pinnedSingleInstanceAborted() {
716         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
717         runAndVerifyBackgroundActivityStartsSubtest(
718                 "disallowed_pinned_singleinstance_aborted", true,
719                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
720                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
721                 false, false, false, false, false, false, true, false);
722     }
723 
724     /**
725      * This test ensures that supported usecases aren't aborted when background starts are
726      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
727      * this case the calling process runs as ROOT_UID.
728      */
729     @Test
testBackgroundActivityStartsDisallowed_rootUidNotAborted()730     public void testBackgroundActivityStartsDisallowed_rootUidNotAborted() {
731         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
732         runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
733                 Process.ROOT_UID, false, PROCESS_STATE_BOUND_TOP,
734                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
735                 false, false, false, false, false, false, false, false);
736     }
737 
738     /**
739      * This test ensures that supported usecases aren't aborted when background starts are
740      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
741      * this case the calling process is running as SYSTEM_UID.
742      */
743     @Test
testBackgroundActivityStartsDisallowed_systemUidNotAborted()744     public void testBackgroundActivityStartsDisallowed_systemUidNotAborted() {
745         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
746         runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
747                 Process.SYSTEM_UID, false, PROCESS_STATE_BOUND_TOP,
748                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
749                 false, false, false, false, false, false, false, false);
750     }
751 
752     /**
753      * This test ensures that supported usecases aren't aborted when background starts are
754      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
755      * this case the calling process is running as NFC_UID.
756      */
757     @Test
testBackgroundActivityStartsDisallowed_nfcUidNotAborted()758     public void testBackgroundActivityStartsDisallowed_nfcUidNotAborted() {
759         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
760         runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false,
761                 Process.NFC_UID, false, PROCESS_STATE_BOUND_TOP,
762                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
763                 false, false, false, false, false, false, false, false);
764     }
765 
766     /**
767      * This test ensures that supported usecases aren't aborted when background starts are
768      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
769      * this case the calling process has a visible window.
770      */
771     @Test
testBackgroundActivityStartsDisallowed_callingUidHasVisibleWindowNotAborted()772     public void testBackgroundActivityStartsDisallowed_callingUidHasVisibleWindowNotAborted() {
773         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
774         runAndVerifyBackgroundActivityStartsSubtest(
775                 "disallowed_callingUidHasVisibleWindow_notAborted", false,
776                 UNIMPORTANT_UID, true, PROCESS_STATE_BOUND_TOP,
777                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
778                 false, false, false, false, false, false, false, false);
779     }
780 
781     /**
782      * The sending app has a visible window, but does not (by default) allow the pending intent to
783      * start the background activity.
784      */
785     @Test
786     @Ignore("b/266015587")
testBackgroundActivityStartsDisallowed_realCallingUidHasVisibleWindowAborted()787     public void testBackgroundActivityStartsDisallowed_realCallingUidHasVisibleWindowAborted() {
788         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
789 
790         runAndVerifyBackgroundActivityStartsSubtest(
791                 "disallowed_realCallingUidHasVisibleWindow_abortedInU", true,
792                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
793                 UNIMPORTANT_UID2, true, PROCESS_STATE_BOUND_TOP,
794                 false, false, false, false, false, false, false, false);
795     }
796 
797     /**
798      * This test ensures that supported usecases aren't aborted when background starts are
799      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
800      * this case the caller is in the recent activity list.
801      */
802     @Test
testBackgroundActivityStartsDisallowed_callerIsRecentsNotAborted()803     public void testBackgroundActivityStartsDisallowed_callerIsRecentsNotAborted() {
804         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
805         runAndVerifyBackgroundActivityStartsSubtest(
806                 "disallowed_callerIsRecents_notAborted", false,
807                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
808                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
809                 false, true, false, false, false, false, false, false);
810     }
811 
812     /**
813      * This test ensures that supported usecases aren't aborted when background starts are
814      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
815      * this case the caller is temporarily (10s) allowed to start.
816      */
817     @Test
testBackgroundActivityStartsDisallowed_callerIsAllowedNotAborted()818     public void testBackgroundActivityStartsDisallowed_callerIsAllowedNotAborted() {
819         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
820         runAndVerifyBackgroundActivityStartsSubtest(
821                 "disallowed_callerIsAllowed_notAborted", false,
822                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
823                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
824                 false, false, true, false, false, false, false, false);
825     }
826 
827     /**
828      * This test ensures that supported usecases aren't aborted when background starts are
829      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
830      * this case the caller explicitly has background activity start privilege.
831      */
832     @Test
testBackgroundActivityStartsDisallowed_callerIsInstrumentingWithBASPnotAborted()833     public void testBackgroundActivityStartsDisallowed_callerIsInstrumentingWithBASPnotAborted() {
834         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
835         runAndVerifyBackgroundActivityStartsSubtest(
836                 "disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted",
837                 false,
838                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
839                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
840                 false, false, false, true, false, false, false, false);
841     }
842 
843     /**
844      * This test ensures that supported usecases aren't aborted when background starts are
845      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
846      * this case the caller is a device owner.
847      */
848     @Test
849     public void
testBackgroundActivityStartsDisallowed_callingPackageNameIsDeviceOwnerNotAborted()850             testBackgroundActivityStartsDisallowed_callingPackageNameIsDeviceOwnerNotAborted() {
851         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
852         runAndVerifyBackgroundActivityStartsSubtest(
853                 "disallowed_callingPackageNameIsDeviceOwner_notAborted", false,
854                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
855                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
856                 false, false, false, false, true, false, false, false);
857     }
858 
859     /**
860      * This test ensures that supported usecases aren't aborted when background starts are
861      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
862      * this case the caller is a affiliated profile owner.
863      */
864     @Test
865     public void
testBackgroundActivityStartsDisallowed_isAffiliatedProfileOwnerNotAborted()866             testBackgroundActivityStartsDisallowed_isAffiliatedProfileOwnerNotAborted() {
867         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
868         runAndVerifyBackgroundActivityStartsSubtest(
869                 "disallowed_callingUidIsAffiliatedProfileOwner_notAborted", false,
870                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
871                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
872                 false, false, false, false, false, true, false, false);
873     }
874 
875     /**
876      * This test ensures that supported usecases aren't aborted when background starts are
877      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
878      * this case the caller has the OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop.
879      */
880     @Test
testBackgroundActivityStartsDisallowed_callerHasSystemExemptAppOpNotAborted()881     public void testBackgroundActivityStartsDisallowed_callerHasSystemExemptAppOpNotAborted() {
882         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
883         runAndVerifyBackgroundActivityStartsSubtest(
884                 "disallowed_callerHasSystemExemptAppOpNotAborted", false,
885                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
886                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
887                 false, false, false, false, false, false, false, true);
888     }
889 
890     /**
891      * This test ensures that supported usecases aren't aborted when background starts are
892      * disallowed. Each scenarios tests one condition that makes them supported in isolation. In
893      * this case the caller is an IME.
894      */
895     @Test
testBackgroundActivityStartsDisallowed_callingPackageNameIsImeNotAborted()896     public void testBackgroundActivityStartsDisallowed_callingPackageNameIsImeNotAborted() {
897         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
898         setupImeWindow();
899         runAndVerifyBackgroundActivityStartsSubtest(
900                 "disallowed_callingPackageNameIsIme_notAborted", false,
901                 CURRENT_IME_UID, false, PROCESS_STATE_BOUND_TOP,
902                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
903                 false, false, false, false, false, false, false, false);
904     }
905 
906     /**
907      * This test ensures proper logging for BAL_ALLOW_PERMISSION.
908      */
909     @Test
testBackgroundActivityStartsAllowed_logging()910     public void testBackgroundActivityStartsAllowed_logging() {
911         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
912         MockitoSession mockingSession = mockitoSession()
913                 .mockStatic(ActivityTaskManagerService.class)
914                 .mockStatic(FrameworkStatsLog.class)
915                 .strictness(Strictness.LENIENT)
916                 .startMocking();
917         doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission(
918                 eq(START_ACTIVITIES_FROM_BACKGROUND),
919                 anyInt(), anyInt()));
920         runAndVerifyBackgroundActivityStartsSubtest(
921                 "allowed_notAborted", false,
922                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
923                 UNIMPORTANT_UID2, false, PROCESS_STATE_BOUND_TOP,
924                 false, true, false, false, false, false, false, false);
925         verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
926                 "",  // activity name
927                 BackgroundActivityStartController.BAL_ALLOW_PERMISSION,
928                 UNIMPORTANT_UID,
929                 UNIMPORTANT_UID2));
930         mockingSession.finishMocking();
931     }
932 
933     /**
934      * This test ensures proper logging for BAL_ALLOW_PENDING_INTENT.
935      */
936     @Test
testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed()937     public void testBackgroundActivityStartsAllowed_loggingPendingIntentAllowed() {
938         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
939         MockitoSession mockingSession = mockitoSession()
940                 .mockStatic(ActivityTaskManagerService.class)
941                 .mockStatic(FrameworkStatsLog.class)
942                 .mockStatic(PendingIntentRecord.class)
943                 .strictness(Strictness.LENIENT)
944                 .startMocking();
945         doReturn(PERMISSION_GRANTED).when(() -> ActivityTaskManagerService.checkPermission(
946                 eq(START_ACTIVITIES_FROM_BACKGROUND),
947                 anyInt(), anyInt()));
948         doReturn(BackgroundStartPrivileges.allowBackgroundActivityStarts(null)).when(
949                 () -> PendingIntentRecord.getBackgroundStartPrivilegesAllowedByCaller(
950                 anyObject(), anyInt(), anyObject()));
951         runAndVerifyBackgroundActivityStartsSubtest(
952                 "allowed_notAborted", false,
953                 UNIMPORTANT_UID, false, PROCESS_STATE_BOUND_TOP,
954                 Process.SYSTEM_UID, true, PROCESS_STATE_BOUND_TOP,
955                 false, true, false, false, false, false, false, false);
956         verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.BAL_ALLOWED,
957                 DEFAULT_COMPONENT_PACKAGE_NAME + "/" + DEFAULT_COMPONENT_PACKAGE_NAME,
958                 BackgroundActivityStartController.BAL_ALLOW_PENDING_INTENT,
959                 UNIMPORTANT_UID,
960                 Process.SYSTEM_UID));
961         mockingSession.finishMocking();
962     }
963 
964 
965     @Test
testBackgroundActivityStartsAllowed_sdkSandboxClientAppHasVisibleWindow()966     public void testBackgroundActivityStartsAllowed_sdkSandboxClientAppHasVisibleWindow() {
967         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
968         // The SDK's associated client app has a visible window
969         doReturn(true).when(mAtm).hasActiveVisibleWindow(
970                 Process.getAppUidForSdkSandboxUid(SDK_SANDBOX_UID));
971         runAndVerifyBackgroundActivityStartsSubtest(
972                 "allowed_sdkSandboxClientAppHasVisibleWindow", false, SDK_SANDBOX_UID,
973                 false, PROCESS_STATE_TOP, SDK_SANDBOX_UID, false,
974                 PROCESS_STATE_TOP, true, false, false,
975                 false, false, false, false, false);
976     }
977 
978     @Test
testBackgroundActivityStartsDisallowed_sdkSandboxClientHasNoVisibleWindow()979     public void testBackgroundActivityStartsDisallowed_sdkSandboxClientHasNoVisibleWindow() {
980         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
981         // The SDK's associated client app does not have a visible window
982         doReturn(false).when(mAtm).hasActiveVisibleWindow(
983                 Process.getAppUidForSdkSandboxUid(SDK_SANDBOX_UID));
984         runAndVerifyBackgroundActivityStartsSubtest(
985                 "disallowed_sdkSandboxClientHasNoVisibleWindow", true, SDK_SANDBOX_UID,
986                 false, PROCESS_STATE_TOP, SDK_SANDBOX_UID, false,
987                 PROCESS_STATE_TOP, true, false, false,
988                 false, false, false, false, false);
989 
990     }
991 
992     @Test
testBackgroundActivityStartsAllowed_sdkSandboxMultiUserClientHasVisibleWindow()993     public void testBackgroundActivityStartsAllowed_sdkSandboxMultiUserClientHasVisibleWindow() {
994         doReturn(false).when(mAtm).isBackgroundActivityStartsEnabled();
995         // The SDK's associated client app has a visible window
996         doReturn(true).when(mAtm).hasActiveVisibleWindow(
997                 Process.getAppUidForSdkSandboxUid(SECONDARY_USER_SDK_SANDBOX_UID));
998         runAndVerifyBackgroundActivityStartsSubtest(
999                 "allowed_sdkSandboxMultiUserClientHasVisibleWindow", false,
1000                 SECONDARY_USER_SDK_SANDBOX_UID, false, PROCESS_STATE_TOP,
1001                 SECONDARY_USER_SDK_SANDBOX_UID, false, PROCESS_STATE_TOP,
1002                 false, false, false, false,
1003                 false, false, false, false);
1004     }
1005 
runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted, int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState, int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState, boolean hasForegroundActivities, boolean callerIsRecents, boolean callerIsTempAllowed, boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges, boolean isCallingUidDeviceOwner, boolean isCallingUidAffiliatedProfileOwner, boolean isPinnedSingleInstance, boolean hasSystemExemptAppOp)1006     private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
1007             int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
1008             int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
1009             boolean hasForegroundActivities, boolean callerIsRecents,
1010             boolean callerIsTempAllowed,
1011             boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
1012             boolean isCallingUidDeviceOwner,
1013             boolean isCallingUidAffiliatedProfileOwner,
1014             boolean isPinnedSingleInstance,
1015             boolean hasSystemExemptAppOp) {
1016         // window visibility
1017         doReturn(callingUidHasVisibleWindow).when(mAtm).hasActiveVisibleWindow(callingUid);
1018         doReturn(realCallingUidHasVisibleWindow).when(mAtm).hasActiveVisibleWindow(realCallingUid);
1019         // process importance
1020         mAtm.mActiveUids.onUidActive(callingUid, callingUidProcState);
1021         mAtm.mActiveUids.onUidActive(realCallingUid, realCallingUidProcState);
1022         // foreground activities
1023         final IApplicationThread caller = mock(IApplicationThread.class);
1024         final WindowProcessListener listener = mock(WindowProcessListener.class);
1025         final ApplicationInfo ai = new ApplicationInfo();
1026         ai.uid = callingUid;
1027         ai.packageName = "com.android.test.package";
1028         final WindowProcessController callerApp =
1029                 spy(new WindowProcessController(mAtm, ai, null, callingUid, -1, null, listener));
1030         doReturn(hasForegroundActivities).when(callerApp).hasForegroundActivities();
1031         doReturn(callerApp).when(mAtm).getProcessController(caller);
1032         // caller is recents
1033         RecentTasks recentTasks = mock(RecentTasks.class);
1034         mAtm.mTaskSupervisor.setRecentTasks(recentTasks);
1035         doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
1036         // caller is temp allowed
1037         if (callerIsTempAllowed) {
1038             callerApp.addOrUpdateBackgroundStartPrivileges(new Binder(),
1039                     BackgroundStartPrivileges.ALLOW_BAL);
1040         }
1041         // caller is instrumenting with background activity starts privileges
1042         callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
1043                 callerIsInstrumentingWithBackgroundActivityStartPrivileges ? Process.SHELL_UID : -1,
1044                 callerIsInstrumentingWithBackgroundActivityStartPrivileges);
1045         // callingUid is the device owner
1046         doReturn(isCallingUidDeviceOwner).when(mAtm).isDeviceOwner(callingUid);
1047         // callingUid is the affiliated profile owner
1048         doReturn(isCallingUidAffiliatedProfileOwner).when(mAtm)
1049             .isAffiliatedProfileOwner(callingUid);
1050 
1051         // caller has OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION appop
1052         doReturn(hasSystemExemptAppOp ? AppOpsManager.MODE_ALLOWED
1053                 : AppOpsManager.MODE_DEFAULT).when(mAppOpsManager).checkOpNoThrow(
1054                 eq(AppOpsManager.OP_SYSTEM_EXEMPT_FROM_ACTIVITY_BG_START_RESTRICTION),
1055                 anyInt(), any());
1056 
1057         int launchMode = LAUNCH_MULTIPLE;
1058         if (isPinnedSingleInstance) {
1059             final ActivityRecord baseActivity =
1060                     new ActivityBuilder(mAtm).setCreateTask(true).build();
1061             baseActivity.getRootTask()
1062                     .setWindowingMode(WINDOWING_MODE_PINNED);
1063             doReturn(baseActivity).when(mRootWindowContainer).findTask(any(), any());
1064             launchMode = LAUNCH_SINGLE_INSTANCE;
1065         }
1066 
1067         final ActivityOptions options = spy(ActivityOptions.makeBasic());
1068         ActivityRecord[] outActivity = new ActivityRecord[1];
1069         ActivityStarter starter = prepareStarter(
1070                 FLAG_ACTIVITY_NEW_TASK, true, launchMode)
1071                 .setCallingPackage("com.whatever.dude")
1072                 .setCaller(caller)
1073                 .setCallingUid(callingUid)
1074                 .setRealCallingUid(realCallingUid)
1075                 .setActivityOptions(new SafeActivityOptions(options))
1076                 .setOutActivity(outActivity);
1077 
1078         final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();
1079 
1080         assertEquals(ActivityStarter.getExternalResult(
1081                 shouldHaveAborted ? START_ABORTED : START_SUCCESS), result);
1082         verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
1083 
1084         final ActivityRecord startedActivity = outActivity[0];
1085         if (startedActivity != null && startedActivity.getTask() != null) {
1086             // Remove the activity so it doesn't interfere with with subsequent activity launch
1087             // tests from this method.
1088             startedActivity.getTask().removeChild(startedActivity);
1089         }
1090     }
1091 
1092     /**
1093      * This test ensures that {@link ActivityStarter#setTargetRootTaskIfNeeded} will task the
1094      * adjacent task of indicated launch target into account. So the existing task will be launched
1095      * into closer target.
1096      */
1097     @Test
testAdjustLaunchTargetWithAdjacentTask()1098     public void testAdjustLaunchTargetWithAdjacentTask() {
1099         // Create adjacent tasks and put one activity under it
1100         final Task parent = new TaskBuilder(mSupervisor).build();
1101         final Task adjacentParent = new TaskBuilder(mSupervisor).build();
1102         parent.setAdjacentTaskFragment(adjacentParent);
1103         final ActivityRecord activity = new ActivityBuilder(mAtm)
1104                 .setParentTask(parent)
1105                 .setCreateTask(true).build();
1106 
1107         // Launch the activity to its adjacent parent
1108         final ActivityOptions options = ActivityOptions.makeBasic()
1109                 .setLaunchRootTask(adjacentParent.mRemoteToken.toWindowContainerToken());
1110         prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */)
1111                 .setReason("testAdjustLaunchTargetWithAdjacentTask")
1112                 .setIntent(activity.intent)
1113                 .setActivityOptions(options.toBundle())
1114                 .execute();
1115 
1116         // Verify the activity will be launched into the original parent
1117         assertTrue(activity.isDescendantOf(parent));
1118     }
1119 
1120     /**
1121      * This test ensures that {@link ActivityStarter#setTargetRootTaskIfNeeded} will
1122      * move the existing task to front if the current focused root task doesn't have running task.
1123      */
1124     @Test
testBringTaskToFrontWhenFocusedTaskIsFinishing()1125     public void testBringTaskToFrontWhenFocusedTaskIsFinishing() {
1126         // Put 2 tasks in the same root task (simulate the behavior of home root task).
1127         final Task rootTask = new TaskBuilder(mSupervisor).build();
1128         final ActivityRecord activity = new ActivityBuilder(mAtm)
1129                 .setParentTask(rootTask)
1130                 .setCreateTask(true).build();
1131         new ActivityBuilder(mAtm)
1132                 .setParentTask(activity.getRootTask())
1133                 .setCreateTask(true).build();
1134 
1135         // Create a top finishing activity.
1136         final ActivityRecord finishingTopActivity = new ActivityBuilder(mAtm)
1137                 .setCreateTask(true).build();
1138         finishingTopActivity.getRootTask().moveToFront("finishingTopActivity");
1139 
1140         assertEquals(finishingTopActivity, mRootWindowContainer.topRunningActivity());
1141         finishingTopActivity.finishing = true;
1142 
1143         // Launch the bottom task of the target root task.
1144         prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */)
1145                 .setReason("testBringTaskToFrontWhenFocusedTaskIsFinishing")
1146                 .setIntent(activity.intent.addFlags(
1147                         FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
1148                 .execute();
1149         verify(activity.getRootTask()).startActivityLocked(any(), any(), anyBoolean(),
1150                 eq(true) /* isTaskSwitch */, any(), any());
1151         // The hierarchies of the activity should move to front.
1152         assertEquals(activity.getTask(), mRootWindowContainer.topRunningActivity().getTask());
1153     }
1154 
1155     /**
1156      * This test ensures that when starting an existing single task activity on secondary display
1157      * which is not the top focused display, it should deliver new intent to the activity and not
1158      * create a new stack.
1159      */
1160     @Test
testDeliverIntentToTopActivityOfNonTopDisplay()1161     public void testDeliverIntentToTopActivityOfNonTopDisplay() {
1162         final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
1163                 false /* mockGetRootTask */);
1164 
1165         // Create a secondary display at bottom.
1166         final TestDisplayContent secondaryDisplay =
1167                 new TestDisplayContent.Builder(mAtm, 1000, 1500)
1168                         .setPosition(POSITION_BOTTOM).build();
1169         final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
1170         final Task stack = secondaryTaskContainer.createRootTask(
1171                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
1172 
1173         // Create an activity record on the top of secondary display.
1174         final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
1175 
1176         // Put an activity on default display as the top focused activity.
1177         new ActivityBuilder(mAtm).setCreateTask(true).build();
1178 
1179         // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
1180         // on secondary display.
1181         final ActivityOptions options = ActivityOptions.makeBasic()
1182                 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
1183         final int result = starter.setReason("testDeliverIntentToTopActivityOfNonTopDisplay")
1184                 .setIntent(topActivityOnSecondaryDisplay.intent)
1185                 .setActivityOptions(options.toBundle())
1186                 .execute();
1187 
1188         // Ensure result is delivering intent to top.
1189         assertEquals(START_DELIVERED_TO_TOP, result);
1190 
1191         // Ensure secondary display only creates one stack.
1192         verify(secondaryTaskContainer, times(1)).createRootTask(anyInt(), anyInt(), anyBoolean());
1193     }
1194 
1195     /**
1196      * This test ensures that when starting an existing non-top single task activity on secondary
1197      * display which is the top focused display, it should bring the task to front without creating
1198      * unused stack.
1199      */
1200     @Test
testBringTaskToFrontOnSecondaryDisplay()1201     public void testBringTaskToFrontOnSecondaryDisplay() {
1202         final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
1203                 false /* mockGetRootTask */);
1204 
1205         // Create a secondary display with an activity.
1206         final TestDisplayContent secondaryDisplay =
1207                 new TestDisplayContent.Builder(mAtm, 1000, 1500).build();
1208         mRootWindowContainer.positionChildAt(POSITION_TOP, secondaryDisplay,
1209                 false /* includingParents */);
1210         final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
1211         final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
1212                 secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN,
1213                         ACTIVITY_TYPE_STANDARD, false /* onTop */));
1214         // Activity should start invisible since we are bringing it to front.
1215         singleTaskActivity.setVisible(false);
1216         singleTaskActivity.setVisibleRequested(false);
1217 
1218         // Create another activity on top of the secondary display.
1219         final Task topStack = secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN,
1220                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
1221         final Task topTask = new TaskBuilder(mSupervisor).setParentTask(topStack).build();
1222         new ActivityBuilder(mAtm).setTask(topTask).build();
1223 
1224         doReturn(mActivityMetricsLogger).when(mSupervisor).getActivityMetricsLogger();
1225         // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
1226         final ActivityOptions options = ActivityOptions.makeBasic()
1227                 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
1228         final int result = starter.setReason("testBringTaskToFrontOnSecondaryDisplay")
1229                 .setIntent(singleTaskActivity.intent)
1230                 .setActivityOptions(options.toBundle())
1231                 .execute();
1232 
1233         // Ensure result is moving existing task to front.
1234         assertEquals(START_TASK_TO_FRONT, result);
1235 
1236         // Ensure secondary display only creates two stacks.
1237         verify(secondaryTaskContainer, times(2)).createRootTask(anyInt(), anyInt(), anyBoolean());
1238         // The metrics logger should receive the same result and non-null options.
1239         verify(mActivityMetricsLogger).notifyActivityLaunched(any() /* launchingState */,
1240                 eq(result), eq(false) /* newActivityCreated */, eq(singleTaskActivity),
1241                 notNull() /* options */);
1242     }
1243 
1244     @Test
testWasVisibleInRestartAttempt()1245     public void testWasVisibleInRestartAttempt() {
1246         final ActivityStarter starter = prepareStarter(
1247                 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | FLAG_ACTIVITY_SINGLE_TOP, false);
1248         final ActivityRecord reusableActivity =
1249                 new ActivityBuilder(mAtm).setCreateTask(true).build();
1250         final ActivityRecord topActivity =
1251                 new ActivityBuilder(mAtm).setCreateTask(true).build();
1252 
1253         // Make sure topActivity is on top
1254         topActivity.getRootTask().moveToFront("testWasVisibleInRestartAttempt");
1255         reusableActivity.setVisible(false);
1256 
1257         final TaskChangeNotificationController taskChangeNotifier =
1258                 mAtm.getTaskChangeNotificationController();
1259         spyOn(taskChangeNotifier);
1260 
1261         Task task = topActivity.getTask();
1262         starter.postStartActivityProcessing(
1263                 task.getTopNonFinishingActivity(), START_DELIVERED_TO_TOP, task.getRootTask());
1264 
1265         verify(taskChangeNotifier).notifyActivityRestartAttempt(
1266                 any(), anyBoolean(), anyBoolean(), anyBoolean());
1267         verify(taskChangeNotifier).notifyActivityRestartAttempt(
1268                 any(), anyBoolean(), anyBoolean(), eq(true));
1269 
1270         Task task2 = reusableActivity.getTask();
1271         starter.postStartActivityProcessing(
1272                 task2.getTopNonFinishingActivity(), START_TASK_TO_FRONT, task.getRootTask());
1273         verify(taskChangeNotifier, times(2)).notifyActivityRestartAttempt(
1274                 any(), anyBoolean(), anyBoolean(), anyBoolean());
1275         verify(taskChangeNotifier).notifyActivityRestartAttempt(
1276                 any(), anyBoolean(), anyBoolean(), eq(false));
1277     }
1278 
createSingleTaskActivityOn(Task task)1279     private ActivityRecord createSingleTaskActivityOn(Task task) {
1280         final ComponentName componentName = ComponentName.createRelative(
1281                 DEFAULT_COMPONENT_PACKAGE_NAME,
1282                 DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
1283         return new ActivityBuilder(mAtm)
1284                 .setComponent(componentName)
1285                 .setLaunchMode(LAUNCH_SINGLE_TASK)
1286                 .setTask(task)
1287                 .build();
1288     }
1289 
1290     /**
1291      * This test ensures that a reused top activity in the top focused stack is able to be
1292      * reparented to another display.
1293      */
1294     @Test
testReparentTopFocusedActivityToSecondaryDisplay()1295     public void testReparentTopFocusedActivityToSecondaryDisplay() {
1296         final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
1297                 false /* mockGetRootTask */);
1298 
1299         // Create a secondary display at bottom.
1300         final TestDisplayContent secondaryDisplay = addNewDisplayContentAt(POSITION_BOTTOM);
1301         final TaskDisplayArea secondaryTaskContainer = secondaryDisplay.getDefaultTaskDisplayArea();
1302         secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
1303                 true /* onTop */);
1304 
1305         // Put an activity on default display as the top focused activity.
1306         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1307                 .setCreateTask(true)
1308                 .setLaunchMode(LAUNCH_SINGLE_TASK)
1309                 .build();
1310 
1311         // Start activity with the same intent as {@code topActivity} on secondary display.
1312         final ActivityOptions options = ActivityOptions.makeBasic()
1313                 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
1314         starter.setReason("testReparentTopFocusedActivityToSecondaryDisplay")
1315                 .setIntent(topActivity.intent)
1316                 .setActivityOptions(options.toBundle())
1317                 .execute();
1318 
1319         // Ensure the activity is moved to secondary display.
1320         assertEquals(secondaryDisplay, topActivity.mDisplayContent);
1321     }
1322 
1323     /**
1324      * This test ensures that starting an activity with the freeze-task-list activity option will
1325      * actually freeze the task list
1326      */
1327     @Test
testFreezeTaskListActivityOption()1328     public void testFreezeTaskListActivityOption() {
1329         RecentTasks recentTasks = mock(RecentTasks.class);
1330         mAtm.mTaskSupervisor.setRecentTasks(recentTasks);
1331         doReturn(true).when(recentTasks).isCallerRecents(anyInt());
1332 
1333         final ActivityStarter starter = prepareStarter(0 /* flags */);
1334         final ActivityOptions options = ActivityOptions.makeBasic();
1335         options.setFreezeRecentTasksReordering();
1336 
1337         starter.setReason("testFreezeTaskListActivityOption")
1338                 .setActivityOptions(new SafeActivityOptions(options))
1339                 .execute();
1340 
1341         verify(recentTasks, times(1)).setFreezeTaskListReordering();
1342         verify(recentTasks, times(0)).resetFreezeTaskListReorderingOnTimeout();
1343     }
1344 
1345     /**
1346      * This test ensures that if we froze the task list as a part of starting an activity that fails
1347      * to start, that we also reset the task list.
1348      */
1349     @Test
testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList()1350     public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() {
1351         RecentTasks recentTasks = mock(RecentTasks.class);
1352         mAtm.mTaskSupervisor.setRecentTasks(recentTasks);
1353         doReturn(true).when(recentTasks).isCallerRecents(anyInt());
1354 
1355         final ActivityStarter starter = prepareStarter(0 /* flags */);
1356         final ActivityOptions options = ActivityOptions.makeBasic();
1357         options.setFreezeRecentTasksReordering();
1358 
1359         starter.setReason("testFreezeTaskListActivityOptionFailedStart")
1360                 .setActivityOptions(new SafeActivityOptions(options))
1361                 .execute();
1362 
1363         // Simulate a failed start
1364         starter.postStartActivityProcessing(null, START_CANCELED, null);
1365 
1366         verify(recentTasks, times(1)).setFreezeTaskListReordering();
1367         verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
1368     }
1369 
1370     @Test
testNoActivityInfo()1371     public void testNoActivityInfo() {
1372         final ActivityStarter starter = prepareStarter(0 /* flags */);
1373         spyOn(starter.mRequest);
1374 
1375         final Intent intent = new Intent();
1376         intent.setComponent(ActivityBuilder.getDefaultComponent());
1377         starter.setReason("testNoActivityInfo").setIntent(intent)
1378                 .setActivityInfo(null).execute();
1379         verify(starter.mRequest).resolveActivity(any());
1380     }
1381 
1382     @Test
testResolveEphemeralInstaller()1383     public void testResolveEphemeralInstaller() {
1384         final ActivityStarter starter = prepareStarter(0 /* flags */);
1385         final Intent intent = new Intent();
1386         intent.setComponent(ActivityBuilder.getDefaultComponent());
1387 
1388         doReturn(true).when(mMockPackageManager).isInstantAppInstallerComponent(any());
1389         starter.setIntent(intent).mRequest.resolveActivity(mAtm.mTaskSupervisor);
1390 
1391         // Make sure the client intent won't be modified.
1392         assertThat(intent.getComponent()).isNotNull();
1393         assertThat(starter.getIntent().getComponent()).isNull();
1394     }
1395 
1396     @Test
testNotAllowIntentWithFd()1397     public void testNotAllowIntentWithFd() {
1398         final ActivityStarter starter = prepareStarter(0 /* flags */);
1399         final Intent intent = spy(new Intent());
1400         intent.setComponent(ActivityBuilder.getDefaultComponent());
1401         doReturn(true).when(intent).hasFileDescriptors();
1402 
1403         boolean exceptionCaught = false;
1404         try {
1405             starter.setIntent(intent).execute();
1406         } catch (IllegalArgumentException ex) {
1407             exceptionCaught = true;
1408         }
1409         assertThat(exceptionCaught).isTrue();
1410     }
1411 
1412     @Test
testRecycleTaskFromAnotherUser()1413     public void testRecycleTaskFromAnotherUser() {
1414         final ActivityStarter starter = prepareStarter(0 /* flags */);
1415         starter.mStartActivity = new ActivityBuilder(mAtm).build();
1416         final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
1417                 .setParentTask(createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
1418                         ACTIVITY_TYPE_STANDARD))
1419                 .setUserId(10)
1420                 .build();
1421 
1422         final int result = starter.recycleTask(task, null, null, null);
1423         assertThat(result == START_SUCCESS).isTrue();
1424         assertThat(starter.mAddingToTask).isTrue();
1425     }
1426 
1427     @Test
testRecycleTaskWakeUpWhenDreaming()1428     public void testRecycleTaskWakeUpWhenDreaming() {
1429         doNothing().when(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString());
1430         doReturn(true).when(mWm.mAtmService).isDreaming();
1431         final ActivityStarter starter = prepareStarter(0 /* flags */);
1432         final ActivityRecord target = new ActivityBuilder(mAtm).setCreateTask(true).build();
1433         starter.mStartActivity = target;
1434         target.setVisibleRequested(false);
1435         target.setTurnScreenOn(true);
1436         // Assume the flag was consumed by relayout.
1437         target.setCurrentLaunchCanTurnScreenOn(false);
1438         startActivityInner(starter, target, null /* source */, null /* options */,
1439                 null /* inTask */, null /* inTaskFragment */);
1440         // The flag should be set again when resuming (from recycleTask) the target as top.
1441         assertTrue(target.currentLaunchCanTurnScreenOn());
1442         // In real case, dream activity has a higher priority (TaskDisplayArea#getPriority) that
1443         // will be put at a higher z-order. So it relies on wakeUp() to be dismissed.
1444         verify(mWm.mAtmService.mTaskSupervisor).wakeUp(anyString());
1445     }
1446 
1447     @Test
testTargetTaskInSplitScreen()1448     public void testTargetTaskInSplitScreen() {
1449         final ActivityStarter starter =
1450                 prepareStarter(FLAG_ACTIVITY_LAUNCH_ADJACENT, false /* mockGetRootTask */);
1451         final ActivityRecord top = new ActivityBuilder(mAtm).setCreateTask(true).build();
1452         final ActivityOptions options = ActivityOptions.makeBasic();
1453         final ActivityRecord[] outActivity = new ActivityRecord[1];
1454 
1455         // Activity must not land on split-screen task if currently not in split-screen mode.
1456         starter.setActivityOptions(options.toBundle())
1457                 .setReason("testTargetTaskInSplitScreen")
1458                 .setOutActivity(outActivity).execute();
1459         assertThat(outActivity[0].inMultiWindowMode()).isFalse();
1460 
1461         // Move activity to split-screen-primary task and make sure it has the focus.
1462         TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm, top.getDisplayContent());
1463         top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM);
1464         top.getRootTask().moveToFront("testTargetTaskInSplitScreen");
1465 
1466         // Activity must land on split-screen-secondary when launch adjacent.
1467         startActivityInner(starter, outActivity[0], top, options, null /* inTask */,
1468                 null /* taskFragment*/);
1469         assertThat(outActivity[0].inMultiWindowMode()).isTrue();
1470     }
1471 
1472     @Test
testActivityStart_expectAddedToRecentTask()1473     public void testActivityStart_expectAddedToRecentTask() {
1474         RecentTasks recentTasks = mock(RecentTasks.class);
1475         mAtm.mTaskSupervisor.setRecentTasks(recentTasks);
1476         doReturn(true).when(recentTasks).isCallerRecents(anyInt());
1477 
1478         final ActivityStarter starter = prepareStarter(0 /* flags */);
1479 
1480         starter.setReason("testAddToTaskListOnActivityStart")
1481                 .execute();
1482 
1483         verify(recentTasks, times(1)).add(any());
1484     }
1485 
1486     @Test
testStartActivityInner_inTaskFragment_failsByDefault()1487     public void testStartActivityInner_inTaskFragment_failsByDefault() {
1488         final ActivityStarter starter = prepareStarter(0, false);
1489         final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
1490         final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
1491         final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
1492                 true /* createdByOrganizer */);
1493         sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
1494 
1495         startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
1496                 null /* inTask */, taskFragment);
1497 
1498         assertFalse(taskFragment.hasChild());
1499         assertNotNull("Target record must be started on Task.", targetRecord.getParent().asTask());
1500     }
1501 
1502     @Test
testStartActivityInner_inTaskFragment_allowedForSystemUid()1503     public void testStartActivityInner_inTaskFragment_allowedForSystemUid() {
1504         final ActivityStarter starter = prepareStarter(0, false);
1505         final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
1506         final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
1507         final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
1508                 true /* createdByOrganizer */);
1509         sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
1510 
1511         taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class), SYSTEM_UID,
1512                 "system_uid");
1513 
1514         startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
1515                 null /* inTask */, taskFragment);
1516 
1517         assertTrue(taskFragment.hasChild());
1518     }
1519 
1520     @Test
testStartActivityInner_inTaskFragment_allowedForSameUid()1521     public void testStartActivityInner_inTaskFragment_allowedForSameUid() {
1522         final ActivityStarter starter = prepareStarter(0, false);
1523         final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
1524         final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
1525         final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
1526                 true /* createdByOrganizer */);
1527         sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
1528 
1529         taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class),
1530                 targetRecord.getUid(), "test_process_name");
1531 
1532         startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
1533                 null /* inTask */, taskFragment);
1534 
1535         assertTrue(taskFragment.hasChild());
1536     }
1537 
1538     @Test
testStartActivityInner_inTaskFragment_allowedTrustedCertUid()1539     public void testStartActivityInner_inTaskFragment_allowedTrustedCertUid() {
1540         final ActivityStarter starter = prepareStarter(0, false);
1541         final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
1542         final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
1543         final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
1544                 true /* createdByOrganizer */);
1545         sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
1546 
1547         taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class),
1548                 12345, "test_process_name");
1549         AndroidPackage androidPackage = mock(AndroidPackage.class);
1550         doReturn(androidPackage).when(mMockPackageManager).getPackage(eq(12345));
1551 
1552         Set<String> certs = new HashSet(Arrays.asList("test_cert1", "test_cert1"));
1553         targetRecord.info.setKnownActivityEmbeddingCerts(certs);
1554         SigningDetails signingDetails = mock(SigningDetails.class);
1555         doReturn(true).when(signingDetails).hasAncestorOrSelfWithDigest(any());
1556         doReturn(signingDetails).when(androidPackage).getSigningDetails();
1557 
1558         startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
1559                 null /* inTask */, taskFragment);
1560 
1561         assertTrue(taskFragment.hasChild());
1562     }
1563 
1564     @Test
testStartActivityInner_inTaskFragment_allowedForUntrustedEmbedding()1565     public void testStartActivityInner_inTaskFragment_allowedForUntrustedEmbedding() {
1566         final ActivityStarter starter = prepareStarter(0, false);
1567         final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
1568         final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
1569         final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
1570                 true /* createdByOrganizer */);
1571         sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
1572 
1573         targetRecord.info.flags |= ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
1574 
1575         startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
1576                 null /* inTask */, taskFragment);
1577 
1578         assertTrue(taskFragment.hasChild());
1579     }
1580 
1581     @Test
testStartActivityInner_inTask()1582     public void testStartActivityInner_inTask() {
1583         final ActivityStarter starter = prepareStarter(0, false);
1584         // Simulate an app uses AppTask to create a non-attached task, and then it requests to
1585         // start activity in the task.
1586         final Task inTask = new TaskBuilder(mSupervisor).setTaskDisplayArea(null).setTaskId(123)
1587                 .build();
1588         inTask.inRecents = true;
1589         assertFalse(inTask.isAttached());
1590         final ActivityRecord target = new ActivityBuilder(mAtm).build();
1591         startActivityInner(starter, target, null /* source */, null /* options */, inTask,
1592                 null /* inTaskFragment */);
1593 
1594         assertTrue(inTask.isAttached());
1595         assertEquals(inTask, target.getTask());
1596     }
1597 
1598     @Test
testLaunchCookie_newAndExistingTask()1599     public void testLaunchCookie_newAndExistingTask() {
1600         final ActivityStarter starter = prepareStarter(0, false);
1601 
1602         // Put an activity on default display as the top focused activity.
1603         ActivityRecord r = new ActivityBuilder(mAtm).setCreateTask(true).build();
1604 
1605         // Start an activity with a launch cookie
1606         final Binder cookie = new Binder();
1607         final ActivityOptions options = ActivityOptions.makeBasic();
1608         options.setLaunchCookie(cookie);
1609         final Intent intent = new Intent();
1610         intent.setComponent(ActivityBuilder.getDefaultComponent());
1611         starter.setReason("testLaunchCookie_newTask")
1612                 .setIntent(intent)
1613                 .setActivityOptions(options.toBundle())
1614                 .execute();
1615 
1616         // Verify the cookie is set
1617         assertTrue(mRootWindowContainer.topRunningActivity().mLaunchCookie == cookie);
1618 
1619         // Relaunch the activity to bring the task forward
1620         final Binder newCookie = new Binder();
1621         final ActivityOptions newOptions = ActivityOptions.makeBasic();
1622         newOptions.setLaunchCookie(newCookie);
1623         starter.setReason("testLaunchCookie_existingTask")
1624                 .setIntent(intent)
1625                 .setActivityOptions(newOptions.toBundle())
1626                 .execute();
1627 
1628         // Verify the cookie is updated
1629         assertTrue(mRootWindowContainer.topRunningActivity().mLaunchCookie == newCookie);
1630     }
1631 
1632     @Test
testRemoteAnimation_appliesToExistingTask()1633     public void testRemoteAnimation_appliesToExistingTask() {
1634         final ActivityStarter starter = prepareStarter(0, false);
1635 
1636         // Put an activity on default display as the top focused activity.
1637         ActivityRecord r = new ActivityBuilder(mAtm).setCreateTask(true).build();
1638         final Intent intent = new Intent();
1639         intent.setComponent(ActivityBuilder.getDefaultComponent());
1640         starter.setReason("testRemoteAnimation_newTask")
1641                 .setIntent(intent)
1642                 .execute();
1643 
1644         assertNull(mRootWindowContainer.topRunningActivity().mPendingRemoteAnimation);
1645 
1646         // Relaunch the activity with remote animation indicated in options.
1647         final RemoteAnimationAdapter adaptor = mock(RemoteAnimationAdapter.class);
1648         final ActivityOptions options = ActivityOptions.makeRemoteAnimation(adaptor);
1649         starter.setReason("testRemoteAnimation_existingTask")
1650                 .setIntent(intent)
1651                 .setActivityOptions(options.toBundle())
1652                 .execute();
1653 
1654         // Verify the remote animation is updated.
1655         assertEquals(adaptor, mRootWindowContainer.topRunningActivity().mPendingRemoteAnimation);
1656     }
1657 
1658     @Test
testStartLaunchIntoPipActivity()1659     public void testStartLaunchIntoPipActivity() {
1660         final ActivityStarter starter = prepareStarter(0, false);
1661 
1662         // Create an activity from ActivityOptions#makeLaunchIntoPip
1663         final PictureInPictureParams params = new PictureInPictureParams.Builder()
1664                 .build();
1665         final ActivityOptions opts = ActivityOptions.makeLaunchIntoPip(params);
1666         ActivityRecord targetRecord = new ActivityBuilder(mAtm)
1667                 .setActivityOptions(opts)
1668                 .build();
1669 
1670         // Start the target launch-into-pip activity from a source
1671         final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
1672         startActivityInner(starter, targetRecord, sourceRecord, opts,
1673                 null /* inTask */, null /* inTaskFragment */);
1674 
1675         // Verify the ActivityRecord#getLaunchIntoPipHostActivity points to sourceRecord.
1676         assertThat(targetRecord.getLaunchIntoPipHostActivity()).isNotNull();
1677         assertEquals(targetRecord.getLaunchIntoPipHostActivity(), sourceRecord);
1678     }
1679 
1680     @Test
testResultCanceledWhenNotAllowedStartingActivity()1681     public void testResultCanceledWhenNotAllowedStartingActivity() {
1682         final Task task = new TaskBuilder(mSupervisor).build();
1683         final ActivityStarter starter = prepareStarter(0, false);
1684         final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
1685         final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setTask(task).build();
1686         targetRecord.resultTo = sourceRecord;
1687 
1688         // Abort the activity start and ensure the sourceRecord gets the result (RESULT_CANCELED).
1689         spyOn(starter);
1690         doReturn(START_ABORTED).when(starter).isAllowedToStart(any(), anyBoolean(), any());
1691         startActivityInner(starter, targetRecord, sourceRecord, null /* options */,
1692                 null /* inTask */, null /* inTaskFragment */);
1693         verify(sourceRecord).sendResult(anyInt(), any(), anyInt(), eq(RESULT_CANCELED), any(),
1694                 any());
1695     }
1696 
1697     @Test
testCanEmbedActivity()1698     public void testCanEmbedActivity() {
1699         final Size minDimensions = new Size(1000, 1000);
1700         final WindowLayout windowLayout = new WindowLayout(0, 0, 0, 0, 0,
1701                 minDimensions.getWidth(), minDimensions.getHeight());
1702         final ActivityRecord starting = new ActivityBuilder(mAtm)
1703                 .setUid(UNIMPORTANT_UID)
1704                 .setWindowLayout(windowLayout)
1705                 .build();
1706 
1707         // Task fragment hasn't attached to a task yet. Start activity to a new task.
1708         TaskFragment taskFragment = new TaskFragmentBuilder(mAtm).build();
1709         final Task task = new TaskBuilder(mSupervisor).build();
1710 
1711         assertEquals(EMBEDDING_DISALLOWED_NEW_TASK,
1712                 canEmbedActivity(taskFragment, starting, task));
1713 
1714         // Starting activity is going to be started on a task different from task fragment's parent
1715         // task. Start activity to a new task.
1716         task.addChild(taskFragment, POSITION_TOP);
1717         final Task newTask = new TaskBuilder(mSupervisor).build();
1718 
1719         assertEquals(EMBEDDING_DISALLOWED_NEW_TASK,
1720                 canEmbedActivity(taskFragment, starting, newTask));
1721 
1722         // Make task fragment bounds exceed task bounds.
1723         final Rect taskBounds = task.getBounds();
1724         taskFragment.setBounds(taskBounds.left, taskBounds.top, taskBounds.right + 1,
1725                 taskBounds.bottom + 1);
1726 
1727         assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
1728                 canEmbedActivity(taskFragment, starting, task));
1729 
1730         taskFragment.setBounds(taskBounds);
1731         starting.info.flags |= FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
1732 
1733         assertEquals(EMBEDDING_ALLOWED, canEmbedActivity(taskFragment, starting, task));
1734 
1735         starting.info.flags &= ~FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
1736         // Set task fragment's uid as the same as starting activity's uid.
1737         taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class),
1738                 UNIMPORTANT_UID, "test");
1739 
1740         assertEquals(EMBEDDING_ALLOWED, canEmbedActivity(taskFragment, starting, task));
1741 
1742         // Make task fragment bounds smaller than starting activity's minimum dimensions
1743         taskFragment.setBounds(0, 0, minDimensions.getWidth() - 1, minDimensions.getHeight() - 1);
1744 
1745         assertEquals(EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
1746                 canEmbedActivity(taskFragment, starting, task));
1747     }
1748 
1749     @Test
testRecordActivityMovementBeforeDeliverToTop()1750     public void testRecordActivityMovementBeforeDeliverToTop() {
1751         // Mock recents as task is only marked to be in recents
1752         mAtm.mTaskSupervisor.setRecentTasks(mock(RecentTasks.class));
1753 
1754         final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
1755         final ActivityRecord activityBot = new ActivityBuilder(mAtm).setTask(task).build();
1756         final ActivityRecord activityTop = new ActivityBuilder(mAtm).setTask(task).build();
1757 
1758         activityBot.setVisible(false);
1759         activityBot.setVisibleRequested(false);
1760 
1761         assertTrue(activityTop.isVisible());
1762         assertTrue(activityTop.isVisibleRequested());
1763 
1764         final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_REORDER_TO_FRONT
1765                         | FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */);
1766         starter.mStartActivity = activityBot;
1767         task.inRecents = true;
1768         starter.setInTask(task);
1769         starter.getIntent().setComponent(activityBot.mActivityComponent);
1770         final int result = starter.setReason("testRecordActivityMovement").execute();
1771 
1772         assertEquals(START_DELIVERED_TO_TOP, result);
1773         assertNotNull(starter.mMovedToTopActivity);
1774 
1775         final ActivityStarter starter2 = prepareStarter(FLAG_ACTIVITY_REORDER_TO_FRONT
1776                         | FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */);
1777         starter2.setInTask(task);
1778         starter2.getIntent().setComponent(activityBot.mActivityComponent);
1779         final int result2 = starter2.setReason("testRecordActivityMovement").execute();
1780 
1781         assertEquals(START_DELIVERED_TO_TOP, result2);
1782         assertNull(starter2.mMovedToTopActivity);
1783     }
1784 
1785     /**
1786      * Tests a task with specific display category exist in system and then launching another
1787      * activity with the same affinity but without define the display category. Make sure the
1788      * lunching activity is placed on the different task.
1789      */
1790     @Test
testLaunchActivityWithoutDisplayCategory()1791     public void testLaunchActivityWithoutDisplayCategory() {
1792         final ActivityInfo info = new ActivityInfo();
1793         info.applicationInfo = new ApplicationInfo();
1794         info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID);
1795         info.requiredDisplayCategory = "automotive";
1796         final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info)
1797                 .build();
1798 
1799         final ActivityRecord target = new ActivityBuilder(mAtm).setAffinity(info.taskAffinity)
1800                 .build();
1801         final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK, false);
1802         spyOn(starter);
1803         doReturn(START_SUCCESS).when(starter).isAllowedToStart(any(), anyBoolean(), any());
1804         startActivityInner(starter, target, null /* source */, null /* options */,
1805                 null /* inTask */, null /* inTaskFragment */);
1806 
1807         assertNotEquals(task, target.getTask());
1808     }
1809 
1810     /**
1811      * Tests a task with a specific display category exist in the system and then launches another
1812      * activity with the different display category. Make sure the launching activity is not placed
1813      * on the sourceRecord's task.
1814      */
1815     @Test
testLaunchActivityWithDifferentDisplayCategory()1816     public void testLaunchActivityWithDifferentDisplayCategory() {
1817         final ActivityInfo info = new ActivityInfo();
1818         info.applicationInfo = new ApplicationInfo();
1819         info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID);
1820         info.requiredDisplayCategory = "automotive";
1821         final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info)
1822                 .build();
1823 
1824         final ActivityRecord target = new ActivityBuilder(mAtm).setRequiredDisplayCategory("auto")
1825                 .setAffinity(info.taskAffinity).build();
1826         final ActivityStarter starter = prepareStarter(0, false);
1827         spyOn(starter);
1828         doReturn(START_SUCCESS).when(starter).isAllowedToStart(any(), anyBoolean(), any());
1829         startActivityInner(starter, target,  task.getBottomMostActivity(), null /* options */,
1830                 null /* inTask */, null /* inTaskFragment */);
1831 
1832         assertNotEquals(task, target.getTask());
1833     }
1834 
1835     /**
1836      * Tests a task with specific display category exist in system and then launching another
1837      * activity with the same display category. Make sure the launching activity is placed on the
1838      * same task.
1839      */
1840     @Test
testLaunchActivityWithSameDisplayCategory()1841     public void testLaunchActivityWithSameDisplayCategory() {
1842         final ActivityInfo info = new ActivityInfo();
1843         info.applicationInfo = new ApplicationInfo();
1844         info.taskAffinity = ActivityRecord.computeTaskAffinity("test", DEFAULT_FAKE_UID);
1845         info.requiredDisplayCategory = "automotive";
1846         final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).setActivityInfo(info)
1847                 .build();
1848 
1849         final ActivityRecord target = new ActivityBuilder(mAtm)
1850                 .setRequiredDisplayCategory(info.requiredDisplayCategory)
1851                 .setAffinity(info.taskAffinity).build();
1852 
1853         final ActivityStarter starter = prepareStarter(0, false);
1854         spyOn(starter);
1855         doReturn(START_SUCCESS).when(starter).isAllowedToStart(any(), anyBoolean(), any());
1856         startActivityInner(starter, target,  task.getBottomMostActivity(), null /* options */,
1857                 null /* inTask */, null /* inTaskFragment */);
1858 
1859         assertEquals(task, target.getTask());
1860     }
1861 
1862     /**
1863      * Tests a task with specific display category exist in system and launching activity into the
1864      * specific task within inTask attribute. Make sure the activity is not placed on the task since
1865      * the display category is different.
1866      */
1867     @Test
testLaunchActivityInTaskWithDisplayCategory()1868     public void testLaunchActivityInTaskWithDisplayCategory() {
1869         final ActivityInfo info = new ActivityInfo();
1870         info.applicationInfo = new ApplicationInfo();
1871         info.requiredDisplayCategory = "automotive";
1872         final Task inTask = new TaskBuilder(mSupervisor).setActivityInfo(info).build();
1873         inTask.inRecents = true;
1874 
1875         final ActivityStarter starter = prepareStarter(0, false);
1876         spyOn(starter);
1877         doReturn(START_SUCCESS).when(starter).isAllowedToStart(any(), anyBoolean(), any());
1878         final ActivityRecord target = new ActivityBuilder(mAtm).build();
1879         startActivityInner(starter, target, null /* source */, null /* options */, inTask,
1880                 null /* inTaskFragment */);
1881 
1882         assertNotEquals(inTask, target.getTask());
1883     }
1884 
1885     /**
1886      * Tests a task without a specific display category exist in the system and launches activity
1887      * with display category into the task within the inTask attribute. Make sure the activity is
1888      * not placed on the task since the display category is different.
1889      */
1890     @Test
testLaunchDisplayCategoryActivityInTask()1891     public void testLaunchDisplayCategoryActivityInTask() {
1892         final Task inTask = new TaskBuilder(mSupervisor).build();
1893         inTask.inRecents = true;
1894 
1895         final ActivityStarter starter = prepareStarter(0, false);
1896         spyOn(starter);
1897         doReturn(START_SUCCESS).when(starter).isAllowedToStart(any(), anyBoolean(), any());
1898         final ActivityRecord target = new ActivityBuilder(mAtm).setRequiredDisplayCategory("auto")
1899                 .build();
1900         startActivityInner(starter, target, null /* source */, null /* options */, inTask,
1901                 null /* inTaskFragment */);
1902 
1903         assertNotEquals(inTask, target.getTask());
1904     }
1905 
startActivityInner(ActivityStarter starter, ActivityRecord target, ActivityRecord source, ActivityOptions options, Task inTask, TaskFragment inTaskFragment)1906     private static void startActivityInner(ActivityStarter starter, ActivityRecord target,
1907             ActivityRecord source, ActivityOptions options, Task inTask,
1908             TaskFragment inTaskFragment) {
1909         starter.startActivityInner(target, source, null /* voiceSession */,
1910                 null /* voiceInteractor */, 0 /* startFlags */,
1911                 options, inTask, inTaskFragment,
1912                 BackgroundActivityStartController.BAL_ALLOW_DEFAULT, null /* intentGrants */,
1913                 -1 /* realCallingUid */);
1914     }
1915 }
1916