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.app.AppOpsManager.MODE_ALLOWED;
20 import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
21 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
22 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
23 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
24 import static android.app.TaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
25 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
26 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
27 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
28 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
29 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
30 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
31 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
32 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
33 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
34 import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
35 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
36 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
37 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
38 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
39 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
40 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
41 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
42 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
43 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
44 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
45 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
46 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
47 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
48 import static android.content.res.Configuration.UI_MODE_TYPE_DESK;
49 import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
50 import static android.os.Process.NOBODY_UID;
51 import static android.view.Display.DEFAULT_DISPLAY;
52 import static android.view.InsetsSource.ID_IME;
53 import static android.view.WindowInsets.Type.ime;
54 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
55 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
56 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
57 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
58 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
59 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
60 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
61 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
62 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
63 import static android.view.WindowManager.TRANSIT_CLOSE;
64 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
65 import static android.view.WindowManager.TRANSIT_PIP;
66 import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN;
67 
68 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
69 
70 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
71 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
72 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
73 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
74 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
75 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
76 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
77 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
78 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
79 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
80 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
81 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
82 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
83 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
84 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
85 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
86 import static com.android.server.wm.ActivityRecord.LAUNCH_SOURCE_TYPE_HOME;
87 import static com.android.server.wm.ActivityRecord.State.DESTROYED;
88 import static com.android.server.wm.ActivityRecord.State.DESTROYING;
89 import static com.android.server.wm.ActivityRecord.State.FINISHING;
90 import static com.android.server.wm.ActivityRecord.State.INITIALIZING;
91 import static com.android.server.wm.ActivityRecord.State.PAUSED;
92 import static com.android.server.wm.ActivityRecord.State.PAUSING;
93 import static com.android.server.wm.ActivityRecord.State.RESUMED;
94 import static com.android.server.wm.ActivityRecord.State.STARTED;
95 import static com.android.server.wm.ActivityRecord.State.STOPPED;
96 import static com.android.server.wm.ActivityRecord.State.STOPPING;
97 import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS;
98 import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_INVISIBLE;
99 import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE;
100 import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
101 import static com.android.server.wm.WindowContainer.POSITION_TOP;
102 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM;
103 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
104 
105 import static com.google.common.truth.Truth.assertThat;
106 
107 import static org.junit.Assert.assertEquals;
108 import static org.junit.Assert.assertFalse;
109 import static org.junit.Assert.assertNotEquals;
110 import static org.junit.Assert.assertNotNull;
111 import static org.junit.Assert.assertNull;
112 import static org.junit.Assert.assertTrue;
113 import static org.mockito.ArgumentMatchers.anyInt;
114 import static org.mockito.ArgumentMatchers.anyString;
115 import static org.mockito.ArgumentMatchers.isA;
116 import static org.mockito.Mockito.atLeastOnce;
117 import static org.mockito.Mockito.clearInvocations;
118 import static org.mockito.Mockito.never;
119 
120 import android.app.ActivityOptions;
121 import android.app.AppOpsManager;
122 import android.app.ICompatCameraControlCallback;
123 import android.app.PictureInPictureParams;
124 import android.app.servertransaction.ActivityConfigurationChangeItem;
125 import android.app.servertransaction.ClientTransaction;
126 import android.app.servertransaction.DestroyActivityItem;
127 import android.app.servertransaction.PauseActivityItem;
128 import android.content.ComponentName;
129 import android.content.Intent;
130 import android.content.pm.ActivityInfo;
131 import android.content.pm.ApplicationInfo;
132 import android.content.res.Configuration;
133 import android.content.res.Resources;
134 import android.graphics.Point;
135 import android.graphics.Rect;
136 import android.os.Binder;
137 import android.os.Build;
138 import android.os.Bundle;
139 import android.os.PersistableBundle;
140 import android.os.Process;
141 import android.os.RemoteException;
142 import android.platform.test.annotations.Presubmit;
143 import android.provider.DeviceConfig;
144 import android.util.MergedConfiguration;
145 import android.util.MutableBoolean;
146 import android.view.DisplayInfo;
147 import android.view.IRemoteAnimationFinishedCallback;
148 import android.view.IRemoteAnimationRunner.Stub;
149 import android.view.IWindowManager;
150 import android.view.IWindowSession;
151 import android.view.InsetsSource;
152 import android.view.InsetsState;
153 import android.view.RemoteAnimationAdapter;
154 import android.view.RemoteAnimationTarget;
155 import android.view.Surface;
156 import android.view.WindowManager;
157 import android.view.WindowManagerGlobal;
158 import android.window.TaskSnapshot;
159 
160 import androidx.test.filters.MediumTest;
161 
162 import com.android.internal.R;
163 import com.android.server.wm.ActivityRecord.State;
164 
165 import org.junit.Assert;
166 import org.junit.Before;
167 import org.junit.Test;
168 import org.junit.runner.RunWith;
169 import org.mockito.ArgumentCaptor;
170 import org.mockito.invocation.InvocationOnMock;
171 
172 import java.util.ArrayList;
173 import java.util.function.BiConsumer;
174 import java.util.function.Consumer;
175 
176 
177 /**
178  * Tests for the {@link ActivityRecord} class.
179  *
180  * Build/Install/Run:
181  *  atest WmTests:ActivityRecordTests
182  */
183 @MediumTest
184 @Presubmit
185 @RunWith(WindowTestRunner.class)
186 public class ActivityRecordTests extends WindowTestsBase {
187 
188     private final String mPackageName = getInstrumentation().getTargetContext().getPackageName();
189 
190     private static final int ORIENTATION_CONFIG_CHANGES =
191             CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT | CONFIG_SCREEN_SIZE
192                     | CONFIG_SMALLEST_SCREEN_SIZE;
193 
194     @Before
setUp()195     public void setUp() throws Exception {
196         setBooted(mAtm);
197         // Because the booted state is set, avoid starting real home if there is no task.
198         doReturn(false).when(mRootWindowContainer).resumeHomeActivity(any(), anyString(), any());
199     }
200 
registerTestStartingWindowOrganizer()201     private TestStartingWindowOrganizer registerTestStartingWindowOrganizer() {
202         return new TestStartingWindowOrganizer(mAtm,
203                 mSystemServicesTestRule.getPowerManagerWrapper());
204     }
205 
206     @Test
testTaskFragmentCleanupOnClearingTask()207     public void testTaskFragmentCleanupOnClearingTask() {
208         final ActivityRecord activity = createActivityWith2LevelTask();
209         final Task task = activity.getTask();
210         final TaskFragment taskFragment = activity.getTaskFragment();
211         activity.onParentChanged(null /*newParent*/, task);
212         verify(taskFragment).cleanUpActivityReferences(any());
213     }
214 
215     @Test
testTaskFragmentCleanupOnActivityRemoval()216     public void testTaskFragmentCleanupOnActivityRemoval() {
217         final ActivityRecord activity = createActivityWith2LevelTask();
218         final Task task = activity.getTask();
219         final TaskFragment taskFragment = activity.getTaskFragment();
220         task.removeChild(activity);
221         verify(taskFragment).cleanUpActivityReferences(any());
222     }
223 
224     @Test
testRootTaskCleanupOnTaskRemoval()225     public void testRootTaskCleanupOnTaskRemoval() {
226         final ActivityRecord activity = createActivityWith2LevelTask();
227         final Task task = activity.getTask();
228         final Task rootTask = activity.getRootTask();
229         rootTask.removeChild(task, null /*reason*/);
230         // parentTask should be gone on task removal.
231         assertNull(mAtm.mRootWindowContainer.getRootTask(rootTask.mTaskId));
232     }
233 
234     @Test
testRemoveChildWithOverlayActivity()235     public void testRemoveChildWithOverlayActivity() {
236         final ActivityRecord activity = createActivityWithTask();
237         final Task task = activity.getTask();
238         final ActivityRecord overlayActivity = new ActivityBuilder(mAtm).setTask(task).build();
239         overlayActivity.setTaskOverlay(true);
240         final ActivityRecord overlayActivity2 = new ActivityBuilder(mAtm).setTask(task).build();
241         overlayActivity2.setTaskOverlay(true);
242 
243         task.removeChild(overlayActivity2, "test");
244         verify(mSupervisor, never()).removeTask(any(), anyBoolean(), anyBoolean(), any());
245     }
246 
247     @Test
testNoCleanupMovingActivityInSameStack()248     public void testNoCleanupMovingActivityInSameStack() {
249         final ActivityRecord activity = createActivityWith2LevelTask();
250         final Task rootTask = activity.getRootTask();
251         final Task newTask = createTaskInRootTask(rootTask, 0 /* userId */);
252         activity.reparent(newTask, 0, null /*reason*/);
253         verify(rootTask, times(0)).cleanUpActivityReferences(any());
254     }
255 
256     @Test
testPausingWhenVisibleFromStopped()257     public void testPausingWhenVisibleFromStopped() throws Exception {
258         final ActivityRecord activity = createActivityWithTask();
259         final MutableBoolean pauseFound = new MutableBoolean(false);
260         doAnswer((InvocationOnMock invocationOnMock) -> {
261             final ClientTransaction transaction = invocationOnMock.getArgument(0);
262             if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
263                 pauseFound.value = true;
264             }
265             return null;
266         }).when(activity.app.getThread()).scheduleTransaction(any());
267 
268         activity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
269 
270         // The activity is in the focused stack so it should be resumed.
271         activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
272         assertTrue(activity.isState(RESUMED));
273         assertFalse(pauseFound.value);
274 
275         // Make the activity non focusable
276         activity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
277         doReturn(false).when(activity).isFocusable();
278 
279         // If the activity is not focusable, it should move to paused.
280         activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
281         assertTrue(activity.isState(PAUSING));
282         assertTrue(pauseFound.value);
283 
284         // Make sure that the state does not change for current non-stopping states.
285         activity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
286         doReturn(true).when(activity).isFocusable();
287 
288         activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
289 
290         assertTrue(activity.isState(INITIALIZING));
291 
292         // Make sure the state does not change if we are not the current top activity.
293         activity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
294 
295         final Task task = activity.getTask();
296         final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
297         task.mTranslucentActivityWaiting = topActivity;
298         activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
299         assertTrue(activity.isState(STARTED));
300 
301         task.mTranslucentActivityWaiting = null;
302         topActivity.setOccludesParent(false);
303         activity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
304         activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
305         assertTrue(activity.isState(STARTED));
306     }
307 
ensureActivityConfiguration(ActivityRecord activity)308     private void ensureActivityConfiguration(ActivityRecord activity) {
309         activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
310     }
311 
312     @Test
testCanBeLaunchedOnDisplay()313     public void testCanBeLaunchedOnDisplay() {
314         mAtm.mSupportsMultiWindow = true;
315         final ActivityRecord activity = new ActivityBuilder(mAtm).build();
316 
317         // An activity can be launched on default display.
318         assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
319         // An activity cannot be launched on a non-existent display.
320         assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE));
321     }
322 
323     @Test
testsApplyOptionsLocked()324     public void testsApplyOptionsLocked() {
325         final ActivityRecord activity = createActivityWithTask();
326         ActivityOptions activityOptions = ActivityOptions.makeBasic();
327 
328         // Set and apply options for ActivityRecord. Pending options should be cleared
329         activity.updateOptionsLocked(activityOptions);
330         activity.applyOptionsAnimation();
331         assertNull(activity.getOptions());
332 
333         // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
334         // Pending options should be cleared for both ActivityRecords
335         ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(activity.getTask()).build();
336         activity2.updateOptionsLocked(activityOptions);
337         activity.updateOptionsLocked(activityOptions);
338         activity.applyOptionsAnimation();
339         assertNull(activity.getOptions());
340         assertNull(activity2.getOptions());
341 
342         // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
343         // Pending options should be cleared for only ActivityRecord that was applied
344         activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
345         activity2.updateOptionsLocked(activityOptions);
346         activity.updateOptionsLocked(activityOptions);
347         activity.applyOptionsAnimation();
348         assertNull(activity.getOptions());
349         assertNotNull(activity2.getOptions());
350     }
351 
352     @Test
testNewOverrideConfigurationIncrementsSeq()353     public void testNewOverrideConfigurationIncrementsSeq() {
354         final ActivityRecord activity = createActivityWithTask();
355         final Configuration newConfig = new Configuration();
356 
357         final int prevSeq = activity.getMergedOverrideConfiguration().seq;
358         activity.onRequestedOverrideConfigurationChanged(newConfig);
359         assertEquals(prevSeq + 1, activity.getMergedOverrideConfiguration().seq);
360     }
361 
362     @Test
testNewParentConfigurationIncrementsSeq()363     public void testNewParentConfigurationIncrementsSeq() {
364         final ActivityRecord activity = createActivityWithTask();
365         final Task task = activity.getTask();
366         final Configuration newConfig = new Configuration(
367                 task.getRequestedOverrideConfiguration());
368         newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
369                 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
370 
371         final int prevSeq = activity.getMergedOverrideConfiguration().seq;
372         task.onRequestedOverrideConfigurationChanged(newConfig);
373         assertEquals(prevSeq + 1, activity.getMergedOverrideConfiguration().seq);
374     }
375 
376     @Test
testSetsRelaunchReason_NotDragResizing()377     public void testSetsRelaunchReason_NotDragResizing() {
378         final ActivityRecord activity = createActivityWithTask();
379         final Task task = activity.getTask();
380         activity.setState(RESUMED, "Testing");
381 
382         task.onRequestedOverrideConfigurationChanged(task.getConfiguration());
383         activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
384                 activity.getConfiguration()));
385 
386         activity.info.configChanges &= ~CONFIG_ORIENTATION;
387         final Configuration newConfig = new Configuration(task.getConfiguration());
388         newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
389                 ? ORIENTATION_LANDSCAPE
390                 : ORIENTATION_PORTRAIT;
391         task.onRequestedOverrideConfigurationChanged(newConfig);
392 
393         activity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
394 
395         ensureActivityConfiguration(activity);
396 
397         assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
398                 activity.mRelaunchReason);
399     }
400 
401     @Test
testSetsRelaunchReason_DragResizing()402     public void testSetsRelaunchReason_DragResizing() {
403         final ActivityRecord activity = createActivityWithTask();
404         final Task task = activity.getTask();
405         activity.setState(RESUMED, "Testing");
406 
407         task.onRequestedOverrideConfigurationChanged(task.getConfiguration());
408         activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
409                 activity.getConfiguration()));
410 
411         activity.info.configChanges &= ~CONFIG_ORIENTATION;
412         final Configuration newConfig = new Configuration(task.getConfiguration());
413         newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
414                 ? ORIENTATION_LANDSCAPE
415                 : ORIENTATION_PORTRAIT;
416         task.onRequestedOverrideConfigurationChanged(newConfig);
417 
418         doReturn(true).when(task).isDragResizing();
419 
420         activity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
421 
422         ensureActivityConfiguration(activity);
423 
424         assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
425                 activity.mRelaunchReason);
426     }
427 
428     @Test
testRelaunchClearTopWaitingTranslucent()429     public void testRelaunchClearTopWaitingTranslucent() {
430         final ActivityRecord activity = createActivityWithTask();
431         final Task task = activity.getTask();
432         activity.setState(RESUMED, "Testing");
433 
434         task.onRequestedOverrideConfigurationChanged(task.getConfiguration());
435         activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
436                 activity.getConfiguration()));
437 
438         activity.info.configChanges &= ~CONFIG_ORIENTATION;
439         final Configuration newConfig = new Configuration(task.getConfiguration());
440         newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
441                 ? ORIENTATION_LANDSCAPE
442                 : ORIENTATION_PORTRAIT;
443         task.onRequestedOverrideConfigurationChanged(newConfig);
444         task.mTranslucentActivityWaiting = activity;
445         ensureActivityConfiguration(activity);
446         assertNull(task.mTranslucentActivityWaiting);
447     }
448 
449     @Test
testSetsRelaunchReason_NonResizeConfigChanges()450     public void testSetsRelaunchReason_NonResizeConfigChanges() {
451         final ActivityRecord activity = createActivityWithTask();
452         final Task task = activity.getTask();
453         activity.setState(RESUMED, "Testing");
454 
455         task.onRequestedOverrideConfigurationChanged(task.getConfiguration());
456         activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
457                 activity.getConfiguration()));
458 
459         activity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
460         final Configuration newConfig = new Configuration(task.getConfiguration());
461         newConfig.fontScale = 5;
462         task.onRequestedOverrideConfigurationChanged(newConfig);
463 
464         activity.mRelaunchReason =
465                 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
466 
467         ensureActivityConfiguration(activity);
468 
469         assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
470                 activity.mRelaunchReason);
471     }
472 
473     @Test
testDestroyedActivityNotScheduleConfigChanged()474     public void testDestroyedActivityNotScheduleConfigChanged() throws RemoteException {
475         final ActivityRecord activity = new ActivityBuilder(mAtm)
476                 .setCreateTask(true)
477                 .setConfigChanges(CONFIG_ORIENTATION)
478                 .build();
479         final Task task = activity.getTask();
480         activity.setState(DESTROYED, "Testing");
481         clearInvocations(mAtm.getLifecycleManager());
482 
483         final Configuration newConfig = new Configuration(task.getConfiguration());
484         newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
485                 ? ORIENTATION_LANDSCAPE
486                 : ORIENTATION_PORTRAIT;
487         task.onRequestedOverrideConfigurationChanged(newConfig);
488 
489         ensureActivityConfiguration(activity);
490 
491         verify(mAtm.getLifecycleManager(), never())
492                 .scheduleTransaction(any(), any(), isA(ActivityConfigurationChangeItem.class));
493     }
494 
495     @Test
testDeskModeChange_doesNotRelaunch()496     public void testDeskModeChange_doesNotRelaunch() throws RemoteException {
497         mWm.mSkipActivityRelaunchWhenDocking = true;
498 
499         final ActivityRecord activity = createActivityWithTask();
500         // The activity will already be relaunching out of the gate, finish the relaunch so we can
501         // test properly.
502         activity.finishRelaunching();
503         // Clear out any calls to scheduleTransaction from launching the activity.
504         reset(mAtm.getLifecycleManager());
505 
506         final Task task = activity.getTask();
507         activity.setState(RESUMED, "Testing");
508 
509         // Send a desk UI mode config update.
510         final Configuration newConfig = new Configuration(task.getConfiguration());
511         newConfig.uiMode |= UI_MODE_TYPE_DESK;
512         task.onRequestedOverrideConfigurationChanged(newConfig);
513         ensureActivityConfiguration(activity);
514 
515         // The activity shouldn't start relaunching since it doesn't have any desk resources.
516         assertFalse(activity.isRelaunching());
517 
518         // The configuration change is still sent to the activity, even if it doesn't relaunch.
519         final ActivityConfigurationChangeItem expected =
520                 ActivityConfigurationChangeItem.obtain(newConfig);
521         verify(mAtm.getLifecycleManager()).scheduleTransaction(
522                 eq(activity.app.getThread()), eq(activity.token), eq(expected));
523     }
524 
525     @Test
testDeskModeChange_relaunchesWithDeskResources()526     public void testDeskModeChange_relaunchesWithDeskResources() {
527         mWm.mSkipActivityRelaunchWhenDocking = true;
528 
529         final ActivityRecord activity = createActivityWithTask();
530         // The activity will already be relaunching out of the gate, finish the relaunch so we can
531         // test properly.
532         activity.finishRelaunching();
533 
534         // Activities with desk resources should get relaunched when a UI_MODE_TYPE_DESK change
535         // comes in.
536         doReturn(true).when(activity).hasDeskResources();
537 
538         final Task task = activity.getTask();
539         activity.setState(RESUMED, "Testing");
540 
541         // Send a desk UI mode config update.
542         final Configuration newConfig = new Configuration(task.getConfiguration());
543         newConfig.uiMode |= UI_MODE_TYPE_DESK;
544         task.onRequestedOverrideConfigurationChanged(newConfig);
545         ensureActivityConfiguration(activity);
546 
547         // The activity will relaunch since it has desk resources.
548         assertTrue(activity.isRelaunching());
549     }
550 
551     @Test
testSetRequestedOrientationUpdatesConfiguration()552     public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
553         final ActivityRecord activity = new ActivityBuilder(mAtm)
554                 .setCreateTask(true)
555                 .setConfigChanges(ORIENTATION_CONFIG_CHANGES)
556                 .build();
557         activity.setState(RESUMED, "Testing");
558 
559         activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
560                 activity.getConfiguration()));
561 
562         clearInvocations(mAtm.getLifecycleManager());
563         final Configuration newConfig = new Configuration(activity.getConfiguration());
564         final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
565         final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
566         if (newConfig.orientation == ORIENTATION_PORTRAIT) {
567             newConfig.orientation = ORIENTATION_LANDSCAPE;
568             newConfig.screenWidthDp = longSide;
569             newConfig.screenHeightDp = shortSide;
570         } else {
571             newConfig.orientation = ORIENTATION_PORTRAIT;
572             newConfig.screenWidthDp = shortSide;
573             newConfig.screenHeightDp = longSide;
574         }
575 
576         // Mimic the behavior that display doesn't handle app's requested orientation.
577         final DisplayContent dc = activity.getTask().getDisplayContent();
578         doReturn(false).when(dc).onDescendantOrientationChanged(any());
579         doReturn(false).when(dc).handlesOrientationChangeFromDescendant(anyInt());
580 
581         final int requestedOrientation;
582         switch (newConfig.orientation) {
583             case ORIENTATION_LANDSCAPE:
584                 requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE;
585                 break;
586             case ORIENTATION_PORTRAIT:
587                 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
588                 break;
589             default:
590                 throw new IllegalStateException("Orientation in new config should be either"
591                         + "landscape or portrait.");
592         }
593 
594         final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation();
595         spyOn(displayRotation);
596 
597         activity.setRequestedOrientation(requestedOrientation);
598 
599         final ActivityConfigurationChangeItem expected =
600                 ActivityConfigurationChangeItem.obtain(newConfig);
601         verify(mAtm.getLifecycleManager()).scheduleTransaction(eq(activity.app.getThread()),
602                 eq(activity.token), eq(expected));
603 
604         verify(displayRotation).onSetRequestedOrientation();
605     }
606 
607     @Test
ignoreRequestedOrientationInFreeformWindows()608     public void ignoreRequestedOrientationInFreeformWindows() {
609         final ActivityRecord activity = createActivityWithTask();
610         final Task task = activity.getTask();
611         task.setWindowingMode(WINDOWING_MODE_FREEFORM);
612         final Rect stableRect = new Rect();
613         task.mDisplayContent.getStableRect(stableRect);
614 
615         // Carve out non-decor insets from stableRect
616         final Rect insets = new Rect();
617         final DisplayInfo displayInfo = task.mDisplayContent.getDisplayInfo();
618         final DisplayPolicy policy = task.mDisplayContent.getDisplayPolicy();
619 
620         insets.set(policy.getDecorInsetsInfo(displayInfo.rotation, displayInfo.logicalWidth,
621                 displayInfo.logicalHeight).mConfigInsets);
622         Task.intersectWithInsetsIfFits(stableRect, stableRect, insets);
623 
624         final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
625         final Rect bounds = new Rect(stableRect);
626         if (isScreenPortrait) {
627             // Landscape bounds
628             final int newHeight = stableRect.width() - 10;
629             bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
630             bounds.bottom = bounds.top + newHeight;
631         } else {
632             // Portrait bounds
633             final int newWidth = stableRect.height() - 10;
634             bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
635             bounds.right = bounds.left + newWidth;
636         }
637         task.setBounds(bounds);
638 
639         // Requests orientation that's different from its bounds.
640         activity.setRequestedOrientation(
641                 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
642 
643         // Asserts it has orientation derived from bounds.
644         assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
645                 activity.getConfiguration().orientation);
646     }
647 
648     @Test
ignoreRequestedOrientationForResizableInSplitWindows()649     public void ignoreRequestedOrientationForResizableInSplitWindows() {
650         final ActivityRecord activity = createActivityWith2LevelTask();
651         final Task task = activity.getTask();
652         final Task rootTask = activity.getRootTask();
653         rootTask.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
654         final Rect stableRect = new Rect();
655         rootTask.mDisplayContent.getStableRect(stableRect);
656 
657         // Carve out non-decor insets from stableRect
658         final Rect insets = new Rect();
659         final DisplayInfo displayInfo = rootTask.mDisplayContent.getDisplayInfo();
660         final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
661         insets.set(policy.getDecorInsetsInfo(displayInfo.rotation, displayInfo.logicalWidth,
662                 displayInfo.logicalHeight).mConfigInsets);
663         Task.intersectWithInsetsIfFits(stableRect, stableRect, insets);
664 
665         final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
666         final Rect bounds = new Rect(stableRect);
667         if (isScreenPortrait) {
668             // Landscape bounds
669             final int newHeight = stableRect.width() - 10;
670             bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
671             bounds.bottom = bounds.top + newHeight;
672         } else {
673             // Portrait bounds
674             final int newWidth = stableRect.height() - 10;
675             bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
676             bounds.right = bounds.left + newWidth;
677         }
678         task.setBounds(bounds);
679 
680         final int activityCurOrientation = activity.getConfiguration().orientation;
681 
682         // Requests orientation that's different from its bounds.
683         activity.setRequestedOrientation(activityCurOrientation == ORIENTATION_LANDSCAPE
684                 ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
685 
686         // Asserts fixed orientation request is not ignored, and the orientation is changed.
687         assertNotEquals(activityCurOrientation, activity.getConfiguration().orientation);
688         assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
689     }
690 
691     @Test
respectRequestedOrientationForNonResizableInSplitWindows()692     public void respectRequestedOrientationForNonResizableInSplitWindows() {
693         final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
694         spyOn(tda);
695         doReturn(true).when(tda).supportsNonResizableMultiWindow();
696         final Task rootTask = mDisplayContent.getDefaultTaskDisplayArea().createRootTask(
697                 WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD, true /* onTop */);
698         rootTask.setBounds(0, 0, 1000, 500);
699         final ActivityRecord activity = new ActivityBuilder(mAtm)
700                 .setParentTask(rootTask)
701                 .setCreateTask(true)
702                 .setOnTop(true)
703                 .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
704                 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
705                 .build();
706         final Task task = activity.getTask();
707 
708         // Task in landscape.
709         assertEquals(ORIENTATION_LANDSCAPE, task.getConfiguration().orientation);
710 
711         // Asserts fixed orientation request is respected, and the orientation is not changed.
712         assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
713 
714         // Clear size compat.
715         activity.clearSizeCompatMode();
716         activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
717         mDisplayContent.sendNewConfiguration();
718 
719         // Relaunching the app should still respect the orientation request.
720         assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
721         assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio());
722     }
723 
724     @Test
testShouldMakeActive_deferredResume()725     public void testShouldMakeActive_deferredResume() {
726         final ActivityRecord activity = createActivityWithTask();
727         activity.setState(STOPPED, "Testing");
728 
729         mSupervisor.beginDeferResume();
730         assertEquals(false, activity.shouldMakeActive(null /* activeActivity */));
731 
732         mSupervisor.endDeferResume();
733         assertEquals(true, activity.shouldMakeActive(null /* activeActivity */));
734     }
735 
736     @Test
testShouldMakeActive_nonTopVisible()737     public void testShouldMakeActive_nonTopVisible() {
738         final ActivityRecord activity = createActivityWithTask();
739         final Task task = activity.getTask();
740         ActivityRecord finishingActivity = new ActivityBuilder(mAtm).setTask(task).build();
741         finishingActivity.finishing = true;
742         ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
743         activity.setState(STOPPED, "Testing");
744 
745         assertEquals(false, activity.shouldMakeActive(null /* activeActivity */));
746     }
747 
748     @Test
testShouldResume_stackVisibility()749     public void testShouldResume_stackVisibility() {
750         final ActivityRecord activity = createActivityWithTask();
751         final Task task = activity.getTask();
752         activity.setState(STOPPED, "Testing");
753 
754         doReturn(TASK_FRAGMENT_VISIBILITY_VISIBLE).when(task).getVisibility(null);
755         assertEquals(true, activity.shouldResumeActivity(null /* activeActivity */));
756 
757         doReturn(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT)
758                 .when(task).getVisibility(null);
759         assertEquals(false, activity.shouldResumeActivity(null /* activeActivity */));
760 
761         doReturn(TASK_FRAGMENT_VISIBILITY_INVISIBLE).when(task).getVisibility(null);
762         assertEquals(false, activity.shouldResumeActivity(null /* activeActivity */));
763     }
764 
765     @Test
testShouldResumeOrPauseWithResults()766     public void testShouldResumeOrPauseWithResults() {
767         final ActivityRecord activity = createActivityWithTask();
768         final Task task = activity.getTask();
769         activity.setState(STOPPED, "Testing");
770 
771         ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
772         activity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
773         topActivity.finishing = true;
774 
775         doReturn(TASK_FRAGMENT_VISIBILITY_VISIBLE).when(task).getVisibility(null);
776         assertEquals(true, activity.shouldResumeActivity(null /* activeActivity */));
777         assertEquals(false, activity.shouldPauseActivity(null /*activeActivity */));
778     }
779 
780     @Test
testPushConfigurationWhenLaunchTaskBehind()781     public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
782         final ActivityRecord activity = new ActivityBuilder(mAtm)
783                 .setCreateTask(true)
784                 .setLaunchTaskBehind(true)
785                 .setConfigChanges(ORIENTATION_CONFIG_CHANGES)
786                 .build();
787         final Task task = activity.getTask();
788         activity.setState(STOPPED, "Testing");
789 
790         final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
791         try {
792             clearInvocations(mAtm.getLifecycleManager());
793             doReturn(false).when(stack).isTranslucent(any());
794             assertTrue(task.shouldBeVisible(null /* starting */));
795 
796             activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
797                     activity.getConfiguration()));
798 
799             final Configuration newConfig = new Configuration(activity.getConfiguration());
800             final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
801             final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
802             if (newConfig.orientation == ORIENTATION_PORTRAIT) {
803                 newConfig.orientation = ORIENTATION_LANDSCAPE;
804                 newConfig.screenWidthDp = longSide;
805                 newConfig.screenHeightDp = shortSide;
806             } else {
807                 newConfig.orientation = ORIENTATION_PORTRAIT;
808                 newConfig.screenWidthDp = shortSide;
809                 newConfig.screenHeightDp = longSide;
810             }
811 
812             task.onConfigurationChanged(newConfig);
813 
814             activity.ensureActivityConfiguration(0 /* globalChanges */,
815                     false /* preserveWindow */, true /* ignoreStopState */);
816 
817             final ActivityConfigurationChangeItem expected =
818                     ActivityConfigurationChangeItem.obtain(newConfig);
819             verify(mAtm.getLifecycleManager()).scheduleTransaction(
820                     eq(activity.app.getThread()), eq(activity.token), eq(expected));
821         } finally {
822             stack.getDisplayArea().removeChild(stack);
823         }
824     }
825 
826     @Test
testShouldStartWhenMakeClientActive()827     public void testShouldStartWhenMakeClientActive() {
828         final ActivityRecord activity = createActivityWithTask();
829         ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(activity.getTask()).build();
830         topActivity.setOccludesParent(false);
831         // The requested occluding state doesn't affect whether it can decide orientation.
832         assertTrue(topActivity.providesOrientation());
833         activity.setState(STOPPED, "Testing");
834         activity.setVisibility(true);
835         activity.makeActiveIfNeeded(null /* activeActivity */);
836         assertEquals(STARTED, activity.getState());
837     }
838 
839     @Test
testTakeOptions()840     public void testTakeOptions() {
841         final ActivityRecord activity = createActivityWithTask();
842         ActivityOptions opts = ActivityOptions.makeRemoteAnimation(
843                 new RemoteAnimationAdapter(new Stub() {
844 
845                     @Override
846                     public void onAnimationStart(@WindowManager.TransitionOldType int transit,
847                             RemoteAnimationTarget[] apps,
848                             RemoteAnimationTarget[] wallpapers,
849                             RemoteAnimationTarget[] nonApps,
850                             IRemoteAnimationFinishedCallback finishedCallback) {
851                     }
852 
853                     @Override
854                     public void onAnimationCancelled() {
855                     }
856                 }, 0, 0));
857         activity.updateOptionsLocked(opts);
858         assertNotNull(activity.takeOptions());
859         assertNull(activity.getOptions());
860 
861         final AppTransition appTransition = activity.mDisplayContent.mAppTransition;
862         spyOn(appTransition);
863         activity.applyOptionsAnimation();
864 
865         verify(appTransition).overridePendingAppTransitionRemote(any());
866     }
867 
868     @Test
testCanLaunchHomeActivityFromChooser()869     public void testCanLaunchHomeActivityFromChooser() {
870         ComponentName chooserComponent = ComponentName.unflattenFromString(
871                 Resources.getSystem().getString(R.string.config_chooserActivity));
872         ActivityRecord chooserActivity = new ActivityBuilder(mAtm).setComponent(
873                 chooserComponent).build();
874         assertThat(chooserActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
875     }
876 
877     /**
878      * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and
879      * that it is cleared after activity is resumed.
880      */
881     @Test
testHasSavedState()882     public void testHasSavedState() {
883         final ActivityRecord activity = createActivityWithTask();
884         assertTrue(activity.hasSavedState());
885 
886         ActivityRecord.activityResumedLocked(activity.token, false /* handleSplashScreenExit */);
887         assertFalse(activity.hasSavedState());
888         assertNull(activity.getSavedState());
889     }
890 
891     /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */
892     @Test
testUpdateSavedState()893     public void testUpdateSavedState() {
894         final ActivityRecord activity = createActivityWithTask();
895         activity.setSavedState(null /* savedState */);
896         assertFalse(activity.hasSavedState());
897         assertNull(activity.getSavedState());
898 
899         final Bundle savedState = new Bundle();
900         savedState.putString("test", "string");
901         activity.setSavedState(savedState);
902         assertTrue(activity.hasSavedState());
903         assertEquals(savedState, activity.getSavedState());
904     }
905 
906     /** Verify the correct updates of saved state when activity client reports stop. */
907     @Test
testUpdateSavedState_activityStopped()908     public void testUpdateSavedState_activityStopped() {
909         final ActivityRecord activity = createActivityWithTask();
910         final Bundle savedState = new Bundle();
911         savedState.putString("test", "string");
912         final PersistableBundle persistentSavedState = new PersistableBundle();
913         persistentSavedState.putString("persist", "string");
914 
915         // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored.
916         activity.setState(STOPPING, "test");
917         activity.activityStopped(savedState, persistentSavedState, "desc");
918         assertTrue(activity.hasSavedState());
919         assertEquals(savedState, activity.getSavedState());
920         assertEquals(persistentSavedState, activity.getPersistentSavedState());
921 
922         // Sending 'null' for saved state can only happen due to timeout, so previously stored saved
923         // states should not be overridden.
924         activity.setState(STOPPING, "test");
925         activity.activityStopped(null /* savedState */, null /* persistentSavedState */, "desc");
926         assertTrue(activity.hasSavedState());
927         assertEquals(savedState, activity.getSavedState());
928         assertEquals(persistentSavedState, activity.getPersistentSavedState());
929     }
930 
931     /**
932      * Verify that activity finish request is not performed if activity is finishing or is in
933      * incorrect state.
934      */
935     @Test
testFinishActivityIfPossible_cancelled()936     public void testFinishActivityIfPossible_cancelled() {
937         final ActivityRecord activity = createActivityWithTask();
938         // Mark activity as finishing
939         activity.finishing = true;
940         assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED,
941                 activity.finishIfPossible("test", false /* oomAdj */));
942         assertTrue(activity.finishing);
943         assertTrue(activity.isInRootTaskLocked());
944 
945         // Remove activity from task
946         activity.finishing = false;
947         activity.onParentChanged(null /*newParent*/, activity.getTask());
948         assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED,
949                 activity.finishIfPossible("test", false /* oomAdj */));
950         assertFalse(activity.finishing);
951     }
952 
953     /**
954      * Verify that activity finish request is placed, but not executed immediately if activity is
955      * not ready yet.
956      */
957     @Test
testFinishActivityIfPossible_requested()958     public void testFinishActivityIfPossible_requested() {
959         final ActivityRecord activity = createActivityWithTask();
960         activity.finishing = false;
961         assertEquals("Currently resumed activity must be prepared removal", FINISH_RESULT_REQUESTED,
962                 activity.finishIfPossible("test", false /* oomAdj */));
963         assertTrue(activity.finishing);
964         assertTrue(activity.isInRootTaskLocked());
965 
966         // First request to finish activity must schedule a "destroy" request to the client.
967         // Activity must be removed from history after the client reports back or after timeout.
968         activity.finishing = false;
969         activity.setState(STOPPED, "test");
970         assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED,
971                 activity.finishIfPossible("test", false /* oomAdj */));
972         assertTrue(activity.finishing);
973         assertTrue(activity.isInRootTaskLocked());
974     }
975 
976     /**
977      * Verify that activity finish request removes activity immediately if it's ready.
978      */
979     @Test
testFinishActivityIfPossible_removed()980     public void testFinishActivityIfPossible_removed() {
981         final ActivityRecord activity = createActivityWithTask();
982         // Prepare the activity record to be ready for immediate removal. It should be invisible and
983         // have no process. Otherwise, request to finish it will send a message to client first.
984         activity.setState(STOPPED, "test");
985         activity.setVisibleRequested(false);
986         activity.nowVisible = false;
987         // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
988         // this will cause NPE when updating task's process.
989         activity.app = null;
990 
991         // Put a visible activity on top, so the finishing activity doesn't have to wait until the
992         // next activity reports idle to destroy it.
993         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
994                 .setTask(activity.getTask()).build();
995         topActivity.setVisibleRequested(true);
996         topActivity.nowVisible = true;
997         topActivity.setState(RESUMED, "test");
998 
999         assertEquals("Activity outside of task/rootTask cannot be finished", FINISH_RESULT_REMOVED,
1000                 activity.finishIfPossible("test", false /* oomAdj */));
1001         assertTrue(activity.finishing);
1002         assertFalse(activity.isInRootTaskLocked());
1003     }
1004 
1005     /**
1006      * Verify that when finishing the top focused activity on top display, the root task order
1007      * will be changed by adjusting focus.
1008      */
1009     @Test
testFinishActivityIfPossible_adjustStackOrder()1010     public void testFinishActivityIfPossible_adjustStackOrder() {
1011         final ActivityRecord activity = createActivityWithTask();
1012         final Task task = activity.getTask();
1013         // Prepare the tasks with order (top to bottom): task, task1, task2.
1014         final Task task1 = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
1015         task.moveToFront("test");
1016         // The task2 is needed here for moving back to simulate the
1017         // {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so
1018         // {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible
1019         // tasks. Then when mActivity is finishing, its task will be invisible (no running
1020         // activities in the task) that is the key condition to verify.
1021         final Task task2 = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
1022         task2.moveToBack("test", task2.getBottomMostTask());
1023 
1024         assertTrue(task.isTopRootTaskInDisplayArea());
1025 
1026         activity.setState(RESUMED, "test");
1027         activity.finishIfPossible(0 /* resultCode */, null /* resultData */,
1028                 null /* resultGrants */, "test", false /* oomAdj */);
1029 
1030         assertTrue(task1.isTopRootTaskInDisplayArea());
1031     }
1032 
1033     /**
1034      * Verify that when finishing the top focused activity while root task was created by organizer,
1035      * the stack order will be changed by adjusting focus.
1036      */
1037     @Test
testFinishActivityIfPossible_adjustStackOrderOrganizedRoot()1038     public void testFinishActivityIfPossible_adjustStackOrderOrganizedRoot() {
1039         // Make mStack be a the root task that created by task organizer
1040         final Task rootableTask = new TaskBuilder(mSupervisor)
1041                 .setCreateParentTask(true).setCreateActivity(true).build();
1042         final Task rootTask = rootableTask.getRootTask();
1043         rootTask.mCreatedByOrganizer = true;
1044 
1045         // Have two tasks (topRootableTask and rootableTask) as the children of rootTask.
1046         ActivityRecord topActivity = new ActivityBuilder(mAtm)
1047                 .setCreateTask(true)
1048                 .setParentTask(rootTask)
1049                 .build();
1050         Task topRootableTask = topActivity.getTask();
1051         topRootableTask.moveToFront("test");
1052         assertTrue(rootTask.isTopRootTaskInDisplayArea());
1053 
1054         // Finish top activity and verify the next focusable rootable task has adjusted to top.
1055         topActivity.setState(RESUMED, "test");
1056         topActivity.finishIfPossible(0 /* resultCode */, null /* resultData */,
1057                 null /* resultGrants */, "test", false /* oomAdj */);
1058         assertEquals(rootableTask, rootTask.getTopMostTask());
1059     }
1060 
1061     /**
1062      * Verify that when top focused activity is on secondary display, when finishing the top focused
1063      * activity on default display, the preferred top stack on default display should be changed by
1064      * adjusting focus.
1065      */
1066     @Test
testFinishActivityIfPossible_PreferredTopStackChanged()1067     public void testFinishActivityIfPossible_PreferredTopStackChanged() {
1068         final ActivityRecord activity = createActivityWithTask();
1069         final Task task = activity.getTask();
1070         final ActivityRecord topActivityOnNonTopDisplay =
1071                 createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
1072         Task topRootableTask = topActivityOnNonTopDisplay.getRootTask();
1073         topRootableTask.moveToFront("test");
1074         assertTrue(topRootableTask.isTopRootTaskInDisplayArea());
1075         assertEquals(topRootableTask, topActivityOnNonTopDisplay.getDisplayArea()
1076                 .mPreferredTopFocusableRootTask);
1077 
1078         final ActivityRecord secondaryDisplayActivity =
1079                 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1080         topRootableTask = secondaryDisplayActivity.getRootTask();
1081         topRootableTask.moveToFront("test");
1082         assertTrue(topRootableTask.isTopRootTaskInDisplayArea());
1083         assertEquals(topRootableTask,
1084                 secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableRootTask);
1085 
1086         // The global top focus activity is on secondary display now.
1087         // Finish top activity on default display and verify the next preferred top focusable stack
1088         // on default display has changed.
1089         topActivityOnNonTopDisplay.setState(RESUMED, "test");
1090         topActivityOnNonTopDisplay.finishIfPossible(0 /* resultCode */, null /* resultData */,
1091                 null /* resultGrants */, "test", false /* oomAdj */);
1092         assertEquals(task, task.getTopMostTask());
1093         assertEquals(task, activity.getDisplayArea().mPreferredTopFocusableRootTask);
1094     }
1095 
1096     /**
1097      * Verify that resumed activity is paused due to finish request.
1098      */
1099     @Test
testFinishActivityIfPossible_resumedStartsPausing()1100     public void testFinishActivityIfPossible_resumedStartsPausing() {
1101         final ActivityRecord activity = createActivityWithTask();
1102         activity.finishing = false;
1103         activity.setState(RESUMED, "test");
1104         assertEquals("Currently resumed activity must be paused before removal",
1105                 FINISH_RESULT_REQUESTED, activity.finishIfPossible("test", false /* oomAdj */));
1106         assertEquals(PAUSING, activity.getState());
1107         verify(activity).setVisibility(eq(false));
1108         verify(activity.mDisplayContent).prepareAppTransition(eq(TRANSIT_CLOSE));
1109     }
1110 
1111     /**
1112      * Verify that finish request will be completed immediately for non-resumed activity.
1113      */
1114     @Test
testFinishActivityIfPossible_nonResumedFinishCompletesImmediately()1115     public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() {
1116         final ActivityRecord activity = createActivityWithTask();
1117         final State[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED};
1118         for (State state : states) {
1119             activity.finishing = false;
1120             activity.setState(state, "test");
1121             reset(activity);
1122             assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
1123                     activity.finishIfPossible("test", false /* oomAdj */));
1124             verify(activity).completeFinishing(anyString());
1125         }
1126     }
1127 
1128     /**
1129      * Verify that finishing will not be completed in PAUSING state.
1130      */
1131     @Test
testFinishActivityIfPossible_pausing()1132     public void testFinishActivityIfPossible_pausing() {
1133         final ActivityRecord activity = createActivityWithTask();
1134         activity.finishing = false;
1135         activity.setState(PAUSING, "test");
1136         assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
1137                 activity.finishIfPossible("test", false /* oomAdj */));
1138         verify(activity, never()).completeFinishing(anyString());
1139     }
1140 
1141     /**
1142      * Verify that finish request for resumed activity will prepare an app transition but not
1143      * execute it immediately.
1144      */
1145     @Test
testFinishActivityIfPossible_visibleResumedPreparesAppTransition()1146     public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() {
1147         final ActivityRecord activity = createActivityWithTask();
1148         clearInvocations(activity.mDisplayContent);
1149         activity.finishing = false;
1150         activity.setVisibleRequested(true);
1151         activity.setState(RESUMED, "test");
1152         activity.finishIfPossible("test", false /* oomAdj */);
1153 
1154         verify(activity).setVisibility(eq(false));
1155         verify(activity.mDisplayContent).prepareAppTransition(eq(TRANSIT_CLOSE));
1156         verify(activity.mDisplayContent, never()).executeAppTransition();
1157     }
1158 
1159     /**
1160      * Verify that finish request for paused activity will prepare and execute an app transition.
1161      */
1162     @Test
testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition()1163     public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() {
1164         final ActivityRecord activity = createActivityWithTask();
1165         clearInvocations(activity.mDisplayContent);
1166         activity.finishing = false;
1167         activity.setVisibleRequested(true);
1168         activity.setState(PAUSED, "test");
1169         activity.finishIfPossible("test", false /* oomAdj */);
1170 
1171         verify(activity, atLeast(1)).setVisibility(eq(false));
1172         verify(activity.mDisplayContent).prepareAppTransition(eq(TRANSIT_CLOSE));
1173         verify(activity.mDisplayContent).executeAppTransition();
1174     }
1175 
1176     /**
1177      * Verify that finish request for non-visible activity will not prepare any transitions.
1178      */
1179     @Test
testFinishActivityIfPossible_nonVisibleNoAppTransition()1180     public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
1181         registerTestTransitionPlayer();
1182         spyOn(mRootWindowContainer.mTransitionController);
1183         final ActivityRecord bottomActivity = createActivityWithTask();
1184         bottomActivity.setVisibility(false);
1185         bottomActivity.setState(STOPPED, "test");
1186         bottomActivity.mLastSurfaceShowing = false;
1187         final ActivityRecord activity = createActivityWithTask();
1188         activity.setVisibleRequested(false);
1189         activity.setState(STOPPED, "test");
1190 
1191         activity.finishIfPossible("test", false /* oomAdj */);
1192 
1193         verify(activity.mDisplayContent, never()).prepareAppTransition(eq(TRANSIT_CLOSE));
1194         assertFalse(activity.inTransition());
1195 
1196         // finishIfPossible -> completeFinishing -> addToFinishingAndWaitForIdle
1197         // -> resumeFocusedTasksTopActivities
1198         assertTrue(bottomActivity.isState(RESUMED));
1199         assertTrue(bottomActivity.isVisible());
1200         verify(mRootWindowContainer.mTransitionController).onVisibleWithoutCollectingTransition(
1201                 eq(bottomActivity), any());
1202         assertTrue(bottomActivity.mLastSurfaceShowing);
1203     }
1204 
1205     /**
1206      * Verify that finish request for the last activity in a task will request a shell transition
1207      * with that task as a trigger.
1208      */
1209     @Test
testFinishActivityIfPossible_lastInTaskRequestsTransitionWithTrigger()1210     public void testFinishActivityIfPossible_lastInTaskRequestsTransitionWithTrigger() {
1211         final TestTransitionPlayer testPlayer = registerTestTransitionPlayer();
1212         final ActivityRecord activity = createActivityWithTask();
1213         activity.finishing = false;
1214         activity.setVisibleRequested(true);
1215         activity.setState(RESUMED, "test");
1216         activity.finishIfPossible("test", false /* oomAdj */);
1217 
1218         verify(activity).setVisibility(eq(false));
1219         assertEquals(activity.getTask().mTaskId, testPlayer.mLastRequest.getTriggerTask().taskId);
1220     }
1221 
1222     /**
1223      * Verify that when collecting activity to the existing close transition, it should not affect
1224      * ready state.
1225      */
1226     @Test
testFinishActivityIfPossible_collectToExistingTransition()1227     public void testFinishActivityIfPossible_collectToExistingTransition() {
1228         final TestTransitionPlayer testPlayer = registerTestTransitionPlayer();
1229         final ActivityRecord activity = createActivityWithTask();
1230         activity.setState(PAUSED, "test");
1231         activity.finishIfPossible("test", false /* oomAdj */);
1232         final Transition lastTransition = testPlayer.mLastTransit;
1233         assertTrue(lastTransition.allReady());
1234         assertTrue(activity.inTransition());
1235 
1236         // Collect another activity to the existing transition without changing ready state.
1237         final ActivityRecord activity2 = createActivityRecord(activity.getTask());
1238         activity2.setState(PAUSING, "test");
1239         activity2.finishIfPossible("test", false /* oomAdj */);
1240         assertTrue(activity2.inTransition());
1241         assertEquals(lastTransition, testPlayer.mLastTransit);
1242         assertTrue(lastTransition.allReady());
1243     }
1244 
1245     @Test
testFinishActivityIfPossible_sendResultImmediately()1246     public void testFinishActivityIfPossible_sendResultImmediately() {
1247         // Create activity representing the source of the activity result.
1248         final ComponentName sourceComponent = ComponentName.createRelative(
1249                 DEFAULT_COMPONENT_PACKAGE_NAME, ".SourceActivity");
1250         final ComponentName targetComponent = ComponentName.createRelative(
1251                 sourceComponent.getPackageName(), ".TargetActivity");
1252 
1253         final ActivityRecord sourceActivity = new ActivityBuilder(mWm.mAtmService)
1254                 .setComponent(sourceComponent)
1255                 .setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE)
1256                 .setCreateTask(true)
1257                 .build();
1258         sourceActivity.finishing = false;
1259         sourceActivity.setState(STOPPED, "test");
1260 
1261         final ActivityRecord targetActivity = new ActivityBuilder(mWm.mAtmService)
1262                 .setComponent(targetComponent)
1263                 .setTargetActivity(sourceComponent.getClassName())
1264                 .setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE)
1265                 .setCreateTask(true)
1266                 .setOnTop(true)
1267                 .build();
1268         targetActivity.finishing = false;
1269         targetActivity.setState(RESUMED, "test");
1270         targetActivity.resultTo = sourceActivity;
1271         targetActivity.setForceSendResultForMediaProjection();
1272 
1273         clearInvocations(mAtm.getLifecycleManager());
1274 
1275         targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */);
1276 
1277         try {
1278             verify(mAtm.getLifecycleManager(), atLeastOnce()).scheduleTransaction(
1279                     any(ClientTransaction.class));
1280         } catch (RemoteException ignored) {
1281         }
1282 
1283         assertNull(targetActivity.results);
1284     }
1285 
1286     @Test
testFinishActivityIfPossible_sendResultImmediatelyIfResumed()1287     public void testFinishActivityIfPossible_sendResultImmediatelyIfResumed() {
1288         final Task task = new TaskBuilder(mSupervisor).build();
1289         final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task);
1290         final TaskFragment taskFragment2 = createTaskFragmentWithActivity(task);
1291         final ActivityRecord resultToActivity = taskFragment1.getTopMostActivity();
1292         final ActivityRecord targetActivity = taskFragment2.getTopMostActivity();
1293         resultToActivity.setState(RESUMED, "test");
1294         targetActivity.setState(RESUMED, "test");
1295         targetActivity.resultTo = resultToActivity;
1296 
1297         clearInvocations(mAtm.getLifecycleManager());
1298         targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */);
1299         waitUntilHandlersIdle();
1300 
1301         verify(resultToActivity).sendResult(anyInt(), eq(null), anyInt(), anyInt(), any(), eq(null),
1302                 anyBoolean());
1303     }
1304 
1305     /**
1306      * Verify that complete finish request for non-finishing activity is invalid.
1307      */
1308     @Test(expected = IllegalArgumentException.class)
testCompleteFinishing_failNotFinishing()1309     public void testCompleteFinishing_failNotFinishing() {
1310         final ActivityRecord activity = createActivityWithTask();
1311         activity.finishing = false;
1312         activity.completeFinishing("test");
1313     }
1314 
1315     /**
1316      * Verify that complete finish request for resumed activity is invalid.
1317      */
1318     @Test(expected = IllegalArgumentException.class)
testCompleteFinishing_failResumed()1319     public void testCompleteFinishing_failResumed() {
1320         final ActivityRecord activity = createActivityWithTask();
1321         activity.setState(RESUMED, "test");
1322         activity.completeFinishing("test");
1323     }
1324 
1325     /**
1326      * Verify that finish request for pausing activity must be a no-op - activity will finish
1327      * once it completes pausing.
1328      */
1329     @Test
testCompleteFinishing_pausing()1330     public void testCompleteFinishing_pausing() {
1331         final ActivityRecord activity = createActivityWithTask();
1332         activity.setState(PAUSING, "test");
1333         activity.finishing = true;
1334 
1335         assertEquals("Activity must not be removed immediately - waiting for paused",
1336                 activity, activity.completeFinishing("test"));
1337         assertEquals(PAUSING, activity.getState());
1338         verify(activity, never()).destroyIfPossible(anyString());
1339     }
1340 
1341     /**
1342      * Verify that finish request won't change the state of next top activity if the current
1343      * finishing activity doesn't need to be destroyed immediately. The case is usually like
1344      * from {@link Task#completePause(boolean, ActivityRecord)} to
1345      * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the
1346      * responsibility to resume the next activity with updating the state.
1347      */
1348     @Test
testCompleteFinishing_keepStateOfNextInvisible()1349     public void testCompleteFinishing_keepStateOfNextInvisible() {
1350         final ActivityRecord currentTop = createActivityWithTask();
1351         final Task task = currentTop.getTask();
1352 
1353         currentTop.setVisibleRequested(currentTop.nowVisible = true);
1354 
1355         // Simulates that {@code currentTop} starts an existing activity from background (so its
1356         // state is stopped) and the starting flow just goes to place it at top.
1357         final Task nextStack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
1358         final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity();
1359         nextTop.setState(STOPPED, "test");
1360 
1361         task.setPausingActivity(currentTop);
1362         currentTop.finishing = true;
1363         currentTop.setState(PAUSED, "test");
1364         currentTop.completeFinishing(false /* updateVisibility */, "completePause");
1365 
1366         // Current top becomes stopping because it is visible and the next is invisible.
1367         assertEquals(STOPPING, currentTop.getState());
1368         // The state of next activity shouldn't be changed.
1369         assertEquals(STOPPED, nextTop.getState());
1370     }
1371 
1372     /**
1373      * Verify that finish bottom activity from a task won't boost it to top.
1374      */
1375     @Test
testFinishBottomActivityIfPossible_noZBoost()1376     public void testFinishBottomActivityIfPossible_noZBoost() {
1377         final ActivityRecord bottomActivity = createActivityWithTask();
1378         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1379                 .setTask(bottomActivity.getTask()).build();
1380         topActivity.setVisibleRequested(true);
1381         // simulating bottomActivity as a trampoline activity.
1382         bottomActivity.setState(RESUMED, "test");
1383         bottomActivity.finishIfPossible("test", false);
1384         assertFalse(bottomActivity.mNeedsZBoost);
1385     }
1386 
1387     /**
1388      * Verify that complete finish request for visible activity must be delayed before the next one
1389      * becomes visible.
1390      */
1391     @Test
testCompleteFinishing_waitForNextVisible()1392     public void testCompleteFinishing_waitForNextVisible() {
1393         final ActivityRecord activity = createActivityWithTask();
1394         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1395                 .setTask(activity.getTask()).build();
1396         topActivity.setVisibleRequested(true);
1397         topActivity.nowVisible = true;
1398         topActivity.finishing = true;
1399         topActivity.setState(PAUSED, "true");
1400         // Mark the bottom activity as not visible, so that we will wait for it before removing
1401         // the top one.
1402         activity.setVisibleRequested(false);
1403         activity.nowVisible = false;
1404         activity.setState(STOPPED, "test");
1405 
1406         assertEquals("Activity must not be removed immediately - waiting for next visible",
1407                 topActivity, topActivity.completeFinishing("test"));
1408         assertEquals("Activity must be stopped to make next one visible", STOPPING,
1409                 topActivity.getState());
1410         assertTrue("Activity must be stopped to make next one visible",
1411                 topActivity.mTaskSupervisor.mStoppingActivities.contains(topActivity));
1412         verify(topActivity, never()).destroyIfPossible(anyString());
1413     }
1414 
1415     /**
1416      * Verify that complete finish request for top invisible activity must not be delayed while
1417      * sleeping, but next invisible activity must be resumed (and paused/stopped)
1418      */
1419     @Test
testCompleteFinishing_noWaitForNextVisible_sleeping()1420     public void testCompleteFinishing_noWaitForNextVisible_sleeping() {
1421         final ActivityRecord activity = createActivityWithTask();
1422         // Create a top activity on a new task
1423         final ActivityRecord topActivity = createActivityWithTask();
1424         mDisplayContent.setIsSleeping(true);
1425         doReturn(true).when(activity).shouldBeVisible();
1426         topActivity.setVisibleRequested(false);
1427         topActivity.nowVisible = false;
1428         topActivity.finishing = true;
1429         topActivity.setState(STOPPED, "true");
1430 
1431         // Mark the activity behind (on a separate task) as not visible
1432         activity.setVisibleRequested(false);
1433         activity.nowVisible = false;
1434         activity.setState(STOPPED, "test");
1435 
1436         clearInvocations(activity);
1437         topActivity.completeFinishing("test");
1438         verify(activity).setState(eq(RESUMED), any());
1439         verify(topActivity).destroyIfPossible(anyString());
1440     }
1441 
1442     /**
1443      * Verify that complete finish request for invisible activity must not be delayed.
1444      */
1445     @Test
testCompleteFinishing_noWaitForNextVisible_alreadyInvisible()1446     public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
1447         final ActivityRecord activity = createActivityWithTask();
1448         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1449                 .setTask(activity.getTask()).build();
1450         topActivity.setVisibleRequested(false);
1451         topActivity.nowVisible = false;
1452         topActivity.finishing = true;
1453         topActivity.setState(STOPPED, "true");
1454         // Mark the bottom activity as not visible, so that we would wait for it before removing
1455         // the top one.
1456         activity.setVisibleRequested(false);
1457         activity.nowVisible = false;
1458         activity.setState(STOPPED, "test");
1459 
1460         topActivity.completeFinishing("test");
1461 
1462         verify(topActivity).destroyIfPossible(anyString());
1463     }
1464 
1465     /**
1466      * Verify that paused finishing activity will be added to finishing list and wait for next one
1467      * to idle.
1468      */
1469     @Test
testCompleteFinishing_waitForIdle()1470     public void testCompleteFinishing_waitForIdle() {
1471         final ActivityRecord activity = createActivityWithTask();
1472         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1473                 .setTask(activity.getTask()).build();
1474         topActivity.setVisibleRequested(true);
1475         topActivity.nowVisible = true;
1476         topActivity.finishing = true;
1477         topActivity.setState(PAUSED, "true");
1478         // Mark the bottom activity as already visible, so that there is no need to wait for it.
1479         activity.setVisibleRequested(true);
1480         activity.nowVisible = true;
1481         activity.setState(RESUMED, "test");
1482 
1483         topActivity.completeFinishing("test");
1484 
1485         verify(topActivity).addToFinishingAndWaitForIdle();
1486     }
1487 
1488     /**
1489      * Verify that complete finish request for visible activity must not be delayed if the next one
1490      * is already visible and it's not the focused stack.
1491      */
1492     @Test
testCompleteFinishing_noWaitForNextVisible_stopped()1493     public void testCompleteFinishing_noWaitForNextVisible_stopped() {
1494         final ActivityRecord activity = createActivityWithTask();
1495         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1496                 .setTask(activity.getTask()).build();
1497         topActivity.setVisibleRequested(false);
1498         topActivity.nowVisible = false;
1499         topActivity.finishing = true;
1500         topActivity.setState(STOPPED, "true");
1501         // Mark the bottom activity as already visible, so that there is no need to wait for it.
1502         activity.setVisibleRequested(true);
1503         activity.nowVisible = true;
1504         activity.setState(RESUMED, "test");
1505 
1506         topActivity.completeFinishing("test");
1507 
1508         verify(topActivity).destroyIfPossible(anyString());
1509     }
1510 
1511     /**
1512      * Verify that complete finish request for visible activity must not be delayed if the next one
1513      * is already visible and it's not the focused stack.
1514      */
1515     @Test
testCompleteFinishing_noWaitForNextVisible_nonFocusedStack()1516     public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
1517         final ActivityRecord activity = createActivityWithTask();
1518         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1519                 .setTask(activity.getTask()).build();
1520         topActivity.setVisibleRequested(true);
1521         topActivity.nowVisible = true;
1522         topActivity.finishing = true;
1523         topActivity.setState(PAUSED, "true");
1524         // Mark the bottom activity as already visible, so that there is no need to wait for it.
1525         activity.setVisibleRequested(true);
1526         activity.nowVisible = true;
1527         activity.setState(RESUMED, "test");
1528 
1529         // Add another stack to become focused and make the activity there visible. This way it
1530         // simulates finishing in non-focused stack in split-screen.
1531         final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
1532         final ActivityRecord focusedActivity = stack.getTopMostActivity();
1533         focusedActivity.nowVisible = true;
1534         focusedActivity.setVisibleRequested(true);
1535         focusedActivity.setState(RESUMED, "test");
1536         stack.setResumedActivity(focusedActivity, "test");
1537 
1538         topActivity.completeFinishing("test");
1539 
1540         verify(topActivity).destroyIfPossible(anyString());
1541     }
1542 
1543     /**
1544      * Verify that complete finish request for a show-when-locked activity must ensure the
1545      * keyguard occluded state being updated.
1546      */
1547     @Test
testCompleteFinishing_showWhenLocked()1548     public void testCompleteFinishing_showWhenLocked() {
1549         final ActivityRecord activity = createActivityWithTask();
1550         final Task task = activity.getTask();
1551         // Make keyguard locked and set the top activity show-when-locked.
1552         KeyguardController keyguardController = activity.mTaskSupervisor.getKeyguardController();
1553         int displayId = activity.getDisplayId();
1554         doReturn(true).when(keyguardController).isKeyguardLocked(eq(displayId));
1555         final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
1556         topActivity.setVisibleRequested(true);
1557         topActivity.nowVisible = true;
1558         topActivity.setState(RESUMED, "true");
1559         doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
1560                 any() /* starting */, anyInt() /* configChanges */,
1561                 anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
1562         topActivity.setShowWhenLocked(true);
1563 
1564         // Verify the stack-top activity is occluded keyguard.
1565         assertEquals(topActivity, task.topRunningActivity());
1566         assertTrue(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
1567 
1568         // Finish the top activity
1569         topActivity.setState(PAUSED, "true");
1570         topActivity.finishing = true;
1571         topActivity.completeFinishing("test");
1572 
1573         // Verify new top activity does not occlude keyguard.
1574         assertEquals(activity, task.topRunningActivity());
1575         assertFalse(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
1576     }
1577 
1578     /**
1579      * Verify that complete finish request for an activity which the resume activity is translucent
1580      * must ensure the visibilities of activities being updated.
1581      */
1582     @Test
testCompleteFinishing_ensureActivitiesVisible_withConditions()1583     public void testCompleteFinishing_ensureActivitiesVisible_withConditions() {
1584         testCompleteFinishing_ensureActivitiesVisible(false, PAUSED);
1585         testCompleteFinishing_ensureActivitiesVisible(false, STARTED);
1586         testCompleteFinishing_ensureActivitiesVisible(true, PAUSED);
1587         testCompleteFinishing_ensureActivitiesVisible(true, STARTED);
1588     }
1589 
testCompleteFinishing_ensureActivitiesVisible(boolean diffTask, State secondActivityState)1590     private void testCompleteFinishing_ensureActivitiesVisible(boolean diffTask,
1591             State secondActivityState) {
1592         final ActivityRecord activity = createActivityWithTask();
1593         final Task task = activity.getTask();
1594         final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(task).build();
1595         firstActivity.setVisibleRequested(false);
1596         firstActivity.nowVisible = false;
1597         firstActivity.setState(STOPPED, "test");
1598 
1599         final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task).build();
1600         secondActivity.setVisibleRequested(true);
1601         secondActivity.nowVisible = true;
1602         secondActivity.setState(secondActivityState, "test");
1603 
1604         ActivityRecord translucentActivity;
1605         if (diffTask) {
1606             translucentActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
1607         } else {
1608             translucentActivity = new ActivityBuilder(mAtm).setTask(task).build();
1609         }
1610         translucentActivity.setVisibleRequested(true);
1611         translucentActivity.nowVisible = true;
1612         translucentActivity.setState(RESUMED, "test");
1613 
1614         doReturn(true).when(firstActivity).occludesParent(true);
1615         doReturn(true).when(secondActivity).occludesParent(true);
1616 
1617         // Finish the second activity
1618         secondActivity.finishing = true;
1619         secondActivity.completeFinishing("test");
1620         verify(secondActivity.mDisplayContent).ensureActivitiesVisible(null /* starting */,
1621                 0 /* configChanges */ , false /* preserveWindows */,
1622                 true /* notifyClients */);
1623 
1624         // Finish the first activity
1625         firstActivity.finishing = true;
1626         firstActivity.setVisibleRequested(true);
1627         firstActivity.completeFinishing("test");
1628         verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */,
1629                 0 /* configChanges */ , false /* preserveWindows */,
1630                 true /* notifyClients */);
1631 
1632         // Remove the translucent activity and clear invocations for next test
1633         translucentActivity.getTask().removeImmediately("test");
1634         clearInvocations(mDefaultDisplay);
1635     }
1636 
1637     /**
1638      * Verify destroy activity request completes successfully.
1639      */
1640     @Test
testDestroyIfPossible()1641     public void testDestroyIfPossible() {
1642         final ActivityRecord activity = createActivityWithTask();
1643         doReturn(false).when(mRootWindowContainer)
1644                 .resumeFocusedTasksTopActivities();
1645         activity.destroyIfPossible("test");
1646 
1647         assertEquals(DESTROYING, activity.getState());
1648         assertTrue(activity.finishing);
1649         verify(activity).destroyImmediately(anyString());
1650     }
1651 
1652     /**
1653      * Verify that complete finish request for visible activity must not destroy it immediately if
1654      * it is the last running activity on a display with a home stack. We must wait for home
1655      * activity to come up to avoid a black flash in this case.
1656      */
1657     @Test
testDestroyIfPossible_lastActivityAboveEmptyHomeStack()1658     public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
1659         final ActivityRecord activity = createActivityWithTask();
1660         // Empty the home stack.
1661         final Task homeStack = activity.getDisplayArea().getRootHomeTask();
1662         homeStack.forAllLeafTasks((t) -> {
1663             homeStack.removeChild(t, "test");
1664         }, true /* traverseTopToBottom */);
1665         activity.finishing = true;
1666         doReturn(false).when(mRootWindowContainer)
1667                 .resumeFocusedTasksTopActivities();
1668 
1669         // Try to destroy the last activity above the home stack.
1670         activity.destroyIfPossible("test");
1671 
1672         // Verify that the activity was not actually destroyed, but waits for next one to come up
1673         // instead.
1674         verify(activity, never()).destroyImmediately(anyString());
1675         assertEquals(FINISHING, activity.getState());
1676         assertTrue(activity.mTaskSupervisor.mFinishingActivities.contains(activity));
1677     }
1678 
1679     /**
1680      * Verify that complete finish request for visible activity must resume next home stack before
1681      * destroying it immediately if it is the last running activity on a display with a home stack.
1682      * We must wait for home activity to come up to avoid a black flash in this case.
1683      */
1684     @Test
testCompleteFinishing_lastActivityAboveEmptyHomeStack()1685     public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
1686         final ActivityRecord activity = createActivityWithTask();
1687         // Empty the home root task.
1688         final Task homeRootTask = activity.getDisplayArea().getRootHomeTask();
1689         homeRootTask.forAllLeafTasks((t) -> {
1690             homeRootTask.removeChild(t, "test");
1691         }, true /* traverseTopToBottom */);
1692         activity.setState(STARTED, "test");
1693         activity.finishing = true;
1694         activity.setVisibleRequested(true);
1695 
1696         // Try to finish the last activity above the home stack.
1697         activity.completeFinishing("test");
1698 
1699         // Verify that the activity is not destroyed immediately, but waits for next one to come up.
1700         verify(activity, never()).destroyImmediately(anyString());
1701         assertEquals(FINISHING, activity.getState());
1702         assertTrue(activity.mTaskSupervisor.mFinishingActivities.contains(activity));
1703     }
1704 
1705     /**
1706      * Test that the activity will be moved to destroying state and the message to destroy will be
1707      * sent to the client.
1708      */
1709     @Test
testDestroyImmediately_hadApp_finishing()1710     public void testDestroyImmediately_hadApp_finishing() {
1711         final ActivityRecord activity = createActivityWithTask();
1712         activity.finishing = true;
1713         activity.destroyImmediately("test");
1714 
1715         assertEquals(DESTROYING, activity.getState());
1716     }
1717 
1718     /**
1719      * Test that the activity will be moved to destroyed state immediately if it was not marked as
1720      * finishing before {@link ActivityRecord#destroyImmediately(String)}.
1721      */
1722     @Test
testDestroyImmediately_hadApp_notFinishing()1723     public void testDestroyImmediately_hadApp_notFinishing() {
1724         final ActivityRecord activity = createActivityWithTask();
1725         activity.finishing = false;
1726         activity.destroyImmediately("test");
1727 
1728         assertEquals(DESTROYED, activity.getState());
1729     }
1730 
1731     /**
1732      * Test that an activity with no process attached and that is marked as finishing will be
1733      * removed from task when {@link ActivityRecord#destroyImmediately(String)} is called.
1734      */
1735     @Test
testDestroyImmediately_noApp_finishing()1736     public void testDestroyImmediately_noApp_finishing() {
1737         final ActivityRecord activity = createActivityWithTask();
1738         activity.app = null;
1739         activity.finishing = true;
1740         final Task task = activity.getTask();
1741 
1742         activity.destroyImmediately("test");
1743 
1744         assertEquals(DESTROYED, activity.getState());
1745         assertNull(activity.getTask());
1746         assertEquals(0, task.getChildCount());
1747     }
1748 
1749     /**
1750      * Test that an activity with no process attached and that is not marked as finishing will be
1751      * marked as DESTROYED but not removed from task.
1752      */
1753     @Test
testDestroyImmediately_noApp_notFinishing()1754     public void testDestroyImmediately_noApp_notFinishing() {
1755         final ActivityRecord activity = createActivityWithTask();
1756         activity.app = null;
1757         activity.finishing = false;
1758         final Task task = activity.getTask();
1759 
1760         activity.destroyImmediately("test");
1761 
1762         assertEquals(DESTROYED, activity.getState());
1763         assertEquals(task, activity.getTask());
1764         assertEquals(1, task.getChildCount());
1765     }
1766 
1767     /**
1768      * Test that an activity will not be destroyed if it is marked as non-destroyable.
1769      */
1770     @Test
testSafelyDestroy_nonDestroyable()1771     public void testSafelyDestroy_nonDestroyable() {
1772         final ActivityRecord activity = createActivityWithTask();
1773         doReturn(false).when(activity).isDestroyable();
1774 
1775         activity.safelyDestroy("test");
1776 
1777         verify(activity, never()).destroyImmediately(anyString());
1778     }
1779 
1780     /**
1781      * Test that an activity will not be destroyed if it is marked as non-destroyable.
1782      */
1783     @Test
testSafelyDestroy_destroyable()1784     public void testSafelyDestroy_destroyable() {
1785         final ActivityRecord activity = createActivityWithTask();
1786         doReturn(true).when(activity).isDestroyable();
1787 
1788         activity.safelyDestroy("test");
1789 
1790         verify(activity).destroyImmediately(anyString());
1791     }
1792 
1793     @Test
testRemoveImmediately()1794     public void testRemoveImmediately() {
1795         final Consumer<Consumer<ActivityRecord>> test = setup -> {
1796             final ActivityRecord activity = createActivityWithTask();
1797             final WindowProcessController wpc = activity.app;
1798             setup.accept(activity);
1799             activity.getTask().removeImmediately("test");
1800             try {
1801                 verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.token),
1802                         isA(DestroyActivityItem.class));
1803             } catch (RemoteException ignored) {
1804             }
1805             assertNull(activity.app);
1806             assertEquals(DESTROYED, activity.getState());
1807             assertFalse(wpc.hasActivities());
1808         };
1809         test.accept(activity -> activity.setState(RESUMED, "test"));
1810         test.accept(activity -> activity.finishing = true);
1811     }
1812 
1813     @Test
testRemoveFromHistory()1814     public void testRemoveFromHistory() {
1815         final ActivityRecord activity = createActivityWithTask();
1816         final Task rootTask = activity.getRootTask();
1817         final Task task = activity.getTask();
1818         final WindowProcessController wpc = activity.app;
1819         assertTrue(wpc.hasActivities());
1820 
1821         activity.removeFromHistory("test");
1822 
1823         assertEquals(DESTROYED, activity.getState());
1824         assertNull(activity.app);
1825         assertNull(activity.getTask());
1826         assertFalse(wpc.hasActivities());
1827         assertEquals(0, task.getChildCount());
1828         assertEquals(task.getRootTask(), task);
1829         assertEquals(0, rootTask.getChildCount());
1830     }
1831 
1832     /**
1833      * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is
1834      * not in destroying or destroyed state.
1835      */
1836     @Test(expected = IllegalStateException.class)
testDestroyed_notDestroying()1837     public void testDestroyed_notDestroying() {
1838         final ActivityRecord activity = createActivityWithTask();
1839         activity.setState(STOPPED, "test");
1840         activity.destroyed("test");
1841     }
1842 
1843     /**
1844      * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying
1845      */
1846     @Test
testDestroyed_destroying()1847     public void testDestroyed_destroying() {
1848         final ActivityRecord activity = createActivityWithTask();
1849         activity.setState(DESTROYING, "test");
1850         activity.destroyed("test");
1851 
1852         verify(activity).removeFromHistory(anyString());
1853     }
1854 
1855     /**
1856      * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed.
1857      */
1858     @Test
testDestroyed_destroyed()1859     public void testDestroyed_destroyed() {
1860         final ActivityRecord activity = createActivityWithTask();
1861         activity.setState(DESTROYED, "test");
1862         activity.destroyed("test");
1863 
1864         verify(activity).removeFromHistory(anyString());
1865     }
1866 
1867     @Test
testActivityOverridesProcessConfig()1868     public void testActivityOverridesProcessConfig() {
1869         final ActivityRecord activity = createActivityWithTask();
1870         final WindowProcessController wpc = activity.app;
1871         assertTrue(wpc.registeredForActivityConfigChanges());
1872         assertFalse(wpc.registeredForDisplayAreaConfigChanges());
1873 
1874         final ActivityRecord secondaryDisplayActivity =
1875                 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1876 
1877         assertTrue(wpc.registeredForActivityConfigChanges());
1878         assertEquals(0, activity.getMergedOverrideConfiguration()
1879                 .diff(wpc.getRequestedOverrideConfiguration()));
1880         assertNotEquals(activity.getConfiguration(),
1881                 secondaryDisplayActivity.getConfiguration());
1882     }
1883 
1884     @Test
testActivityOverridesProcessConfig_TwoActivities()1885     public void testActivityOverridesProcessConfig_TwoActivities() {
1886         final ActivityRecord activity = createActivityWithTask();
1887         final WindowProcessController wpc = activity.app;
1888         assertTrue(wpc.registeredForActivityConfigChanges());
1889 
1890         final Task firstTaskRecord = activity.getTask();
1891         final ActivityRecord secondActivityRecord =
1892                 new ActivityBuilder(mAtm).setTask(firstTaskRecord).setUseProcess(wpc).build();
1893 
1894         assertTrue(wpc.registeredForActivityConfigChanges());
1895         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1896                 .diff(wpc.getRequestedOverrideConfiguration()));
1897     }
1898 
1899     @Test
testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay()1900     public void testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay() {
1901         final ActivityRecord activity = createActivityWithTask();
1902         final WindowProcessController wpc = activity.app;
1903         assertTrue(wpc.registeredForActivityConfigChanges());
1904 
1905         final ActivityRecord secondActivityRecord =
1906                 new ActivityBuilder(mAtm).setTask(activity.getTask()).setUseProcess(wpc).build();
1907 
1908         assertTrue(wpc.registeredForActivityConfigChanges());
1909         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1910                 .diff(wpc.getRequestedOverrideConfiguration()));
1911     }
1912 
1913     @Test
testActivityOverridesProcessConfig_TwoActivities_DifferentTasks()1914     public void testActivityOverridesProcessConfig_TwoActivities_DifferentTasks() {
1915         final ActivityRecord activity = createActivityWithTask();
1916         final WindowProcessController wpc = activity.app;
1917         assertTrue(wpc.registeredForActivityConfigChanges());
1918 
1919         final ActivityRecord secondActivityRecord =
1920                 createActivityOnDisplay(true /* defaultDisplay */, wpc);
1921 
1922         assertTrue(wpc.registeredForActivityConfigChanges());
1923         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1924                 .diff(wpc.getRequestedOverrideConfiguration()));
1925     }
1926 
1927     @Test
testActivityOnCancelFixedRotationTransform()1928     public void testActivityOnCancelFixedRotationTransform() {
1929         final ActivityRecord activity = createActivityWithTask();
1930         final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation();
1931         final RemoteDisplayChangeController remoteDisplayChangeController = activity
1932                 .mDisplayContent.mRemoteDisplayChangeController;
1933         spyOn(displayRotation);
1934         spyOn(remoteDisplayChangeController);
1935 
1936         final DisplayContent display = activity.mDisplayContent;
1937         final int originalRotation = display.getRotation();
1938 
1939         // Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately.
1940         doReturn(true).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange();
1941         doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation(
1942                 anyInt() /* orientation */, anyInt() /* lastRotation */);
1943         // Set to visible so the activity can freeze the screen.
1944         activity.setVisibility(true);
1945 
1946         display.rotateInDifferentOrientationIfNeeded(activity);
1947         display.setFixedRotationLaunchingAppUnchecked(activity);
1948         displayRotation.updateRotationUnchecked(true /* forceUpdate */);
1949 
1950         assertTrue(displayRotation.isRotatingSeamlessly());
1951 
1952         // The launching rotated app should not be cleared when waiting for remote rotation.
1953         display.continueUpdateOrientationForDiffOrienLaunchingApp();
1954         assertTrue(display.isFixedRotationLaunchingApp(activity));
1955 
1956         // Simulate the rotation has been updated to previous one, e.g. sensor updates before the
1957         // remote rotation is completed.
1958         doReturn(originalRotation).when(displayRotation).rotationForOrientation(
1959                 anyInt() /* orientation */, anyInt() /* lastRotation */);
1960         display.updateOrientation();
1961 
1962         final DisplayInfo rotatedInfo = activity.getFixedRotationTransformDisplayInfo();
1963         activity.finishFixedRotationTransform();
1964         final ScreenRotationAnimation rotationAnim = display.getRotationAnimation();
1965         assertNotNull(rotationAnim);
1966         rotationAnim.setRotation(display.getPendingTransaction(), originalRotation);
1967 
1968         // Because the display doesn't rotate, the rotated activity needs to cancel the fixed
1969         // rotation. There should be a rotation animation to cover the change of activity.
1970         verify(activity).onCancelFixedRotationTransform(rotatedInfo.rotation);
1971         assertTrue(activity.isFreezingScreen());
1972         assertFalse(displayRotation.isRotatingSeamlessly());
1973         assertTrue(rotationAnim.isRotating());
1974 
1975         // Simulate the remote rotation has completed and the configuration doesn't change, then
1976         // the rotated activity should also be restored by clearing the transform.
1977         displayRotation.updateRotationUnchecked(true /* forceUpdate */);
1978         doReturn(false).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange();
1979         clearInvocations(activity);
1980         display.setFixedRotationLaunchingAppUnchecked(activity);
1981         display.sendNewConfiguration();
1982 
1983         assertFalse(display.hasTopFixedRotationLaunchingApp());
1984         assertFalse(activity.hasFixedRotationTransform());
1985 
1986         // Simulate that the activity requests the same orientation as display.
1987         activity.setOrientation(display.getConfiguration().orientation);
1988         // Skip the real freezing.
1989         activity.setVisibleRequested(false);
1990         clearInvocations(activity);
1991         activity.onCancelFixedRotationTransform(originalRotation);
1992         // The implementation of cancellation must be executed.
1993         verify(activity).startFreezingScreen(originalRotation);
1994     }
1995 
1996     @Test
testIsSnapshotCompatible()1997     public void testIsSnapshotCompatible() {
1998         final ActivityRecord activity = createActivityWithTask();
1999         final Task task = activity.getTask();
2000         final Rect taskBounds = task.getBounds();
2001         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
2002                 .setTopActivityComponent(activity.mActivityComponent)
2003                 .setRotation(activity.getWindowConfiguration().getRotation())
2004                 .setTaskSize(taskBounds.width(), taskBounds.height())
2005                 .build();
2006 
2007         assertTrue(activity.isSnapshotCompatible(snapshot));
2008 
2009         doReturn(task.getWindowConfiguration().getRotation() + 1).when(mDisplayContent)
2010                 .rotationForActivityInDifferentOrientation(activity);
2011 
2012         assertFalse(activity.isSnapshotCompatible(snapshot));
2013     }
2014 
2015     /**
2016      * Test that the snapshot should be obsoleted if the top activity changed.
2017      */
2018     @Test
testIsSnapshotCompatibleTopActivityChanged()2019     public void testIsSnapshotCompatibleTopActivityChanged() {
2020         final ActivityRecord activity = createActivityWithTask();
2021         final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
2022                 .setTask(activity.getTask())
2023                 .setOnTop(true)
2024                 .build();
2025         final Task task = secondActivity.getTask();
2026         final Rect taskBounds = task.getBounds();
2027         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
2028                 .setTopActivityComponent(secondActivity.mActivityComponent)
2029                 .setTaskSize(taskBounds.width(), taskBounds.height())
2030                 .build();
2031 
2032         assertTrue(secondActivity.isSnapshotCompatible(snapshot));
2033 
2034         // Emulate the top activity changed.
2035         assertFalse(activity.isSnapshotCompatible(snapshot));
2036     }
2037 
2038     /**
2039      * Test that the snapshot should be obsoleted if the task size changed.
2040      */
2041     @Test
testIsSnapshotCompatibleTaskSizeChanged()2042     public void testIsSnapshotCompatibleTaskSizeChanged() {
2043         final ActivityRecord activity = createActivityWithTask();
2044         final Task task = activity.getTask();
2045         final Rect taskBounds = task.getBounds();
2046         final int currentRotation = mDisplayContent.getRotation();
2047         final int w = taskBounds.width();
2048         final int h = taskBounds.height();
2049         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
2050                 .setTopActivityComponent(activity.mActivityComponent)
2051                 .setRotation(currentRotation)
2052                 .setTaskSize(w, h)
2053                 .build();
2054 
2055         assertTrue(activity.isSnapshotCompatible(snapshot));
2056 
2057         taskBounds.right = taskBounds.width() * 2;
2058         task.getWindowConfiguration().setBounds(taskBounds);
2059         activity.getWindowConfiguration().setBounds(taskBounds);
2060 
2061         assertFalse(activity.isSnapshotCompatible(snapshot));
2062 
2063         // Flipped size should be accepted if the activity will show with 90 degree rotation.
2064         final int targetRotation = currentRotation + 1;
2065         doReturn(targetRotation).when(mDisplayContent)
2066                 .rotationForActivityInDifferentOrientation(any());
2067         final TaskSnapshot rotatedSnapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
2068                 .setTopActivityComponent(activity.mActivityComponent)
2069                 .setRotation(targetRotation)
2070                 .setTaskSize(h, w)
2071                 .build();
2072         task.getWindowConfiguration().getBounds().set(0, 0, w, h);
2073         assertTrue(activity.isSnapshotCompatible(rotatedSnapshot));
2074     }
2075 
2076     @Test
testFixedRotationSnapshotStartingWindow()2077     public void testFixedRotationSnapshotStartingWindow() {
2078         final ActivityRecord activity = createActivityWithTask();
2079         // TaskSnapshotSurface requires a fullscreen opaque window.
2080         final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
2081                 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
2082         params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
2083         final TestWindowState w = new TestWindowState(
2084                 mAtm.mWindowManager, mock(Session.class), new TestIWindow(), params, activity);
2085         activity.addWindow(w);
2086 
2087         // Assume the activity is launching in different rotation, and there was an available
2088         // snapshot accepted by {@link Activity#isSnapshotCompatible}.
2089         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
2090                 .setRotation((activity.getWindowConfiguration().getRotation() + 1) % 4)
2091                 .build();
2092         setRotatedScreenOrientationSilently(activity);
2093         activity.setVisible(false);
2094 
2095         final IWindowSession session = WindowManagerGlobal.getWindowSession();
2096         spyOn(session);
2097         try {
2098             // Return error to skip unnecessary operation.
2099             doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
2100                     any() /* window */,  any() /* attrs */,
2101                     anyInt() /* viewVisibility */, anyInt() /* displayId */,
2102                     anyInt() /* requestedVisibleTypes */, any() /* outInputChannel */,
2103                     any() /* outInsetsState */, any() /* outActiveControls */,
2104                     any() /* outAttachedFrame */, any() /* outSizeCompatScale */);
2105             mAtm.mWindowManager.mStartingSurfaceController
2106                     .createTaskSnapshotSurface(activity, snapshot);
2107         } catch (RemoteException ignored) {
2108         } finally {
2109             reset(session);
2110         }
2111 
2112         // Because the rotation of snapshot and the corresponding top activity are different, fixed
2113         // rotation should be applied when creating snapshot surface if the display rotation may be
2114         // changed according to the activity orientation.
2115         assertTrue(activity.hasFixedRotationTransform());
2116         assertTrue(activity.mDisplayContent.isFixedRotationLaunchingApp(activity));
2117     }
2118 
2119     /**
2120      * Sets orientation without notifying the parent to simulate that the display has not applied
2121      * the requested orientation yet.
2122      */
setRotatedScreenOrientationSilently(ActivityRecord r)2123     static void setRotatedScreenOrientationSilently(ActivityRecord r) {
2124         final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT
2125                 ? SCREEN_ORIENTATION_LANDSCAPE
2126                 : SCREEN_ORIENTATION_PORTRAIT;
2127         doReturn(false).when(r).onDescendantOrientationChanged(any());
2128         r.setOrientation(rotatedOrentation);
2129     }
2130 
2131     @Test
testActivityOnDifferentDisplayUpdatesProcessOverride()2132     public void testActivityOnDifferentDisplayUpdatesProcessOverride() {
2133         final ActivityRecord secondaryDisplayActivity =
2134                 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
2135         final WindowProcessController wpc = secondaryDisplayActivity.app;
2136         assertTrue(wpc.registeredForActivityConfigChanges());
2137 
2138         final ActivityRecord secondActivityRecord =
2139                 createActivityOnDisplay(true /* defaultDisplay */, wpc);
2140 
2141         assertTrue(wpc.registeredForActivityConfigChanges());
2142         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
2143                 .diff(wpc.getRequestedOverrideConfiguration()));
2144         assertFalse(wpc.registeredForDisplayAreaConfigChanges());
2145     }
2146 
2147     @Test
testActivityReparentChangesProcessOverride()2148     public void testActivityReparentChangesProcessOverride() {
2149         final ActivityRecord activity = createActivityWithTask();
2150         final WindowProcessController wpc = activity.app;
2151         final Task initialTask = activity.getTask();
2152         final Configuration initialConf =
2153                 new Configuration(activity.getMergedOverrideConfiguration());
2154         assertEquals(0, activity.getMergedOverrideConfiguration()
2155                 .diff(wpc.getRequestedOverrideConfiguration()));
2156         assertTrue(wpc.registeredForActivityConfigChanges());
2157 
2158         // Create a new task with custom config to reparent the activity to.
2159         final Task newTask = new TaskBuilder(mSupervisor).build();
2160         final Configuration newConfig = newTask.getConfiguration();
2161         newConfig.densityDpi += 100;
2162         newTask.onRequestedOverrideConfigurationChanged(newConfig);
2163         assertEquals(newTask.getConfiguration().densityDpi, newConfig.densityDpi);
2164 
2165         // Reparent the activity and verify that config override changed.
2166         activity.reparent(newTask, 0 /* top */, "test");
2167         assertEquals(activity.getConfiguration().densityDpi, newConfig.densityDpi);
2168         assertEquals(activity.getMergedOverrideConfiguration().densityDpi, newConfig.densityDpi);
2169 
2170         assertTrue(wpc.registeredForActivityConfigChanges());
2171         assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
2172         assertEquals(0, activity.getMergedOverrideConfiguration()
2173                 .diff(wpc.getRequestedOverrideConfiguration()));
2174     }
2175 
2176     @Test
testActivityReparentDoesntClearProcessOverride_TwoActivities()2177     public void testActivityReparentDoesntClearProcessOverride_TwoActivities() {
2178         final ActivityRecord activity = createActivityWithTask();
2179         final WindowProcessController wpc = activity.app;
2180         final Configuration initialConf =
2181                 new Configuration(activity.getMergedOverrideConfiguration());
2182         final Task initialTask = activity.getTask();
2183         final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(initialTask)
2184                 .setUseProcess(wpc).build();
2185 
2186         assertTrue(wpc.registeredForActivityConfigChanges());
2187         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
2188                 .diff(wpc.getRequestedOverrideConfiguration()));
2189 
2190         // Create a new task with custom config to reparent the second activity to.
2191         final Task newTask = new TaskBuilder(mSupervisor).build();
2192         final Configuration newConfig = newTask.getConfiguration();
2193         newConfig.densityDpi += 100;
2194         newTask.onRequestedOverrideConfigurationChanged(newConfig);
2195 
2196         // Reparent the activity and verify that config override changed.
2197         secondActivity.reparent(newTask, 0 /* top */, "test");
2198 
2199         assertTrue(wpc.registeredForActivityConfigChanges());
2200         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
2201                 .diff(wpc.getRequestedOverrideConfiguration()));
2202         assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
2203 
2204         // Reparent the first activity and verify that config override didn't change.
2205         activity.reparent(newTask, 1 /* top */, "test");
2206         assertTrue(wpc.registeredForActivityConfigChanges());
2207         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
2208                 .diff(wpc.getRequestedOverrideConfiguration()));
2209         assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
2210     }
2211 
2212     @Test
testActivityDestroyDoesntChangeProcessOverride()2213     public void testActivityDestroyDoesntChangeProcessOverride() {
2214         final ActivityRecord firstActivity =
2215                 createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
2216         final WindowProcessController wpc = firstActivity.app;
2217         assertTrue(wpc.registeredForActivityConfigChanges());
2218         assertEquals(0, firstActivity.getMergedOverrideConfiguration()
2219                 .diff(wpc.getRequestedOverrideConfiguration()));
2220 
2221         final ActivityRecord secondActivity =
2222                 createActivityOnDisplay(false /* defaultDisplay */, wpc);
2223         assertTrue(wpc.registeredForActivityConfigChanges());
2224         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
2225                 .diff(wpc.getRequestedOverrideConfiguration()));
2226 
2227         final ActivityRecord thirdActivity =
2228                 createActivityOnDisplay(false /* defaultDisplay */, wpc);
2229         assertTrue(wpc.registeredForActivityConfigChanges());
2230         assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
2231                 .diff(wpc.getRequestedOverrideConfiguration()));
2232 
2233         secondActivity.destroyImmediately("");
2234 
2235         assertTrue(wpc.registeredForActivityConfigChanges());
2236         assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
2237                 .diff(wpc.getRequestedOverrideConfiguration()));
2238 
2239         firstActivity.destroyImmediately("");
2240 
2241         assertTrue(wpc.registeredForActivityConfigChanges());
2242         assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
2243                 .diff(wpc.getRequestedOverrideConfiguration()));
2244     }
2245 
2246     @Test
testFullscreenWindowCanTurnScreenOn()2247     public void testFullscreenWindowCanTurnScreenOn() {
2248         final ActivityRecord activity = createActivityWithTask();
2249         final Task task = activity.getTask();
2250         task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
2251         doReturn(true).when(activity).getTurnScreenOnFlag();
2252 
2253         assertTrue(activity.canTurnScreenOn());
2254     }
2255 
2256     @Test
testFreeformWindowCanTurnScreenOn()2257     public void testFreeformWindowCanTurnScreenOn() {
2258         final ActivityRecord activity = createActivityWithTask();
2259         final Task task = activity.getTask();
2260         task.setWindowingMode(WINDOWING_MODE_FREEFORM);
2261         doReturn(true).when(activity).getTurnScreenOnFlag();
2262 
2263         assertTrue(activity.canTurnScreenOn());
2264     }
2265 
2266     @Test
testGetLockTaskLaunchMode()2267     public void testGetLockTaskLaunchMode() {
2268         final ActivityRecord activity = createActivityWithTask();
2269         final ActivityOptions options = ActivityOptions.makeBasic().setLockTaskEnabled(true);
2270         activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
2271         assertEquals(LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED,
2272                 ActivityRecord.getLockTaskLaunchMode(activity.info, options));
2273 
2274         activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_ALWAYS;
2275         assertEquals(LOCK_TASK_LAUNCH_MODE_DEFAULT,
2276                 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/));
2277 
2278         activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_NEVER;
2279         assertEquals(LOCK_TASK_LAUNCH_MODE_DEFAULT,
2280                 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/));
2281 
2282         activity.info.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
2283         activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_ALWAYS;
2284         assertEquals(LOCK_TASK_LAUNCH_MODE_ALWAYS,
2285                 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/));
2286 
2287         activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_NEVER;
2288         assertEquals(LOCK_TASK_LAUNCH_MODE_NEVER,
2289                 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/));
2290 
2291     }
2292 
2293     @Test
testProcessInfoUpdateWhenSetState()2294     public void testProcessInfoUpdateWhenSetState() {
2295         final ActivityRecord activity = createActivityWithTask();
2296         activity.setState(INITIALIZING, "test");
2297         spyOn(activity.app);
2298         verifyProcessInfoUpdate(activity, RESUMED,
2299                 true /* shouldUpdate */, true /* activityChange */);
2300         verifyProcessInfoUpdate(activity, PAUSED,
2301                 false /* shouldUpdate */, false /* activityChange */);
2302         verifyProcessInfoUpdate(activity, STOPPED,
2303                 false /* shouldUpdate */, false /* activityChange */);
2304         verifyProcessInfoUpdate(activity, STARTED,
2305                 true /* shouldUpdate */, true /* activityChange */);
2306 
2307         activity.app.removeActivity(activity, true /* keepAssociation */);
2308         verifyProcessInfoUpdate(activity, DESTROYING,
2309                 true /* shouldUpdate */, false /* activityChange */);
2310         verifyProcessInfoUpdate(activity, DESTROYED,
2311                 true /* shouldUpdate */, false /* activityChange */);
2312     }
2313 
2314     @Test
testSupportsFreeform()2315     public void testSupportsFreeform() {
2316         final ActivityRecord activity = new ActivityBuilder(mAtm)
2317                 .setCreateTask(true)
2318                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
2319                 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
2320                 .build();
2321 
2322         // Not allow non-resizable
2323         mAtm.mForceResizableActivities = false;
2324         mAtm.mSupportsNonResizableMultiWindow = -1;
2325         mAtm.mDevEnableNonResizableMultiWindow = false;
2326         assertFalse(activity.supportsFreeform());
2327 
2328         // Force resizable
2329         mAtm.mForceResizableActivities = true;
2330         mAtm.mSupportsNonResizableMultiWindow = -1;
2331         mAtm.mDevEnableNonResizableMultiWindow = false;
2332         assertTrue(activity.supportsFreeform());
2333 
2334         // Use development option to allow non-resizable
2335         mAtm.mForceResizableActivities = false;
2336         mAtm.mSupportsNonResizableMultiWindow = -1;
2337         mAtm.mDevEnableNonResizableMultiWindow = true;
2338         assertTrue(activity.supportsFreeform());
2339 
2340         // Always allow non-resizable
2341         mAtm.mForceResizableActivities = false;
2342         mAtm.mSupportsNonResizableMultiWindow = 1;
2343         mAtm.mDevEnableNonResizableMultiWindow = false;
2344         assertTrue(activity.supportsFreeform());
2345     }
2346 
2347     @Test
testSupportsPictureInPicture()2348     public void testSupportsPictureInPicture() {
2349         final ActivityRecord activity = new ActivityBuilder(mAtm)
2350                 .setCreateTask(true)
2351                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
2352                 .setActivityFlags(FLAG_SUPPORTS_PICTURE_IN_PICTURE)
2353                 .build();
2354 
2355         // Device not supports PIP
2356         mAtm.mSupportsPictureInPicture = false;
2357         assertFalse(activity.supportsPictureInPicture());
2358 
2359         // Device and app support PIP
2360         mAtm.mSupportsPictureInPicture = true;
2361         assertTrue(activity.supportsPictureInPicture());
2362 
2363         // Activity not supports PIP
2364         activity.info.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE;
2365         assertFalse(activity.supportsPictureInPicture());
2366     }
2367 
2368     @Test
testCheckEnterPictureInPictureState_displayNotSupportedPip()2369     public void testCheckEnterPictureInPictureState_displayNotSupportedPip() {
2370         final Task task = new TaskBuilder(mSupervisor)
2371                 .setDisplay(mDisplayContent).build();
2372         final ActivityRecord activity = new ActivityBuilder(mAtm)
2373                 .setTask(task)
2374                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
2375                 .setActivityFlags(FLAG_SUPPORTS_PICTURE_IN_PICTURE)
2376                 .build();
2377         mAtm.mSupportsPictureInPicture = true;
2378         AppOpsManager appOpsManager = mAtm.getAppOpsManager();
2379         doReturn(MODE_ALLOWED).when(appOpsManager).checkOpNoThrow(eq(OP_PICTURE_IN_PICTURE),
2380                 anyInt(), any());
2381         doReturn(false).when(mAtm).shouldDisableNonVrUiLocked();
2382 
2383         spyOn(mDisplayContent.mDwpcHelper);
2384         doReturn(false).when(mDisplayContent.mDwpcHelper).isEnteringPipAllowed(anyInt());
2385 
2386         assertFalse(activity.checkEnterPictureInPictureState("TEST", false /* beforeStopping */));
2387     }
2388 
2389     @Test
testLaunchIntoPip()2390     public void testLaunchIntoPip() {
2391         final PictureInPictureParams params = new PictureInPictureParams.Builder()
2392                 .build();
2393         final ActivityOptions opts = ActivityOptions.makeLaunchIntoPip(params);
2394         final ActivityRecord activity = new ActivityBuilder(mAtm)
2395                 .setActivityOptions(opts)
2396                 .build();
2397 
2398         // Verify the pictureInPictureArgs is set on the new Activity
2399         assertNotNull(activity.pictureInPictureArgs);
2400         assertTrue(activity.pictureInPictureArgs.isLaunchIntoPip());
2401     }
2402 
2403     @Test
testActivityServiceConnectionsHolder()2404     public void testActivityServiceConnectionsHolder() {
2405         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2406         final ActivityServiceConnectionsHolder<Object> holder =
2407                 mAtm.mInternal.getServiceConnectionsHolder(activity.token);
2408         assertNotNull(holder);
2409         final Object connection = new Object();
2410         holder.addConnection(connection);
2411         assertTrue(holder.isActivityVisible());
2412         final int[] count = new int[1];
2413         final Consumer<Object> c = conn -> {
2414             count[0]++;
2415             assertFalse(Thread.holdsLock(activity));
2416         };
2417         holder.forEachConnection(c);
2418         assertEquals(1, count[0]);
2419 
2420         holder.removeConnection(connection);
2421         holder.forEachConnection(c);
2422         assertEquals(1, count[0]);
2423 
2424         activity.setVisibleRequested(false);
2425         activity.setState(STOPPED, "test");
2426         assertFalse(holder.isActivityVisible());
2427 
2428         activity.removeImmediately();
2429         assertNull(mAtm.mInternal.getServiceConnectionsHolder(activity.token));
2430     }
2431 
2432     @Test
testTransferLaunchCookieWhenFinishing()2433     public void testTransferLaunchCookieWhenFinishing() {
2434         final ActivityRecord activity1 = createActivityWithTask();
2435         final Binder launchCookie = new Binder();
2436         activity1.mLaunchCookie = launchCookie;
2437         final ActivityRecord activity2 = createActivityRecord(activity1.getTask());
2438         activity1.setState(PAUSED, "test");
2439         activity1.makeFinishingLocked();
2440 
2441         assertEquals(launchCookie, activity2.mLaunchCookie);
2442         assertNull(activity1.mLaunchCookie);
2443         activity2.makeFinishingLocked();
2444         assertTrue(activity1.getTask().getTaskInfo().launchCookies.contains(launchCookie));
2445     }
2446 
2447     @Test
testOrientationForScreenOrientationBehind()2448     public void testOrientationForScreenOrientationBehind() {
2449         final Task task = createTask(mDisplayContent);
2450         // Activity below
2451         new ActivityBuilder(mAtm)
2452                 .setTask(task)
2453                 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
2454                 .build();
2455         final ActivityRecord activityTop = new ActivityBuilder(mAtm)
2456                 .setTask(task)
2457                 .setScreenOrientation(SCREEN_ORIENTATION_BEHIND)
2458                 .build();
2459         final int topOrientation = activityTop.getRequestedConfigurationOrientation();
2460         assertEquals(ORIENTATION_PORTRAIT, topOrientation);
2461     }
2462 
verifyProcessInfoUpdate(ActivityRecord activity, State state, boolean shouldUpdate, boolean activityChange)2463     private void verifyProcessInfoUpdate(ActivityRecord activity, State state,
2464             boolean shouldUpdate, boolean activityChange) {
2465         reset(activity.app);
2466         activity.setState(state, "test");
2467         verify(activity.app, times(shouldUpdate ? 1 : 0)).updateProcessInfo(anyBoolean(),
2468                 eq(activityChange), anyBoolean(), anyBoolean());
2469     }
2470 
createActivityWithTask()2471     private ActivityRecord createActivityWithTask() {
2472         return new ActivityBuilder(mAtm).setCreateTask(true).setOnTop(true).build();
2473     }
2474 
createActivityWith2LevelTask()2475     private ActivityRecord createActivityWith2LevelTask() {
2476         final Task task = new TaskBuilder(mSupervisor)
2477                 .setCreateParentTask(true).setCreateActivity(true).build();
2478         return task.getTopNonFinishingActivity();
2479     }
2480 
2481     /**
2482      * Creates an activity on display. For non-default display request it will also create a new
2483      * display with custom DisplayInfo.
2484      */
createActivityOnDisplay(boolean defaultDisplay, WindowProcessController process)2485     private ActivityRecord createActivityOnDisplay(boolean defaultDisplay,
2486             WindowProcessController process) {
2487         final DisplayContent display;
2488         if (defaultDisplay) {
2489             display = mRootWindowContainer.getDefaultDisplay();
2490         } else {
2491             display = new TestDisplayContent.Builder(mAtm, 2000, 1000).setDensityDpi(300)
2492                     .setPosition(DisplayContent.POSITION_TOP).build();
2493         }
2494         final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
2495         return new ActivityBuilder(mAtm).setTask(task).setUseProcess(process).build();
2496     }
2497 
2498     @Test
2499     @Presubmit
testAddWindow_Order()2500     public void testAddWindow_Order() {
2501         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2502         assertEquals(0, activity.getChildCount());
2503 
2504         final WindowState win1 = createWindow(null, TYPE_APPLICATION, activity, "win1");
2505         final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity,
2506                 "startingWin");
2507         final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, activity, "baseWin");
2508         final WindowState win4 = createWindow(null, TYPE_APPLICATION, activity, "win4");
2509 
2510         // Should not contain the windows that were added above.
2511         assertEquals(4, activity.getChildCount());
2512         assertTrue(activity.mChildren.contains(win1));
2513         assertTrue(activity.mChildren.contains(startingWin));
2514         assertTrue(activity.mChildren.contains(baseWin));
2515         assertTrue(activity.mChildren.contains(win4));
2516 
2517         // The starting window should be on-top of all other windows.
2518         assertEquals(startingWin, activity.mChildren.peekLast());
2519 
2520         // The base application window should be below all other windows.
2521         assertEquals(baseWin, activity.mChildren.peekFirst());
2522         activity.removeImmediately();
2523     }
2524 
2525     @Test
2526     @Presubmit
testFindMainWindow()2527     public void testFindMainWindow() {
2528         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2529         assertNull(activity.findMainWindow());
2530 
2531         final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "window1");
2532         final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, activity, "window11");
2533         final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, activity, "window12");
2534         assertEquals(window1, activity.findMainWindow());
2535         window1.mAnimatingExit = true;
2536         assertEquals(window1, activity.findMainWindow());
2537         final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, activity,
2538                 "window2");
2539         assertEquals(window2, activity.findMainWindow());
2540         activity.removeImmediately();
2541     }
2542 
2543     @Test
2544     @Presubmit
testGetTopFullscreenOpaqueWindow()2545     public void testGetTopFullscreenOpaqueWindow() {
2546         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2547         assertNull(activity.getTopFullscreenOpaqueWindow());
2548 
2549         final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "window1");
2550         final WindowState window11 = createWindow(null, TYPE_APPLICATION, activity, "window11");
2551         final WindowState window12 = createWindow(null, TYPE_APPLICATION, activity, "window12");
2552         assertEquals(window12, activity.getTopFullscreenOpaqueWindow());
2553         window12.mAttrs.width = 500;
2554         assertEquals(window11, activity.getTopFullscreenOpaqueWindow());
2555         window11.mAttrs.width = 500;
2556         assertEquals(window1, activity.getTopFullscreenOpaqueWindow());
2557         window1.mAttrs.alpha = 0f;
2558         assertNull(activity.getTopFullscreenOpaqueWindow());
2559         activity.removeImmediately();
2560     }
2561 
2562     @SetupWindows(addWindows = W_ACTIVITY)
2563     @Test
testLandscapeSeascapeRotationByApp()2564     public void testLandscapeSeascapeRotationByApp() {
2565         final Task task = new TaskBuilder(mSupervisor)
2566                 .setDisplay(mDisplayContent).setCreateActivity(true).build();
2567         final ActivityRecord activity = task.getTopNonFinishingActivity();
2568         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
2569                 TYPE_BASE_APPLICATION);
2570         attrs.setTitle("AppWindow");
2571         final TestWindowState appWindow = createWindowState(attrs, activity);
2572         activity.addWindow(appWindow);
2573         spyOn(appWindow);
2574         doNothing().when(appWindow).onStartFreezingScreen();
2575 
2576         // Set initial orientation and update.
2577         activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
2578         mDisplayContent.updateOrientation(null /* freezeThisOneIfNeeded */,
2579                 false /* forceUpdate */);
2580         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
2581         appWindow.mResizeReported = false;
2582 
2583         // Update the orientation to perform 180 degree rotation and check that resize was reported.
2584         activity.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
2585         mDisplayContent.updateOrientation(null /* freezeThisOneIfNeeded */,
2586                 false /* forceUpdate */);
2587         // In this test, DC will not get config update. Set the waiting flag to false.
2588         mDisplayContent.mWaitingForConfig = false;
2589         mWm.mRoot.performSurfacePlacement();
2590         assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation());
2591         assertTrue(appWindow.mResizeReported);
2592         appWindow.removeImmediately();
2593     }
2594 
2595     @SetupWindows(addWindows = W_ACTIVITY)
2596     @Test
testLandscapeSeascapeRotationByPolicy()2597     public void testLandscapeSeascapeRotationByPolicy() {
2598         final Task task = new TaskBuilder(mSupervisor)
2599                 .setDisplay(mDisplayContent).setCreateActivity(true).build();
2600         final ActivityRecord activity = task.getTopNonFinishingActivity();
2601         final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2602         spyOn(displayRotation);
2603 
2604         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
2605                 TYPE_BASE_APPLICATION);
2606         attrs.setTitle("RotationByPolicy");
2607         final TestWindowState appWindow = createWindowState(attrs, activity);
2608         activity.addWindow(appWindow);
2609         spyOn(appWindow);
2610         doNothing().when(appWindow).onStartFreezingScreen();
2611         doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
2612 
2613         // Set initial orientation and update.
2614         performRotation(displayRotation, Surface.ROTATION_90);
2615         appWindow.mResizeReported = false;
2616 
2617         // Update the rotation to perform 180 degree rotation and check that resize was reported.
2618         performRotation(displayRotation, Surface.ROTATION_270);
2619         assertTrue(appWindow.mResizeReported);
2620     }
2621 
performRotation(DisplayRotation spiedRotation, int rotationToReport)2622     private void performRotation(DisplayRotation spiedRotation, int rotationToReport) {
2623         doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt());
2624         mWm.updateRotation(false, false);
2625     }
2626 
2627     @Test
2628     @Presubmit
testGetOrientation()2629     public void testGetOrientation() {
2630         // ActivityBuilder will resume top activities and cause the activity been added into
2631         // opening apps list. Since this test is focus on the effect of visible on getting
2632         // orientation, we skip app transition to avoid interference.
2633         doNothing().when(mDisplayContent).prepareAppTransition(anyInt());
2634         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2635         activity.setVisible(true);
2636 
2637         activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
2638 
2639         activity.setOccludesParent(false);
2640         // Can specify orientation if app doesn't occludes parent.
2641         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation());
2642 
2643         doReturn(true).when(activity).shouldIgnoreOrientationRequests();
2644         assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation());
2645 
2646         doReturn(false).when(activity).shouldIgnoreOrientationRequests();
2647         activity.setOccludesParent(true);
2648         activity.setVisible(false);
2649         activity.setVisibleRequested(false);
2650         // Can not specify orientation if app isn't visible even though it occludes parent.
2651         assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation());
2652         // Can specify orientation if the current orientation candidate is orientation behind.
2653         assertEquals(SCREEN_ORIENTATION_LANDSCAPE,
2654                 activity.getOrientation(SCREEN_ORIENTATION_BEHIND));
2655     }
2656 
2657     @Test
2658     @Presubmit
testKeyguardFlagsDuringRelaunch()2659     public void testKeyguardFlagsDuringRelaunch() {
2660         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2661         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
2662                 TYPE_BASE_APPLICATION);
2663         attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD;
2664         attrs.setTitle("AppWindow");
2665         final TestWindowState appWindow = createWindowState(attrs, activity);
2666 
2667         // Add window with show when locked flag
2668         activity.addWindow(appWindow);
2669         assertTrue(activity.containsShowWhenLockedWindow()
2670                 && activity.containsDismissKeyguardWindow());
2671 
2672         // Start relaunching
2673         activity.startRelaunching();
2674         assertTrue(activity.containsShowWhenLockedWindow()
2675                 && activity.containsDismissKeyguardWindow());
2676 
2677         // Remove window and make sure that we still report back flag
2678         activity.removeChild(appWindow);
2679         assertTrue(activity.containsShowWhenLockedWindow()
2680                 && activity.containsDismissKeyguardWindow());
2681 
2682         // Finish relaunching and ensure flag is now not reported
2683         activity.finishRelaunching();
2684         assertFalse(activity.containsShowWhenLockedWindow()
2685                 || activity.containsDismissKeyguardWindow());
2686     }
2687 
2688     @Test
testStuckExitingWindow()2689     public void testStuckExitingWindow() {
2690         final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
2691                 "closingWindow");
2692         closingWindow.mAnimatingExit = true;
2693         closingWindow.mRemoveOnExit = true;
2694         closingWindow.mActivityRecord.commitVisibility(
2695                 false /* visible */, true /* performLayout */);
2696 
2697         // We pretended that we were running an exit animation, but that should have been cleared up
2698         // by changing visibility of ActivityRecord
2699         closingWindow.removeIfPossible();
2700         assertTrue(closingWindow.mRemoved);
2701     }
2702 
2703     @Test
testSetOrientation()2704     public void testSetOrientation() {
2705         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2706         activity.setVisible(true);
2707 
2708         // Assert orientation is unspecified to start.
2709         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, activity.getOrientation());
2710 
2711         activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
2712         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation());
2713 
2714         mDisplayContent.removeAppToken(activity.token);
2715         // Assert orientation is unset to after container is removed.
2716         assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation());
2717 
2718         // Reset display frozen state
2719         mWm.mDisplayFrozen = false;
2720     }
2721 
2722     @Test
testRespectTopFullscreenOrientation()2723     public void testRespectTopFullscreenOrientation() {
2724         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2725         final Configuration displayConfig = activity.mDisplayContent.getConfiguration();
2726         final Configuration activityConfig = activity.getConfiguration();
2727         activity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
2728 
2729         assertEquals(Configuration.ORIENTATION_PORTRAIT, displayConfig.orientation);
2730         assertEquals(Configuration.ORIENTATION_PORTRAIT, activityConfig.orientation);
2731 
2732         final ActivityRecord topActivity = createActivityRecord(activity.getTask());
2733         topActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
2734 
2735         assertEquals(Configuration.ORIENTATION_LANDSCAPE, displayConfig.orientation);
2736         // Although the activity requested portrait, it is not the top activity that determines
2737         // the display orientation. So it should be able to inherit the orientation from parent.
2738         // Otherwise its configuration will be inconsistent that its orientation is portrait but
2739         // other screen configurations are in landscape, e.g. screenWidthDp, screenHeightDp, and
2740         // window configuration.
2741         assertEquals(Configuration.ORIENTATION_LANDSCAPE, activityConfig.orientation);
2742     }
2743 
2744     @Test
testReportOrientationChange()2745     public void testReportOrientationChange() {
2746         final Task task = new TaskBuilder(mSupervisor)
2747                 .setDisplay(mDisplayContent).setCreateActivity(true).build();
2748         final ActivityRecord activity = task.getTopNonFinishingActivity();
2749         activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
2750 
2751         mDisplayContent.getDisplayRotation().setFixedToUserRotation(
2752                 IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
2753         reset(task);
2754         activity.reportDescendantOrientationChangeIfNeeded();
2755         verify(task, atLeast(1)).onConfigurationChanged(any(Configuration.class));
2756     }
2757 
2758     @Test
testCreateRemoveStartingWindow()2759     public void testCreateRemoveStartingWindow() {
2760         registerTestStartingWindowOrganizer();
2761         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2762         activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2763                 true, false, false, false);
2764         waitUntilHandlersIdle();
2765         assertHasStartingWindow(activity);
2766         activity.removeStartingWindow();
2767         waitUntilHandlersIdle();
2768         assertNoStartingWindow(activity);
2769     }
2770 
testLegacySplashScreen(int targetSdk, int verifyType)2771     private void testLegacySplashScreen(int targetSdk, int verifyType) {
2772         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2773         activity.mTargetSdk = targetSdk;
2774         activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2775                 true, false, false, false);
2776         waitUntilHandlersIdle();
2777         assertHasStartingWindow(activity);
2778         assertEquals(activity.mStartingData.mTypeParams & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN,
2779                 verifyType);
2780         activity.removeStartingWindow();
2781         waitUntilHandlersIdle();
2782         assertNoStartingWindow(activity);
2783     }
2784 
2785     @Test
testCreateRemoveLegacySplashScreenWindow()2786     public void testCreateRemoveLegacySplashScreenWindow() {
2787         registerTestStartingWindowOrganizer();
2788         DeviceConfig.Properties properties = DeviceConfig.getProperties(
2789                 DeviceConfig.NAMESPACE_WINDOW_MANAGER);
2790         try {
2791             DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
2792                     "splash_screen_exception_list", DEFAULT_COMPONENT_PACKAGE_NAME, false);
2793             testLegacySplashScreen(Build.VERSION_CODES.R, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
2794             testLegacySplashScreen(Build.VERSION_CODES.S, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
2795             testLegacySplashScreen(Build.VERSION_CODES.TIRAMISU,
2796                     TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
2797             testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
2798                     TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
2799             testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1,
2800                     TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
2801             // Above V
2802             testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 2, 0);
2803         } finally {
2804             try {
2805                 DeviceConfig.setProperties(properties);
2806             } catch (DeviceConfig.BadConfigException e) {
2807                 Assert.fail(e.getMessage());
2808             }
2809         }
2810     }
2811 
2812     @Test
testTransferStartingWindow()2813     public void testTransferStartingWindow() {
2814         registerTestStartingWindowOrganizer();
2815         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true)
2816                 .setVisible(false).build();
2817         final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true)
2818                 .setVisible(false).build();
2819         activity1.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2820                 true, false, false, false);
2821         waitUntilHandlersIdle();
2822         activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1, true, true,
2823                 false, true, false, false, false);
2824         waitUntilHandlersIdle();
2825         assertFalse(mDisplayContent.mSkipAppTransitionAnimation);
2826         assertNoStartingWindow(activity1);
2827         assertHasStartingWindow(activity2);
2828     }
2829 
2830     @Test
testTransferStartingWindowWhileCreating()2831     public void testTransferStartingWindowWhileCreating() {
2832         final TestStartingWindowOrganizer organizer = registerTestStartingWindowOrganizer();
2833         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2834         final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2835         organizer.setRunnableWhenAddingSplashScreen(
2836                 () -> {
2837                     // Surprise, ...! Transfer window in the middle of the creation flow.
2838                     activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1,
2839                             true, true, false, true, false, false, false);
2840                 });
2841         activity1.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2842                 true, false, false, false);
2843         waitUntilHandlersIdle();
2844         assertNoStartingWindow(activity1);
2845         assertHasStartingWindow(activity2);
2846     }
2847 
2848     @Test
testTransferStartingWindowCanAnimate()2849     public void testTransferStartingWindowCanAnimate() {
2850         registerTestStartingWindowOrganizer();
2851         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2852         final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2853         activity1.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2854                 true, false, false, false);
2855         waitUntilHandlersIdle();
2856         activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1, true, true,
2857                 false, true, false, false, false);
2858         waitUntilHandlersIdle();
2859         assertNoStartingWindow(activity1);
2860         assertHasStartingWindow(activity2);
2861 
2862         // Assert that bottom activity is allowed to do animation.
2863         ArrayList<WindowContainer> sources = new ArrayList<>();
2864         sources.add(activity2);
2865         doReturn(true).when(activity2).okToAnimate();
2866         doReturn(true).when(activity2).isAnimating();
2867         assertTrue(activity2.applyAnimation(null, TRANSIT_OLD_ACTIVITY_OPEN, true, false, sources));
2868     }
2869     @Test
testTrackingStartingWindowThroughTrampoline()2870     public void testTrackingStartingWindowThroughTrampoline() {
2871         final ActivityRecord sourceRecord = new ActivityBuilder(mAtm)
2872                 .setCreateTask(true).setLaunchedFromUid(Process.SYSTEM_UID).build();
2873         sourceRecord.showStartingWindow(null /* prev */, true /* newTask */, false,
2874                 true /* startActivity */, null);
2875 
2876         final ActivityRecord secondRecord = new ActivityBuilder(mAtm)
2877                 .setTask(sourceRecord.getTask()).build();
2878         secondRecord.showStartingWindow(null /* prev */, true /* newTask */, false,
2879                 true /* startActivity */, sourceRecord);
2880         assertFalse(secondRecord.mSplashScreenStyleSolidColor);
2881         secondRecord.onStartingWindowDrawn();
2882 
2883         final ActivityRecord finalRecord = new ActivityBuilder(mAtm)
2884                 .setTask(sourceRecord.getTask()).build();
2885         finalRecord.showStartingWindow(null /* prev */, true /* newTask */, false,
2886                 true /* startActivity */, secondRecord);
2887         assertTrue(finalRecord.mSplashScreenStyleSolidColor);
2888     }
2889 
2890     @Test
testTransferStartingWindowFromFinishingActivity()2891     public void testTransferStartingWindowFromFinishingActivity() {
2892         registerTestStartingWindowOrganizer();
2893         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2894         final Task task = activity.getTask();
2895         activity.addStartingWindow(mPackageName, android.R.style.Theme, null /* transferFrom */,
2896                 true /* newTask */, true /* taskSwitch */, false /* processRunning */,
2897                 false /* allowTaskSnapshot */, false /* activityCreate */, false /* suggestEmpty
2898                 */, false /* activityAllDrawn */);
2899         waitUntilHandlersIdle();
2900         assertHasStartingWindow(activity);
2901 
2902         doCallRealMethod().when(task).startActivityLocked(
2903                 any(), any(), anyBoolean(), anyBoolean(), any(), any());
2904         // In normal case, resumeFocusedTasksTopActivities() should be called after
2905         // startActivityLocked(). So skip resumeFocusedTasksTopActivities() in ActivityBuilder.
2906         doReturn(false).when(mRootWindowContainer)
2907                 .resumeFocusedTasksTopActivities();
2908         // Make mVisibleSetFromTransferredStartingWindow true.
2909         final ActivityRecord middle = new ActivityBuilder(mAtm).setTask(task).build();
2910         task.startActivityLocked(middle, null /* topTask */,
2911                 false /* newTask */, false /* isTaskSwitch */, null /* options */,
2912                 null /* sourceRecord */);
2913         middle.makeFinishingLocked();
2914 
2915         assertNull(activity.mStartingWindow);
2916         assertHasStartingWindow(middle);
2917 
2918         final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).build();
2919         // Expect the visibility should be updated to true when transferring starting window from
2920         // a visible activity.
2921         top.setVisible(false);
2922         // The finishing middle should be able to transfer starting window to top.
2923         task.startActivityLocked(top, null /* topTask */,
2924                 false /* newTask */, false /* isTaskSwitch */, null /* options */,
2925                 null /* sourceRecord */);
2926 
2927         assertTrue(mDisplayContent.mSkipAppTransitionAnimation);
2928         assertNull(middle.mStartingWindow);
2929         assertHasStartingWindow(top);
2930         assertTrue(top.isVisible());
2931         // The activity was visible by mVisibleSetFromTransferredStartingWindow, so after its
2932         // starting window is transferred, it should restore to invisible.
2933         assertFalse(middle.isVisible());
2934     }
2935 
2936     @Test
testTransferStartingWindowSetFixedRotation()2937     public void testTransferStartingWindowSetFixedRotation() {
2938         registerTestStartingWindowOrganizer();
2939         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2940         final Task task = activity.getTask();
2941         final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
2942         topActivity.setVisible(false);
2943         task.positionChildAt(POSITION_TOP, topActivity, false /* includeParents */);
2944         activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2945                 true, false, false, false);
2946         waitUntilHandlersIdle();
2947 
2948         // Make activities to have different rotation from it display and set fixed rotation
2949         // transform to activity1.
2950         int rotation = (mDisplayContent.getRotation() + 1) % 4;
2951         mDisplayContent.setFixedRotationLaunchingApp(activity, rotation);
2952         // The configuration with rotation change should not trigger task-association.
2953         assertNotNull(activity.mStartingData);
2954         assertNull(activity.mStartingData.mAssociatedTask);
2955         doReturn(rotation).when(mDisplayContent)
2956                 .rotationForActivityInDifferentOrientation(topActivity);
2957 
2958         // The transform will be finished because there is no running animation. Keep activity in
2959         // animating state to avoid the transform being finished.
2960         doReturn(true).when(activity).isAnimating(anyInt());
2961         // Make sure the fixed rotation transform linked to activity2 when adding starting window
2962         // on activity2.
2963         topActivity.addStartingWindow(mPackageName, android.R.style.Theme, activity, false, false,
2964                 false, true, false, false, false);
2965         waitUntilHandlersIdle();
2966         assertTrue(topActivity.hasFixedRotationTransform());
2967     }
2968 
2969     @Test
testTryTransferStartingWindowFromHiddenAboveToken()2970     public void testTryTransferStartingWindowFromHiddenAboveToken() {
2971         registerTestStartingWindowOrganizer();
2972         // Add two tasks on top of each other.
2973         final ActivityRecord activityTop = new ActivityBuilder(mAtm).setCreateTask(true).build();
2974         final ActivityRecord activityBottom = new ActivityBuilder(mAtm).build();
2975         activityTop.getTask().addChild(activityBottom, 0);
2976 
2977         // Add a starting window.
2978         activityTop.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2979                 true, false, false, false);
2980         waitUntilHandlersIdle();
2981 
2982         final WindowState startingWindow = activityTop.mStartingWindow;
2983         assertNotNull(startingWindow);
2984 
2985         // Make the top one invisible, and try transferring the starting window from the top to the
2986         // bottom one.
2987         activityTop.setVisibility(false);
2988         activityBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded();
2989         waitUntilHandlersIdle();
2990 
2991         // Expect getFrozenInsetsState will be null when transferring the starting window.
2992         assertNull(startingWindow.getFrozenInsetsState());
2993 
2994         // Assert that the bottom window now has the starting window.
2995         assertNoStartingWindow(activityTop);
2996         assertHasStartingWindow(activityBottom);
2997     }
2998 
2999     @Test
testStartingWindowInTaskFragment()3000     public void testStartingWindowInTaskFragment() {
3001         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
3002         final WindowState startingWindow = createWindowState(
3003                 new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING), activity1);
3004         activity1.addWindow(startingWindow);
3005         activity1.mStartingData = mock(StartingData.class);
3006         activity1.attachStartingWindow(startingWindow);
3007         final Task task = activity1.getTask();
3008         final Rect taskBounds = task.getBounds();
3009         final int width = taskBounds.width();
3010         final int height = taskBounds.height();
3011         final BiConsumer<TaskFragment, Rect> fragmentSetup = (fragment, bounds) -> {
3012             final Configuration config = fragment.getRequestedOverrideConfiguration();
3013             config.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
3014             config.windowConfiguration.setBounds(bounds);
3015             fragment.onRequestedOverrideConfigurationChanged(config);
3016         };
3017 
3018         final TaskFragment taskFragment1 = new TaskFragment(
3019                 mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
3020         fragmentSetup.accept(taskFragment1, new Rect(0, 0, width / 2, height));
3021         task.addChild(taskFragment1, POSITION_TOP);
3022         assertEquals(task, activity1.mStartingData.mAssociatedTask);
3023         assertEquals(activity1.mStartingData, task.mSharedStartingData);
3024 
3025         final TaskFragment taskFragment2 = new TaskFragment(
3026                 mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
3027         fragmentSetup.accept(taskFragment2, new Rect(width / 2, 0, width, height));
3028         task.addChild(taskFragment2, POSITION_TOP);
3029         final ActivityRecord activity2 = new ActivityBuilder(mAtm)
3030                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE).build();
3031         activity2.setVisibleRequested(true);
3032         taskFragment2.addChild(activity2);
3033         assertTrue(activity2.isResizeable());
3034         activity1.reparent(taskFragment1, POSITION_TOP);
3035 
3036         // Adds an Activity which doesn't have shared starting data, and verify if it blocks
3037         // starting window removal.
3038         final ActivityRecord activity3 = new ActivityBuilder(mAtm).build();
3039         taskFragment2.addChild(activity3, POSITION_TOP);
3040 
3041         verify(activity1.getSyncTransaction()).reparent(eq(startingWindow.mSurfaceControl),
3042                 eq(task.mSurfaceControl));
3043         assertEquals(task.mSurfaceControl, startingWindow.getAnimationLeashParent());
3044         assertEquals(taskFragment1.getBounds(), activity1.getBounds());
3045         // The activity was resized by task fragment, but starting window must still cover the task.
3046         assertEquals(taskBounds, activity1.mStartingWindow.getBounds());
3047 
3048         // The starting window is only removed when all embedded activities are drawn.
3049         final WindowState activityWindow = mock(WindowState.class);
3050         activity1.onFirstWindowDrawn(activityWindow);
3051         activity2.onFirstWindowDrawn(activityWindow);
3052         assertNull(activity1.mStartingWindow);
3053         assertNull(task.mSharedStartingData);
3054     }
3055 
3056     @Test
testTransitionAnimationBounds()3057     public void testTransitionAnimationBounds() {
3058         removeGlobalMinSizeRestriction();
3059         final Task task = new TaskBuilder(mSupervisor)
3060                 .setCreateParentTask(true).setCreateActivity(true).build();
3061         final Task rootTask = task.getRootTask();
3062         final ActivityRecord activity = task.getTopNonFinishingActivity();
3063         final Rect stackBounds = new Rect(0, 0, 1000, 600);
3064         final Rect taskBounds = new Rect(100, 400, 600, 800);
3065         // Set the bounds and windowing mode to window configuration directly, otherwise the
3066         // testing setups may be discarded by configuration resolving.
3067         rootTask.getWindowConfiguration().setBounds(stackBounds);
3068         task.getWindowConfiguration().setBounds(taskBounds);
3069         activity.getWindowConfiguration().setBounds(taskBounds);
3070 
3071         // Check that anim bounds for freeform window match task bounds
3072         task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
3073         assertEquals(task.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_NONE));
3074 
3075         // ROOT_TASK_CLIP_AFTER_ANIM should use task bounds since they will be clipped by
3076         // bounds animation layer.
3077         task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
3078         assertEquals(task.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM));
3079 
3080         // Even the activity is smaller than task and it is not aligned to the top-left corner of
3081         // task, the animation bounds the same as task and position should be zero because in real
3082         // case the letterbox will fill the remaining area in task.
3083         final Rect halfBounds = new Rect(taskBounds);
3084         halfBounds.scale(0.5f);
3085         activity.getWindowConfiguration().setBounds(halfBounds);
3086         final Point animationPosition = new Point();
3087         activity.getAnimationPosition(animationPosition);
3088 
3089         assertEquals(taskBounds, activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM));
3090         assertEquals(new Point(0, 0), animationPosition);
3091     }
3092 
3093     @Test
testTransitionAnimationBounds_returnTaskFragment()3094     public void testTransitionAnimationBounds_returnTaskFragment() {
3095         removeGlobalMinSizeRestriction();
3096         final Task task = new TaskBuilder(mSupervisor).setCreateParentTask(true).build();
3097         final Task rootTask = task.getRootTask();
3098         final TaskFragment taskFragment = createTaskFragmentWithActivity(task);
3099         final ActivityRecord activity = taskFragment.getTopNonFinishingActivity();
3100         final Rect stackBounds = new Rect(0, 0, 1000, 600);
3101         final Rect taskBounds = new Rect(100, 400, 600, 800);
3102         final Rect taskFragmentBounds = new Rect(100, 400, 300, 800);
3103         final Rect activityBounds = new Rect(100, 400, 300, 600);
3104         // Set the bounds and windowing mode to window configuration directly, otherwise the
3105         // testing setups may be discarded by configuration resolving.
3106         rootTask.getWindowConfiguration().setBounds(stackBounds);
3107         task.getWindowConfiguration().setBounds(taskBounds);
3108         taskFragment.getWindowConfiguration().setBounds(taskFragmentBounds);
3109         activity.getWindowConfiguration().setBounds(activityBounds);
3110 
3111         // Check that anim bounds for freeform window match task fragment bounds
3112         task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
3113         assertEquals(taskFragment.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_NONE));
3114 
3115         // ROOT_TASK_CLIP_AFTER_ANIM should use task fragment bounds since they will be clipped by
3116         // bounds animation layer.
3117         task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
3118         assertEquals(taskFragment.getBounds(),
3119                 activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM));
3120     }
3121 
3122     @Test
testHasStartingWindow()3123     public void testHasStartingWindow() {
3124         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
3125         final WindowManager.LayoutParams attrs =
3126                 new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING);
3127         final TestWindowState startingWindow = createWindowState(attrs, activity);
3128         activity.mStartingData = mock(StartingData.class);
3129         activity.addWindow(startingWindow);
3130         assertTrue("Starting window should be present", activity.hasStartingWindow());
3131         activity.mStartingData = null;
3132         assertTrue("Starting window should be present", activity.hasStartingWindow());
3133 
3134         activity.removeChild(startingWindow);
3135         assertFalse("Starting window should not be present", activity.hasStartingWindow());
3136     }
3137 
3138     @Test
testCloseToSquareFixedOrientation()3139     public void testCloseToSquareFixedOrientation() {
3140         // create a square display
3141         final DisplayContent squareDisplay = new TestDisplayContent.Builder(mAtm, 2000, 2000)
3142                 .setSystemDecorations(true).build();
3143         // Add a decor insets provider window.
3144         final WindowState navbar = createNavBarWithProvidedInsets(squareDisplay);
3145         assertTrue(navbar.providesDisplayDecorInsets()
3146                 && squareDisplay.getDisplayPolicy().updateDecorInsetsInfo());
3147         squareDisplay.sendNewConfiguration();
3148         final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
3149 
3150         // create a fixed portrait activity
3151         ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
3152                 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT).build();
3153 
3154         // The available space could be landscape because of decor insets, but the configuration
3155         // should still respect the requested portrait orientation.
3156         assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
3157         assertTrue(activity.getConfiguration().windowConfiguration.getAppBounds().width()
3158                 <= activity.getConfiguration().windowConfiguration.getAppBounds().height());
3159 
3160         // create a fixed landscape activity
3161         activity = new ActivityBuilder(mAtm).setTask(task)
3162                 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE).build();
3163 
3164         // check that both the configuration and app bounds are landscape
3165         assertEquals(ORIENTATION_LANDSCAPE, activity.getConfiguration().orientation);
3166         assertTrue(activity.getConfiguration().windowConfiguration.getAppBounds().width()
3167                 > activity.getConfiguration().windowConfiguration.getAppBounds().height());
3168     }
3169 
3170     @Test
testSetVisibility_visibleToVisible()3171     public void testSetVisibility_visibleToVisible() {
3172         final ActivityRecord activity = new ActivityBuilder(mAtm)
3173                 .setCreateTask(true).build();
3174         // By default, activity is visible.
3175         assertTrue(activity.isVisible());
3176         assertTrue(activity.isVisibleRequested());
3177         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3178         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3179 
3180         // Request the activity to be visible. Although the activity is already visible, app
3181         // transition animation should be applied on this activity. This might be unnecessary, but
3182         // until we verify no logic relies on this behavior, we'll keep this as is.
3183         activity.setVisibility(true);
3184         assertTrue(activity.isVisible());
3185         assertTrue(activity.isVisibleRequested());
3186         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3187         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3188     }
3189 
3190     @Test
testSetVisibility_visibleToInvisible()3191     public void testSetVisibility_visibleToInvisible() {
3192         final ActivityRecord activity = new ActivityBuilder(mAtm)
3193                 .setCreateTask(true).build();
3194         // By default, activity is visible.
3195         assertTrue(activity.isVisible());
3196         assertTrue(activity.isVisibleRequested());
3197         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3198         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3199 
3200         // Request the activity to be invisible. Since the visibility changes, app transition
3201         // animation should be applied on this activity.
3202         activity.setVisibility(false);
3203         assertTrue(activity.isVisible());
3204         assertFalse(activity.isVisibleRequested());
3205         assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity));
3206         assertTrue(activity.mDisplayContent.mClosingApps.contains(activity));
3207     }
3208 
3209     @Test
testSetVisibility_invisibleToVisible()3210     public void testSetVisibility_invisibleToVisible() {
3211         final ActivityRecord activity = new ActivityBuilder(mAtm)
3212                 .setCreateTask(true).setVisible(false).build();
3213         // Activiby is invisible. However ATMS requests it to become visible, since this is a top
3214         // activity.
3215         assertFalse(activity.isVisible());
3216         assertTrue(activity.isVisibleRequested());
3217         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3218         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3219 
3220         // Request the activity to be visible. Since the visibility changes, app transition
3221         // animation should be applied on this activity.
3222         activity.setVisibility(true);
3223         assertFalse(activity.isVisible());
3224         assertTrue(activity.isVisibleRequested());
3225         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3226         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3227 
3228         // There should still be animation (add to opening) if keyguard is going away while the
3229         // screen is off because it will be visible after screen is turned on by unlocking.
3230         mDisplayContent.mOpeningApps.remove(activity);
3231         mDisplayContent.mClosingApps.remove(activity);
3232         activity.commitVisibility(false /* visible */, false /* performLayout */);
3233         mDisplayContent.getDisplayPolicy().screenTurnedOff();
3234         final KeyguardController controller = mSupervisor.getKeyguardController();
3235         doReturn(true).when(controller).isKeyguardGoingAway(anyInt());
3236         activity.setVisibility(true);
3237         assertTrue(mDisplayContent.mOpeningApps.contains(activity));
3238     }
3239 
3240     @Test
testSetVisibility_invisibleToInvisible()3241     public void testSetVisibility_invisibleToInvisible() {
3242         final ActivityRecord activity = new ActivityBuilder(mAtm)
3243                 .setCreateTask(true).setVisible(false).build();
3244         // Activiby is invisible. However ATMS requests it to become visible, since this is a top
3245         // activity.
3246         assertFalse(activity.isVisible());
3247         assertTrue(activity.isVisibleRequested());
3248         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3249         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3250 
3251         // Request the activity to be invisible. Since the activity is already invisible, no app
3252         // transition should be applied on this activity.
3253         activity.setVisibility(false);
3254         assertFalse(activity.isVisible());
3255         assertFalse(activity.isVisibleRequested());
3256         assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity));
3257         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3258     }
3259 
3260     @SetupWindows(addWindows = W_INPUT_METHOD)
3261     @Test
testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity()3262     public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() {
3263         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
3264         makeWindowVisibleAndDrawn(app, mImeWindow);
3265         mDisplayContent.setImeLayeringTarget(app);
3266         mDisplayContent.setImeInputTarget(app);
3267 
3268         // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
3269         mDisplayContent.mOpeningApps.clear();
3270         app.mActivityRecord.commitVisibility(false, false);
3271         app.mActivityRecord.onWindowsGone();
3272 
3273         assertTrue(app.mActivityRecord.mLastImeShown);
3274         assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3275 
3276         // Expect IME insets frozen state will reset when the activity has no IME focusable window.
3277         app.mActivityRecord.forAllWindows(w -> {
3278             w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
3279             return true;
3280         }, true);
3281 
3282         app.mActivityRecord.commitVisibility(true, false);
3283         app.mActivityRecord.onWindowsVisible();
3284 
3285         assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3286     }
3287 
3288     @SetupWindows(addWindows = W_INPUT_METHOD)
3289     @Test
testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget()3290     public void testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget() {
3291         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
3292 
3293         mDisplayContent.getInsetsStateController().getImeSourceProvider().setWindowContainer(
3294                 mImeWindow, null, null);
3295         mImeWindow.getControllableInsetProvider().setServerVisible(true);
3296 
3297         InsetsSource imeSource = new InsetsSource(ID_IME, ime());
3298         app.mAboveInsetsState.addSource(imeSource);
3299         mDisplayContent.setImeLayeringTarget(app);
3300         mDisplayContent.updateImeInputAndControlTarget(app);
3301 
3302         InsetsState state = app.getInsetsState();
3303         assertFalse(state.getOrCreateSource(imeSource.getId(), ime()).isVisible());
3304         assertTrue(state.getOrCreateSource(imeSource.getId(), ime()).getFrame().isEmpty());
3305 
3306         // Simulate app is closing and expect IME insets is frozen.
3307         mDisplayContent.mOpeningApps.clear();
3308         app.mActivityRecord.commitVisibility(false, false);
3309         app.mActivityRecord.onWindowsGone();
3310         assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3311 
3312         // Simulate app re-start input or turning screen off/on then unlocked by un-secure
3313         // keyguard to back to the app, expect IME insets is not frozen
3314         app.mActivityRecord.commitVisibility(true, false);
3315         mDisplayContent.updateImeInputAndControlTarget(app);
3316         mDisplayContent.mWmService.mRoot.performSurfacePlacement();
3317 
3318         assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3319 
3320         imeSource.setVisible(true);
3321         imeSource.setFrame(new Rect(100, 400, 500, 500));
3322         app.mAboveInsetsState.addSource(imeSource);
3323 
3324         // Verify when IME is visible and the app can receive the right IME insets from policy.
3325         makeWindowVisibleAndDrawn(app, mImeWindow);
3326         state = app.getInsetsState();
3327         assertTrue(state.peekSource(ID_IME).isVisible());
3328         assertEquals(state.peekSource(ID_IME).getFrame(), imeSource.getFrame());
3329     }
3330 
3331     @SetupWindows(addWindows = { W_ACTIVITY, W_INPUT_METHOD })
3332     @Test
testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest()3333     public void testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest()
3334             throws RemoteException {
3335         final WindowState app1 = createWindow(null, TYPE_APPLICATION, "app1");
3336         final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
3337 
3338         mDisplayContent.getInsetsStateController().getImeSourceProvider().setWindowContainer(
3339                 mImeWindow, null, null);
3340         mImeWindow.getControllableInsetProvider().setServerVisible(true);
3341 
3342         // Simulate app2 is closing and let app1 is visible to be IME targets.
3343         makeWindowVisibleAndDrawn(app1, mImeWindow);
3344         mDisplayContent.setImeLayeringTarget(app1);
3345         mDisplayContent.updateImeInputAndControlTarget(app1);
3346         app2.mActivityRecord.commitVisibility(false, false);
3347 
3348         // app1 requests IME visible.
3349         app1.setRequestedVisibleTypes(ime(), ime());
3350         mDisplayContent.getInsetsStateController().onRequestedVisibleTypesChanged(app1);
3351 
3352         // Verify app1's IME insets is visible and app2's IME insets frozen flag set.
3353         assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible());
3354         assertTrue(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3355 
3356         // Simulate switching to app2 to make it visible to be IME targets.
3357         spyOn(app2);
3358         spyOn(app2.mClient);
3359         ArgumentCaptor<InsetsState> insetsStateCaptor = ArgumentCaptor.forClass(InsetsState.class);
3360         doReturn(true).when(app2).isReadyToDispatchInsetsState();
3361         mDisplayContent.setImeLayeringTarget(app2);
3362         app2.mActivityRecord.commitVisibility(true, false);
3363         mDisplayContent.updateImeInputAndControlTarget(app2);
3364         mDisplayContent.mWmService.mRoot.performSurfacePlacement();
3365 
3366         // Verify after unfreezing app2's IME insets state, we won't dispatch visible IME insets
3367         // to client if the app didn't request IME visible.
3368         assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3369         verify(app2.mClient, atLeastOnce()).resized(any(), anyBoolean(), any(),
3370                 insetsStateCaptor.capture(), anyBoolean(), anyBoolean(), anyInt(), anyInt(),
3371                 anyBoolean());
3372         assertFalse(app2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
3373     }
3374 
3375     @Test
testImeInsetsFrozenFlag_multiWindowActivities()3376     public void testImeInsetsFrozenFlag_multiWindowActivities() {
3377         final WindowToken imeToken = createTestWindowToken(TYPE_INPUT_METHOD, mDisplayContent);
3378         final WindowState ime = createWindow(null, TYPE_INPUT_METHOD, imeToken, "ime");
3379         makeWindowVisibleAndDrawn(ime);
3380 
3381         // Create a split-screen root task with activity1 and activity 2.
3382         final Task task = new TaskBuilder(mSupervisor)
3383                 .setCreateParentTask(true).setCreateActivity(true).build();
3384         task.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
3385         final ActivityRecord activity1 = task.getTopNonFinishingActivity();
3386         activity1.getTask().setResumedActivity(activity1, "testApp1");
3387 
3388         final ActivityRecord activity2 = new TaskBuilder(mSupervisor)
3389                 .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
3390                 .setCreateActivity(true).build().getTopMostActivity();
3391         activity2.getTask().setResumedActivity(activity2, "testApp2");
3392         activity2.getTask().setParent(task.getRootTask());
3393 
3394         // Simulate activity1 and activity2 both have set mImeInsetsFrozenUntilStartInput when
3395         // invisible to user.
3396         activity1.mImeInsetsFrozenUntilStartInput = true;
3397         activity2.mImeInsetsFrozenUntilStartInput = true;
3398 
3399         final WindowState app1 = createWindow(null, TYPE_APPLICATION, activity1, "app1");
3400         final WindowState app2 = createWindow(null, TYPE_APPLICATION, activity2, "app2");
3401         makeWindowVisibleAndDrawn(app1, app2);
3402 
3403         final InsetsStateController controller = mDisplayContent.getInsetsStateController();
3404         controller.getImeSourceProvider().setWindowContainer(
3405                 ime, null, null);
3406         ime.getControllableInsetProvider().setServerVisible(true);
3407 
3408         // app1 starts input and expect IME insets for all activities in split-screen will be
3409         // frozen until the input started.
3410         mDisplayContent.setImeLayeringTarget(app1);
3411         mDisplayContent.updateImeInputAndControlTarget(app1);
3412         mDisplayContent.mWmService.mRoot.performSurfacePlacement();
3413 
3414         assertEquals(app1, mDisplayContent.getImeInputTarget());
3415         assertFalse(activity1.mImeInsetsFrozenUntilStartInput);
3416         assertFalse(activity2.mImeInsetsFrozenUntilStartInput);
3417 
3418         app1.setRequestedVisibleTypes(ime());
3419         controller.onRequestedVisibleTypesChanged(app1);
3420 
3421         // Expect all activities in split-screen will get IME insets visible state
3422         assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible());
3423         assertTrue(app2.getInsetsState().peekSource(ID_IME).isVisible());
3424     }
3425 
3426     @Test
testInClosingAnimation_visibilityNotCommitted_doNotHideSurface()3427     public void testInClosingAnimation_visibilityNotCommitted_doNotHideSurface() {
3428         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
3429         makeWindowVisibleAndDrawn(app);
3430 
3431         // Put the activity in close transition.
3432         mDisplayContent.mOpeningApps.clear();
3433         mDisplayContent.mClosingApps.add(app.mActivityRecord);
3434         mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
3435 
3436         // Remove window during transition, so it is requested to hide, but won't be committed until
3437         // the transition is finished.
3438         app.mActivityRecord.onRemovedFromDisplay();
3439 
3440         assertTrue(mDisplayContent.mClosingApps.contains(app.mActivityRecord));
3441         assertFalse(app.mActivityRecord.isVisibleRequested());
3442         assertTrue(app.mActivityRecord.isVisible());
3443         assertTrue(app.mActivityRecord.isSurfaceShowing());
3444 
3445         // Start transition.
3446         app.mActivityRecord.prepareSurfaces();
3447 
3448         // Because the app is waiting for transition, it should not hide the surface.
3449         assertTrue(app.mActivityRecord.isSurfaceShowing());
3450     }
3451 
3452     @Test
testInClosingAnimation_visibilityCommitted_hideSurface()3453     public void testInClosingAnimation_visibilityCommitted_hideSurface() {
3454         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
3455         makeWindowVisibleAndDrawn(app);
3456 
3457         // Put the activity in close transition.
3458         mDisplayContent.mOpeningApps.clear();
3459         mDisplayContent.mClosingApps.add(app.mActivityRecord);
3460         mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
3461 
3462         // Commit visibility before start transition.
3463         app.mActivityRecord.commitVisibility(false, false);
3464 
3465         assertFalse(app.mActivityRecord.isVisibleRequested());
3466         assertFalse(app.mActivityRecord.isVisible());
3467         assertTrue(app.mActivityRecord.isSurfaceShowing());
3468 
3469         // Start transition.
3470         app.mActivityRecord.prepareSurfaces();
3471 
3472         // Because the app visibility has been committed before the transition start, it should hide
3473         // the surface.
3474         assertFalse(app.mActivityRecord.isSurfaceShowing());
3475     }
3476 
3477     @Test
testUpdateCameraCompatState_flagIsEnabled_controlStateIsUpdated()3478     public void testUpdateCameraCompatState_flagIsEnabled_controlStateIsUpdated() {
3479         final ActivityRecord activity = createActivityWithTask();
3480         // Mock a flag being enabled.
3481         doReturn(true).when(activity).isCameraCompatControlEnabled();
3482 
3483         activity.updateCameraCompatState(/* showControl */ true,
3484                 /* transformationApplied */ false, /* callback */ null);
3485 
3486         assertEquals(activity.getCameraCompatControlState(),
3487                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3488 
3489         activity.updateCameraCompatState(/* showControl */ true,
3490                 /* transformationApplied */ true, /* callback */ null);
3491 
3492         assertEquals(activity.getCameraCompatControlState(),
3493                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3494 
3495         activity.updateCameraCompatState(/* showControl */ false,
3496                 /* transformationApplied */ false, /* callback */ null);
3497 
3498         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3499 
3500         activity.updateCameraCompatState(/* showControl */ false,
3501                 /* transformationApplied */ true, /* callback */ null);
3502 
3503         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3504     }
3505 
3506     @Test
testUpdateCameraCompatState_flagIsDisabled_controlStateIsHidden()3507     public void testUpdateCameraCompatState_flagIsDisabled_controlStateIsHidden() {
3508         final ActivityRecord activity = createActivityWithTask();
3509         // Mock a flag being disabled.
3510         doReturn(false).when(activity).isCameraCompatControlEnabled();
3511 
3512         activity.updateCameraCompatState(/* showControl */ true,
3513                 /* transformationApplied */ false, /* callback */ null);
3514 
3515         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3516 
3517         activity.updateCameraCompatState(/* showControl */ true,
3518                 /* transformationApplied */ true, /* callback */ null);
3519 
3520         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3521     }
3522 
3523     @Test
testUpdateCameraCompatStateFromUser_clickedOnDismiss()3524     public void testUpdateCameraCompatStateFromUser_clickedOnDismiss() throws RemoteException {
3525         final ActivityRecord activity = createActivityWithTask();
3526         // Mock a flag being enabled.
3527         doReturn(true).when(activity).isCameraCompatControlEnabled();
3528 
3529         ICompatCameraControlCallback callback = getCompatCameraControlCallback();
3530         spyOn(callback);
3531         activity.updateCameraCompatState(/* showControl */ true,
3532                 /* transformationApplied */ false, callback);
3533 
3534         assertEquals(activity.getCameraCompatControlState(),
3535                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3536 
3537         // Clicking on the button.
3538         activity.updateCameraCompatStateFromUser(CAMERA_COMPAT_CONTROL_DISMISSED);
3539 
3540         verify(callback, never()).revertCameraCompatTreatment();
3541         verify(callback, never()).applyCameraCompatTreatment();
3542         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED);
3543 
3544         // All following updates are ignored.
3545         activity.updateCameraCompatState(/* showControl */ true,
3546                 /* transformationApplied */ false, /* callback */ null);
3547 
3548         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED);
3549 
3550         activity.updateCameraCompatState(/* showControl */ true,
3551                 /* transformationApplied */ true, /* callback */ null);
3552 
3553         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED);
3554 
3555         activity.updateCameraCompatState(/* showControl */ false,
3556                 /* transformationApplied */ true, /* callback */ null);
3557 
3558         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED);
3559     }
3560 
3561     @Test
testUpdateCameraCompatStateFromUser_clickedOnApplyTreatment()3562     public void testUpdateCameraCompatStateFromUser_clickedOnApplyTreatment()
3563             throws RemoteException {
3564         final ActivityRecord activity = createActivityWithTask();
3565         // Mock a flag being enabled.
3566         doReturn(true).when(activity).isCameraCompatControlEnabled();
3567 
3568         ICompatCameraControlCallback callback = getCompatCameraControlCallback();
3569         spyOn(callback);
3570         activity.updateCameraCompatState(/* showControl */ true,
3571                 /* transformationApplied */ false, callback);
3572 
3573         assertEquals(activity.getCameraCompatControlState(),
3574                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3575 
3576         // Clicking on the button.
3577         activity.updateCameraCompatStateFromUser(CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3578 
3579         verify(callback, never()).revertCameraCompatTreatment();
3580         verify(callback).applyCameraCompatTreatment();
3581         assertEquals(activity.getCameraCompatControlState(),
3582                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3583 
3584         // Request from the client to show the control are ignored respecting the user choice.
3585         activity.updateCameraCompatState(/* showControl */ true,
3586                 /* transformationApplied */ false, /* callback */ null);
3587 
3588         assertEquals(activity.getCameraCompatControlState(),
3589                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3590 
3591         // Request from the client to hide the control is respected.
3592         activity.updateCameraCompatState(/* showControl */ false,
3593                 /* transformationApplied */ true, /* callback */ null);
3594 
3595         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3596 
3597         // Request from the client to show the control again is respected.
3598         activity.updateCameraCompatState(/* showControl */ true,
3599                 /* transformationApplied */ false, /* callback */ null);
3600 
3601         assertEquals(activity.getCameraCompatControlState(),
3602                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3603     }
3604 
3605     @Test
testUpdateCameraCompatStateFromUser_clickedOnRevertTreatment()3606     public void testUpdateCameraCompatStateFromUser_clickedOnRevertTreatment()
3607             throws RemoteException {
3608         final ActivityRecord activity = createActivityWithTask();
3609         // Mock a flag being enabled.
3610         doReturn(true).when(activity).isCameraCompatControlEnabled();
3611 
3612         ICompatCameraControlCallback callback = getCompatCameraControlCallback();
3613         spyOn(callback);
3614         activity.updateCameraCompatState(/* showControl */ true,
3615                 /* transformationApplied */ true, callback);
3616 
3617         assertEquals(activity.getCameraCompatControlState(),
3618                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3619 
3620         // Clicking on the button.
3621         activity.updateCameraCompatStateFromUser(CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3622 
3623         verify(callback).revertCameraCompatTreatment();
3624         verify(callback, never()).applyCameraCompatTreatment();
3625         assertEquals(activity.getCameraCompatControlState(),
3626                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3627 
3628         // Request from the client to show the control are ignored respecting the user choice.
3629         activity.updateCameraCompatState(/* showControl */ true,
3630                 /* transformationApplied */ true, /* callback */ null);
3631 
3632         assertEquals(activity.getCameraCompatControlState(),
3633                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3634 
3635         // Request from the client to hide the control is respected.
3636         activity.updateCameraCompatState(/* showControl */ false,
3637                 /* transformationApplied */ true, /* callback */ null);
3638 
3639         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3640 
3641         // Request from the client to show the control again is respected.
3642         activity.updateCameraCompatState(/* showControl */ true,
3643                 /* transformationApplied */ true, /* callback */ null);
3644 
3645         assertEquals(activity.getCameraCompatControlState(),
3646                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3647     }
3648 
3649     @Test // b/162542125
testInputDispatchTimeout()3650     public void testInputDispatchTimeout() throws RemoteException {
3651         final ActivityRecord activity = createActivityWithTask();
3652         final WindowProcessController wpc = activity.app;
3653         spyOn(wpc);
3654         doReturn(true).when(wpc).isInstrumenting();
3655         final ActivityRecord instrumentingActivity = createActivityOnDisplay(
3656                 true /* defaultDisplay */, wpc);
3657         assertEquals(INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS,
3658                 instrumentingActivity.mInputDispatchingTimeoutMillis);
3659 
3660         doReturn(false).when(wpc).isInstrumenting();
3661         final ActivityRecord nonInstrumentingActivity = createActivityOnDisplay(
3662                 true /* defaultDisplay */, wpc);
3663         assertEquals(DEFAULT_DISPATCHING_TIMEOUT_MILLIS,
3664                 nonInstrumentingActivity.mInputDispatchingTimeoutMillis);
3665 
3666         final ActivityRecord noProcActivity = createActivityOnDisplay(true /* defaultDisplay */,
3667                 null);
3668         assertEquals(DEFAULT_DISPATCHING_TIMEOUT_MILLIS,
3669                 noProcActivity.mInputDispatchingTimeoutMillis);
3670     }
3671 
3672     @Test
testEnsureActivitiesVisibleAnotherUserTasks()3673     public void testEnsureActivitiesVisibleAnotherUserTasks() {
3674         // Create an activity with hierarchy:
3675         //    RootTask
3676         //       - TaskFragment
3677         //          - Activity
3678         DisplayContent display = createNewDisplay();
3679         Task rootTask = createTask(display);
3680         ActivityRecord activity = createActivityRecord(rootTask);
3681         final TaskFragment taskFragment = new TaskFragment(mAtm, new Binder(),
3682                 true /* createdByOrganizer */, true /* isEmbedded */);
3683         activity.getTask().addChild(taskFragment, POSITION_TOP);
3684         activity.reparent(taskFragment, POSITION_TOP);
3685 
3686         // Ensure the activity visibility is updated even it is not shown to current user.
3687         activity.setVisibleRequested(true);
3688         doReturn(false).when(activity).showToCurrentUser();
3689         spyOn(taskFragment);
3690         doReturn(false).when(taskFragment).shouldBeVisible(any());
3691         display.ensureActivitiesVisible(null, 0, false, false);
3692         assertFalse(activity.isVisibleRequested());
3693     }
3694 
3695     @Test
testShellTransitionTaskWindowingModeChange()3696     public void testShellTransitionTaskWindowingModeChange() {
3697         final ActivityRecord activity = createActivityWithTask();
3698         final Task task = activity.getTask();
3699         task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
3700 
3701         assertTrue(activity.isVisible());
3702         assertTrue(activity.isVisibleRequested());
3703         assertEquals(WINDOWING_MODE_FULLSCREEN, activity.getWindowingMode());
3704 
3705         registerTestTransitionPlayer();
3706         task.mTransitionController.requestTransitionIfNeeded(TRANSIT_PIP, task);
3707         task.setWindowingMode(WINDOWING_MODE_PINNED);
3708 
3709         // Collect activity in the transition if the Task windowing mode is going to change.
3710         assertTrue(activity.inTransition());
3711     }
3712 
3713     /**
3714      * Verifies the task is moved to back when back pressed if the root activity was originally
3715      * started from Launcher.
3716      */
3717     @Test
testMoveTaskToBackWhenStartedFromLauncher()3718     public void testMoveTaskToBackWhenStartedFromLauncher() {
3719         final Task task = createTask(mDisplayContent);
3720         final ActivityRecord ar = createActivityRecord(task);
3721         task.realActivity = ar.mActivityComponent;
3722         ar.intent.setAction(Intent.ACTION_MAIN);
3723         ar.intent.addCategory(Intent.CATEGORY_LAUNCHER);
3724         doReturn(true).when(ar).isLaunchSourceType(eq(LAUNCH_SOURCE_TYPE_HOME));
3725 
3726         mAtm.mActivityClientController.onBackPressed(ar.token, null /* callback */);
3727         verify(task).moveTaskToBack(any());
3728     }
3729 
getCompatCameraControlCallback()3730     private ICompatCameraControlCallback getCompatCameraControlCallback() {
3731         return new ICompatCameraControlCallback.Stub() {
3732             @Override
3733             public void applyCameraCompatTreatment() {}
3734 
3735             @Override
3736             public void revertCameraCompatTreatment() {}
3737         };
3738     }
3739 
assertHasStartingWindow(ActivityRecord atoken)3740     private void assertHasStartingWindow(ActivityRecord atoken) {
3741         assertNotNull(atoken.mStartingSurface);
3742         assertNotNull(atoken.mStartingData);
3743         assertNotNull(atoken.mStartingWindow);
3744     }
3745 
assertNoStartingWindow(ActivityRecord atoken)3746     private void assertNoStartingWindow(ActivityRecord atoken) {
3747         assertNull(atoken.mStartingSurface);
3748         assertNull(atoken.mStartingWindow);
3749         assertNull(atoken.mStartingData);
3750         atoken.forAllWindows(windowState -> {
3751             assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING);
3752         }, true);
3753     }
3754 }
3755