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