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