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