1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 
17 package com.android.server.wm;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
21 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
22 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
25 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
26 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
27 import static android.os.Process.NOBODY_UID;
28 import static android.view.Display.DEFAULT_DISPLAY;
29 import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
30 
31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
33 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
34 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
35 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
36 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
37 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
38 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
39 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
40 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
43 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
44 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
45 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
46 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
47 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
48 import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
49 import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
50 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
51 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
52 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
53 import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
54 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
55 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
56 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
57 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
58 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
59 
60 import static com.google.common.truth.Truth.assertThat;
61 
62 import static org.junit.Assert.assertEquals;
63 import static org.junit.Assert.assertFalse;
64 import static org.junit.Assert.assertNotEquals;
65 import static org.junit.Assert.assertNotNull;
66 import static org.junit.Assert.assertNull;
67 import static org.junit.Assert.assertTrue;
68 import static org.mockito.ArgumentMatchers.anyInt;
69 import static org.mockito.ArgumentMatchers.anyString;
70 import static org.mockito.Mockito.clearInvocations;
71 import static org.mockito.Mockito.never;
72 
73 import android.app.ActivityManager.TaskSnapshot;
74 import android.app.ActivityOptions;
75 import android.app.WindowConfiguration;
76 import android.app.servertransaction.ActivityConfigurationChangeItem;
77 import android.app.servertransaction.ClientTransaction;
78 import android.app.servertransaction.PauseActivityItem;
79 import android.content.ComponentName;
80 import android.content.Intent;
81 import android.content.pm.ActivityInfo;
82 import android.content.res.Configuration;
83 import android.content.res.Resources;
84 import android.graphics.Rect;
85 import android.os.Bundle;
86 import android.os.PersistableBundle;
87 import android.os.RemoteException;
88 import android.platform.test.annotations.Presubmit;
89 import android.util.MergedConfiguration;
90 import android.util.MutableBoolean;
91 import android.view.DisplayInfo;
92 import android.view.IRemoteAnimationFinishedCallback;
93 import android.view.IRemoteAnimationRunner.Stub;
94 import android.view.IWindowSession;
95 import android.view.RemoteAnimationAdapter;
96 import android.view.RemoteAnimationTarget;
97 import android.view.WindowManager;
98 import android.view.WindowManagerGlobal;
99 
100 import androidx.test.filters.MediumTest;
101 
102 import com.android.internal.R;
103 import com.android.server.wm.ActivityStack.ActivityState;
104 
105 import org.junit.Before;
106 import org.junit.Test;
107 import org.junit.runner.RunWith;
108 import org.mockito.invocation.InvocationOnMock;
109 
110 /**
111  * Tests for the {@link ActivityRecord} class.
112  *
113  * Build/Install/Run:
114  *  atest WmTests:ActivityRecordTests
115  */
116 @MediumTest
117 @Presubmit
118 @RunWith(WindowTestRunner.class)
119 public class ActivityRecordTests extends ActivityTestsBase {
120     private ActivityStack mStack;
121     private Task mTask;
122     private ActivityRecord mActivity;
123 
124     @Before
setUp()125     public void setUp() throws Exception {
126         mStack = new StackBuilder(mRootWindowContainer).build();
127         mTask = mStack.getBottomMostTask();
128         mActivity = mTask.getTopNonFinishingActivity();
129 
130         setBooted(mService);
131     }
132 
133     @Test
testStackCleanupOnClearingTask()134     public void testStackCleanupOnClearingTask() {
135         mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
136         verify(mStack, times(1)).cleanUpActivityReferences(any());
137     }
138 
139     @Test
testStackCleanupOnActivityRemoval()140     public void testStackCleanupOnActivityRemoval() {
141         mTask.removeChild(mActivity);
142         verify(mStack, times(1)).cleanUpActivityReferences(any());
143     }
144 
145     @Test
testStackCleanupOnTaskRemoval()146     public void testStackCleanupOnTaskRemoval() {
147         mStack.removeChild(mTask, null /*reason*/);
148         // Stack should be gone on task removal.
149         assertNull(mService.mRootWindowContainer.getStack(mStack.mTaskId));
150     }
151 
152     @Test
testRemoveChildWithOverlayActivity()153     public void testRemoveChildWithOverlayActivity() {
154         final ActivityRecord overlayActivity =
155                 new ActivityBuilder(mService).setTask(mTask).build();
156         overlayActivity.setTaskOverlay(true);
157         final ActivityRecord overlayActivity2 =
158                 new ActivityBuilder(mService).setTask(mTask).build();
159         overlayActivity2.setTaskOverlay(true);
160 
161         mTask.removeChild(overlayActivity2, "test");
162         verify(mSupervisor, never()).removeTask(any(), anyBoolean(), anyBoolean(), any());
163     }
164 
165     @Test
testNoCleanupMovingActivityInSameStack()166     public void testNoCleanupMovingActivityInSameStack() {
167         final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
168         mActivity.reparent(newTask, 0, null /*reason*/);
169         verify(mStack, times(0)).cleanUpActivityReferences(any());
170     }
171 
172     @Test
testPausingWhenVisibleFromStopped()173     public void testPausingWhenVisibleFromStopped() throws Exception {
174         final MutableBoolean pauseFound = new MutableBoolean(false);
175         doAnswer((InvocationOnMock invocationOnMock) -> {
176             final ClientTransaction transaction = invocationOnMock.getArgument(0);
177             if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
178                 pauseFound.value = true;
179             }
180             return null;
181         }).when(mActivity.app.getThread()).scheduleTransaction(any());
182 
183         mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
184 
185         // The activity is in the focused stack so it should be resumed.
186         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
187         assertTrue(mActivity.isState(RESUMED));
188         assertFalse(pauseFound.value);
189 
190         // Make the activity non focusable
191         mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
192         doReturn(false).when(mActivity).isFocusable();
193 
194         // If the activity is not focusable, it should move to paused.
195         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
196         assertTrue(mActivity.isState(PAUSING));
197         assertTrue(pauseFound.value);
198 
199         // Make sure that the state does not change for current non-stopping states.
200         mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
201         doReturn(true).when(mActivity).isFocusable();
202 
203         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
204 
205         assertTrue(mActivity.isState(INITIALIZING));
206 
207         // Make sure the state does not change if we are not the current top activity.
208         mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
209 
210         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
211         mStack.mTranslucentActivityWaiting = topActivity;
212         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
213         assertTrue(mActivity.isState(STARTED));
214 
215         mStack.mTranslucentActivityWaiting = null;
216         topActivity.setOccludesParent(false);
217         mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
218         mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
219         assertTrue(mActivity.isState(STARTED));
220     }
221 
ensureActivityConfiguration()222     private void ensureActivityConfiguration() {
223         mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
224     }
225 
226     @Test
testCanBeLaunchedOnDisplay()227     public void testCanBeLaunchedOnDisplay() {
228         mService.mSupportsMultiWindow = true;
229         final ActivityRecord activity = new ActivityBuilder(mService).build();
230 
231         // An activity can be launched on default display.
232         assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
233         // An activity cannot be launched on a non-existent display.
234         assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE));
235     }
236 
237     @Test
testsApplyOptionsLocked()238     public void testsApplyOptionsLocked() {
239         ActivityOptions activityOptions = ActivityOptions.makeBasic();
240 
241         // Set and apply options for ActivityRecord. Pending options should be cleared
242         mActivity.updateOptionsLocked(activityOptions);
243         mActivity.applyOptionsLocked();
244         assertNull(mActivity.pendingOptions);
245 
246         // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
247         // Pending options should be cleared for both ActivityRecords
248         ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
249         activity2.updateOptionsLocked(activityOptions);
250         mActivity.updateOptionsLocked(activityOptions);
251         mActivity.applyOptionsLocked();
252         assertNull(mActivity.pendingOptions);
253         assertNull(activity2.pendingOptions);
254 
255         // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
256         // Pending options should be cleared for only ActivityRecord that was applied
257         Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
258         activity2 = new ActivityBuilder(mService).setTask(task2).build();
259         activity2.updateOptionsLocked(activityOptions);
260         mActivity.updateOptionsLocked(activityOptions);
261         mActivity.applyOptionsLocked();
262         assertNull(mActivity.pendingOptions);
263         assertNotNull(activity2.pendingOptions);
264     }
265 
266     @Test
testNewOverrideConfigurationIncrementsSeq()267     public void testNewOverrideConfigurationIncrementsSeq() {
268         final Configuration newConfig = new Configuration();
269 
270         final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
271         mActivity.onRequestedOverrideConfigurationChanged(newConfig);
272         assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
273     }
274 
275     @Test
testNewParentConfigurationIncrementsSeq()276     public void testNewParentConfigurationIncrementsSeq() {
277         final Configuration newConfig = new Configuration(
278                 mTask.getRequestedOverrideConfiguration());
279         newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
280                 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
281 
282         final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
283         mTask.onRequestedOverrideConfigurationChanged(newConfig);
284         assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
285     }
286 
287     @Test
testSetsRelaunchReason_NotDragResizing()288     public void testSetsRelaunchReason_NotDragResizing() {
289         mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
290 
291         mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
292         mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
293                 mActivity.getConfiguration()));
294 
295         mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
296         final Configuration newConfig = new Configuration(mTask.getConfiguration());
297         newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
298                 ? ORIENTATION_LANDSCAPE
299                 : ORIENTATION_PORTRAIT;
300         mTask.onRequestedOverrideConfigurationChanged(newConfig);
301 
302         mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
303 
304         ensureActivityConfiguration();
305 
306         assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
307                 mActivity.mRelaunchReason);
308     }
309 
310     @Test
testSetsRelaunchReason_DragResizing()311     public void testSetsRelaunchReason_DragResizing() {
312         mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
313 
314         mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
315         mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
316                 mActivity.getConfiguration()));
317 
318         mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
319         final Configuration newConfig = new Configuration(mTask.getConfiguration());
320         newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
321                 ? ORIENTATION_LANDSCAPE
322                 : ORIENTATION_PORTRAIT;
323         mTask.onRequestedOverrideConfigurationChanged(newConfig);
324 
325         doReturn(true).when(mTask).isDragResizing();
326 
327         mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
328 
329         ensureActivityConfiguration();
330 
331         assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
332                 mActivity.mRelaunchReason);
333     }
334 
335     @Test
testSetsRelaunchReason_NonResizeConfigChanges()336     public void testSetsRelaunchReason_NonResizeConfigChanges() {
337         mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
338 
339         mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
340         mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
341                 mActivity.getConfiguration()));
342 
343         mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
344         final Configuration newConfig = new Configuration(mTask.getConfiguration());
345         newConfig.fontScale = 5;
346         mTask.onRequestedOverrideConfigurationChanged(newConfig);
347 
348         mActivity.mRelaunchReason =
349                 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
350 
351         ensureActivityConfiguration();
352 
353         assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
354                 mActivity.mRelaunchReason);
355     }
356 
357     @Test
testSetRequestedOrientationUpdatesConfiguration()358     public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
359         mActivity = new ActivityBuilder(mService)
360                 .setTask(mTask)
361                 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
362                 .build();
363         mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
364 
365         mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
366                 mActivity.getConfiguration()));
367 
368         final Configuration newConfig = new Configuration(mActivity.getConfiguration());
369         final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
370         final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
371         if (newConfig.orientation == ORIENTATION_PORTRAIT) {
372             newConfig.orientation = ORIENTATION_LANDSCAPE;
373             newConfig.screenWidthDp = longSide;
374             newConfig.screenHeightDp = shortSide;
375         } else {
376             newConfig.orientation = ORIENTATION_PORTRAIT;
377             newConfig.screenWidthDp = shortSide;
378             newConfig.screenHeightDp = longSide;
379         }
380 
381         // Mimic the behavior that display doesn't handle app's requested orientation.
382         final DisplayContent dc = mTask.getDisplayContent();
383         doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
384         doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
385 
386         final int requestedOrientation;
387         switch (newConfig.orientation) {
388             case ORIENTATION_LANDSCAPE:
389                 requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE;
390                 break;
391             case ORIENTATION_PORTRAIT:
392                 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
393                 break;
394             default:
395                 throw new IllegalStateException("Orientation in new config should be either"
396                         + "landscape or portrait.");
397         }
398         mActivity.setRequestedOrientation(requestedOrientation);
399 
400         final ActivityConfigurationChangeItem expected =
401                 ActivityConfigurationChangeItem.obtain(newConfig);
402         verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
403                 eq(mActivity.appToken), eq(expected));
404     }
405 
406     @Test
ignoreRequestedOrientationInFreeformWindows()407     public void ignoreRequestedOrientationInFreeformWindows() {
408         mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
409         final Rect stableRect = new Rect();
410         mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
411 
412         // Carve out non-decor insets from stableRect
413         final Rect insets = new Rect();
414         final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo();
415         final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy();
416         policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
417                 displayInfo.logicalHeight, displayInfo.displayCutout, insets);
418         policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
419         Task.intersectWithInsetsIfFits(stableRect, stableRect, insets);
420 
421         final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
422         final Rect bounds = new Rect(stableRect);
423         if (isScreenPortrait) {
424             // Landscape bounds
425             final int newHeight = stableRect.width() - 10;
426             bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
427             bounds.bottom = bounds.top + newHeight;
428         } else {
429             // Portrait bounds
430             final int newWidth = stableRect.height() - 10;
431             bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
432             bounds.right = bounds.left + newWidth;
433         }
434         mTask.setBounds(bounds);
435 
436         // Requests orientation that's different from its bounds.
437         mActivity.setRequestedOrientation(
438                 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
439 
440         // Asserts it has orientation derived from bounds.
441         assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
442                 mActivity.getConfiguration().orientation);
443     }
444 
445     @Test
ignoreRequestedOrientationInSplitWindows()446     public void ignoreRequestedOrientationInSplitWindows() {
447         mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
448         final Rect stableRect = new Rect();
449         mStack.getDisplay().getStableRect(stableRect);
450 
451         // Carve out non-decor insets from stableRect
452         final Rect insets = new Rect();
453         final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo();
454         final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy();
455         policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
456                 displayInfo.logicalHeight, displayInfo.displayCutout, insets);
457         policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
458         Task.intersectWithInsetsIfFits(stableRect, stableRect, insets);
459 
460         final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
461         final Rect bounds = new Rect(stableRect);
462         if (isScreenPortrait) {
463             // Landscape bounds
464             final int newHeight = stableRect.width() - 10;
465             bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
466             bounds.bottom = bounds.top + newHeight;
467         } else {
468             // Portrait bounds
469             final int newWidth = stableRect.height() - 10;
470             bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
471             bounds.right = bounds.left + newWidth;
472         }
473         mTask.setBounds(bounds);
474 
475         // Requests orientation that's different from its bounds.
476         mActivity.setRequestedOrientation(
477                 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
478 
479         // Asserts it has orientation derived from bounds.
480         assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
481                 mActivity.getConfiguration().orientation);
482     }
483 
484     @Test
testShouldMakeActive_deferredResume()485     public void testShouldMakeActive_deferredResume() {
486         mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
487 
488         mSupervisor.beginDeferResume();
489         assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
490 
491         mSupervisor.endDeferResume();
492         assertEquals(true, mActivity.shouldMakeActive(null /* activeActivity */));
493     }
494 
495     @Test
testShouldMakeActive_nonTopVisible()496     public void testShouldMakeActive_nonTopVisible() {
497         ActivityRecord finishingActivity = new ActivityBuilder(mService).setTask(mTask).build();
498         finishingActivity.finishing = true;
499         ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
500         mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
501 
502         assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
503     }
504 
505     @Test
testShouldResume_stackVisibility()506     public void testShouldResume_stackVisibility() {
507         mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
508         spyOn(mStack);
509 
510         doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
511         assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
512 
513         doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
514         assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
515 
516         doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
517         assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
518     }
519 
520     @Test
testShouldResumeOrPauseWithResults()521     public void testShouldResumeOrPauseWithResults() {
522         mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
523         spyOn(mStack);
524 
525         ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
526         mActivity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
527         topActivity.finishing = true;
528 
529         doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
530         assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
531         assertEquals(false, mActivity.shouldPauseActivity(null /*activeActivity */));
532     }
533 
534     @Test
testPushConfigurationWhenLaunchTaskBehind()535     public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
536         mActivity = new ActivityBuilder(mService)
537                 .setTask(mTask)
538                 .setLaunchTaskBehind(true)
539                 .setConfigChanges(CONFIG_ORIENTATION)
540                 .build();
541         mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
542 
543         final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
544         try {
545             doReturn(false).when(stack).isTranslucent(any());
546             assertFalse(mStack.shouldBeVisible(null /* starting */));
547 
548             mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
549                     mActivity.getConfiguration()));
550 
551             final Configuration newConfig = new Configuration(mActivity.getConfiguration());
552             final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
553             final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
554             if (newConfig.orientation == ORIENTATION_PORTRAIT) {
555                 newConfig.orientation = ORIENTATION_LANDSCAPE;
556                 newConfig.screenWidthDp = longSide;
557                 newConfig.screenHeightDp = shortSide;
558             } else {
559                 newConfig.orientation = ORIENTATION_PORTRAIT;
560                 newConfig.screenWidthDp = shortSide;
561                 newConfig.screenHeightDp = longSide;
562             }
563 
564             mTask.onConfigurationChanged(newConfig);
565 
566             mActivity.ensureActivityConfiguration(0 /* globalChanges */,
567                     false /* preserveWindow */, true /* ignoreStopState */);
568 
569             final ActivityConfigurationChangeItem expected =
570                     ActivityConfigurationChangeItem.obtain(newConfig);
571             verify(mService.getLifecycleManager()).scheduleTransaction(
572                     eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
573         } finally {
574             stack.getDisplayArea().removeChild(stack);
575         }
576     }
577 
578     @Test
testShouldStartWhenMakeClientActive()579     public void testShouldStartWhenMakeClientActive() {
580         ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
581         topActivity.setOccludesParent(false);
582         mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
583         mActivity.setVisibility(true);
584         mActivity.makeActiveIfNeeded(null /* activeActivity */);
585         assertEquals(STARTED, mActivity.getState());
586     }
587 
588     @Test
testTakeOptions()589     public void testTakeOptions() {
590         ActivityOptions opts = ActivityOptions.makeRemoteAnimation(
591                 new RemoteAnimationAdapter(new Stub() {
592 
593                     @Override
594                     public void onAnimationStart(RemoteAnimationTarget[] apps,
595                             RemoteAnimationTarget[] wallpapers,
596                             IRemoteAnimationFinishedCallback finishedCallback) {
597 
598                     }
599 
600                     @Override
601                     public void onAnimationCancelled() {
602 
603                     }
604                 }, 0, 0));
605         mActivity.updateOptionsLocked(opts);
606         assertNotNull(mActivity.takeOptionsLocked(true /* fromClient */));
607         assertNotNull(mActivity.pendingOptions);
608 
609         mActivity.updateOptionsLocked(ActivityOptions.makeBasic());
610         assertNotNull(mActivity.takeOptionsLocked(false /* fromClient */));
611         assertNull(mActivity.pendingOptions);
612     }
613 
614     @Test
testCanLaunchHomeActivityFromChooser()615     public void testCanLaunchHomeActivityFromChooser() {
616         ComponentName chooserComponent = ComponentName.unflattenFromString(
617                 Resources.getSystem().getString(R.string.config_chooserActivity));
618         ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
619                 chooserComponent).build();
620         assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
621     }
622 
623     /**
624      * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and
625      * that it is cleared after activity is resumed.
626      */
627     @Test
testHasSavedState()628     public void testHasSavedState() {
629         assertTrue(mActivity.hasSavedState());
630 
631         ActivityRecord.activityResumedLocked(mActivity.appToken);
632         assertFalse(mActivity.hasSavedState());
633         assertNull(mActivity.getSavedState());
634     }
635 
636     /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */
637     @Test
testUpdateSavedState()638     public void testUpdateSavedState() {
639         mActivity.setSavedState(null /* savedState */);
640         assertFalse(mActivity.hasSavedState());
641         assertNull(mActivity.getSavedState());
642 
643         final Bundle savedState = new Bundle();
644         savedState.putString("test", "string");
645         mActivity.setSavedState(savedState);
646         assertTrue(mActivity.hasSavedState());
647         assertEquals(savedState, mActivity.getSavedState());
648     }
649 
650     /** Verify the correct updates of saved state when activity client reports stop. */
651     @Test
testUpdateSavedState_activityStopped()652     public void testUpdateSavedState_activityStopped() {
653         final Bundle savedState = new Bundle();
654         savedState.putString("test", "string");
655         final PersistableBundle persistentSavedState = new PersistableBundle();
656         persistentSavedState.putString("persist", "string");
657 
658         // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored.
659         mActivity.setState(STOPPING, "test");
660         mActivity.activityStopped(savedState, persistentSavedState, "desc");
661         assertTrue(mActivity.hasSavedState());
662         assertEquals(savedState, mActivity.getSavedState());
663         assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
664 
665         // Sending 'null' for saved state can only happen due to timeout, so previously stored saved
666         // states should not be overridden.
667         mActivity.setState(STOPPING, "test");
668         mActivity.activityStopped(null /* savedState */, null /* persistentSavedState */, "desc");
669         assertTrue(mActivity.hasSavedState());
670         assertEquals(savedState, mActivity.getSavedState());
671         assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
672     }
673 
674     /**
675      * Verify that activity finish request is not performed if activity is finishing or is in
676      * incorrect state.
677      */
678     @Test
testFinishActivityIfPossible_cancelled()679     public void testFinishActivityIfPossible_cancelled() {
680         // Mark activity as finishing
681         mActivity.finishing = true;
682         assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED,
683                 mActivity.finishIfPossible("test", false /* oomAdj */));
684         assertTrue(mActivity.finishing);
685         assertTrue(mActivity.isInStackLocked());
686 
687         // Remove activity from task
688         mActivity.finishing = false;
689         mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
690         assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED,
691                 mActivity.finishIfPossible("test", false /* oomAdj */));
692         assertFalse(mActivity.finishing);
693     }
694 
695     /**
696      * Verify that activity finish request is placed, but not executed immediately if activity is
697      * not ready yet.
698      */
699     @Test
testFinishActivityIfPossible_requested()700     public void testFinishActivityIfPossible_requested() {
701         mActivity.finishing = false;
702         assertEquals("Currently resumed activity must be prepared removal", FINISH_RESULT_REQUESTED,
703                 mActivity.finishIfPossible("test", false /* oomAdj */));
704         assertTrue(mActivity.finishing);
705         assertTrue(mActivity.isInStackLocked());
706 
707         // First request to finish activity must schedule a "destroy" request to the client.
708         // Activity must be removed from history after the client reports back or after timeout.
709         mActivity.finishing = false;
710         mActivity.setState(STOPPED, "test");
711         assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED,
712                 mActivity.finishIfPossible("test", false /* oomAdj */));
713         assertTrue(mActivity.finishing);
714         assertTrue(mActivity.isInStackLocked());
715     }
716 
717     /**
718      * Verify that activity finish request removes activity immediately if it's ready.
719      */
720     @Test
testFinishActivityIfPossible_removed()721     public void testFinishActivityIfPossible_removed() {
722         // Prepare the activity record to be ready for immediate removal. It should be invisible and
723         // have no process. Otherwise, request to finish it will send a message to client first.
724         mActivity.setState(STOPPED, "test");
725         mActivity.mVisibleRequested = false;
726         mActivity.nowVisible = false;
727         // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
728         // this will cause NPE when updating task's process.
729         mActivity.app = null;
730 
731         // Put a visible activity on top, so the finishing activity doesn't have to wait until the
732         // next activity reports idle to destroy it.
733         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
734         topActivity.mVisibleRequested = true;
735         topActivity.nowVisible = true;
736         topActivity.setState(RESUMED, "test");
737 
738         assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REMOVED,
739                 mActivity.finishIfPossible("test", false /* oomAdj */));
740         assertTrue(mActivity.finishing);
741         assertFalse(mActivity.isInStackLocked());
742     }
743 
744     /**
745      * Verify that when finishing the top focused activity on top display, the stack order will be
746      * changed by adjusting focus.
747      */
748     @Test
testFinishActivityIfPossible_adjustStackOrder()749     public void testFinishActivityIfPossible_adjustStackOrder() {
750         // Prepare the stacks with order (top to bottom): mStack, stack1, stack2.
751         final ActivityStack stack1 = new StackBuilder(mRootWindowContainer).build();
752         mStack.moveToFront("test");
753         // The stack2 is needed here for moving back to simulate the
754         // {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so
755         // {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible
756         // stacks. Then when mActivity is finishing, its stack will be invisible (no running
757         // activities in the stack) that is the key condition to verify.
758         final ActivityStack stack2 = new StackBuilder(mRootWindowContainer).build();
759         stack2.moveToBack("test", stack2.getBottomMostTask());
760 
761         assertTrue(mStack.isTopStackInDisplayArea());
762 
763         mActivity.setState(RESUMED, "test");
764         mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */,
765                 null /* resultGrants */, "test", false /* oomAdj */);
766 
767         assertTrue(stack1.isTopStackInDisplayArea());
768     }
769 
770     /**
771      * Verify that when finishing the top focused activity while root task was created by organizer,
772      * the stack order will be changed by adjusting focus.
773      */
774     @Test
testFinishActivityIfPossible_adjustStackOrderOrganizedRoot()775     public void testFinishActivityIfPossible_adjustStackOrderOrganizedRoot() {
776         // Make mStack be a the root task that created by task organizer
777         mStack.mCreatedByOrganizer = true;
778 
779         // Have two tasks (topRootableTask and mTask) as the children of mStack.
780         ActivityRecord topActivity = new ActivityBuilder(mActivity.mAtmService)
781                 .setCreateTask(true)
782                 .setStack(mStack)
783                 .build();
784         ActivityStack topRootableTask = (ActivityStack) topActivity.getTask();
785         topRootableTask.moveToFront("test");
786         assertTrue(mStack.isTopStackInDisplayArea());
787 
788         // Finish top activity and verify the next focusable rootable task has adjusted to top.
789         topActivity.setState(RESUMED, "test");
790         topActivity.finishIfPossible(0 /* resultCode */, null /* resultData */,
791                 null /* resultGrants */, "test", false /* oomAdj */);
792         assertEquals(mTask, mStack.getTopMostTask());
793     }
794 
795     /**
796      * Verify that when top focused activity is on secondary display, when finishing the top focused
797      * activity on default display, the preferred top stack on default display should be changed by
798      * adjusting focus.
799      */
800     @Test
testFinishActivityIfPossible_PreferredTopStackChanged()801     public void testFinishActivityIfPossible_PreferredTopStackChanged() {
802         final ActivityRecord topActivityOnNonTopDisplay =
803                 createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
804         ActivityStack topRootableTask = topActivityOnNonTopDisplay.getRootTask();
805         topRootableTask.moveToFront("test");
806         assertTrue(topRootableTask.isTopStackInDisplayArea());
807         assertEquals(topRootableTask, topActivityOnNonTopDisplay.getDisplayArea()
808                 .mPreferredTopFocusableStack);
809 
810         final ActivityRecord secondaryDisplayActivity =
811                 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
812         topRootableTask = secondaryDisplayActivity.getRootTask();
813         topRootableTask.moveToFront("test");
814         assertTrue(topRootableTask.isTopStackInDisplayArea());
815         assertEquals(topRootableTask,
816                 secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableStack);
817 
818         // The global top focus activity is on secondary display now.
819         // Finish top activity on default display and verify the next preferred top focusable stack
820         // on default display has changed.
821         topActivityOnNonTopDisplay.setState(RESUMED, "test");
822         topActivityOnNonTopDisplay.finishIfPossible(0 /* resultCode */, null /* resultData */,
823                 null /* resultGrants */, "test", false /* oomAdj */);
824         assertEquals(mTask, mStack.getTopMostTask());
825         assertEquals(mStack, mActivity.getDisplayArea().mPreferredTopFocusableStack);
826     }
827 
828     /**
829      * Verify that resumed activity is paused due to finish request.
830      */
831     @Test
testFinishActivityIfPossible_resumedStartsPausing()832     public void testFinishActivityIfPossible_resumedStartsPausing() {
833         mActivity.finishing = false;
834         mActivity.setState(RESUMED, "test");
835         assertEquals("Currently resumed activity must be paused before removal",
836                 FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */));
837         assertEquals(PAUSING, mActivity.getState());
838         verify(mActivity).setVisibility(eq(false));
839         verify(mActivity.getDisplay().mDisplayContent)
840                 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
841     }
842 
843     /**
844      * Verify that finish request will be completed immediately for non-resumed activity.
845      */
846     @Test
testFinishActivityIfPossible_nonResumedFinishCompletesImmediately()847     public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() {
848         final ActivityState[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED};
849         for (ActivityState state : states) {
850             mActivity.finishing = false;
851             mActivity.setState(state, "test");
852             reset(mActivity);
853             assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
854                     mActivity.finishIfPossible("test", false /* oomAdj */));
855             verify(mActivity).completeFinishing(anyString());
856         }
857     }
858 
859     /**
860      * Verify that finishing will not be completed in PAUSING state.
861      */
862     @Test
testFinishActivityIfPossible_pausing()863     public void testFinishActivityIfPossible_pausing() {
864         mActivity.finishing = false;
865         mActivity.setState(PAUSING, "test");
866         assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
867                 mActivity.finishIfPossible("test", false /* oomAdj */));
868         verify(mActivity, never()).completeFinishing(anyString());
869     }
870 
871     /**
872      * Verify that finish request for resumed activity will prepare an app transition but not
873      * execute it immediately.
874      */
875     @Test
testFinishActivityIfPossible_visibleResumedPreparesAppTransition()876     public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() {
877         mActivity.finishing = false;
878         mActivity.mVisibleRequested = true;
879         mActivity.setState(RESUMED, "test");
880         mActivity.finishIfPossible("test", false /* oomAdj */);
881 
882         verify(mActivity).setVisibility(eq(false));
883         verify(mActivity.getDisplay().mDisplayContent)
884                 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
885         verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition();
886     }
887 
888     /**
889      * Verify that finish request for paused activity will prepare and execute an app transition.
890      */
891     @Test
testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition()892     public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() {
893         mActivity.finishing = false;
894         mActivity.mVisibleRequested = true;
895         mActivity.setState(PAUSED, "test");
896         mActivity.finishIfPossible("test", false /* oomAdj */);
897 
898         verify(mActivity, atLeast(1)).setVisibility(eq(false));
899         verify(mActivity.getDisplay().mDisplayContent)
900                 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
901         verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
902     }
903 
904     /**
905      * Verify that finish request for non-visible activity will not prepare any transitions.
906      */
907     @Test
testFinishActivityIfPossible_nonVisibleNoAppTransition()908     public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
909         // Put an activity on top of test activity to make it invisible and prevent us from
910         // accidentally resuming the topmost one again.
911         new ActivityBuilder(mService).build();
912         mActivity.mVisibleRequested = false;
913         mActivity.setState(STOPPED, "test");
914 
915         mActivity.finishIfPossible("test", false /* oomAdj */);
916 
917         verify(mActivity.getDisplay().mDisplayContent, never())
918                 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
919     }
920 
921     /**
922      * Verify that complete finish request for non-finishing activity is invalid.
923      */
924     @Test(expected = IllegalArgumentException.class)
testCompleteFinishing_failNotFinishing()925     public void testCompleteFinishing_failNotFinishing() {
926         mActivity.finishing = false;
927         mActivity.completeFinishing("test");
928     }
929 
930     /**
931      * Verify that complete finish request for resumed activity is invalid.
932      */
933     @Test(expected = IllegalArgumentException.class)
testCompleteFinishing_failResumed()934     public void testCompleteFinishing_failResumed() {
935         mActivity.setState(RESUMED, "test");
936         mActivity.completeFinishing("test");
937     }
938 
939     /**
940      * Verify that finish request for pausing activity must be a no-op - activity will finish
941      * once it completes pausing.
942      */
943     @Test
testCompleteFinishing_pausing()944     public void testCompleteFinishing_pausing() {
945         mActivity.setState(PAUSING, "test");
946         mActivity.finishing = true;
947 
948         assertEquals("Activity must not be removed immediately - waiting for paused",
949                 mActivity, mActivity.completeFinishing("test"));
950         assertEquals(PAUSING, mActivity.getState());
951         verify(mActivity, never()).destroyIfPossible(anyString());
952     }
953 
954     /**
955      * Verify that finish request won't change the state of next top activity if the current
956      * finishing activity doesn't need to be destroyed immediately. The case is usually like
957      * from {@link ActivityStack#completePauseLocked(boolean, ActivityRecord)} to
958      * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the
959      * responsibility to resume the next activity with updating the state.
960      */
961     @Test
testCompleteFinishing_keepStateOfNextInvisible()962     public void testCompleteFinishing_keepStateOfNextInvisible() {
963         final ActivityRecord currentTop = mActivity;
964         currentTop.mVisibleRequested = currentTop.nowVisible = true;
965 
966         // Simulates that {@code currentTop} starts an existing activity from background (so its
967         // state is stopped) and the starting flow just goes to place it at top.
968         final ActivityStack nextStack = new StackBuilder(mRootWindowContainer).build();
969         final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity();
970         nextTop.setState(STOPPED, "test");
971 
972         mStack.mPausingActivity = currentTop;
973         currentTop.finishing = true;
974         currentTop.setState(PAUSED, "test");
975         currentTop.completeFinishing("completePauseLocked");
976 
977         // Current top becomes stopping because it is visible and the next is invisible.
978         assertEquals(STOPPING, currentTop.getState());
979         // The state of next activity shouldn't be changed.
980         assertEquals(STOPPED, nextTop.getState());
981     }
982 
983     /**
984      * Verify that complete finish request for visible activity must be delayed before the next one
985      * becomes visible.
986      */
987     @Test
testCompleteFinishing_waitForNextVisible()988     public void testCompleteFinishing_waitForNextVisible() {
989         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
990         topActivity.mVisibleRequested = true;
991         topActivity.nowVisible = true;
992         topActivity.finishing = true;
993         topActivity.setState(PAUSED, "true");
994         // Mark the bottom activity as not visible, so that we will wait for it before removing
995         // the top one.
996         mActivity.mVisibleRequested = false;
997         mActivity.nowVisible = false;
998         mActivity.setState(STOPPED, "test");
999 
1000         assertEquals("Activity must not be removed immediately - waiting for next visible",
1001                 topActivity, topActivity.completeFinishing("test"));
1002         assertEquals("Activity must be stopped to make next one visible", STOPPING,
1003                 topActivity.getState());
1004         assertTrue("Activity must be stopped to make next one visible",
1005                 topActivity.mStackSupervisor.mStoppingActivities.contains(topActivity));
1006         verify(topActivity, never()).destroyIfPossible(anyString());
1007     }
1008 
1009     /**
1010      * Verify that complete finish request for invisible activity must not be delayed.
1011      */
1012     @Test
testCompleteFinishing_noWaitForNextVisible_alreadyInvisible()1013     public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
1014         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
1015         topActivity.mVisibleRequested = false;
1016         topActivity.nowVisible = false;
1017         topActivity.finishing = true;
1018         topActivity.setState(STOPPED, "true");
1019         // Mark the bottom activity as not visible, so that we would wait for it before removing
1020         // the top one.
1021         mActivity.mVisibleRequested = false;
1022         mActivity.nowVisible = false;
1023         mActivity.setState(STOPPED, "test");
1024 
1025         topActivity.completeFinishing("test");
1026 
1027         verify(topActivity).destroyIfPossible(anyString());
1028     }
1029 
1030     /**
1031      * Verify that paused finishing activity will be added to finishing list and wait for next one
1032      * to idle.
1033      */
1034     @Test
testCompleteFinishing_waitForIdle()1035     public void testCompleteFinishing_waitForIdle() {
1036         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
1037         topActivity.mVisibleRequested = true;
1038         topActivity.nowVisible = true;
1039         topActivity.finishing = true;
1040         topActivity.setState(PAUSED, "true");
1041         // Mark the bottom activity as already visible, so that there is no need to wait for it.
1042         mActivity.mVisibleRequested = true;
1043         mActivity.nowVisible = true;
1044         mActivity.setState(RESUMED, "test");
1045 
1046         topActivity.completeFinishing("test");
1047 
1048         verify(topActivity).addToFinishingAndWaitForIdle();
1049     }
1050 
1051     /**
1052      * Verify that complete finish request for visible activity must not be delayed if the next one
1053      * is already visible and it's not the focused stack.
1054      */
1055     @Test
testCompleteFinishing_noWaitForNextVisible_stopped()1056     public void testCompleteFinishing_noWaitForNextVisible_stopped() {
1057         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
1058         topActivity.mVisibleRequested = false;
1059         topActivity.nowVisible = false;
1060         topActivity.finishing = true;
1061         topActivity.setState(STOPPED, "true");
1062         // Mark the bottom activity as already visible, so that there is no need to wait for it.
1063         mActivity.mVisibleRequested = true;
1064         mActivity.nowVisible = true;
1065         mActivity.setState(RESUMED, "test");
1066 
1067         topActivity.completeFinishing("test");
1068 
1069         verify(topActivity).destroyIfPossible(anyString());
1070     }
1071 
1072     /**
1073      * Verify that complete finish request for visible activity must not be delayed if the next one
1074      * is already visible and it's not the focused stack.
1075      */
1076     @Test
testCompleteFinishing_noWaitForNextVisible_nonFocusedStack()1077     public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
1078         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
1079         topActivity.mVisibleRequested = true;
1080         topActivity.nowVisible = true;
1081         topActivity.finishing = true;
1082         topActivity.setState(PAUSED, "true");
1083         // Mark the bottom activity as already visible, so that there is no need to wait for it.
1084         mActivity.mVisibleRequested = true;
1085         mActivity.nowVisible = true;
1086         mActivity.setState(RESUMED, "test");
1087 
1088         // Add another stack to become focused and make the activity there visible. This way it
1089         // simulates finishing in non-focused stack in split-screen.
1090         final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
1091         final ActivityRecord focusedActivity = stack.getTopMostActivity();
1092         focusedActivity.nowVisible = true;
1093         focusedActivity.mVisibleRequested = true;
1094         focusedActivity.setState(RESUMED, "test");
1095         stack.mResumedActivity = focusedActivity;
1096 
1097         topActivity.completeFinishing("test");
1098 
1099         verify(topActivity).destroyIfPossible(anyString());
1100     }
1101 
1102     /**
1103      * Verify that complete finish request for a show-when-locked activity must ensure the
1104      * keyguard occluded state being updated.
1105      */
1106     @Test
testCompleteFinishing_showWhenLocked()1107     public void testCompleteFinishing_showWhenLocked() {
1108         // Make keyguard locked and set the top activity show-when-locked.
1109         KeyguardController keyguardController = mActivity.mStackSupervisor.getKeyguardController();
1110         doReturn(true).when(keyguardController).isKeyguardLocked();
1111         final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
1112         topActivity.mVisibleRequested = true;
1113         topActivity.nowVisible = true;
1114         topActivity.setState(RESUMED, "true");
1115         doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
1116                 any() /* starting */, anyInt() /* configChanges */,
1117                 anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
1118         topActivity.setShowWhenLocked(true);
1119 
1120         // Verify the stack-top activity is occluded keyguard.
1121         assertEquals(topActivity, mStack.topRunningActivity());
1122         assertTrue(mStack.topActivityOccludesKeyguard());
1123 
1124         // Finish the top activity
1125         topActivity.setState(PAUSED, "true");
1126         topActivity.finishing = true;
1127         topActivity.completeFinishing("test");
1128 
1129         // Verify new top activity does not occlude keyguard.
1130         assertEquals(mActivity, mStack.topRunningActivity());
1131         assertFalse(mStack.topActivityOccludesKeyguard());
1132     }
1133 
1134     /**
1135      * Verify that complete finish request for an activity which the resume activity is translucent
1136      * must ensure the visibilities of activities being updated.
1137      */
1138     @Test
testCompleteFinishing_ensureActivitiesVisible()1139     public void testCompleteFinishing_ensureActivitiesVisible() {
1140         final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
1141         firstActivity.mVisibleRequested = false;
1142         firstActivity.nowVisible = false;
1143         firstActivity.setState(STOPPED, "true");
1144 
1145         final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
1146         secondActivity.mVisibleRequested = true;
1147         secondActivity.nowVisible = true;
1148         secondActivity.setState(PAUSED, "true");
1149 
1150         final ActivityRecord translucentActivity =
1151                 new ActivityBuilder(mService).setTask(mTask).build();
1152         translucentActivity.mVisibleRequested = true;
1153         translucentActivity.nowVisible = true;
1154         translucentActivity.setState(RESUMED, "true");
1155 
1156         doReturn(false).when(translucentActivity).occludesParent();
1157 
1158         // Finish the second activity
1159         secondActivity.finishing = true;
1160         secondActivity.completeFinishing("test");
1161         verify(secondActivity.getDisplay()).ensureActivitiesVisible(null /* starting */,
1162                 0 /* configChanges */ , false /* preserveWindows */,
1163                 true /* notifyClients */);
1164 
1165         // Finish the first activity
1166         firstActivity.finishing = true;
1167         firstActivity.mVisibleRequested = true;
1168         firstActivity.completeFinishing("test");
1169         verify(firstActivity.getDisplay(), times(2)).ensureActivitiesVisible(null /* starting */,
1170                 0 /* configChanges */ , false /* preserveWindows */,
1171                 true /* notifyClients */);
1172     }
1173 
1174     /**
1175      * Verify destroy activity request completes successfully.
1176      */
1177     @Test
testDestroyIfPossible()1178     public void testDestroyIfPossible() {
1179         doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
1180         spyOn(mStack);
1181         mActivity.destroyIfPossible("test");
1182 
1183         assertEquals(DESTROYING, mActivity.getState());
1184         assertTrue(mActivity.finishing);
1185         verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1186     }
1187 
1188     /**
1189      * Verify that complete finish request for visible activity must not destroy it immediately if
1190      * it is the last running activity on a display with a home stack. We must wait for home
1191      * activity to come up to avoid a black flash in this case.
1192      */
1193     @Test
testDestroyIfPossible_lastActivityAboveEmptyHomeStack()1194     public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
1195         // Empty the home stack.
1196         final ActivityStack homeStack = mActivity.getDisplayArea().getRootHomeTask();
1197         homeStack.forAllLeafTasks((t) -> {
1198             homeStack.removeChild(t, "test");
1199         }, true /* traverseTopToBottom */);
1200         mActivity.finishing = true;
1201         doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
1202         spyOn(mStack);
1203 
1204         // Try to destroy the last activity above the home stack.
1205         mActivity.destroyIfPossible("test");
1206 
1207         // Verify that the activity was not actually destroyed, but waits for next one to come up
1208         // instead.
1209         verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1210         assertEquals(FINISHING, mActivity.getState());
1211         assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1212     }
1213 
1214     /**
1215      * Verify that complete finish request for visible activity must resume next home stack before
1216      * destroying it immediately if it is the last running activity on a display with a home stack.
1217      * We must wait for home activity to come up to avoid a black flash in this case.
1218      */
1219     @Test
testCompleteFinishing_lastActivityAboveEmptyHomeStack()1220     public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
1221         // Empty the home stack.
1222         final ActivityStack homeStack = mActivity.getDisplayArea().getRootHomeTask();
1223         homeStack.forAllLeafTasks((t) -> {
1224             homeStack.removeChild(t, "test");
1225         }, true /* traverseTopToBottom */);
1226         mActivity.finishing = true;
1227         spyOn(mStack);
1228 
1229         // Try to finish the last activity above the home stack.
1230         mActivity.completeFinishing("test");
1231 
1232         // Verify that the activity is not destroyed immediately, but waits for next one to come up.
1233         verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1234         assertEquals(FINISHING, mActivity.getState());
1235         assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1236     }
1237 
1238     /**
1239      * Test that the activity will be moved to destroying state and the message to destroy will be
1240      * sent to the client.
1241      */
1242     @Test
testDestroyImmediately_hadApp_finishing()1243     public void testDestroyImmediately_hadApp_finishing() {
1244         mActivity.finishing = true;
1245         mActivity.destroyImmediately(false /* removeFromApp */, "test");
1246 
1247         assertEquals(DESTROYING, mActivity.getState());
1248     }
1249 
1250     /**
1251      * Test that the activity will be moved to destroyed state immediately if it was not marked as
1252      * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
1253      */
1254     @Test
testDestroyImmediately_hadApp_notFinishing()1255     public void testDestroyImmediately_hadApp_notFinishing() {
1256         mActivity.finishing = false;
1257         mActivity.destroyImmediately(false /* removeFromApp */, "test");
1258 
1259         assertEquals(DESTROYED, mActivity.getState());
1260     }
1261 
1262     /**
1263      * Test that an activity with no process attached and that is marked as finishing will be
1264      * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
1265      */
1266     @Test
testDestroyImmediately_noApp_finishing()1267     public void testDestroyImmediately_noApp_finishing() {
1268         mActivity.app = null;
1269         mActivity.finishing = true;
1270         final Task task = mActivity.getTask();
1271 
1272         mActivity.destroyImmediately(false /* removeFromApp */, "test");
1273 
1274         assertEquals(DESTROYED, mActivity.getState());
1275         assertNull(mActivity.getTask());
1276         assertEquals(0, task.getChildCount());
1277     }
1278 
1279     /**
1280      * Test that an activity with no process attached and that is not marked as finishing will be
1281      * marked as DESTROYED but not removed from task.
1282      */
1283     @Test
testDestroyImmediately_noApp_notFinishing()1284     public void testDestroyImmediately_noApp_notFinishing() {
1285         mActivity.app = null;
1286         mActivity.finishing = false;
1287         final Task task = mActivity.getTask();
1288 
1289         mActivity.destroyImmediately(false /* removeFromApp */, "test");
1290 
1291         assertEquals(DESTROYED, mActivity.getState());
1292         assertEquals(task, mActivity.getTask());
1293         assertEquals(1, task.getChildCount());
1294     }
1295 
1296     /**
1297      * Test that an activity will not be destroyed if it is marked as non-destroyable.
1298      */
1299     @Test
testSafelyDestroy_nonDestroyable()1300     public void testSafelyDestroy_nonDestroyable() {
1301         doReturn(false).when(mActivity).isDestroyable();
1302 
1303         mActivity.safelyDestroy("test");
1304 
1305         verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1306     }
1307 
1308     /**
1309      * Test that an activity will not be destroyed if it is marked as non-destroyable.
1310      */
1311     @Test
testSafelyDestroy_destroyable()1312     public void testSafelyDestroy_destroyable() {
1313         doReturn(true).when(mActivity).isDestroyable();
1314 
1315         mActivity.safelyDestroy("test");
1316 
1317         verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1318     }
1319 
1320     @Test
testRemoveFromHistory()1321     public void testRemoveFromHistory() {
1322         final ActivityStack stack = mActivity.getRootTask();
1323         final Task task = mActivity.getTask();
1324 
1325         mActivity.removeFromHistory("test");
1326 
1327         assertEquals(DESTROYED, mActivity.getState());
1328         assertNull(mActivity.app);
1329         assertNull(mActivity.getTask());
1330         assertEquals(0, task.getChildCount());
1331         assertEquals(task.getStack(), task);
1332         assertEquals(0, stack.getChildCount());
1333     }
1334 
1335     /**
1336      * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is
1337      * not in destroying or destroyed state.
1338      */
1339     @Test(expected = IllegalStateException.class)
testDestroyed_notDestroying()1340     public void testDestroyed_notDestroying() {
1341         mActivity.setState(STOPPED, "test");
1342         mActivity.destroyed("test");
1343     }
1344 
1345     /**
1346      * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying
1347      */
1348     @Test
testDestroyed_destroying()1349     public void testDestroyed_destroying() {
1350         mActivity.setState(DESTROYING, "test");
1351         mActivity.destroyed("test");
1352 
1353         verify(mActivity).removeFromHistory(anyString());
1354     }
1355 
1356     /**
1357      * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed.
1358      */
1359     @Test
testDestroyed_destroyed()1360     public void testDestroyed_destroyed() {
1361         mActivity.setState(DESTROYED, "test");
1362         mActivity.destroyed("test");
1363 
1364         verify(mActivity).removeFromHistory(anyString());
1365     }
1366 
1367     @Test
testActivityOverridesProcessConfig()1368     public void testActivityOverridesProcessConfig() {
1369         final WindowProcessController wpc = mActivity.app;
1370         assertTrue(wpc.registeredForActivityConfigChanges());
1371         assertFalse(wpc.registeredForDisplayConfigChanges());
1372 
1373         final ActivityRecord secondaryDisplayActivity =
1374                 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1375 
1376         assertTrue(wpc.registeredForActivityConfigChanges());
1377         assertEquals(0, mActivity.getMergedOverrideConfiguration()
1378                 .diff(wpc.getRequestedOverrideConfiguration()));
1379         assertNotEquals(mActivity.getConfiguration(),
1380                 secondaryDisplayActivity.getConfiguration());
1381     }
1382 
1383     @Test
testActivityOverridesProcessConfig_TwoActivities()1384     public void testActivityOverridesProcessConfig_TwoActivities() {
1385         final WindowProcessController wpc = mActivity.app;
1386         assertTrue(wpc.registeredForActivityConfigChanges());
1387 
1388         final Task firstTaskRecord = mActivity.getTask();
1389         final ActivityRecord secondActivityRecord =
1390                 new ActivityBuilder(mService).setTask(firstTaskRecord).setUseProcess(wpc).build();
1391 
1392         assertTrue(wpc.registeredForActivityConfigChanges());
1393         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1394                 .diff(wpc.getRequestedOverrideConfiguration()));
1395     }
1396 
1397     @Test
testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay()1398     public void testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay() {
1399         final WindowProcessController wpc = mActivity.app;
1400         assertTrue(wpc.registeredForActivityConfigChanges());
1401 
1402         final ActivityRecord secondActivityRecord =
1403                 new ActivityBuilder(mService).setTask(mTask).setUseProcess(wpc).build();
1404 
1405         assertTrue(wpc.registeredForActivityConfigChanges());
1406         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1407                 .diff(wpc.getRequestedOverrideConfiguration()));
1408     }
1409 
1410     @Test
testActivityOverridesProcessConfig_TwoActivities_DifferentTasks()1411     public void testActivityOverridesProcessConfig_TwoActivities_DifferentTasks() {
1412         final WindowProcessController wpc = mActivity.app;
1413         assertTrue(wpc.registeredForActivityConfigChanges());
1414 
1415         final ActivityRecord secondActivityRecord =
1416                 createActivityOnDisplay(true /* defaultDisplay */, wpc);
1417 
1418         assertTrue(wpc.registeredForActivityConfigChanges());
1419         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1420                 .diff(wpc.getRequestedOverrideConfiguration()));
1421     }
1422 
1423     @Test
testActivityOnCancelFixedRotationTransform()1424     public void testActivityOnCancelFixedRotationTransform() {
1425         final DisplayRotation displayRotation = mActivity.mDisplayContent.getDisplayRotation();
1426         spyOn(displayRotation);
1427 
1428         final DisplayContent display = mActivity.mDisplayContent;
1429         final int originalRotation = display.getRotation();
1430 
1431         // Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately.
1432         doReturn(true).when(displayRotation).isWaitingForRemoteRotation();
1433         doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation(
1434                 anyInt() /* orientation */, anyInt() /* lastRotation */);
1435         // Set to visible so the activity can freeze the screen.
1436         mActivity.setVisibility(true);
1437 
1438         display.rotateInDifferentOrientationIfNeeded(mActivity);
1439         display.setFixedRotationLaunchingAppUnchecked(mActivity);
1440         displayRotation.updateRotationUnchecked(true /* forceUpdate */);
1441 
1442         assertTrue(displayRotation.isRotatingSeamlessly());
1443 
1444         // The launching rotated app should not be cleared when waiting for remote rotation.
1445         display.continueUpdateOrientationForDiffOrienLaunchingApp();
1446         assertTrue(display.isFixedRotationLaunchingApp(mActivity));
1447 
1448         // Simulate the rotation has been updated to previous one, e.g. sensor updates before the
1449         // remote rotation is completed.
1450         doReturn(originalRotation).when(displayRotation).rotationForOrientation(
1451                 anyInt() /* orientation */, anyInt() /* lastRotation */);
1452         display.updateOrientation();
1453 
1454         final DisplayInfo rotatedInfo = mActivity.getFixedRotationTransformDisplayInfo();
1455         mActivity.finishFixedRotationTransform();
1456         final ScreenRotationAnimation rotationAnim = display.getRotationAnimation();
1457         assertNotNull(rotationAnim);
1458         rotationAnim.setRotation(display.getPendingTransaction(), originalRotation);
1459 
1460         // Because the display doesn't rotate, the rotated activity needs to cancel the fixed
1461         // rotation. There should be a rotation animation to cover the change of activity.
1462         verify(mActivity).onCancelFixedRotationTransform(rotatedInfo.rotation);
1463         assertTrue(mActivity.isFreezingScreen());
1464         assertFalse(displayRotation.isRotatingSeamlessly());
1465         assertTrue(rotationAnim.isRotating());
1466 
1467         // Simulate the remote rotation has completed and the configuration doesn't change, then
1468         // the rotated activity should also be restored by clearing the transform.
1469         displayRotation.updateRotationUnchecked(true /* forceUpdate */);
1470         doReturn(false).when(displayRotation).isWaitingForRemoteRotation();
1471         clearInvocations(mActivity);
1472         display.setFixedRotationLaunchingAppUnchecked(mActivity);
1473         display.sendNewConfiguration();
1474 
1475         assertFalse(display.hasTopFixedRotationLaunchingApp());
1476         assertFalse(mActivity.hasFixedRotationTransform());
1477     }
1478 
1479     @Test
testIsSnapshotCompatible()1480     public void testIsSnapshotCompatible() {
1481         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
1482                 .setRotation(mActivity.getWindowConfiguration().getRotation())
1483                 .build();
1484 
1485         assertTrue(mActivity.isSnapshotCompatible(snapshot));
1486 
1487         setRotatedScreenOrientationSilently(mActivity);
1488 
1489         assertFalse(mActivity.isSnapshotCompatible(snapshot));
1490     }
1491 
1492     @Test
testFixedRotationSnapshotStartingWindow()1493     public void testFixedRotationSnapshotStartingWindow() {
1494         // TaskSnapshotSurface requires a fullscreen opaque window.
1495         final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
1496                 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
1497         params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
1498         final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
1499                 mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
1500         mActivity.addWindow(w);
1501 
1502         // Assume the activity is launching in different rotation, and there was an available
1503         // snapshot accepted by {@link Activity#isSnapshotCompatible}.
1504         final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
1505                 .setRotation((mActivity.getWindowConfiguration().getRotation() + 1) % 4)
1506                 .build();
1507         setRotatedScreenOrientationSilently(mActivity);
1508         mActivity.setVisible(false);
1509 
1510         final IWindowSession session = WindowManagerGlobal.getWindowSession();
1511         spyOn(session);
1512         try {
1513             // Return error to skip unnecessary operation.
1514             doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
1515                     any() /* window */, anyInt() /* seq */, any() /* attrs */,
1516                     anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */,
1517                     any() /* outContentInsets */, any() /* outStableInsets */,
1518                     any() /* outDisplayCutout */, any() /* outInputChannel */,
1519                     any() /* outInsetsState */, any() /* outActiveControls */);
1520             TaskSnapshotSurface.create(mService.mWindowManager, mActivity, snapshot);
1521         } catch (RemoteException ignored) {
1522         } finally {
1523             reset(session);
1524         }
1525 
1526         // Because the rotation of snapshot and the corresponding top activity are different, fixed
1527         // rotation should be applied when creating snapshot surface if the display rotation may be
1528         // changed according to the activity orientation.
1529         assertTrue(mActivity.hasFixedRotationTransform());
1530         assertTrue(mActivity.mDisplayContent.isFixedRotationLaunchingApp(mActivity));
1531     }
1532 
1533     /**
1534      * Sets orientation without notifying the parent to simulate that the display has not applied
1535      * the requested orientation yet.
1536      */
setRotatedScreenOrientationSilently(ActivityRecord r)1537     static void setRotatedScreenOrientationSilently(ActivityRecord r) {
1538         final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT
1539                 ? SCREEN_ORIENTATION_LANDSCAPE
1540                 : SCREEN_ORIENTATION_PORTRAIT;
1541         doReturn(false).when(r).onDescendantOrientationChanged(any(), any());
1542         r.setOrientation(rotatedOrentation);
1543     }
1544 
1545     @Test
testActivityOnDifferentDisplayUpdatesProcessOverride()1546     public void testActivityOnDifferentDisplayUpdatesProcessOverride() {
1547         final ActivityRecord secondaryDisplayActivity =
1548                 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1549         final WindowProcessController wpc = secondaryDisplayActivity.app;
1550         assertTrue(wpc.registeredForActivityConfigChanges());
1551 
1552         final ActivityRecord secondActivityRecord =
1553                 createActivityOnDisplay(true /* defaultDisplay */, wpc);
1554 
1555         assertTrue(wpc.registeredForActivityConfigChanges());
1556         assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1557                 .diff(wpc.getRequestedOverrideConfiguration()));
1558         assertFalse(wpc.registeredForDisplayConfigChanges());
1559     }
1560 
1561     @Test
testActivityReparentChangesProcessOverride()1562     public void testActivityReparentChangesProcessOverride() {
1563         final WindowProcessController wpc = mActivity.app;
1564         final Task initialTask = mActivity.getTask();
1565         final Configuration initialConf =
1566                 new Configuration(mActivity.getMergedOverrideConfiguration());
1567         assertEquals(0, mActivity.getMergedOverrideConfiguration()
1568                 .diff(wpc.getRequestedOverrideConfiguration()));
1569         assertTrue(wpc.registeredForActivityConfigChanges());
1570 
1571         // Create a new task with custom config to reparent the activity to.
1572         final Task newTask =
1573                 new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build();
1574         final Configuration newConfig = newTask.getConfiguration();
1575         newConfig.densityDpi += 100;
1576         newTask.onRequestedOverrideConfigurationChanged(newConfig);
1577         assertEquals(newTask.getConfiguration().densityDpi, newConfig.densityDpi);
1578 
1579         // Reparent the activity and verify that config override changed.
1580         mActivity.reparent(newTask, 0 /* top */, "test");
1581         assertEquals(mActivity.getConfiguration().densityDpi, newConfig.densityDpi);
1582         assertEquals(mActivity.getMergedOverrideConfiguration().densityDpi, newConfig.densityDpi);
1583 
1584         assertTrue(wpc.registeredForActivityConfigChanges());
1585         assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1586         assertEquals(0, mActivity.getMergedOverrideConfiguration()
1587                 .diff(wpc.getRequestedOverrideConfiguration()));
1588     }
1589 
1590     @Test
testActivityReparentDoesntClearProcessOverride_TwoActivities()1591     public void testActivityReparentDoesntClearProcessOverride_TwoActivities() {
1592         final WindowProcessController wpc = mActivity.app;
1593         final Configuration initialConf =
1594                 new Configuration(mActivity.getMergedOverrideConfiguration());
1595         final Task initialTask = mActivity.getTask();
1596         final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(initialTask)
1597                 .setUseProcess(wpc).build();
1598 
1599         assertTrue(wpc.registeredForActivityConfigChanges());
1600         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1601                 .diff(wpc.getRequestedOverrideConfiguration()));
1602 
1603         // Create a new task with custom config to reparent the second activity to.
1604         final Task newTask =
1605                 new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build();
1606         final Configuration newConfig = newTask.getConfiguration();
1607         newConfig.densityDpi += 100;
1608         newTask.onRequestedOverrideConfigurationChanged(newConfig);
1609 
1610         // Reparent the activity and verify that config override changed.
1611         secondActivity.reparent(newTask, 0 /* top */, "test");
1612 
1613         assertTrue(wpc.registeredForActivityConfigChanges());
1614         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1615                 .diff(wpc.getRequestedOverrideConfiguration()));
1616         assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1617 
1618         // Reparent the first activity and verify that config override didn't change.
1619         mActivity.reparent(newTask, 1 /* top */, "test");
1620         assertTrue(wpc.registeredForActivityConfigChanges());
1621         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1622                 .diff(wpc.getRequestedOverrideConfiguration()));
1623         assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1624     }
1625 
1626     @Test
testActivityDestroyDoesntChangeProcessOverride()1627     public void testActivityDestroyDoesntChangeProcessOverride() {
1628         final ActivityRecord firstActivity =
1629                 createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
1630         final WindowProcessController wpc = firstActivity.app;
1631         assertTrue(wpc.registeredForActivityConfigChanges());
1632         assertEquals(0, firstActivity.getMergedOverrideConfiguration()
1633                 .diff(wpc.getRequestedOverrideConfiguration()));
1634 
1635         final ActivityRecord secondActivity =
1636                 createActivityOnDisplay(false /* defaultDisplay */, wpc);
1637         assertTrue(wpc.registeredForActivityConfigChanges());
1638         assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1639                 .diff(wpc.getRequestedOverrideConfiguration()));
1640 
1641         final ActivityRecord thirdActivity =
1642                 createActivityOnDisplay(false /* defaultDisplay */, wpc);
1643         assertTrue(wpc.registeredForActivityConfigChanges());
1644         assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
1645                 .diff(wpc.getRequestedOverrideConfiguration()));
1646 
1647         secondActivity.destroyImmediately(true, "");
1648 
1649         assertTrue(wpc.registeredForActivityConfigChanges());
1650         assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
1651                 .diff(wpc.getRequestedOverrideConfiguration()));
1652 
1653         firstActivity.destroyImmediately(true, "");
1654 
1655         assertTrue(wpc.registeredForActivityConfigChanges());
1656         assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
1657                 .diff(wpc.getRequestedOverrideConfiguration()));
1658     }
1659 
1660     /**
1661      * Creates an activity on display. For non-default display request it will also create a new
1662      * display with custom DisplayInfo.
1663      */
createActivityOnDisplay(boolean defaultDisplay, WindowProcessController process)1664     private ActivityRecord createActivityOnDisplay(boolean defaultDisplay,
1665             WindowProcessController process) {
1666         final DisplayContent display;
1667         if (defaultDisplay) {
1668             display = mRootWindowContainer.getDefaultDisplay();
1669         } else {
1670             display = new TestDisplayContent.Builder(mService, 2000, 1000).setDensityDpi(300)
1671                     .setPosition(DisplayContent.POSITION_TOP).build();
1672         }
1673         final ActivityStack stack = display.getDefaultTaskDisplayArea()
1674                 .createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
1675         final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
1676         return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build();
1677     }
1678 }
1679