• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         final ActivityRecord activity = createActivityWithTask();
1183         // Put an activity on top of test activity to make it invisible and prevent us from
1184         // accidentally resuming the topmost one again.
1185         new ActivityBuilder(mAtm).build();
1186         activity.setVisibleRequested(false);
1187         activity.setState(STOPPED, "test");
1188 
1189         activity.finishIfPossible("test", false /* oomAdj */);
1190 
1191         verify(activity.mDisplayContent, never()).prepareAppTransition(eq(TRANSIT_CLOSE));
1192         assertFalse(activity.inTransition());
1193     }
1194 
1195     /**
1196      * Verify that finish request for the last activity in a task will request a shell transition
1197      * with that task as a trigger.
1198      */
1199     @Test
testFinishActivityIfPossible_lastInTaskRequestsTransitionWithTrigger()1200     public void testFinishActivityIfPossible_lastInTaskRequestsTransitionWithTrigger() {
1201         final TestTransitionPlayer testPlayer = registerTestTransitionPlayer();
1202         final ActivityRecord activity = createActivityWithTask();
1203         activity.finishing = false;
1204         activity.setVisibleRequested(true);
1205         activity.setState(RESUMED, "test");
1206         activity.finishIfPossible("test", false /* oomAdj */);
1207 
1208         verify(activity).setVisibility(eq(false));
1209         assertEquals(activity.getTask().mTaskId, testPlayer.mLastRequest.getTriggerTask().taskId);
1210     }
1211 
1212     /**
1213      * Verify that when collecting activity to the existing close transition, it should not affect
1214      * ready state.
1215      */
1216     @Test
testFinishActivityIfPossible_collectToExistingTransition()1217     public void testFinishActivityIfPossible_collectToExistingTransition() {
1218         final TestTransitionPlayer testPlayer = registerTestTransitionPlayer();
1219         final ActivityRecord activity = createActivityWithTask();
1220         activity.setState(PAUSED, "test");
1221         activity.finishIfPossible("test", false /* oomAdj */);
1222         final Transition lastTransition = testPlayer.mLastTransit;
1223         assertTrue(lastTransition.allReady());
1224         assertTrue(activity.inTransition());
1225 
1226         // Collect another activity to the existing transition without changing ready state.
1227         final ActivityRecord activity2 = createActivityRecord(activity.getTask());
1228         activity2.setState(PAUSING, "test");
1229         activity2.finishIfPossible("test", false /* oomAdj */);
1230         assertTrue(activity2.inTransition());
1231         assertEquals(lastTransition, testPlayer.mLastTransit);
1232         assertTrue(lastTransition.allReady());
1233     }
1234 
1235     @Test
testFinishActivityIfPossible_sendResultImmediately()1236     public void testFinishActivityIfPossible_sendResultImmediately() {
1237         // Create activity representing the source of the activity result.
1238         final ComponentName sourceComponent = ComponentName.createRelative(
1239                 DEFAULT_COMPONENT_PACKAGE_NAME, ".SourceActivity");
1240         final ComponentName targetComponent = ComponentName.createRelative(
1241                 sourceComponent.getPackageName(), ".TargetActivity");
1242 
1243         final ActivityRecord sourceActivity = new ActivityBuilder(mWm.mAtmService)
1244                 .setComponent(sourceComponent)
1245                 .setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE)
1246                 .setCreateTask(true)
1247                 .build();
1248         sourceActivity.finishing = false;
1249         sourceActivity.setState(STOPPED, "test");
1250 
1251         final ActivityRecord targetActivity = new ActivityBuilder(mWm.mAtmService)
1252                 .setComponent(targetComponent)
1253                 .setTargetActivity(sourceComponent.getClassName())
1254                 .setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE)
1255                 .setCreateTask(true)
1256                 .setOnTop(true)
1257                 .build();
1258         targetActivity.finishing = false;
1259         targetActivity.setState(RESUMED, "test");
1260         targetActivity.resultTo = sourceActivity;
1261         targetActivity.setForceSendResultForMediaProjection();
1262 
1263         clearInvocations(mAtm.getLifecycleManager());
1264 
1265         targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */);
1266 
1267         try {
1268             verify(mAtm.getLifecycleManager(), atLeastOnce()).scheduleTransaction(
1269                     any(ClientTransaction.class));
1270         } catch (RemoteException ignored) {
1271         }
1272 
1273         assertNull(targetActivity.results);
1274     }
1275 
1276     @Test
testFinishActivityIfPossible_sendResultImmediatelyIfResumed()1277     public void testFinishActivityIfPossible_sendResultImmediatelyIfResumed() {
1278         final Task task = new TaskBuilder(mSupervisor).build();
1279         final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task);
1280         final TaskFragment taskFragment2 = createTaskFragmentWithActivity(task);
1281         final ActivityRecord resultToActivity = taskFragment1.getTopMostActivity();
1282         final ActivityRecord targetActivity = taskFragment2.getTopMostActivity();
1283         resultToActivity.setState(RESUMED, "test");
1284         targetActivity.setState(RESUMED, "test");
1285         targetActivity.resultTo = resultToActivity;
1286 
1287         clearInvocations(mAtm.getLifecycleManager());
1288         targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */);
1289         waitUntilHandlersIdle();
1290 
1291         verify(resultToActivity).sendResult(anyInt(), eq(null), anyInt(), anyInt(), any(), eq(null),
1292                 anyBoolean());
1293     }
1294 
1295     /**
1296      * Verify that complete finish request for non-finishing activity is invalid.
1297      */
1298     @Test(expected = IllegalArgumentException.class)
testCompleteFinishing_failNotFinishing()1299     public void testCompleteFinishing_failNotFinishing() {
1300         final ActivityRecord activity = createActivityWithTask();
1301         activity.finishing = false;
1302         activity.completeFinishing("test");
1303     }
1304 
1305     /**
1306      * Verify that complete finish request for resumed activity is invalid.
1307      */
1308     @Test(expected = IllegalArgumentException.class)
testCompleteFinishing_failResumed()1309     public void testCompleteFinishing_failResumed() {
1310         final ActivityRecord activity = createActivityWithTask();
1311         activity.setState(RESUMED, "test");
1312         activity.completeFinishing("test");
1313     }
1314 
1315     /**
1316      * Verify that finish request for pausing activity must be a no-op - activity will finish
1317      * once it completes pausing.
1318      */
1319     @Test
testCompleteFinishing_pausing()1320     public void testCompleteFinishing_pausing() {
1321         final ActivityRecord activity = createActivityWithTask();
1322         activity.setState(PAUSING, "test");
1323         activity.finishing = true;
1324 
1325         assertEquals("Activity must not be removed immediately - waiting for paused",
1326                 activity, activity.completeFinishing("test"));
1327         assertEquals(PAUSING, activity.getState());
1328         verify(activity, never()).destroyIfPossible(anyString());
1329     }
1330 
1331     /**
1332      * Verify that finish request won't change the state of next top activity if the current
1333      * finishing activity doesn't need to be destroyed immediately. The case is usually like
1334      * from {@link Task#completePause(boolean, ActivityRecord)} to
1335      * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the
1336      * responsibility to resume the next activity with updating the state.
1337      */
1338     @Test
testCompleteFinishing_keepStateOfNextInvisible()1339     public void testCompleteFinishing_keepStateOfNextInvisible() {
1340         final ActivityRecord currentTop = createActivityWithTask();
1341         final Task task = currentTop.getTask();
1342 
1343         currentTop.setVisibleRequested(currentTop.nowVisible = true);
1344 
1345         // Simulates that {@code currentTop} starts an existing activity from background (so its
1346         // state is stopped) and the starting flow just goes to place it at top.
1347         final Task nextStack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
1348         final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity();
1349         nextTop.setState(STOPPED, "test");
1350 
1351         task.setPausingActivity(currentTop);
1352         currentTop.finishing = true;
1353         currentTop.setState(PAUSED, "test");
1354         currentTop.completeFinishing(false /* updateVisibility */, "completePause");
1355 
1356         // Current top becomes stopping because it is visible and the next is invisible.
1357         assertEquals(STOPPING, currentTop.getState());
1358         // The state of next activity shouldn't be changed.
1359         assertEquals(STOPPED, nextTop.getState());
1360     }
1361 
1362     /**
1363      * Verify that finish bottom activity from a task won't boost it to top.
1364      */
1365     @Test
testFinishBottomActivityIfPossible_noZBoost()1366     public void testFinishBottomActivityIfPossible_noZBoost() {
1367         final ActivityRecord bottomActivity = createActivityWithTask();
1368         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1369                 .setTask(bottomActivity.getTask()).build();
1370         topActivity.setVisibleRequested(true);
1371         // simulating bottomActivity as a trampoline activity.
1372         bottomActivity.setState(RESUMED, "test");
1373         bottomActivity.finishIfPossible("test", false);
1374         assertFalse(bottomActivity.mNeedsZBoost);
1375     }
1376 
1377     /**
1378      * Verify that complete finish request for visible activity must be delayed before the next one
1379      * becomes visible.
1380      */
1381     @Test
testCompleteFinishing_waitForNextVisible()1382     public void testCompleteFinishing_waitForNextVisible() {
1383         final ActivityRecord activity = createActivityWithTask();
1384         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1385                 .setTask(activity.getTask()).build();
1386         topActivity.setVisibleRequested(true);
1387         topActivity.nowVisible = true;
1388         topActivity.finishing = true;
1389         topActivity.setState(PAUSED, "true");
1390         // Mark the bottom activity as not visible, so that we will wait for it before removing
1391         // the top one.
1392         activity.setVisibleRequested(false);
1393         activity.nowVisible = false;
1394         activity.setState(STOPPED, "test");
1395 
1396         assertEquals("Activity must not be removed immediately - waiting for next visible",
1397                 topActivity, topActivity.completeFinishing("test"));
1398         assertEquals("Activity must be stopped to make next one visible", STOPPING,
1399                 topActivity.getState());
1400         assertTrue("Activity must be stopped to make next one visible",
1401                 topActivity.mTaskSupervisor.mStoppingActivities.contains(topActivity));
1402         verify(topActivity, never()).destroyIfPossible(anyString());
1403     }
1404 
1405     /**
1406      * Verify that complete finish request for top invisible activity must not be delayed while
1407      * sleeping, but next invisible activity must be resumed (and paused/stopped)
1408      */
1409     @Test
testCompleteFinishing_noWaitForNextVisible_sleeping()1410     public void testCompleteFinishing_noWaitForNextVisible_sleeping() {
1411         final ActivityRecord activity = createActivityWithTask();
1412         // Create a top activity on a new task
1413         final ActivityRecord topActivity = createActivityWithTask();
1414         mDisplayContent.setIsSleeping(true);
1415         doReturn(true).when(activity).shouldBeVisible();
1416         topActivity.setVisibleRequested(false);
1417         topActivity.nowVisible = false;
1418         topActivity.finishing = true;
1419         topActivity.setState(STOPPED, "true");
1420 
1421         // Mark the activity behind (on a separate task) as not visible
1422         activity.setVisibleRequested(false);
1423         activity.nowVisible = false;
1424         activity.setState(STOPPED, "test");
1425 
1426         clearInvocations(activity);
1427         topActivity.completeFinishing("test");
1428         verify(activity).setState(eq(RESUMED), any());
1429         verify(topActivity).destroyIfPossible(anyString());
1430     }
1431 
1432     /**
1433      * Verify that complete finish request for invisible activity must not be delayed.
1434      */
1435     @Test
testCompleteFinishing_noWaitForNextVisible_alreadyInvisible()1436     public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
1437         final ActivityRecord activity = createActivityWithTask();
1438         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1439                 .setTask(activity.getTask()).build();
1440         topActivity.setVisibleRequested(false);
1441         topActivity.nowVisible = false;
1442         topActivity.finishing = true;
1443         topActivity.setState(STOPPED, "true");
1444         // Mark the bottom activity as not visible, so that we would wait for it before removing
1445         // the top one.
1446         activity.setVisibleRequested(false);
1447         activity.nowVisible = false;
1448         activity.setState(STOPPED, "test");
1449 
1450         topActivity.completeFinishing("test");
1451 
1452         verify(topActivity).destroyIfPossible(anyString());
1453     }
1454 
1455     /**
1456      * Verify that paused finishing activity will be added to finishing list and wait for next one
1457      * to idle.
1458      */
1459     @Test
testCompleteFinishing_waitForIdle()1460     public void testCompleteFinishing_waitForIdle() {
1461         final ActivityRecord activity = createActivityWithTask();
1462         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1463                 .setTask(activity.getTask()).build();
1464         topActivity.setVisibleRequested(true);
1465         topActivity.nowVisible = true;
1466         topActivity.finishing = true;
1467         topActivity.setState(PAUSED, "true");
1468         // Mark the bottom activity as already visible, so that there is no need to wait for it.
1469         activity.setVisibleRequested(true);
1470         activity.nowVisible = true;
1471         activity.setState(RESUMED, "test");
1472 
1473         topActivity.completeFinishing("test");
1474 
1475         verify(topActivity).addToFinishingAndWaitForIdle();
1476     }
1477 
1478     /**
1479      * Verify that complete finish request for visible activity must not be delayed if the next one
1480      * is already visible and it's not the focused stack.
1481      */
1482     @Test
testCompleteFinishing_noWaitForNextVisible_stopped()1483     public void testCompleteFinishing_noWaitForNextVisible_stopped() {
1484         final ActivityRecord activity = createActivityWithTask();
1485         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1486                 .setTask(activity.getTask()).build();
1487         topActivity.setVisibleRequested(false);
1488         topActivity.nowVisible = false;
1489         topActivity.finishing = true;
1490         topActivity.setState(STOPPED, "true");
1491         // Mark the bottom activity as already visible, so that there is no need to wait for it.
1492         activity.setVisibleRequested(true);
1493         activity.nowVisible = true;
1494         activity.setState(RESUMED, "test");
1495 
1496         topActivity.completeFinishing("test");
1497 
1498         verify(topActivity).destroyIfPossible(anyString());
1499     }
1500 
1501     /**
1502      * Verify that complete finish request for visible activity must not be delayed if the next one
1503      * is already visible and it's not the focused stack.
1504      */
1505     @Test
testCompleteFinishing_noWaitForNextVisible_nonFocusedStack()1506     public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
1507         final ActivityRecord activity = createActivityWithTask();
1508         final ActivityRecord topActivity = new ActivityBuilder(mAtm)
1509                 .setTask(activity.getTask()).build();
1510         topActivity.setVisibleRequested(true);
1511         topActivity.nowVisible = true;
1512         topActivity.finishing = true;
1513         topActivity.setState(PAUSED, "true");
1514         // Mark the bottom activity as already visible, so that there is no need to wait for it.
1515         activity.setVisibleRequested(true);
1516         activity.nowVisible = true;
1517         activity.setState(RESUMED, "test");
1518 
1519         // Add another stack to become focused and make the activity there visible. This way it
1520         // simulates finishing in non-focused stack in split-screen.
1521         final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
1522         final ActivityRecord focusedActivity = stack.getTopMostActivity();
1523         focusedActivity.nowVisible = true;
1524         focusedActivity.setVisibleRequested(true);
1525         focusedActivity.setState(RESUMED, "test");
1526         stack.setResumedActivity(focusedActivity, "test");
1527 
1528         topActivity.completeFinishing("test");
1529 
1530         verify(topActivity).destroyIfPossible(anyString());
1531     }
1532 
1533     /**
1534      * Verify that complete finish request for a show-when-locked activity must ensure the
1535      * keyguard occluded state being updated.
1536      */
1537     @Test
testCompleteFinishing_showWhenLocked()1538     public void testCompleteFinishing_showWhenLocked() {
1539         final ActivityRecord activity = createActivityWithTask();
1540         final Task task = activity.getTask();
1541         // Make keyguard locked and set the top activity show-when-locked.
1542         KeyguardController keyguardController = activity.mTaskSupervisor.getKeyguardController();
1543         int displayId = activity.getDisplayId();
1544         doReturn(true).when(keyguardController).isKeyguardLocked(eq(displayId));
1545         final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
1546         topActivity.setVisibleRequested(true);
1547         topActivity.nowVisible = true;
1548         topActivity.setState(RESUMED, "true");
1549         doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
1550                 any() /* starting */, anyInt() /* configChanges */,
1551                 anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
1552         topActivity.setShowWhenLocked(true);
1553 
1554         // Verify the stack-top activity is occluded keyguard.
1555         assertEquals(topActivity, task.topRunningActivity());
1556         assertTrue(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
1557 
1558         // Finish the top activity
1559         topActivity.setState(PAUSED, "true");
1560         topActivity.finishing = true;
1561         topActivity.completeFinishing("test");
1562 
1563         // Verify new top activity does not occlude keyguard.
1564         assertEquals(activity, task.topRunningActivity());
1565         assertFalse(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY));
1566     }
1567 
1568     /**
1569      * Verify that complete finish request for an activity which the resume activity is translucent
1570      * must ensure the visibilities of activities being updated.
1571      */
1572     @Test
testCompleteFinishing_ensureActivitiesVisible_withConditions()1573     public void testCompleteFinishing_ensureActivitiesVisible_withConditions() {
1574         testCompleteFinishing_ensureActivitiesVisible(false, PAUSED);
1575         testCompleteFinishing_ensureActivitiesVisible(false, STARTED);
1576         testCompleteFinishing_ensureActivitiesVisible(true, PAUSED);
1577         testCompleteFinishing_ensureActivitiesVisible(true, STARTED);
1578     }
1579 
testCompleteFinishing_ensureActivitiesVisible(boolean diffTask, State secondActivityState)1580     private void testCompleteFinishing_ensureActivitiesVisible(boolean diffTask,
1581             State secondActivityState) {
1582         final ActivityRecord activity = createActivityWithTask();
1583         final Task task = activity.getTask();
1584         final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(task).build();
1585         firstActivity.setVisibleRequested(false);
1586         firstActivity.nowVisible = false;
1587         firstActivity.setState(STOPPED, "test");
1588 
1589         final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task).build();
1590         secondActivity.setVisibleRequested(true);
1591         secondActivity.nowVisible = true;
1592         secondActivity.setState(secondActivityState, "test");
1593 
1594         ActivityRecord translucentActivity;
1595         if (diffTask) {
1596             translucentActivity = new ActivityBuilder(mAtm).setCreateTask(true).build();
1597         } else {
1598             translucentActivity = new ActivityBuilder(mAtm).setTask(task).build();
1599         }
1600         translucentActivity.setVisibleRequested(true);
1601         translucentActivity.nowVisible = true;
1602         translucentActivity.setState(RESUMED, "test");
1603 
1604         doReturn(true).when(firstActivity).occludesParent(true);
1605         doReturn(true).when(secondActivity).occludesParent(true);
1606 
1607         // Finish the second activity
1608         secondActivity.finishing = true;
1609         secondActivity.completeFinishing("test");
1610         verify(secondActivity.mDisplayContent).ensureActivitiesVisible(null /* starting */,
1611                 0 /* configChanges */ , false /* preserveWindows */,
1612                 true /* notifyClients */);
1613 
1614         // Finish the first activity
1615         firstActivity.finishing = true;
1616         firstActivity.setVisibleRequested(true);
1617         firstActivity.completeFinishing("test");
1618         verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */,
1619                 0 /* configChanges */ , false /* preserveWindows */,
1620                 true /* notifyClients */);
1621 
1622         // Remove the translucent activity and clear invocations for next test
1623         translucentActivity.getTask().removeImmediately("test");
1624         clearInvocations(mDefaultDisplay);
1625     }
1626 
1627     /**
1628      * Verify destroy activity request completes successfully.
1629      */
1630     @Test
testDestroyIfPossible()1631     public void testDestroyIfPossible() {
1632         final ActivityRecord activity = createActivityWithTask();
1633         doReturn(false).when(mRootWindowContainer)
1634                 .resumeFocusedTasksTopActivities();
1635         activity.destroyIfPossible("test");
1636 
1637         assertEquals(DESTROYING, activity.getState());
1638         assertTrue(activity.finishing);
1639         verify(activity).destroyImmediately(anyString());
1640     }
1641 
1642     /**
1643      * Verify that complete finish request for visible activity must not destroy it immediately if
1644      * it is the last running activity on a display with a home stack. We must wait for home
1645      * activity to come up to avoid a black flash in this case.
1646      */
1647     @Test
testDestroyIfPossible_lastActivityAboveEmptyHomeStack()1648     public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
1649         final ActivityRecord activity = createActivityWithTask();
1650         // Empty the home stack.
1651         final Task homeStack = activity.getDisplayArea().getRootHomeTask();
1652         homeStack.forAllLeafTasks((t) -> {
1653             homeStack.removeChild(t, "test");
1654         }, true /* traverseTopToBottom */);
1655         activity.finishing = true;
1656         doReturn(false).when(mRootWindowContainer)
1657                 .resumeFocusedTasksTopActivities();
1658 
1659         // Try to destroy the last activity above the home stack.
1660         activity.destroyIfPossible("test");
1661 
1662         // Verify that the activity was not actually destroyed, but waits for next one to come up
1663         // instead.
1664         verify(activity, never()).destroyImmediately(anyString());
1665         assertEquals(FINISHING, activity.getState());
1666         assertTrue(activity.mTaskSupervisor.mFinishingActivities.contains(activity));
1667     }
1668 
1669     /**
1670      * Verify that complete finish request for visible activity must resume next home stack before
1671      * destroying it immediately if it is the last running activity on a display with a home stack.
1672      * We must wait for home activity to come up to avoid a black flash in this case.
1673      */
1674     @Test
testCompleteFinishing_lastActivityAboveEmptyHomeStack()1675     public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
1676         final ActivityRecord activity = createActivityWithTask();
1677         // Empty the home root task.
1678         final Task homeRootTask = activity.getDisplayArea().getRootHomeTask();
1679         homeRootTask.forAllLeafTasks((t) -> {
1680             homeRootTask.removeChild(t, "test");
1681         }, true /* traverseTopToBottom */);
1682         activity.setState(STARTED, "test");
1683         activity.finishing = true;
1684         activity.setVisibleRequested(true);
1685 
1686         // Try to finish the last activity above the home stack.
1687         activity.completeFinishing("test");
1688 
1689         // Verify that the activity is not destroyed immediately, but waits for next one to come up.
1690         verify(activity, never()).destroyImmediately(anyString());
1691         assertEquals(FINISHING, activity.getState());
1692         assertTrue(activity.mTaskSupervisor.mFinishingActivities.contains(activity));
1693     }
1694 
1695     /**
1696      * Test that the activity will be moved to destroying state and the message to destroy will be
1697      * sent to the client.
1698      */
1699     @Test
testDestroyImmediately_hadApp_finishing()1700     public void testDestroyImmediately_hadApp_finishing() {
1701         final ActivityRecord activity = createActivityWithTask();
1702         activity.finishing = true;
1703         activity.destroyImmediately("test");
1704 
1705         assertEquals(DESTROYING, activity.getState());
1706     }
1707 
1708     /**
1709      * Test that the activity will be moved to destroyed state immediately if it was not marked as
1710      * finishing before {@link ActivityRecord#destroyImmediately(String)}.
1711      */
1712     @Test
testDestroyImmediately_hadApp_notFinishing()1713     public void testDestroyImmediately_hadApp_notFinishing() {
1714         final ActivityRecord activity = createActivityWithTask();
1715         activity.finishing = false;
1716         activity.destroyImmediately("test");
1717 
1718         assertEquals(DESTROYED, activity.getState());
1719     }
1720 
1721     /**
1722      * Test that an activity with no process attached and that is marked as finishing will be
1723      * removed from task when {@link ActivityRecord#destroyImmediately(String)} is called.
1724      */
1725     @Test
testDestroyImmediately_noApp_finishing()1726     public void testDestroyImmediately_noApp_finishing() {
1727         final ActivityRecord activity = createActivityWithTask();
1728         activity.app = null;
1729         activity.finishing = true;
1730         final Task task = activity.getTask();
1731 
1732         activity.destroyImmediately("test");
1733 
1734         assertEquals(DESTROYED, activity.getState());
1735         assertNull(activity.getTask());
1736         assertEquals(0, task.getChildCount());
1737     }
1738 
1739     /**
1740      * Test that an activity with no process attached and that is not marked as finishing will be
1741      * marked as DESTROYED but not removed from task.
1742      */
1743     @Test
testDestroyImmediately_noApp_notFinishing()1744     public void testDestroyImmediately_noApp_notFinishing() {
1745         final ActivityRecord activity = createActivityWithTask();
1746         activity.app = null;
1747         activity.finishing = false;
1748         final Task task = activity.getTask();
1749 
1750         activity.destroyImmediately("test");
1751 
1752         assertEquals(DESTROYED, activity.getState());
1753         assertEquals(task, activity.getTask());
1754         assertEquals(1, task.getChildCount());
1755     }
1756 
1757     /**
1758      * Test that an activity will not be destroyed if it is marked as non-destroyable.
1759      */
1760     @Test
testSafelyDestroy_nonDestroyable()1761     public void testSafelyDestroy_nonDestroyable() {
1762         final ActivityRecord activity = createActivityWithTask();
1763         doReturn(false).when(activity).isDestroyable();
1764 
1765         activity.safelyDestroy("test");
1766 
1767         verify(activity, never()).destroyImmediately(anyString());
1768     }
1769 
1770     /**
1771      * Test that an activity will not be destroyed if it is marked as non-destroyable.
1772      */
1773     @Test
testSafelyDestroy_destroyable()1774     public void testSafelyDestroy_destroyable() {
1775         final ActivityRecord activity = createActivityWithTask();
1776         doReturn(true).when(activity).isDestroyable();
1777 
1778         activity.safelyDestroy("test");
1779 
1780         verify(activity).destroyImmediately(anyString());
1781     }
1782 
1783     @Test
testRemoveImmediately()1784     public void testRemoveImmediately() {
1785         final Consumer<Consumer<ActivityRecord>> test = setup -> {
1786             final ActivityRecord activity = createActivityWithTask();
1787             final WindowProcessController wpc = activity.app;
1788             setup.accept(activity);
1789             activity.getTask().removeImmediately("test");
1790             try {
1791                 verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.token),
1792                         isA(DestroyActivityItem.class));
1793             } catch (RemoteException ignored) {
1794             }
1795             assertNull(activity.app);
1796             assertEquals(DESTROYED, activity.getState());
1797             assertFalse(wpc.hasActivities());
1798         };
1799         test.accept(activity -> activity.setState(RESUMED, "test"));
1800         test.accept(activity -> activity.finishing = true);
1801     }
1802 
1803     @Test
testRemoveFromHistory()1804     public void testRemoveFromHistory() {
1805         final ActivityRecord activity = createActivityWithTask();
1806         final Task rootTask = activity.getRootTask();
1807         final Task task = activity.getTask();
1808         final WindowProcessController wpc = activity.app;
1809         assertTrue(wpc.hasActivities());
1810 
1811         activity.removeFromHistory("test");
1812 
1813         assertEquals(DESTROYED, activity.getState());
1814         assertNull(activity.app);
1815         assertNull(activity.getTask());
1816         assertFalse(wpc.hasActivities());
1817         assertEquals(0, task.getChildCount());
1818         assertEquals(task.getRootTask(), task);
1819         assertEquals(0, rootTask.getChildCount());
1820     }
1821 
1822     /**
1823      * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is
1824      * not in destroying or destroyed state.
1825      */
1826     @Test(expected = IllegalStateException.class)
testDestroyed_notDestroying()1827     public void testDestroyed_notDestroying() {
1828         final ActivityRecord activity = createActivityWithTask();
1829         activity.setState(STOPPED, "test");
1830         activity.destroyed("test");
1831     }
1832 
1833     /**
1834      * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying
1835      */
1836     @Test
testDestroyed_destroying()1837     public void testDestroyed_destroying() {
1838         final ActivityRecord activity = createActivityWithTask();
1839         activity.setState(DESTROYING, "test");
1840         activity.destroyed("test");
1841 
1842         verify(activity).removeFromHistory(anyString());
1843     }
1844 
1845     /**
1846      * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed.
1847      */
1848     @Test
testDestroyed_destroyed()1849     public void testDestroyed_destroyed() {
1850         final ActivityRecord activity = createActivityWithTask();
1851         activity.setState(DESTROYED, "test");
1852         activity.destroyed("test");
1853 
1854         verify(activity).removeFromHistory(anyString());
1855     }
1856 
1857     @Test
testActivityOverridesProcessConfig()1858     public void testActivityOverridesProcessConfig() {
1859         final ActivityRecord activity = createActivityWithTask();
1860         final WindowProcessController wpc = activity.app;
1861         assertTrue(wpc.registeredForActivityConfigChanges());
1862         assertFalse(wpc.registeredForDisplayAreaConfigChanges());
1863 
1864         final ActivityRecord secondaryDisplayActivity =
1865                 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1866 
1867         assertTrue(wpc.registeredForActivityConfigChanges());
1868         assertEquals(0, activity.getMergedOverrideConfiguration()
1869                 .diff(wpc.getRequestedOverrideConfiguration()));
1870         assertNotEquals(activity.getConfiguration(),
1871                 secondaryDisplayActivity.getConfiguration());
1872     }
1873 
1874     @Test
testActivityOverridesProcessConfig_TwoActivities()1875     public void testActivityOverridesProcessConfig_TwoActivities() {
1876         final ActivityRecord activity = createActivityWithTask();
1877         final WindowProcessController wpc = activity.app;
1878         assertTrue(wpc.registeredForActivityConfigChanges());
1879 
1880         final Task firstTaskRecord = activity.getTask();
1881         final ActivityRecord secondActivityRecord =
1882                 new ActivityBuilder(mAtm).setTask(firstTaskRecord).setUseProcess(wpc).build();
1883 
1884         assertTrue(wpc.registeredForActivityConfigChanges());
1885         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1886                 .diff(wpc.getRequestedOverrideConfiguration()));
1887     }
1888 
1889     @Test
testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay()1890     public void testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay() {
1891         final ActivityRecord activity = createActivityWithTask();
1892         final WindowProcessController wpc = activity.app;
1893         assertTrue(wpc.registeredForActivityConfigChanges());
1894 
1895         final ActivityRecord secondActivityRecord =
1896                 new ActivityBuilder(mAtm).setTask(activity.getTask()).setUseProcess(wpc).build();
1897 
1898         assertTrue(wpc.registeredForActivityConfigChanges());
1899         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1900                 .diff(wpc.getRequestedOverrideConfiguration()));
1901     }
1902 
1903     @Test
testActivityOverridesProcessConfig_TwoActivities_DifferentTasks()1904     public void testActivityOverridesProcessConfig_TwoActivities_DifferentTasks() {
1905         final ActivityRecord activity = createActivityWithTask();
1906         final WindowProcessController wpc = activity.app;
1907         assertTrue(wpc.registeredForActivityConfigChanges());
1908 
1909         final ActivityRecord secondActivityRecord =
1910                 createActivityOnDisplay(true /* defaultDisplay */, wpc);
1911 
1912         assertTrue(wpc.registeredForActivityConfigChanges());
1913         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1914                 .diff(wpc.getRequestedOverrideConfiguration()));
1915     }
1916 
1917     @Test
testActivityOnCancelFixedRotationTransform()1918     public void testActivityOnCancelFixedRotationTransform() {
1919         final ActivityRecord activity = createActivityWithTask();
1920         final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation();
1921         final RemoteDisplayChangeController remoteDisplayChangeController = activity
1922                 .mDisplayContent.mRemoteDisplayChangeController;
1923         spyOn(displayRotation);
1924         spyOn(remoteDisplayChangeController);
1925 
1926         final DisplayContent display = activity.mDisplayContent;
1927         final int originalRotation = display.getRotation();
1928 
1929         // Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately.
1930         doReturn(true).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange();
1931         doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation(
1932                 anyInt() /* orientation */, anyInt() /* lastRotation */);
1933         // Set to visible so the activity can freeze the screen.
1934         activity.setVisibility(true);
1935 
1936         display.rotateInDifferentOrientationIfNeeded(activity);
1937         display.setFixedRotationLaunchingAppUnchecked(activity);
1938         displayRotation.updateRotationUnchecked(true /* forceUpdate */);
1939 
1940         assertTrue(displayRotation.isRotatingSeamlessly());
1941 
1942         // The launching rotated app should not be cleared when waiting for remote rotation.
1943         display.continueUpdateOrientationForDiffOrienLaunchingApp();
1944         assertTrue(display.isFixedRotationLaunchingApp(activity));
1945 
1946         // Simulate the rotation has been updated to previous one, e.g. sensor updates before the
1947         // remote rotation is completed.
1948         doReturn(originalRotation).when(displayRotation).rotationForOrientation(
1949                 anyInt() /* orientation */, anyInt() /* lastRotation */);
1950         display.updateOrientation();
1951 
1952         final DisplayInfo rotatedInfo = activity.getFixedRotationTransformDisplayInfo();
1953         activity.finishFixedRotationTransform();
1954         final ScreenRotationAnimation rotationAnim = display.getRotationAnimation();
1955         assertNotNull(rotationAnim);
1956         rotationAnim.setRotation(display.getPendingTransaction(), originalRotation);
1957 
1958         // Because the display doesn't rotate, the rotated activity needs to cancel the fixed
1959         // rotation. There should be a rotation animation to cover the change of activity.
1960         verify(activity).onCancelFixedRotationTransform(rotatedInfo.rotation);
1961         assertTrue(activity.isFreezingScreen());
1962         assertFalse(displayRotation.isRotatingSeamlessly());
1963         assertTrue(rotationAnim.isRotating());
1964 
1965         // Simulate the remote rotation has completed and the configuration doesn't change, then
1966         // the rotated activity should also be restored by clearing the transform.
1967         displayRotation.updateRotationUnchecked(true /* forceUpdate */);
1968         doReturn(false).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange();
1969         clearInvocations(activity);
1970         display.setFixedRotationLaunchingAppUnchecked(activity);
1971         display.sendNewConfiguration();
1972 
1973         assertFalse(display.hasTopFixedRotationLaunchingApp());
1974         assertFalse(activity.hasFixedRotationTransform());
1975 
1976         // Simulate that the activity requests the same orientation as display.
1977         activity.setOrientation(display.getConfiguration().orientation);
1978         // Skip the real freezing.
1979         activity.setVisibleRequested(false);
1980         clearInvocations(activity);
1981         activity.onCancelFixedRotationTransform(originalRotation);
1982         // The implementation of cancellation must be executed.
1983         verify(activity).startFreezingScreen(originalRotation);
1984     }
1985 
1986     @Test
testIsSnapshotCompatible()1987     public void testIsSnapshotCompatible() {
1988         final ActivityRecord activity = createActivityWithTask();
1989         final Task task = activity.getTask();
1990         final Rect taskBounds = task.getBounds();
1991         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
1992                 .setTopActivityComponent(activity.mActivityComponent)
1993                 .setRotation(activity.getWindowConfiguration().getRotation())
1994                 .setTaskSize(taskBounds.width(), taskBounds.height())
1995                 .build();
1996 
1997         assertTrue(activity.isSnapshotCompatible(snapshot));
1998 
1999         doReturn(task.getWindowConfiguration().getRotation() + 1).when(mDisplayContent)
2000                 .rotationForActivityInDifferentOrientation(activity);
2001 
2002         assertFalse(activity.isSnapshotCompatible(snapshot));
2003     }
2004 
2005     /**
2006      * Test that the snapshot should be obsoleted if the top activity changed.
2007      */
2008     @Test
testIsSnapshotCompatibleTopActivityChanged()2009     public void testIsSnapshotCompatibleTopActivityChanged() {
2010         final ActivityRecord activity = createActivityWithTask();
2011         final ActivityRecord secondActivity = new ActivityBuilder(mAtm)
2012                 .setTask(activity.getTask())
2013                 .setOnTop(true)
2014                 .build();
2015         final Task task = secondActivity.getTask();
2016         final Rect taskBounds = task.getBounds();
2017         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
2018                 .setTopActivityComponent(secondActivity.mActivityComponent)
2019                 .setTaskSize(taskBounds.width(), taskBounds.height())
2020                 .build();
2021 
2022         assertTrue(secondActivity.isSnapshotCompatible(snapshot));
2023 
2024         // Emulate the top activity changed.
2025         assertFalse(activity.isSnapshotCompatible(snapshot));
2026     }
2027 
2028     /**
2029      * Test that the snapshot should be obsoleted if the task size changed.
2030      */
2031     @Test
testIsSnapshotCompatibleTaskSizeChanged()2032     public void testIsSnapshotCompatibleTaskSizeChanged() {
2033         final ActivityRecord activity = createActivityWithTask();
2034         final Task task = activity.getTask();
2035         final Rect taskBounds = task.getBounds();
2036         final int currentRotation = mDisplayContent.getRotation();
2037         final int w = taskBounds.width();
2038         final int h = taskBounds.height();
2039         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
2040                 .setTopActivityComponent(activity.mActivityComponent)
2041                 .setRotation(currentRotation)
2042                 .setTaskSize(w, h)
2043                 .build();
2044 
2045         assertTrue(activity.isSnapshotCompatible(snapshot));
2046 
2047         taskBounds.right = taskBounds.width() * 2;
2048         task.getWindowConfiguration().setBounds(taskBounds);
2049         activity.getWindowConfiguration().setBounds(taskBounds);
2050 
2051         assertFalse(activity.isSnapshotCompatible(snapshot));
2052 
2053         // Flipped size should be accepted if the activity will show with 90 degree rotation.
2054         final int targetRotation = currentRotation + 1;
2055         doReturn(targetRotation).when(mDisplayContent)
2056                 .rotationForActivityInDifferentOrientation(any());
2057         final TaskSnapshot rotatedSnapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
2058                 .setTopActivityComponent(activity.mActivityComponent)
2059                 .setRotation(targetRotation)
2060                 .setTaskSize(h, w)
2061                 .build();
2062         task.getWindowConfiguration().getBounds().set(0, 0, w, h);
2063         assertTrue(activity.isSnapshotCompatible(rotatedSnapshot));
2064     }
2065 
2066     @Test
testFixedRotationSnapshotStartingWindow()2067     public void testFixedRotationSnapshotStartingWindow() {
2068         final ActivityRecord activity = createActivityWithTask();
2069         // TaskSnapshotSurface requires a fullscreen opaque window.
2070         final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
2071                 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
2072         params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
2073         final TestWindowState w = new TestWindowState(
2074                 mAtm.mWindowManager, mock(Session.class), new TestIWindow(), params, activity);
2075         activity.addWindow(w);
2076 
2077         // Assume the activity is launching in different rotation, and there was an available
2078         // snapshot accepted by {@link Activity#isSnapshotCompatible}.
2079         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
2080                 .setRotation((activity.getWindowConfiguration().getRotation() + 1) % 4)
2081                 .build();
2082         setRotatedScreenOrientationSilently(activity);
2083         activity.setVisible(false);
2084 
2085         final IWindowSession session = WindowManagerGlobal.getWindowSession();
2086         spyOn(session);
2087         try {
2088             // Return error to skip unnecessary operation.
2089             doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
2090                     any() /* window */,  any() /* attrs */,
2091                     anyInt() /* viewVisibility */, anyInt() /* displayId */,
2092                     anyInt() /* requestedVisibleTypes */, any() /* outInputChannel */,
2093                     any() /* outInsetsState */, any() /* outActiveControls */,
2094                     any() /* outAttachedFrame */, any() /* outSizeCompatScale */);
2095             mAtm.mWindowManager.mStartingSurfaceController
2096                     .createTaskSnapshotSurface(activity, snapshot);
2097         } catch (RemoteException ignored) {
2098         } finally {
2099             reset(session);
2100         }
2101 
2102         // Because the rotation of snapshot and the corresponding top activity are different, fixed
2103         // rotation should be applied when creating snapshot surface if the display rotation may be
2104         // changed according to the activity orientation.
2105         assertTrue(activity.hasFixedRotationTransform());
2106         assertTrue(activity.mDisplayContent.isFixedRotationLaunchingApp(activity));
2107     }
2108 
2109     /**
2110      * Sets orientation without notifying the parent to simulate that the display has not applied
2111      * the requested orientation yet.
2112      */
setRotatedScreenOrientationSilently(ActivityRecord r)2113     static void setRotatedScreenOrientationSilently(ActivityRecord r) {
2114         final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT
2115                 ? SCREEN_ORIENTATION_LANDSCAPE
2116                 : SCREEN_ORIENTATION_PORTRAIT;
2117         doReturn(false).when(r).onDescendantOrientationChanged(any());
2118         r.setOrientation(rotatedOrentation);
2119     }
2120 
2121     @Test
testActivityOnDifferentDisplayUpdatesProcessOverride()2122     public void testActivityOnDifferentDisplayUpdatesProcessOverride() {
2123         final ActivityRecord secondaryDisplayActivity =
2124                 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
2125         final WindowProcessController wpc = secondaryDisplayActivity.app;
2126         assertTrue(wpc.registeredForActivityConfigChanges());
2127 
2128         final ActivityRecord secondActivityRecord =
2129                 createActivityOnDisplay(true /* defaultDisplay */, wpc);
2130 
2131         assertTrue(wpc.registeredForActivityConfigChanges());
2132         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
2133                 .diff(wpc.getRequestedOverrideConfiguration()));
2134         assertFalse(wpc.registeredForDisplayAreaConfigChanges());
2135     }
2136 
2137     @Test
testActivityReparentChangesProcessOverride()2138     public void testActivityReparentChangesProcessOverride() {
2139         final ActivityRecord activity = createActivityWithTask();
2140         final WindowProcessController wpc = activity.app;
2141         final Task initialTask = activity.getTask();
2142         final Configuration initialConf =
2143                 new Configuration(activity.getMergedOverrideConfiguration());
2144         assertEquals(0, activity.getMergedOverrideConfiguration()
2145                 .diff(wpc.getRequestedOverrideConfiguration()));
2146         assertTrue(wpc.registeredForActivityConfigChanges());
2147 
2148         // Create a new task with custom config to reparent the activity to.
2149         final Task newTask = new TaskBuilder(mSupervisor).build();
2150         final Configuration newConfig = newTask.getConfiguration();
2151         newConfig.densityDpi += 100;
2152         newTask.onRequestedOverrideConfigurationChanged(newConfig);
2153         assertEquals(newTask.getConfiguration().densityDpi, newConfig.densityDpi);
2154 
2155         // Reparent the activity and verify that config override changed.
2156         activity.reparent(newTask, 0 /* top */, "test");
2157         assertEquals(activity.getConfiguration().densityDpi, newConfig.densityDpi);
2158         assertEquals(activity.getMergedOverrideConfiguration().densityDpi, newConfig.densityDpi);
2159 
2160         assertTrue(wpc.registeredForActivityConfigChanges());
2161         assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
2162         assertEquals(0, activity.getMergedOverrideConfiguration()
2163                 .diff(wpc.getRequestedOverrideConfiguration()));
2164     }
2165 
2166     @Test
testActivityReparentDoesntClearProcessOverride_TwoActivities()2167     public void testActivityReparentDoesntClearProcessOverride_TwoActivities() {
2168         final ActivityRecord activity = createActivityWithTask();
2169         final WindowProcessController wpc = activity.app;
2170         final Configuration initialConf =
2171                 new Configuration(activity.getMergedOverrideConfiguration());
2172         final Task initialTask = activity.getTask();
2173         final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(initialTask)
2174                 .setUseProcess(wpc).build();
2175 
2176         assertTrue(wpc.registeredForActivityConfigChanges());
2177         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
2178                 .diff(wpc.getRequestedOverrideConfiguration()));
2179 
2180         // Create a new task with custom config to reparent the second activity to.
2181         final Task newTask = new TaskBuilder(mSupervisor).build();
2182         final Configuration newConfig = newTask.getConfiguration();
2183         newConfig.densityDpi += 100;
2184         newTask.onRequestedOverrideConfigurationChanged(newConfig);
2185 
2186         // Reparent the activity and verify that config override changed.
2187         secondActivity.reparent(newTask, 0 /* top */, "test");
2188 
2189         assertTrue(wpc.registeredForActivityConfigChanges());
2190         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
2191                 .diff(wpc.getRequestedOverrideConfiguration()));
2192         assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
2193 
2194         // Reparent the first activity and verify that config override didn't change.
2195         activity.reparent(newTask, 1 /* top */, "test");
2196         assertTrue(wpc.registeredForActivityConfigChanges());
2197         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
2198                 .diff(wpc.getRequestedOverrideConfiguration()));
2199         assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
2200     }
2201 
2202     @Test
testActivityDestroyDoesntChangeProcessOverride()2203     public void testActivityDestroyDoesntChangeProcessOverride() {
2204         final ActivityRecord firstActivity =
2205                 createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
2206         final WindowProcessController wpc = firstActivity.app;
2207         assertTrue(wpc.registeredForActivityConfigChanges());
2208         assertEquals(0, firstActivity.getMergedOverrideConfiguration()
2209                 .diff(wpc.getRequestedOverrideConfiguration()));
2210 
2211         final ActivityRecord secondActivity =
2212                 createActivityOnDisplay(false /* defaultDisplay */, wpc);
2213         assertTrue(wpc.registeredForActivityConfigChanges());
2214         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
2215                 .diff(wpc.getRequestedOverrideConfiguration()));
2216 
2217         final ActivityRecord thirdActivity =
2218                 createActivityOnDisplay(false /* defaultDisplay */, wpc);
2219         assertTrue(wpc.registeredForActivityConfigChanges());
2220         assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
2221                 .diff(wpc.getRequestedOverrideConfiguration()));
2222 
2223         secondActivity.destroyImmediately("");
2224 
2225         assertTrue(wpc.registeredForActivityConfigChanges());
2226         assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
2227                 .diff(wpc.getRequestedOverrideConfiguration()));
2228 
2229         firstActivity.destroyImmediately("");
2230 
2231         assertTrue(wpc.registeredForActivityConfigChanges());
2232         assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
2233                 .diff(wpc.getRequestedOverrideConfiguration()));
2234     }
2235 
2236     @Test
testFullscreenWindowCanTurnScreenOn()2237     public void testFullscreenWindowCanTurnScreenOn() {
2238         final ActivityRecord activity = createActivityWithTask();
2239         final Task task = activity.getTask();
2240         task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
2241         doReturn(true).when(activity).getTurnScreenOnFlag();
2242 
2243         assertTrue(activity.canTurnScreenOn());
2244     }
2245 
2246     @Test
testFreeformWindowCanTurnScreenOn()2247     public void testFreeformWindowCanTurnScreenOn() {
2248         final ActivityRecord activity = createActivityWithTask();
2249         final Task task = activity.getTask();
2250         task.setWindowingMode(WINDOWING_MODE_FREEFORM);
2251         doReturn(true).when(activity).getTurnScreenOnFlag();
2252 
2253         assertTrue(activity.canTurnScreenOn());
2254     }
2255 
2256     @Test
testGetLockTaskLaunchMode()2257     public void testGetLockTaskLaunchMode() {
2258         final ActivityRecord activity = createActivityWithTask();
2259         final ActivityOptions options = ActivityOptions.makeBasic().setLockTaskEnabled(true);
2260         activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
2261         assertEquals(LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED,
2262                 ActivityRecord.getLockTaskLaunchMode(activity.info, options));
2263 
2264         activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_ALWAYS;
2265         assertEquals(LOCK_TASK_LAUNCH_MODE_DEFAULT,
2266                 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/));
2267 
2268         activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_NEVER;
2269         assertEquals(LOCK_TASK_LAUNCH_MODE_DEFAULT,
2270                 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/));
2271 
2272         activity.info.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
2273         activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_ALWAYS;
2274         assertEquals(LOCK_TASK_LAUNCH_MODE_ALWAYS,
2275                 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/));
2276 
2277         activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_NEVER;
2278         assertEquals(LOCK_TASK_LAUNCH_MODE_NEVER,
2279                 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/));
2280 
2281     }
2282 
2283     @Test
testProcessInfoUpdateWhenSetState()2284     public void testProcessInfoUpdateWhenSetState() {
2285         final ActivityRecord activity = createActivityWithTask();
2286         activity.setState(INITIALIZING, "test");
2287         spyOn(activity.app);
2288         verifyProcessInfoUpdate(activity, RESUMED,
2289                 true /* shouldUpdate */, true /* activityChange */);
2290         verifyProcessInfoUpdate(activity, PAUSED,
2291                 false /* shouldUpdate */, false /* activityChange */);
2292         verifyProcessInfoUpdate(activity, STOPPED,
2293                 false /* shouldUpdate */, false /* activityChange */);
2294         verifyProcessInfoUpdate(activity, STARTED,
2295                 true /* shouldUpdate */, true /* activityChange */);
2296 
2297         activity.app.removeActivity(activity, true /* keepAssociation */);
2298         verifyProcessInfoUpdate(activity, DESTROYING,
2299                 true /* shouldUpdate */, false /* activityChange */);
2300         verifyProcessInfoUpdate(activity, DESTROYED,
2301                 true /* shouldUpdate */, false /* activityChange */);
2302     }
2303 
2304     @Test
testSupportsFreeform()2305     public void testSupportsFreeform() {
2306         final ActivityRecord activity = new ActivityBuilder(mAtm)
2307                 .setCreateTask(true)
2308                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
2309                 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE)
2310                 .build();
2311 
2312         // Not allow non-resizable
2313         mAtm.mForceResizableActivities = false;
2314         mAtm.mSupportsNonResizableMultiWindow = -1;
2315         mAtm.mDevEnableNonResizableMultiWindow = false;
2316         assertFalse(activity.supportsFreeform());
2317 
2318         // Force resizable
2319         mAtm.mForceResizableActivities = true;
2320         mAtm.mSupportsNonResizableMultiWindow = -1;
2321         mAtm.mDevEnableNonResizableMultiWindow = false;
2322         assertTrue(activity.supportsFreeform());
2323 
2324         // Use development option to allow non-resizable
2325         mAtm.mForceResizableActivities = false;
2326         mAtm.mSupportsNonResizableMultiWindow = -1;
2327         mAtm.mDevEnableNonResizableMultiWindow = true;
2328         assertTrue(activity.supportsFreeform());
2329 
2330         // Always allow non-resizable
2331         mAtm.mForceResizableActivities = false;
2332         mAtm.mSupportsNonResizableMultiWindow = 1;
2333         mAtm.mDevEnableNonResizableMultiWindow = false;
2334         assertTrue(activity.supportsFreeform());
2335     }
2336 
2337     @Test
testSupportsPictureInPicture()2338     public void testSupportsPictureInPicture() {
2339         final ActivityRecord activity = new ActivityBuilder(mAtm)
2340                 .setCreateTask(true)
2341                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
2342                 .setActivityFlags(FLAG_SUPPORTS_PICTURE_IN_PICTURE)
2343                 .build();
2344 
2345         // Device not supports PIP
2346         mAtm.mSupportsPictureInPicture = false;
2347         assertFalse(activity.supportsPictureInPicture());
2348 
2349         // Device and app support PIP
2350         mAtm.mSupportsPictureInPicture = true;
2351         assertTrue(activity.supportsPictureInPicture());
2352 
2353         // Activity not supports PIP
2354         activity.info.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE;
2355         assertFalse(activity.supportsPictureInPicture());
2356     }
2357 
2358     @Test
testCheckEnterPictureInPictureState_displayNotSupportedPip()2359     public void testCheckEnterPictureInPictureState_displayNotSupportedPip() {
2360         final Task task = new TaskBuilder(mSupervisor)
2361                 .setDisplay(mDisplayContent).build();
2362         final ActivityRecord activity = new ActivityBuilder(mAtm)
2363                 .setTask(task)
2364                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE)
2365                 .setActivityFlags(FLAG_SUPPORTS_PICTURE_IN_PICTURE)
2366                 .build();
2367         mAtm.mSupportsPictureInPicture = true;
2368         AppOpsManager appOpsManager = mAtm.getAppOpsManager();
2369         doReturn(MODE_ALLOWED).when(appOpsManager).checkOpNoThrow(eq(OP_PICTURE_IN_PICTURE),
2370                 anyInt(), any());
2371         doReturn(false).when(mAtm).shouldDisableNonVrUiLocked();
2372 
2373         spyOn(mDisplayContent.mDwpcHelper);
2374         doReturn(false).when(mDisplayContent.mDwpcHelper).isEnteringPipAllowed(anyInt());
2375 
2376         assertFalse(activity.checkEnterPictureInPictureState("TEST", false /* beforeStopping */));
2377     }
2378 
2379     @Test
testLaunchIntoPip()2380     public void testLaunchIntoPip() {
2381         final PictureInPictureParams params = new PictureInPictureParams.Builder()
2382                 .build();
2383         final ActivityOptions opts = ActivityOptions.makeLaunchIntoPip(params);
2384         final ActivityRecord activity = new ActivityBuilder(mAtm)
2385                 .setActivityOptions(opts)
2386                 .build();
2387 
2388         // Verify the pictureInPictureArgs is set on the new Activity
2389         assertNotNull(activity.pictureInPictureArgs);
2390         assertTrue(activity.pictureInPictureArgs.isLaunchIntoPip());
2391     }
2392 
2393     @Test
testActivityServiceConnectionsHolder()2394     public void testActivityServiceConnectionsHolder() {
2395         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2396         final ActivityServiceConnectionsHolder<Object> holder =
2397                 mAtm.mInternal.getServiceConnectionsHolder(activity.token);
2398         assertNotNull(holder);
2399         final Object connection = new Object();
2400         holder.addConnection(connection);
2401         assertTrue(holder.isActivityVisible());
2402         final int[] count = new int[1];
2403         final Consumer<Object> c = conn -> {
2404             count[0]++;
2405             assertFalse(Thread.holdsLock(activity));
2406         };
2407         holder.forEachConnection(c);
2408         assertEquals(1, count[0]);
2409 
2410         holder.removeConnection(connection);
2411         holder.forEachConnection(c);
2412         assertEquals(1, count[0]);
2413 
2414         activity.setVisibleRequested(false);
2415         activity.setState(STOPPED, "test");
2416         assertFalse(holder.isActivityVisible());
2417 
2418         activity.removeImmediately();
2419         assertNull(mAtm.mInternal.getServiceConnectionsHolder(activity.token));
2420     }
2421 
2422     @Test
testTransferLaunchCookieWhenFinishing()2423     public void testTransferLaunchCookieWhenFinishing() {
2424         final ActivityRecord activity1 = createActivityWithTask();
2425         final Binder launchCookie = new Binder();
2426         activity1.mLaunchCookie = launchCookie;
2427         final ActivityRecord activity2 = createActivityRecord(activity1.getTask());
2428         activity1.setState(PAUSED, "test");
2429         activity1.makeFinishingLocked();
2430 
2431         assertEquals(launchCookie, activity2.mLaunchCookie);
2432         assertNull(activity1.mLaunchCookie);
2433         activity2.makeFinishingLocked();
2434         assertTrue(activity1.getTask().getTaskInfo().launchCookies.contains(launchCookie));
2435     }
2436 
2437     @Test
testOrientationForScreenOrientationBehind()2438     public void testOrientationForScreenOrientationBehind() {
2439         final Task task = createTask(mDisplayContent);
2440         // Activity below
2441         new ActivityBuilder(mAtm)
2442                 .setTask(task)
2443                 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
2444                 .build();
2445         final ActivityRecord activityTop = new ActivityBuilder(mAtm)
2446                 .setTask(task)
2447                 .setScreenOrientation(SCREEN_ORIENTATION_BEHIND)
2448                 .build();
2449         final int topOrientation = activityTop.getRequestedConfigurationOrientation();
2450         assertEquals(ORIENTATION_PORTRAIT, topOrientation);
2451     }
2452 
verifyProcessInfoUpdate(ActivityRecord activity, State state, boolean shouldUpdate, boolean activityChange)2453     private void verifyProcessInfoUpdate(ActivityRecord activity, State state,
2454             boolean shouldUpdate, boolean activityChange) {
2455         reset(activity.app);
2456         activity.setState(state, "test");
2457         verify(activity.app, times(shouldUpdate ? 1 : 0)).updateProcessInfo(anyBoolean(),
2458                 eq(activityChange), anyBoolean(), anyBoolean());
2459     }
2460 
createActivityWithTask()2461     private ActivityRecord createActivityWithTask() {
2462         return new ActivityBuilder(mAtm).setCreateTask(true).setOnTop(true).build();
2463     }
2464 
createActivityWith2LevelTask()2465     private ActivityRecord createActivityWith2LevelTask() {
2466         final Task task = new TaskBuilder(mSupervisor)
2467                 .setCreateParentTask(true).setCreateActivity(true).build();
2468         return task.getTopNonFinishingActivity();
2469     }
2470 
2471     /**
2472      * Creates an activity on display. For non-default display request it will also create a new
2473      * display with custom DisplayInfo.
2474      */
createActivityOnDisplay(boolean defaultDisplay, WindowProcessController process)2475     private ActivityRecord createActivityOnDisplay(boolean defaultDisplay,
2476             WindowProcessController process) {
2477         final DisplayContent display;
2478         if (defaultDisplay) {
2479             display = mRootWindowContainer.getDefaultDisplay();
2480         } else {
2481             display = new TestDisplayContent.Builder(mAtm, 2000, 1000).setDensityDpi(300)
2482                     .setPosition(DisplayContent.POSITION_TOP).build();
2483         }
2484         final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build();
2485         return new ActivityBuilder(mAtm).setTask(task).setUseProcess(process).build();
2486     }
2487 
2488     @Test
2489     @Presubmit
testAddWindow_Order()2490     public void testAddWindow_Order() {
2491         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2492         assertEquals(0, activity.getChildCount());
2493 
2494         final WindowState win1 = createWindow(null, TYPE_APPLICATION, activity, "win1");
2495         final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity,
2496                 "startingWin");
2497         final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, activity, "baseWin");
2498         final WindowState win4 = createWindow(null, TYPE_APPLICATION, activity, "win4");
2499 
2500         // Should not contain the windows that were added above.
2501         assertEquals(4, activity.getChildCount());
2502         assertTrue(activity.mChildren.contains(win1));
2503         assertTrue(activity.mChildren.contains(startingWin));
2504         assertTrue(activity.mChildren.contains(baseWin));
2505         assertTrue(activity.mChildren.contains(win4));
2506 
2507         // The starting window should be on-top of all other windows.
2508         assertEquals(startingWin, activity.mChildren.peekLast());
2509 
2510         // The base application window should be below all other windows.
2511         assertEquals(baseWin, activity.mChildren.peekFirst());
2512         activity.removeImmediately();
2513     }
2514 
2515     @Test
2516     @Presubmit
testFindMainWindow()2517     public void testFindMainWindow() {
2518         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2519         assertNull(activity.findMainWindow());
2520 
2521         final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "window1");
2522         final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, activity, "window11");
2523         final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, activity, "window12");
2524         assertEquals(window1, activity.findMainWindow());
2525         window1.mAnimatingExit = true;
2526         assertEquals(window1, activity.findMainWindow());
2527         final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, activity,
2528                 "window2");
2529         assertEquals(window2, activity.findMainWindow());
2530         activity.removeImmediately();
2531     }
2532 
2533     @Test
2534     @Presubmit
testGetTopFullscreenOpaqueWindow()2535     public void testGetTopFullscreenOpaqueWindow() {
2536         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2537         assertNull(activity.getTopFullscreenOpaqueWindow());
2538 
2539         final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "window1");
2540         final WindowState window11 = createWindow(null, TYPE_APPLICATION, activity, "window11");
2541         final WindowState window12 = createWindow(null, TYPE_APPLICATION, activity, "window12");
2542         assertEquals(window12, activity.getTopFullscreenOpaqueWindow());
2543         window12.mAttrs.width = 500;
2544         assertEquals(window11, activity.getTopFullscreenOpaqueWindow());
2545         window11.mAttrs.width = 500;
2546         assertEquals(window1, activity.getTopFullscreenOpaqueWindow());
2547         window1.mAttrs.alpha = 0f;
2548         assertNull(activity.getTopFullscreenOpaqueWindow());
2549         activity.removeImmediately();
2550     }
2551 
2552     @SetupWindows(addWindows = W_ACTIVITY)
2553     @Test
testLandscapeSeascapeRotationByApp()2554     public void testLandscapeSeascapeRotationByApp() {
2555         final Task task = new TaskBuilder(mSupervisor)
2556                 .setDisplay(mDisplayContent).setCreateActivity(true).build();
2557         final ActivityRecord activity = task.getTopNonFinishingActivity();
2558         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
2559                 TYPE_BASE_APPLICATION);
2560         attrs.setTitle("AppWindow");
2561         final TestWindowState appWindow = createWindowState(attrs, activity);
2562         activity.addWindow(appWindow);
2563         spyOn(appWindow);
2564         doNothing().when(appWindow).onStartFreezingScreen();
2565 
2566         // Set initial orientation and update.
2567         activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
2568         mDisplayContent.updateOrientation(null /* freezeThisOneIfNeeded */,
2569                 false /* forceUpdate */);
2570         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation());
2571         appWindow.mResizeReported = false;
2572 
2573         // Update the orientation to perform 180 degree rotation and check that resize was reported.
2574         activity.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
2575         mDisplayContent.updateOrientation(null /* freezeThisOneIfNeeded */,
2576                 false /* forceUpdate */);
2577         // In this test, DC will not get config update. Set the waiting flag to false.
2578         mDisplayContent.mWaitingForConfig = false;
2579         mWm.mRoot.performSurfacePlacement();
2580         assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation());
2581         assertTrue(appWindow.mResizeReported);
2582         appWindow.removeImmediately();
2583     }
2584 
2585     @SetupWindows(addWindows = W_ACTIVITY)
2586     @Test
testLandscapeSeascapeRotationByPolicy()2587     public void testLandscapeSeascapeRotationByPolicy() {
2588         final Task task = new TaskBuilder(mSupervisor)
2589                 .setDisplay(mDisplayContent).setCreateActivity(true).build();
2590         final ActivityRecord activity = task.getTopNonFinishingActivity();
2591         final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2592         spyOn(displayRotation);
2593 
2594         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
2595                 TYPE_BASE_APPLICATION);
2596         attrs.setTitle("RotationByPolicy");
2597         final TestWindowState appWindow = createWindowState(attrs, activity);
2598         activity.addWindow(appWindow);
2599         spyOn(appWindow);
2600         doNothing().when(appWindow).onStartFreezingScreen();
2601         doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
2602 
2603         // Set initial orientation and update.
2604         performRotation(displayRotation, Surface.ROTATION_90);
2605         appWindow.mResizeReported = false;
2606 
2607         // Update the rotation to perform 180 degree rotation and check that resize was reported.
2608         performRotation(displayRotation, Surface.ROTATION_270);
2609         assertTrue(appWindow.mResizeReported);
2610     }
2611 
performRotation(DisplayRotation spiedRotation, int rotationToReport)2612     private void performRotation(DisplayRotation spiedRotation, int rotationToReport) {
2613         doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt());
2614         mWm.updateRotation(false, false);
2615     }
2616 
2617     @Test
2618     @Presubmit
testGetOrientation()2619     public void testGetOrientation() {
2620         // ActivityBuilder will resume top activities and cause the activity been added into
2621         // opening apps list. Since this test is focus on the effect of visible on getting
2622         // orientation, we skip app transition to avoid interference.
2623         doNothing().when(mDisplayContent).prepareAppTransition(anyInt());
2624         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2625         activity.setVisible(true);
2626 
2627         activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
2628 
2629         activity.setOccludesParent(false);
2630         // Can specify orientation if app doesn't occludes parent.
2631         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation());
2632 
2633         doReturn(true).when(activity).shouldIgnoreOrientationRequests();
2634         assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation());
2635 
2636         doReturn(false).when(activity).shouldIgnoreOrientationRequests();
2637         activity.setOccludesParent(true);
2638         activity.setVisible(false);
2639         activity.setVisibleRequested(false);
2640         // Can not specify orientation if app isn't visible even though it occludes parent.
2641         assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation());
2642         // Can specify orientation if the current orientation candidate is orientation behind.
2643         assertEquals(SCREEN_ORIENTATION_LANDSCAPE,
2644                 activity.getOrientation(SCREEN_ORIENTATION_BEHIND));
2645     }
2646 
2647     @Test
2648     @Presubmit
testKeyguardFlagsDuringRelaunch()2649     public void testKeyguardFlagsDuringRelaunch() {
2650         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2651         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
2652                 TYPE_BASE_APPLICATION);
2653         attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD;
2654         attrs.setTitle("AppWindow");
2655         final TestWindowState appWindow = createWindowState(attrs, activity);
2656 
2657         // Add window with show when locked flag
2658         activity.addWindow(appWindow);
2659         assertTrue(activity.containsShowWhenLockedWindow()
2660                 && activity.containsDismissKeyguardWindow());
2661 
2662         // Start relaunching
2663         activity.startRelaunching();
2664         assertTrue(activity.containsShowWhenLockedWindow()
2665                 && activity.containsDismissKeyguardWindow());
2666 
2667         // Remove window and make sure that we still report back flag
2668         activity.removeChild(appWindow);
2669         assertTrue(activity.containsShowWhenLockedWindow()
2670                 && activity.containsDismissKeyguardWindow());
2671 
2672         // Finish relaunching and ensure flag is now not reported
2673         activity.finishRelaunching();
2674         assertFalse(activity.containsShowWhenLockedWindow()
2675                 || activity.containsDismissKeyguardWindow());
2676     }
2677 
2678     @Test
testStuckExitingWindow()2679     public void testStuckExitingWindow() {
2680         final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW,
2681                 "closingWindow");
2682         closingWindow.mAnimatingExit = true;
2683         closingWindow.mRemoveOnExit = true;
2684         closingWindow.mActivityRecord.commitVisibility(
2685                 false /* visible */, true /* performLayout */);
2686 
2687         // We pretended that we were running an exit animation, but that should have been cleared up
2688         // by changing visibility of ActivityRecord
2689         closingWindow.removeIfPossible();
2690         assertTrue(closingWindow.mRemoved);
2691     }
2692 
2693     @Test
testSetOrientation()2694     public void testSetOrientation() {
2695         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2696         activity.setVisible(true);
2697 
2698         // Assert orientation is unspecified to start.
2699         assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, activity.getOrientation());
2700 
2701         activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
2702         assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation());
2703 
2704         mDisplayContent.removeAppToken(activity.token);
2705         // Assert orientation is unset to after container is removed.
2706         assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation());
2707 
2708         // Reset display frozen state
2709         mWm.mDisplayFrozen = false;
2710     }
2711 
2712     @Test
testRespectTopFullscreenOrientation()2713     public void testRespectTopFullscreenOrientation() {
2714         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2715         final Configuration displayConfig = activity.mDisplayContent.getConfiguration();
2716         final Configuration activityConfig = activity.getConfiguration();
2717         activity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
2718 
2719         assertEquals(Configuration.ORIENTATION_PORTRAIT, displayConfig.orientation);
2720         assertEquals(Configuration.ORIENTATION_PORTRAIT, activityConfig.orientation);
2721 
2722         final ActivityRecord topActivity = createActivityRecord(activity.getTask());
2723         topActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
2724 
2725         assertEquals(Configuration.ORIENTATION_LANDSCAPE, displayConfig.orientation);
2726         // Although the activity requested portrait, it is not the top activity that determines
2727         // the display orientation. So it should be able to inherit the orientation from parent.
2728         // Otherwise its configuration will be inconsistent that its orientation is portrait but
2729         // other screen configurations are in landscape, e.g. screenWidthDp, screenHeightDp, and
2730         // window configuration.
2731         assertEquals(Configuration.ORIENTATION_LANDSCAPE, activityConfig.orientation);
2732     }
2733 
2734     @Test
testReportOrientationChange()2735     public void testReportOrientationChange() {
2736         final Task task = new TaskBuilder(mSupervisor)
2737                 .setDisplay(mDisplayContent).setCreateActivity(true).build();
2738         final ActivityRecord activity = task.getTopNonFinishingActivity();
2739         activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
2740 
2741         mDisplayContent.getDisplayRotation().setFixedToUserRotation(
2742                 IWindowManager.FIXED_TO_USER_ROTATION_ENABLED);
2743         reset(task);
2744         activity.reportDescendantOrientationChangeIfNeeded();
2745         verify(task, atLeast(1)).onConfigurationChanged(any(Configuration.class));
2746     }
2747 
2748     @Test
testCreateRemoveStartingWindow()2749     public void testCreateRemoveStartingWindow() {
2750         registerTestStartingWindowOrganizer();
2751         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2752         activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2753                 true, false, false, false);
2754         waitUntilHandlersIdle();
2755         assertHasStartingWindow(activity);
2756         activity.removeStartingWindow();
2757         waitUntilHandlersIdle();
2758         assertNoStartingWindow(activity);
2759     }
2760 
testLegacySplashScreen(int targetSdk, int verifyType)2761     private void testLegacySplashScreen(int targetSdk, int verifyType) {
2762         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2763         activity.mTargetSdk = targetSdk;
2764         activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2765                 true, false, false, false);
2766         waitUntilHandlersIdle();
2767         assertHasStartingWindow(activity);
2768         assertEquals(activity.mStartingData.mTypeParams & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN,
2769                 verifyType);
2770         activity.removeStartingWindow();
2771         waitUntilHandlersIdle();
2772         assertNoStartingWindow(activity);
2773     }
2774 
2775     @Test
testCreateRemoveLegacySplashScreenWindow()2776     public void testCreateRemoveLegacySplashScreenWindow() {
2777         registerTestStartingWindowOrganizer();
2778         DeviceConfig.Properties properties = DeviceConfig.getProperties(
2779                 DeviceConfig.NAMESPACE_WINDOW_MANAGER);
2780         try {
2781             DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
2782                     "splash_screen_exception_list", DEFAULT_COMPONENT_PACKAGE_NAME, false);
2783             testLegacySplashScreen(Build.VERSION_CODES.R, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
2784             testLegacySplashScreen(Build.VERSION_CODES.S, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
2785             testLegacySplashScreen(Build.VERSION_CODES.TIRAMISU,
2786                     TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
2787             testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE,
2788                     TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
2789             testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1,
2790                     TYPE_PARAMETER_LEGACY_SPLASH_SCREEN);
2791             // Above V
2792             testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 2, 0);
2793         } finally {
2794             try {
2795                 DeviceConfig.setProperties(properties);
2796             } catch (DeviceConfig.BadConfigException e) {
2797                 Assert.fail(e.getMessage());
2798             }
2799         }
2800     }
2801 
2802     @Test
testTransferStartingWindow()2803     public void testTransferStartingWindow() {
2804         registerTestStartingWindowOrganizer();
2805         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true)
2806                 .setVisible(false).build();
2807         final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true)
2808                 .setVisible(false).build();
2809         activity1.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2810                 true, false, false, false);
2811         waitUntilHandlersIdle();
2812         activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1, true, true,
2813                 false, true, false, false, false);
2814         waitUntilHandlersIdle();
2815         assertFalse(mDisplayContent.mSkipAppTransitionAnimation);
2816         assertNoStartingWindow(activity1);
2817         assertHasStartingWindow(activity2);
2818     }
2819 
2820     @Test
testTransferStartingWindowWhileCreating()2821     public void testTransferStartingWindowWhileCreating() {
2822         final TestStartingWindowOrganizer organizer = registerTestStartingWindowOrganizer();
2823         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2824         final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2825         organizer.setRunnableWhenAddingSplashScreen(
2826                 () -> {
2827                     // Surprise, ...! Transfer window in the middle of the creation flow.
2828                     activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1,
2829                             true, true, false, true, false, false, false);
2830                 });
2831         activity1.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2832                 true, false, false, false);
2833         waitUntilHandlersIdle();
2834         assertNoStartingWindow(activity1);
2835         assertHasStartingWindow(activity2);
2836     }
2837 
2838     @Test
testTransferStartingWindowCanAnimate()2839     public void testTransferStartingWindowCanAnimate() {
2840         registerTestStartingWindowOrganizer();
2841         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2842         final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2843         activity1.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2844                 true, false, false, false);
2845         waitUntilHandlersIdle();
2846         activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1, true, true,
2847                 false, true, false, false, false);
2848         waitUntilHandlersIdle();
2849         assertNoStartingWindow(activity1);
2850         assertHasStartingWindow(activity2);
2851 
2852         // Assert that bottom activity is allowed to do animation.
2853         ArrayList<WindowContainer> sources = new ArrayList<>();
2854         sources.add(activity2);
2855         doReturn(true).when(activity2).okToAnimate();
2856         doReturn(true).when(activity2).isAnimating();
2857         assertTrue(activity2.applyAnimation(null, TRANSIT_OLD_ACTIVITY_OPEN, true, false, sources));
2858     }
2859     @Test
testTrackingStartingWindowThroughTrampoline()2860     public void testTrackingStartingWindowThroughTrampoline() {
2861         final ActivityRecord sourceRecord = new ActivityBuilder(mAtm)
2862                 .setCreateTask(true).setLaunchedFromUid(Process.SYSTEM_UID).build();
2863         sourceRecord.showStartingWindow(null /* prev */, true /* newTask */, false,
2864                 true /* startActivity */, null);
2865 
2866         final ActivityRecord secondRecord = new ActivityBuilder(mAtm)
2867                 .setTask(sourceRecord.getTask()).build();
2868         secondRecord.showStartingWindow(null /* prev */, true /* newTask */, false,
2869                 true /* startActivity */, sourceRecord);
2870         assertFalse(secondRecord.mSplashScreenStyleSolidColor);
2871         secondRecord.onStartingWindowDrawn();
2872 
2873         final ActivityRecord finalRecord = new ActivityBuilder(mAtm)
2874                 .setTask(sourceRecord.getTask()).build();
2875         finalRecord.showStartingWindow(null /* prev */, true /* newTask */, false,
2876                 true /* startActivity */, secondRecord);
2877         assertTrue(finalRecord.mSplashScreenStyleSolidColor);
2878     }
2879 
2880     @Test
testTransferStartingWindowFromFinishingActivity()2881     public void testTransferStartingWindowFromFinishingActivity() {
2882         registerTestStartingWindowOrganizer();
2883         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2884         final Task task = activity.getTask();
2885         activity.addStartingWindow(mPackageName, android.R.style.Theme, null /* transferFrom */,
2886                 true /* newTask */, true /* taskSwitch */, false /* processRunning */,
2887                 false /* allowTaskSnapshot */, false /* activityCreate */, false /* suggestEmpty
2888                 */, false /* activityAllDrawn */);
2889         waitUntilHandlersIdle();
2890         assertHasStartingWindow(activity);
2891 
2892         doCallRealMethod().when(task).startActivityLocked(
2893                 any(), any(), anyBoolean(), anyBoolean(), any(), any());
2894         // In normal case, resumeFocusedTasksTopActivities() should be called after
2895         // startActivityLocked(). So skip resumeFocusedTasksTopActivities() in ActivityBuilder.
2896         doReturn(false).when(mRootWindowContainer)
2897                 .resumeFocusedTasksTopActivities();
2898         // Make mVisibleSetFromTransferredStartingWindow true.
2899         final ActivityRecord middle = new ActivityBuilder(mAtm).setTask(task).build();
2900         task.startActivityLocked(middle, null /* topTask */,
2901                 false /* newTask */, false /* isTaskSwitch */, null /* options */,
2902                 null /* sourceRecord */);
2903         middle.makeFinishingLocked();
2904 
2905         assertNull(activity.mStartingWindow);
2906         assertHasStartingWindow(middle);
2907 
2908         final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).build();
2909         // Expect the visibility should be updated to true when transferring starting window from
2910         // a visible activity.
2911         top.setVisible(false);
2912         // The finishing middle should be able to transfer starting window to top.
2913         task.startActivityLocked(top, null /* topTask */,
2914                 false /* newTask */, false /* isTaskSwitch */, null /* options */,
2915                 null /* sourceRecord */);
2916 
2917         assertTrue(mDisplayContent.mSkipAppTransitionAnimation);
2918         assertNull(middle.mStartingWindow);
2919         assertHasStartingWindow(top);
2920         assertTrue(top.isVisible());
2921         // The activity was visible by mVisibleSetFromTransferredStartingWindow, so after its
2922         // starting window is transferred, it should restore to invisible.
2923         assertFalse(middle.isVisible());
2924     }
2925 
2926     @Test
testTransferStartingWindowSetFixedRotation()2927     public void testTransferStartingWindowSetFixedRotation() {
2928         registerTestStartingWindowOrganizer();
2929         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
2930         final Task task = activity.getTask();
2931         final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
2932         topActivity.setVisible(false);
2933         task.positionChildAt(POSITION_TOP, topActivity, false /* includeParents */);
2934         activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2935                 true, false, false, false);
2936         waitUntilHandlersIdle();
2937 
2938         // Make activities to have different rotation from it display and set fixed rotation
2939         // transform to activity1.
2940         int rotation = (mDisplayContent.getRotation() + 1) % 4;
2941         mDisplayContent.setFixedRotationLaunchingApp(activity, rotation);
2942         // The configuration with rotation change should not trigger task-association.
2943         assertNotNull(activity.mStartingData);
2944         assertNull(activity.mStartingData.mAssociatedTask);
2945         doReturn(rotation).when(mDisplayContent)
2946                 .rotationForActivityInDifferentOrientation(topActivity);
2947 
2948         // The transform will be finished because there is no running animation. Keep activity in
2949         // animating state to avoid the transform being finished.
2950         doReturn(true).when(activity).isAnimating(anyInt());
2951         // Make sure the fixed rotation transform linked to activity2 when adding starting window
2952         // on activity2.
2953         topActivity.addStartingWindow(mPackageName, android.R.style.Theme, activity, false, false,
2954                 false, true, false, false, false);
2955         waitUntilHandlersIdle();
2956         assertTrue(topActivity.hasFixedRotationTransform());
2957     }
2958 
2959     @Test
testTryTransferStartingWindowFromHiddenAboveToken()2960     public void testTryTransferStartingWindowFromHiddenAboveToken() {
2961         registerTestStartingWindowOrganizer();
2962         // Add two tasks on top of each other.
2963         final ActivityRecord activityTop = new ActivityBuilder(mAtm).setCreateTask(true).build();
2964         final ActivityRecord activityBottom = new ActivityBuilder(mAtm).build();
2965         activityTop.getTask().addChild(activityBottom, 0);
2966 
2967         // Add a starting window.
2968         activityTop.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false,
2969                 true, false, false, false);
2970         waitUntilHandlersIdle();
2971 
2972         final WindowState startingWindow = activityTop.mStartingWindow;
2973         assertNotNull(startingWindow);
2974 
2975         // Make the top one invisible, and try transferring the starting window from the top to the
2976         // bottom one.
2977         activityTop.setVisibility(false);
2978         activityBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded();
2979         waitUntilHandlersIdle();
2980 
2981         // Expect getFrozenInsetsState will be null when transferring the starting window.
2982         assertNull(startingWindow.getFrozenInsetsState());
2983 
2984         // Assert that the bottom window now has the starting window.
2985         assertNoStartingWindow(activityTop);
2986         assertHasStartingWindow(activityBottom);
2987     }
2988 
2989     @Test
testStartingWindowInTaskFragment()2990     public void testStartingWindowInTaskFragment() {
2991         final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
2992         final WindowState startingWindow = createWindowState(
2993                 new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING), activity1);
2994         activity1.addWindow(startingWindow);
2995         activity1.mStartingData = mock(StartingData.class);
2996         activity1.attachStartingWindow(startingWindow);
2997         final Task task = activity1.getTask();
2998         final Rect taskBounds = task.getBounds();
2999         final int width = taskBounds.width();
3000         final int height = taskBounds.height();
3001         final BiConsumer<TaskFragment, Rect> fragmentSetup = (fragment, bounds) -> {
3002             final Configuration config = fragment.getRequestedOverrideConfiguration();
3003             config.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
3004             config.windowConfiguration.setBounds(bounds);
3005             fragment.onRequestedOverrideConfigurationChanged(config);
3006         };
3007 
3008         final TaskFragment taskFragment1 = new TaskFragment(
3009                 mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
3010         fragmentSetup.accept(taskFragment1, new Rect(0, 0, width / 2, height));
3011         task.addChild(taskFragment1, POSITION_TOP);
3012         assertEquals(task, activity1.mStartingData.mAssociatedTask);
3013         assertEquals(activity1.mStartingData, task.mSharedStartingData);
3014 
3015         final TaskFragment taskFragment2 = new TaskFragment(
3016                 mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
3017         fragmentSetup.accept(taskFragment2, new Rect(width / 2, 0, width, height));
3018         task.addChild(taskFragment2, POSITION_TOP);
3019         final ActivityRecord activity2 = new ActivityBuilder(mAtm)
3020                 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE).build();
3021         activity2.setVisibleRequested(true);
3022         taskFragment2.addChild(activity2);
3023         assertTrue(activity2.isResizeable());
3024         activity1.reparent(taskFragment1, POSITION_TOP);
3025 
3026         // Adds an Activity which doesn't have shared starting data, and verify if it blocks
3027         // starting window removal.
3028         final ActivityRecord activity3 = new ActivityBuilder(mAtm).build();
3029         taskFragment2.addChild(activity3, POSITION_TOP);
3030 
3031         verify(activity1.getSyncTransaction()).reparent(eq(startingWindow.mSurfaceControl),
3032                 eq(task.mSurfaceControl));
3033         assertEquals(task.mSurfaceControl, startingWindow.getAnimationLeashParent());
3034         assertEquals(taskFragment1.getBounds(), activity1.getBounds());
3035         // The activity was resized by task fragment, but starting window must still cover the task.
3036         assertEquals(taskBounds, activity1.mStartingWindow.getBounds());
3037 
3038         // The starting window is only removed when all embedded activities are drawn.
3039         final WindowState activityWindow = mock(WindowState.class);
3040         activity1.onFirstWindowDrawn(activityWindow);
3041         activity2.onFirstWindowDrawn(activityWindow);
3042         assertNull(activity1.mStartingWindow);
3043         assertNull(task.mSharedStartingData);
3044     }
3045 
3046     @Test
testTransitionAnimationBounds()3047     public void testTransitionAnimationBounds() {
3048         removeGlobalMinSizeRestriction();
3049         final Task task = new TaskBuilder(mSupervisor)
3050                 .setCreateParentTask(true).setCreateActivity(true).build();
3051         final Task rootTask = task.getRootTask();
3052         final ActivityRecord activity = task.getTopNonFinishingActivity();
3053         final Rect stackBounds = new Rect(0, 0, 1000, 600);
3054         final Rect taskBounds = new Rect(100, 400, 600, 800);
3055         // Set the bounds and windowing mode to window configuration directly, otherwise the
3056         // testing setups may be discarded by configuration resolving.
3057         rootTask.getWindowConfiguration().setBounds(stackBounds);
3058         task.getWindowConfiguration().setBounds(taskBounds);
3059         activity.getWindowConfiguration().setBounds(taskBounds);
3060 
3061         // Check that anim bounds for freeform window match task bounds
3062         task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
3063         assertEquals(task.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_NONE));
3064 
3065         // ROOT_TASK_CLIP_AFTER_ANIM should use task bounds since they will be clipped by
3066         // bounds animation layer.
3067         task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
3068         assertEquals(task.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM));
3069 
3070         // Even the activity is smaller than task and it is not aligned to the top-left corner of
3071         // task, the animation bounds the same as task and position should be zero because in real
3072         // case the letterbox will fill the remaining area in task.
3073         final Rect halfBounds = new Rect(taskBounds);
3074         halfBounds.scale(0.5f);
3075         activity.getWindowConfiguration().setBounds(halfBounds);
3076         final Point animationPosition = new Point();
3077         activity.getAnimationPosition(animationPosition);
3078 
3079         assertEquals(taskBounds, activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM));
3080         assertEquals(new Point(0, 0), animationPosition);
3081     }
3082 
3083     @Test
testTransitionAnimationBounds_returnTaskFragment()3084     public void testTransitionAnimationBounds_returnTaskFragment() {
3085         removeGlobalMinSizeRestriction();
3086         final Task task = new TaskBuilder(mSupervisor).setCreateParentTask(true).build();
3087         final Task rootTask = task.getRootTask();
3088         final TaskFragment taskFragment = createTaskFragmentWithActivity(task);
3089         final ActivityRecord activity = taskFragment.getTopNonFinishingActivity();
3090         final Rect stackBounds = new Rect(0, 0, 1000, 600);
3091         final Rect taskBounds = new Rect(100, 400, 600, 800);
3092         final Rect taskFragmentBounds = new Rect(100, 400, 300, 800);
3093         final Rect activityBounds = new Rect(100, 400, 300, 600);
3094         // Set the bounds and windowing mode to window configuration directly, otherwise the
3095         // testing setups may be discarded by configuration resolving.
3096         rootTask.getWindowConfiguration().setBounds(stackBounds);
3097         task.getWindowConfiguration().setBounds(taskBounds);
3098         taskFragment.getWindowConfiguration().setBounds(taskFragmentBounds);
3099         activity.getWindowConfiguration().setBounds(activityBounds);
3100 
3101         // Check that anim bounds for freeform window match task fragment bounds
3102         task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM);
3103         assertEquals(taskFragment.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_NONE));
3104 
3105         // ROOT_TASK_CLIP_AFTER_ANIM should use task fragment bounds since they will be clipped by
3106         // bounds animation layer.
3107         task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN);
3108         assertEquals(taskFragment.getBounds(),
3109                 activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM));
3110     }
3111 
3112     @Test
testHasStartingWindow()3113     public void testHasStartingWindow() {
3114         final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
3115         final WindowManager.LayoutParams attrs =
3116                 new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING);
3117         final TestWindowState startingWindow = createWindowState(attrs, activity);
3118         activity.mStartingData = mock(StartingData.class);
3119         activity.addWindow(startingWindow);
3120         assertTrue("Starting window should be present", activity.hasStartingWindow());
3121         activity.mStartingData = null;
3122         assertTrue("Starting window should be present", activity.hasStartingWindow());
3123 
3124         activity.removeChild(startingWindow);
3125         assertFalse("Starting window should not be present", activity.hasStartingWindow());
3126     }
3127 
3128     @Test
testCloseToSquareFixedOrientation()3129     public void testCloseToSquareFixedOrientation() {
3130         // create a square display
3131         final DisplayContent squareDisplay = new TestDisplayContent.Builder(mAtm, 2000, 2000)
3132                 .setSystemDecorations(true).build();
3133         // Add a decor insets provider window.
3134         final WindowState navbar = createNavBarWithProvidedInsets(squareDisplay);
3135         assertTrue(navbar.providesDisplayDecorInsets()
3136                 && squareDisplay.getDisplayPolicy().updateDecorInsetsInfo());
3137         squareDisplay.sendNewConfiguration();
3138         final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
3139 
3140         // create a fixed portrait activity
3141         ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
3142                 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT).build();
3143 
3144         // The available space could be landscape because of decor insets, but the configuration
3145         // should still respect the requested portrait orientation.
3146         assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
3147         assertTrue(activity.getConfiguration().windowConfiguration.getAppBounds().width()
3148                 <= activity.getConfiguration().windowConfiguration.getAppBounds().height());
3149 
3150         // create a fixed landscape activity
3151         activity = new ActivityBuilder(mAtm).setTask(task)
3152                 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE).build();
3153 
3154         // check that both the configuration and app bounds are landscape
3155         assertEquals(ORIENTATION_LANDSCAPE, activity.getConfiguration().orientation);
3156         assertTrue(activity.getConfiguration().windowConfiguration.getAppBounds().width()
3157                 > activity.getConfiguration().windowConfiguration.getAppBounds().height());
3158     }
3159 
3160     @Test
testSetVisibility_visibleToVisible()3161     public void testSetVisibility_visibleToVisible() {
3162         final ActivityRecord activity = new ActivityBuilder(mAtm)
3163                 .setCreateTask(true).build();
3164         // By default, activity is visible.
3165         assertTrue(activity.isVisible());
3166         assertTrue(activity.isVisibleRequested());
3167         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3168         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3169 
3170         // Request the activity to be visible. Although the activity is already visible, app
3171         // transition animation should be applied on this activity. This might be unnecessary, but
3172         // until we verify no logic relies on this behavior, we'll keep this as is.
3173         activity.setVisibility(true);
3174         assertTrue(activity.isVisible());
3175         assertTrue(activity.isVisibleRequested());
3176         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3177         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3178     }
3179 
3180     @Test
testSetVisibility_visibleToInvisible()3181     public void testSetVisibility_visibleToInvisible() {
3182         final ActivityRecord activity = new ActivityBuilder(mAtm)
3183                 .setCreateTask(true).build();
3184         // By default, activity is visible.
3185         assertTrue(activity.isVisible());
3186         assertTrue(activity.isVisibleRequested());
3187         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3188         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3189 
3190         // Request the activity to be invisible. Since the visibility changes, app transition
3191         // animation should be applied on this activity.
3192         activity.setVisibility(false);
3193         assertTrue(activity.isVisible());
3194         assertFalse(activity.isVisibleRequested());
3195         assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity));
3196         assertTrue(activity.mDisplayContent.mClosingApps.contains(activity));
3197     }
3198 
3199     @Test
testSetVisibility_invisibleToVisible()3200     public void testSetVisibility_invisibleToVisible() {
3201         final ActivityRecord activity = new ActivityBuilder(mAtm)
3202                 .setCreateTask(true).setVisible(false).build();
3203         // Activiby is invisible. However ATMS requests it to become visible, since this is a top
3204         // activity.
3205         assertFalse(activity.isVisible());
3206         assertTrue(activity.isVisibleRequested());
3207         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3208         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3209 
3210         // Request the activity to be visible. Since the visibility changes, app transition
3211         // animation should be applied on this activity.
3212         activity.setVisibility(true);
3213         assertFalse(activity.isVisible());
3214         assertTrue(activity.isVisibleRequested());
3215         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3216         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3217 
3218         // There should still be animation (add to opening) if keyguard is going away while the
3219         // screen is off because it will be visible after screen is turned on by unlocking.
3220         mDisplayContent.mOpeningApps.remove(activity);
3221         mDisplayContent.mClosingApps.remove(activity);
3222         activity.commitVisibility(false /* visible */, false /* performLayout */);
3223         mDisplayContent.getDisplayPolicy().screenTurnedOff();
3224         final KeyguardController controller = mSupervisor.getKeyguardController();
3225         doReturn(true).when(controller).isKeyguardGoingAway(anyInt());
3226         activity.setVisibility(true);
3227         assertTrue(mDisplayContent.mOpeningApps.contains(activity));
3228     }
3229 
3230     @Test
testSetVisibility_invisibleToInvisible()3231     public void testSetVisibility_invisibleToInvisible() {
3232         final ActivityRecord activity = new ActivityBuilder(mAtm)
3233                 .setCreateTask(true).setVisible(false).build();
3234         // Activiby is invisible. However ATMS requests it to become visible, since this is a top
3235         // activity.
3236         assertFalse(activity.isVisible());
3237         assertTrue(activity.isVisibleRequested());
3238         assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity));
3239         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3240 
3241         // Request the activity to be invisible. Since the activity is already invisible, no app
3242         // transition should be applied on this activity.
3243         activity.setVisibility(false);
3244         assertFalse(activity.isVisible());
3245         assertFalse(activity.isVisibleRequested());
3246         assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity));
3247         assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
3248     }
3249 
3250     @SetupWindows(addWindows = W_INPUT_METHOD)
3251     @Test
testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity()3252     public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() {
3253         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
3254         makeWindowVisibleAndDrawn(app, mImeWindow);
3255         mDisplayContent.setImeLayeringTarget(app);
3256         mDisplayContent.setImeInputTarget(app);
3257 
3258         // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
3259         mDisplayContent.mOpeningApps.clear();
3260         app.mActivityRecord.commitVisibility(false, false);
3261         app.mActivityRecord.onWindowsGone();
3262 
3263         assertTrue(app.mActivityRecord.mLastImeShown);
3264         assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3265 
3266         // Expect IME insets frozen state will reset when the activity has no IME focusable window.
3267         app.mActivityRecord.forAllWindows(w -> {
3268             w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
3269             return true;
3270         }, true);
3271 
3272         app.mActivityRecord.commitVisibility(true, false);
3273         app.mActivityRecord.onWindowsVisible();
3274 
3275         assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3276     }
3277 
3278     @SetupWindows(addWindows = W_INPUT_METHOD)
3279     @Test
testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget()3280     public void testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget() {
3281         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
3282 
3283         mDisplayContent.getInsetsStateController().getImeSourceProvider().setWindowContainer(
3284                 mImeWindow, null, null);
3285         mImeWindow.getControllableInsetProvider().setServerVisible(true);
3286 
3287         InsetsSource imeSource = new InsetsSource(ID_IME, ime());
3288         app.mAboveInsetsState.addSource(imeSource);
3289         mDisplayContent.setImeLayeringTarget(app);
3290         mDisplayContent.updateImeInputAndControlTarget(app);
3291 
3292         InsetsState state = app.getInsetsState();
3293         assertFalse(state.getOrCreateSource(imeSource.getId(), ime()).isVisible());
3294         assertTrue(state.getOrCreateSource(imeSource.getId(), ime()).getFrame().isEmpty());
3295 
3296         // Simulate app is closing and expect IME insets is frozen.
3297         mDisplayContent.mOpeningApps.clear();
3298         app.mActivityRecord.commitVisibility(false, false);
3299         app.mActivityRecord.onWindowsGone();
3300         assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3301 
3302         // Simulate app re-start input or turning screen off/on then unlocked by un-secure
3303         // keyguard to back to the app, expect IME insets is not frozen
3304         app.mActivityRecord.commitVisibility(true, false);
3305         mDisplayContent.updateImeInputAndControlTarget(app);
3306         mDisplayContent.mWmService.mRoot.performSurfacePlacement();
3307 
3308         assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3309 
3310         imeSource.setVisible(true);
3311         imeSource.setFrame(new Rect(100, 400, 500, 500));
3312         app.mAboveInsetsState.addSource(imeSource);
3313 
3314         // Verify when IME is visible and the app can receive the right IME insets from policy.
3315         makeWindowVisibleAndDrawn(app, mImeWindow);
3316         state = app.getInsetsState();
3317         assertTrue(state.peekSource(ID_IME).isVisible());
3318         assertEquals(state.peekSource(ID_IME).getFrame(), imeSource.getFrame());
3319     }
3320 
3321     @SetupWindows(addWindows = { W_ACTIVITY, W_INPUT_METHOD })
3322     @Test
testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest()3323     public void testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest()
3324             throws RemoteException {
3325         final WindowState app1 = createWindow(null, TYPE_APPLICATION, "app1");
3326         final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
3327 
3328         mDisplayContent.getInsetsStateController().getImeSourceProvider().setWindowContainer(
3329                 mImeWindow, null, null);
3330         mImeWindow.getControllableInsetProvider().setServerVisible(true);
3331 
3332         // Simulate app2 is closing and let app1 is visible to be IME targets.
3333         makeWindowVisibleAndDrawn(app1, mImeWindow);
3334         mDisplayContent.setImeLayeringTarget(app1);
3335         mDisplayContent.updateImeInputAndControlTarget(app1);
3336         app2.mActivityRecord.commitVisibility(false, false);
3337 
3338         // app1 requests IME visible.
3339         app1.setRequestedVisibleTypes(ime(), ime());
3340         mDisplayContent.getInsetsStateController().onRequestedVisibleTypesChanged(app1);
3341 
3342         // Verify app1's IME insets is visible and app2's IME insets frozen flag set.
3343         assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible());
3344         assertTrue(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3345 
3346         // Simulate switching to app2 to make it visible to be IME targets.
3347         spyOn(app2);
3348         spyOn(app2.mClient);
3349         ArgumentCaptor<InsetsState> insetsStateCaptor = ArgumentCaptor.forClass(InsetsState.class);
3350         doReturn(true).when(app2).isReadyToDispatchInsetsState();
3351         mDisplayContent.setImeLayeringTarget(app2);
3352         app2.mActivityRecord.commitVisibility(true, false);
3353         mDisplayContent.updateImeInputAndControlTarget(app2);
3354         mDisplayContent.mWmService.mRoot.performSurfacePlacement();
3355 
3356         // Verify after unfreezing app2's IME insets state, we won't dispatch visible IME insets
3357         // to client if the app didn't request IME visible.
3358         assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
3359         verify(app2.mClient, atLeastOnce()).resized(any(), anyBoolean(), any(),
3360                 insetsStateCaptor.capture(), anyBoolean(), anyBoolean(), anyInt(), anyInt(),
3361                 anyBoolean());
3362         assertFalse(app2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime()));
3363     }
3364 
3365     @Test
testImeInsetsFrozenFlag_multiWindowActivities()3366     public void testImeInsetsFrozenFlag_multiWindowActivities() {
3367         final WindowToken imeToken = createTestWindowToken(TYPE_INPUT_METHOD, mDisplayContent);
3368         final WindowState ime = createWindow(null, TYPE_INPUT_METHOD, imeToken, "ime");
3369         makeWindowVisibleAndDrawn(ime);
3370 
3371         // Create a split-screen root task with activity1 and activity 2.
3372         final Task task = new TaskBuilder(mSupervisor)
3373                 .setCreateParentTask(true).setCreateActivity(true).build();
3374         task.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
3375         final ActivityRecord activity1 = task.getTopNonFinishingActivity();
3376         activity1.getTask().setResumedActivity(activity1, "testApp1");
3377 
3378         final ActivityRecord activity2 = new TaskBuilder(mSupervisor)
3379                 .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW)
3380                 .setCreateActivity(true).build().getTopMostActivity();
3381         activity2.getTask().setResumedActivity(activity2, "testApp2");
3382         activity2.getTask().setParent(task.getRootTask());
3383 
3384         // Simulate activity1 and activity2 both have set mImeInsetsFrozenUntilStartInput when
3385         // invisible to user.
3386         activity1.mImeInsetsFrozenUntilStartInput = true;
3387         activity2.mImeInsetsFrozenUntilStartInput = true;
3388 
3389         final WindowState app1 = createWindow(null, TYPE_APPLICATION, activity1, "app1");
3390         final WindowState app2 = createWindow(null, TYPE_APPLICATION, activity2, "app2");
3391         makeWindowVisibleAndDrawn(app1, app2);
3392 
3393         final InsetsStateController controller = mDisplayContent.getInsetsStateController();
3394         controller.getImeSourceProvider().setWindowContainer(
3395                 ime, null, null);
3396         ime.getControllableInsetProvider().setServerVisible(true);
3397 
3398         // app1 starts input and expect IME insets for all activities in split-screen will be
3399         // frozen until the input started.
3400         mDisplayContent.setImeLayeringTarget(app1);
3401         mDisplayContent.updateImeInputAndControlTarget(app1);
3402         mDisplayContent.mWmService.mRoot.performSurfacePlacement();
3403 
3404         assertEquals(app1, mDisplayContent.getImeInputTarget());
3405         assertFalse(activity1.mImeInsetsFrozenUntilStartInput);
3406         assertFalse(activity2.mImeInsetsFrozenUntilStartInput);
3407 
3408         app1.setRequestedVisibleTypes(ime());
3409         controller.onRequestedVisibleTypesChanged(app1);
3410 
3411         // Expect all activities in split-screen will get IME insets visible state
3412         assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible());
3413         assertTrue(app2.getInsetsState().peekSource(ID_IME).isVisible());
3414     }
3415 
3416     @Test
testInClosingAnimation_visibilityNotCommitted_doNotHideSurface()3417     public void testInClosingAnimation_visibilityNotCommitted_doNotHideSurface() {
3418         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
3419         makeWindowVisibleAndDrawn(app);
3420 
3421         // Put the activity in close transition.
3422         mDisplayContent.mOpeningApps.clear();
3423         mDisplayContent.mClosingApps.add(app.mActivityRecord);
3424         mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
3425 
3426         // Remove window during transition, so it is requested to hide, but won't be committed until
3427         // the transition is finished.
3428         app.mActivityRecord.onRemovedFromDisplay();
3429 
3430         assertTrue(mDisplayContent.mClosingApps.contains(app.mActivityRecord));
3431         assertFalse(app.mActivityRecord.isVisibleRequested());
3432         assertTrue(app.mActivityRecord.isVisible());
3433         assertTrue(app.mActivityRecord.isSurfaceShowing());
3434 
3435         // Start transition.
3436         app.mActivityRecord.prepareSurfaces();
3437 
3438         // Because the app is waiting for transition, it should not hide the surface.
3439         assertTrue(app.mActivityRecord.isSurfaceShowing());
3440     }
3441 
3442     @Test
testInClosingAnimation_visibilityCommitted_hideSurface()3443     public void testInClosingAnimation_visibilityCommitted_hideSurface() {
3444         final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
3445         makeWindowVisibleAndDrawn(app);
3446 
3447         // Put the activity in close transition.
3448         mDisplayContent.mOpeningApps.clear();
3449         mDisplayContent.mClosingApps.add(app.mActivityRecord);
3450         mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
3451 
3452         // Commit visibility before start transition.
3453         app.mActivityRecord.commitVisibility(false, false);
3454 
3455         assertFalse(app.mActivityRecord.isVisibleRequested());
3456         assertFalse(app.mActivityRecord.isVisible());
3457         assertTrue(app.mActivityRecord.isSurfaceShowing());
3458 
3459         // Start transition.
3460         app.mActivityRecord.prepareSurfaces();
3461 
3462         // Because the app visibility has been committed before the transition start, it should hide
3463         // the surface.
3464         assertFalse(app.mActivityRecord.isSurfaceShowing());
3465     }
3466 
3467     @Test
testUpdateCameraCompatState_flagIsEnabled_controlStateIsUpdated()3468     public void testUpdateCameraCompatState_flagIsEnabled_controlStateIsUpdated() {
3469         final ActivityRecord activity = createActivityWithTask();
3470         // Mock a flag being enabled.
3471         doReturn(true).when(activity).isCameraCompatControlEnabled();
3472 
3473         activity.updateCameraCompatState(/* showControl */ true,
3474                 /* transformationApplied */ false, /* callback */ null);
3475 
3476         assertEquals(activity.getCameraCompatControlState(),
3477                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3478 
3479         activity.updateCameraCompatState(/* showControl */ true,
3480                 /* transformationApplied */ true, /* callback */ null);
3481 
3482         assertEquals(activity.getCameraCompatControlState(),
3483                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3484 
3485         activity.updateCameraCompatState(/* showControl */ false,
3486                 /* transformationApplied */ false, /* callback */ null);
3487 
3488         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3489 
3490         activity.updateCameraCompatState(/* showControl */ false,
3491                 /* transformationApplied */ true, /* callback */ null);
3492 
3493         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3494     }
3495 
3496     @Test
testUpdateCameraCompatState_flagIsDisabled_controlStateIsHidden()3497     public void testUpdateCameraCompatState_flagIsDisabled_controlStateIsHidden() {
3498         final ActivityRecord activity = createActivityWithTask();
3499         // Mock a flag being disabled.
3500         doReturn(false).when(activity).isCameraCompatControlEnabled();
3501 
3502         activity.updateCameraCompatState(/* showControl */ true,
3503                 /* transformationApplied */ false, /* callback */ null);
3504 
3505         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3506 
3507         activity.updateCameraCompatState(/* showControl */ true,
3508                 /* transformationApplied */ true, /* callback */ null);
3509 
3510         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3511     }
3512 
3513     @Test
testUpdateCameraCompatStateFromUser_clickedOnDismiss()3514     public void testUpdateCameraCompatStateFromUser_clickedOnDismiss() throws RemoteException {
3515         final ActivityRecord activity = createActivityWithTask();
3516         // Mock a flag being enabled.
3517         doReturn(true).when(activity).isCameraCompatControlEnabled();
3518 
3519         ICompatCameraControlCallback callback = getCompatCameraControlCallback();
3520         spyOn(callback);
3521         activity.updateCameraCompatState(/* showControl */ true,
3522                 /* transformationApplied */ false, callback);
3523 
3524         assertEquals(activity.getCameraCompatControlState(),
3525                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3526 
3527         // Clicking on the button.
3528         activity.updateCameraCompatStateFromUser(CAMERA_COMPAT_CONTROL_DISMISSED);
3529 
3530         verify(callback, never()).revertCameraCompatTreatment();
3531         verify(callback, never()).applyCameraCompatTreatment();
3532         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED);
3533 
3534         // All following updates are ignored.
3535         activity.updateCameraCompatState(/* showControl */ true,
3536                 /* transformationApplied */ false, /* callback */ null);
3537 
3538         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED);
3539 
3540         activity.updateCameraCompatState(/* showControl */ true,
3541                 /* transformationApplied */ true, /* callback */ null);
3542 
3543         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED);
3544 
3545         activity.updateCameraCompatState(/* showControl */ false,
3546                 /* transformationApplied */ true, /* callback */ null);
3547 
3548         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED);
3549     }
3550 
3551     @Test
testUpdateCameraCompatStateFromUser_clickedOnApplyTreatment()3552     public void testUpdateCameraCompatStateFromUser_clickedOnApplyTreatment()
3553             throws RemoteException {
3554         final ActivityRecord activity = createActivityWithTask();
3555         // Mock a flag being enabled.
3556         doReturn(true).when(activity).isCameraCompatControlEnabled();
3557 
3558         ICompatCameraControlCallback callback = getCompatCameraControlCallback();
3559         spyOn(callback);
3560         activity.updateCameraCompatState(/* showControl */ true,
3561                 /* transformationApplied */ false, callback);
3562 
3563         assertEquals(activity.getCameraCompatControlState(),
3564                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3565 
3566         // Clicking on the button.
3567         activity.updateCameraCompatStateFromUser(CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3568 
3569         verify(callback, never()).revertCameraCompatTreatment();
3570         verify(callback).applyCameraCompatTreatment();
3571         assertEquals(activity.getCameraCompatControlState(),
3572                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3573 
3574         // Request from the client to show the control are ignored respecting the user choice.
3575         activity.updateCameraCompatState(/* showControl */ true,
3576                 /* transformationApplied */ false, /* callback */ null);
3577 
3578         assertEquals(activity.getCameraCompatControlState(),
3579                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3580 
3581         // Request from the client to hide the control is respected.
3582         activity.updateCameraCompatState(/* showControl */ false,
3583                 /* transformationApplied */ true, /* callback */ null);
3584 
3585         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3586 
3587         // Request from the client to show the control again is respected.
3588         activity.updateCameraCompatState(/* showControl */ true,
3589                 /* transformationApplied */ false, /* callback */ null);
3590 
3591         assertEquals(activity.getCameraCompatControlState(),
3592                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3593     }
3594 
3595     @Test
testUpdateCameraCompatStateFromUser_clickedOnRevertTreatment()3596     public void testUpdateCameraCompatStateFromUser_clickedOnRevertTreatment()
3597             throws RemoteException {
3598         final ActivityRecord activity = createActivityWithTask();
3599         // Mock a flag being enabled.
3600         doReturn(true).when(activity).isCameraCompatControlEnabled();
3601 
3602         ICompatCameraControlCallback callback = getCompatCameraControlCallback();
3603         spyOn(callback);
3604         activity.updateCameraCompatState(/* showControl */ true,
3605                 /* transformationApplied */ true, callback);
3606 
3607         assertEquals(activity.getCameraCompatControlState(),
3608                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3609 
3610         // Clicking on the button.
3611         activity.updateCameraCompatStateFromUser(CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3612 
3613         verify(callback).revertCameraCompatTreatment();
3614         verify(callback, never()).applyCameraCompatTreatment();
3615         assertEquals(activity.getCameraCompatControlState(),
3616                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3617 
3618         // Request from the client to show the control are ignored respecting the user choice.
3619         activity.updateCameraCompatState(/* showControl */ true,
3620                 /* transformationApplied */ true, /* callback */ null);
3621 
3622         assertEquals(activity.getCameraCompatControlState(),
3623                 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED);
3624 
3625         // Request from the client to hide the control is respected.
3626         activity.updateCameraCompatState(/* showControl */ false,
3627                 /* transformationApplied */ true, /* callback */ null);
3628 
3629         assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN);
3630 
3631         // Request from the client to show the control again is respected.
3632         activity.updateCameraCompatState(/* showControl */ true,
3633                 /* transformationApplied */ true, /* callback */ null);
3634 
3635         assertEquals(activity.getCameraCompatControlState(),
3636                 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED);
3637     }
3638 
3639     @Test // b/162542125
testInputDispatchTimeout()3640     public void testInputDispatchTimeout() throws RemoteException {
3641         final ActivityRecord activity = createActivityWithTask();
3642         final WindowProcessController wpc = activity.app;
3643         spyOn(wpc);
3644         doReturn(true).when(wpc).isInstrumenting();
3645         final ActivityRecord instrumentingActivity = createActivityOnDisplay(
3646                 true /* defaultDisplay */, wpc);
3647         assertEquals(INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS,
3648                 instrumentingActivity.mInputDispatchingTimeoutMillis);
3649 
3650         doReturn(false).when(wpc).isInstrumenting();
3651         final ActivityRecord nonInstrumentingActivity = createActivityOnDisplay(
3652                 true /* defaultDisplay */, wpc);
3653         assertEquals(DEFAULT_DISPATCHING_TIMEOUT_MILLIS,
3654                 nonInstrumentingActivity.mInputDispatchingTimeoutMillis);
3655 
3656         final ActivityRecord noProcActivity = createActivityOnDisplay(true /* defaultDisplay */,
3657                 null);
3658         assertEquals(DEFAULT_DISPATCHING_TIMEOUT_MILLIS,
3659                 noProcActivity.mInputDispatchingTimeoutMillis);
3660     }
3661 
3662     @Test
testEnsureActivitiesVisibleAnotherUserTasks()3663     public void testEnsureActivitiesVisibleAnotherUserTasks() {
3664         // Create an activity with hierarchy:
3665         //    RootTask
3666         //       - TaskFragment
3667         //          - Activity
3668         DisplayContent display = createNewDisplay();
3669         Task rootTask = createTask(display);
3670         ActivityRecord activity = createActivityRecord(rootTask);
3671         final TaskFragment taskFragment = new TaskFragment(mAtm, new Binder(),
3672                 true /* createdByOrganizer */, true /* isEmbedded */);
3673         activity.getTask().addChild(taskFragment, POSITION_TOP);
3674         activity.reparent(taskFragment, POSITION_TOP);
3675 
3676         // Ensure the activity visibility is updated even it is not shown to current user.
3677         activity.setVisibleRequested(true);
3678         doReturn(false).when(activity).showToCurrentUser();
3679         spyOn(taskFragment);
3680         doReturn(false).when(taskFragment).shouldBeVisible(any());
3681         display.ensureActivitiesVisible(null, 0, false, false);
3682         assertFalse(activity.isVisibleRequested());
3683     }
3684 
3685     @Test
testShellTransitionTaskWindowingModeChange()3686     public void testShellTransitionTaskWindowingModeChange() {
3687         final ActivityRecord activity = createActivityWithTask();
3688         final Task task = activity.getTask();
3689         task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
3690 
3691         assertTrue(activity.isVisible());
3692         assertTrue(activity.isVisibleRequested());
3693         assertEquals(WINDOWING_MODE_FULLSCREEN, activity.getWindowingMode());
3694 
3695         registerTestTransitionPlayer();
3696         task.mTransitionController.requestTransitionIfNeeded(TRANSIT_PIP, task);
3697         task.setWindowingMode(WINDOWING_MODE_PINNED);
3698 
3699         // Collect activity in the transition if the Task windowing mode is going to change.
3700         assertTrue(activity.inTransition());
3701     }
3702 
3703     /**
3704      * Verifies the task is moved to back when back pressed if the root activity was originally
3705      * started from Launcher.
3706      */
3707     @Test
testMoveTaskToBackWhenStartedFromLauncher()3708     public void testMoveTaskToBackWhenStartedFromLauncher() {
3709         final Task task = createTask(mDisplayContent);
3710         final ActivityRecord ar = createActivityRecord(task);
3711         task.realActivity = ar.mActivityComponent;
3712         ar.intent.setAction(Intent.ACTION_MAIN);
3713         ar.intent.addCategory(Intent.CATEGORY_LAUNCHER);
3714         doReturn(true).when(ar).isLaunchSourceType(eq(LAUNCH_SOURCE_TYPE_HOME));
3715 
3716         mAtm.mActivityClientController.onBackPressed(ar.token, null /* callback */);
3717         verify(task).moveTaskToBack(any());
3718     }
3719 
getCompatCameraControlCallback()3720     private ICompatCameraControlCallback getCompatCameraControlCallback() {
3721         return new ICompatCameraControlCallback.Stub() {
3722             @Override
3723             public void applyCameraCompatTreatment() {}
3724 
3725             @Override
3726             public void revertCameraCompatTreatment() {}
3727         };
3728     }
3729 
assertHasStartingWindow(ActivityRecord atoken)3730     private void assertHasStartingWindow(ActivityRecord atoken) {
3731         assertNotNull(atoken.mStartingSurface);
3732         assertNotNull(atoken.mStartingData);
3733         assertNotNull(atoken.mStartingWindow);
3734     }
3735 
assertNoStartingWindow(ActivityRecord atoken)3736     private void assertNoStartingWindow(ActivityRecord atoken) {
3737         assertNull(atoken.mStartingSurface);
3738         assertNull(atoken.mStartingWindow);
3739         assertNull(atoken.mStartingData);
3740         atoken.forAllWindows(windowState -> {
3741             assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING);
3742         }, true);
3743     }
3744 }
3745