blob: 4da5adfeb87242b3b4c46d6098f7f51e1e88847b [file] [log] [blame]
Bryce Leeaf691c02017-03-20 14:20:22 -07001/*
Wale Ogunwale59507092018-10-29 09:00:30 -07002 * Copyright (C) 2018 The Android Open Source Project
Bryce Leeaf691c02017-03-20 14:20:22 -07003 *
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
Wale Ogunwale59507092018-10-29 09:00:30 -070014 * limitations under the License
Bryce Leeaf691c02017-03-20 14:20:22 -070015 */
16
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Bryce Leeaf691c02017-03-20 14:20:22 -070018
Andrii Kulianfa23a9e2019-10-10 15:15:36 -070019import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070021import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
22import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070023import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
Garfield Tan966c0412019-11-19 11:34:27 -080024import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070025import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
26import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
Louis Chang6a9be162019-07-15 10:41:32 +080027import static android.os.Process.NOBODY_UID;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070028import static android.view.Display.DEFAULT_DISPLAY;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070029import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
Bryce Lee0bd8d422018-01-09 09:45:57 -080030
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090031import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
Louis Changfd5539e2020-02-04 14:34:24 +080032import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
Andrii Kulian149d9ad32019-08-23 15:04:17 -070033import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090034import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
Louis Chang3d718c32020-04-09 16:51:02 +080035import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
Garfield Tan0443b372019-01-04 15:00:13 -080036import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
Garfield Tan36a69ad2019-01-16 17:08:23 -080037import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
Riddle Hsudb94bfd2020-05-13 01:50:17 +080038import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070039import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080040import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070041import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
Garfield Tan0443b372019-01-04 15:00:13 -080042import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Andrii Kulian057a6512019-07-15 16:15:51 -070043import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
44import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
45import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
Andrii Kulian79d67982019-08-19 11:56:16 -070046import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070047import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
48import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
Wale Ogunwale59507092018-10-29 09:00:30 -070049import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070050import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
Wale Ogunwale59507092018-10-29 09:00:30 -070051import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
Andrii Kulian6b321512019-01-23 06:37:00 +000052import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
Louis Changeadb22f2019-06-19 12:09:23 +080053import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
Wale Ogunwale59507092018-10-29 09:00:30 -070054import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070055import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080056import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
57import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
58import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
Adrian Roose99bc052017-11-20 17:55:31 +010059
Louis Chang6a9be162019-07-15 10:41:32 +080060import static com.google.common.truth.Truth.assertThat;
61
Bryce Lee04ab3462017-04-10 15:06:33 -070062import static org.junit.Assert.assertEquals;
Bryce Lee1533b2b2017-09-14 17:06:41 -070063import static org.junit.Assert.assertFalse;
Andrii Kulianfa23a9e2019-10-10 15:15:36 -070064import static org.junit.Assert.assertNotEquals;
Yunfan Chen1ee84ea2018-11-13 16:03:37 -080065import static org.junit.Assert.assertNotNull;
Bryce Lee04ab3462017-04-10 15:06:33 -070066import static org.junit.Assert.assertNull;
Bryce Lee1533b2b2017-09-14 17:06:41 -070067import static org.junit.Assert.assertTrue;
Riddle Hsud16620e2020-04-06 20:48:06 +080068import static org.mockito.ArgumentMatchers.anyInt;
Riddle Hsuaec55442019-03-12 17:25:35 +080069import static org.mockito.ArgumentMatchers.anyString;
Riddle Hsub40f9662020-04-25 01:58:23 +080070import static org.mockito.Mockito.clearInvocations;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070071import static org.mockito.Mockito.never;
chaviw82a0ba82018-03-15 14:26:29 -070072
Riddle Hsueae6ef3e2020-05-13 01:07:33 +080073import android.app.ActivityManager.TaskSnapshot;
chaviw82a0ba82018-03-15 14:26:29 -070074import android.app.ActivityOptions;
Garfield Tan966c0412019-11-19 11:34:27 -080075import android.app.WindowConfiguration;
Garfield Tan36a69ad2019-01-16 17:08:23 -080076import android.app.servertransaction.ActivityConfigurationChangeItem;
Bryce Lee0bd8d422018-01-09 09:45:57 -080077import android.app.servertransaction.ClientTransaction;
78import android.app.servertransaction.PauseActivityItem;
Louis Chang6a9be162019-07-15 10:41:32 +080079import android.content.ComponentName;
wilsonshiha96aac62019-11-18 14:53:34 +080080import android.content.Intent;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080081import android.content.pm.ActivityInfo;
Garfield Tan0443b372019-01-04 15:00:13 -080082import android.content.res.Configuration;
Louis Chang6a9be162019-07-15 10:41:32 +080083import android.content.res.Resources;
Garfield Tan966c0412019-11-19 11:34:27 -080084import android.graphics.Rect;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070085import android.os.Bundle;
86import android.os.PersistableBundle;
Riddle Hsudb94bfd2020-05-13 01:50:17 +080087import android.os.RemoteException;
Bryce Leeaf691c02017-03-20 14:20:22 -070088import android.platform.test.annotations.Presubmit;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080089import android.util.MergedConfiguration;
Andrii Kulian04470682018-01-10 15:32:31 -080090import android.util.MutableBoolean;
Garfield Tan972bbd92020-03-25 18:28:12 -070091import android.view.DisplayInfo;
Jorim Jaggi346702a2019-05-08 17:49:33 +020092import android.view.IRemoteAnimationFinishedCallback;
93import android.view.IRemoteAnimationRunner.Stub;
Riddle Hsudb94bfd2020-05-13 01:50:17 +080094import android.view.IWindowSession;
Jorim Jaggi346702a2019-05-08 17:49:33 +020095import android.view.RemoteAnimationAdapter;
96import android.view.RemoteAnimationTarget;
Riddle Hsudb94bfd2020-05-13 01:50:17 +080097import android.view.WindowManager;
98import android.view.WindowManagerGlobal;
Bryce Leeaf691c02017-03-20 14:20:22 -070099
Brett Chabota26eda92018-07-23 13:08:30 -0700100import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -0700101
Louis Chang6a9be162019-07-15 10:41:32 +0800102import com.android.internal.R;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700103import com.android.server.wm.ActivityStack.ActivityState;
Riddle Hsu74826262019-04-17 14:57:42 +0800104
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700105import org.junit.Before;
Bryce Leeaf691c02017-03-20 14:20:22 -0700106import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +0800107import org.junit.runner.RunWith;
Andrii Kulian04470682018-01-10 15:32:31 -0800108import org.mockito.invocation.InvocationOnMock;
Bryce Lee0bd8d422018-01-09 09:45:57 -0800109
Bryce Leeaf691c02017-03-20 14:20:22 -0700110/**
111 * Tests for the {@link ActivityRecord} class.
112 *
113 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900114 * atest WmTests:ActivityRecordTests
Bryce Leeaf691c02017-03-20 14:20:22 -0700115 */
116@MediumTest
Bryce Lee3115bdf2017-04-05 08:39:40 -0700117@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +0800118@RunWith(WindowTestRunner.class)
Bryce Leeaf691c02017-03-20 14:20:22 -0700119public class ActivityRecordTests extends ActivityTestsBase {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700120 private ActivityStack mStack;
Louis Changcdec0802019-11-11 11:45:07 +0800121 private Task mTask;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700122 private ActivityRecord mActivity;
123
124 @Before
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700125 public void setUp() throws Exception {
Louis Chang149d5c82019-12-30 09:47:39 +0800126 mStack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900127 mTask = mStack.getBottomMostTask();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800128 mActivity = mTask.getTopNonFinishingActivity();
Andrii Kulian6b321512019-01-23 06:37:00 +0000129
130 doReturn(false).when(mService).isBooting();
131 doReturn(true).when(mService).isBooted();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700132 }
133
Bryce Leeaf691c02017-03-20 14:20:22 -0700134 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900135 public void testStackCleanupOnClearingTask() {
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200136 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800137 verify(mStack, times(1)).cleanUpActivityReferences(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700138 }
139
140 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900141 public void testStackCleanupOnActivityRemoval() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200142 mTask.removeChild(mActivity);
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800143 verify(mStack, times(1)).cleanUpActivityReferences(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700144 }
145
146 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900147 public void testStackCleanupOnTaskRemoval() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200148 mStack.removeChild(mTask, null /*reason*/);
Bryce Lee04ab3462017-04-10 15:06:33 -0700149 // Stack should be gone on task removal.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800150 assertNull(mService.mRootWindowContainer.getStack(mStack.mTaskId));
Bryce Leeaf691c02017-03-20 14:20:22 -0700151 }
152
153 @Test
Louis Changfd5539e2020-02-04 14:34:24 +0800154 public void testRemoveChildWithOverlayActivity() {
155 final ActivityRecord overlayActivity =
156 new ActivityBuilder(mService).setTask(mTask).build();
157 overlayActivity.setTaskOverlay(true);
158 final ActivityRecord overlayActivity2 =
159 new ActivityBuilder(mService).setTask(mTask).build();
160 overlayActivity2.setTaskOverlay(true);
161
162 mTask.removeChild(overlayActivity2, "test");
163 verify(mSupervisor, never()).removeTask(any(), anyBoolean(), anyBoolean(), any());
164 }
165
166 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900167 public void testNoCleanupMovingActivityInSameStack() {
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800168 final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700169 mActivity.reparent(newTask, 0, null /*reason*/);
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800170 verify(mStack, times(0)).cleanUpActivityReferences(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700171 }
Andrii Kulian3a1619d2017-07-07 14:38:09 -0700172
Andreas Gampecea9e6d2018-02-22 18:06:44 -0800173 @Test
Bryce Lee0bd8d422018-01-09 09:45:57 -0800174 public void testPausingWhenVisibleFromStopped() throws Exception {
Andrii Kulian04470682018-01-10 15:32:31 -0800175 final MutableBoolean pauseFound = new MutableBoolean(false);
176 doAnswer((InvocationOnMock invocationOnMock) -> {
177 final ClientTransaction transaction = invocationOnMock.getArgument(0);
178 if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
179 pauseFound.value = true;
Bryce Lee0bd8d422018-01-09 09:45:57 -0800180 }
Andrii Kulian04470682018-01-10 15:32:31 -0800181 return null;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700182 }).when(mActivity.app.getThread()).scheduleTransaction(any());
Bryce Leed939cf02018-03-12 09:04:44 -0700183
Bryce Lee7ace3952018-02-16 14:34:32 -0800184 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
Bryce Lee0bd8d422018-01-09 09:45:57 -0800185
Andrii Kulian6b321512019-01-23 06:37:00 +0000186 // The activity is in the focused stack so it should be resumed.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700187 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Andrii Kulian6b321512019-01-23 06:37:00 +0000188 assertTrue(mActivity.isState(RESUMED));
Bryce Leed939cf02018-03-12 09:04:44 -0700189 assertFalse(pauseFound.value);
Andrii Kulian04470682018-01-10 15:32:31 -0800190
Andrii Kulian6b321512019-01-23 06:37:00 +0000191 // Make the activity non focusable
192 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
193 doReturn(false).when(mActivity).isFocusable();
Bryce Leed939cf02018-03-12 09:04:44 -0700194
Andrii Kulian6b321512019-01-23 06:37:00 +0000195 // If the activity is not focusable, it should move to paused.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700196 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee7ace3952018-02-16 14:34:32 -0800197 assertTrue(mActivity.isState(PAUSING));
Andrii Kulian04470682018-01-10 15:32:31 -0800198 assertTrue(pauseFound.value);
Bryce Lee052957b2018-01-16 11:13:30 -0800199
200 // Make sure that the state does not change for current non-stopping states.
Bryce Lee7ace3952018-02-16 14:34:32 -0800201 mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
Andrii Kulian6b321512019-01-23 06:37:00 +0000202 doReturn(true).when(mActivity).isFocusable();
Bryce Lee052957b2018-01-16 11:13:30 -0800203
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700204 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee052957b2018-01-16 11:13:30 -0800205
Bryce Lee7ace3952018-02-16 14:34:32 -0800206 assertTrue(mActivity.isState(INITIALIZING));
Bryce Leea0fb8e02018-02-28 14:21:07 -0800207
208 // Make sure the state does not change if we are not the current top activity.
209 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
210
Bryce Leea0fb8e02018-02-28 14:21:07 -0800211 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
212 mStack.mTranslucentActivityWaiting = topActivity;
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700213 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Louis Changeadb22f2019-06-19 12:09:23 +0800214 assertTrue(mActivity.isState(STARTED));
215
216 mStack.mTranslucentActivityWaiting = null;
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700217 topActivity.setOccludesParent(false);
Louis Changeadb22f2019-06-19 12:09:23 +0800218 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
219 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
220 assertTrue(mActivity.isState(STARTED));
Bryce Lee0bd8d422018-01-09 09:45:57 -0800221 }
222
Riddle Hsu0a343c32018-12-21 00:40:48 +0800223 private void ensureActivityConfiguration() {
224 mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
225 }
226
Bryce Lee1533b2b2017-09-14 17:06:41 -0700227 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900228 public void testCanBeLaunchedOnDisplay() {
Riddle Hsu16567132018-08-16 21:37:47 +0800229 mService.mSupportsMultiWindow = true;
230 final ActivityRecord activity = new ActivityBuilder(mService).build();
Bryce Lee1533b2b2017-09-14 17:06:41 -0700231
Riddle Hsu16567132018-08-16 21:37:47 +0800232 // An activity can be launched on default display.
233 assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
234 // An activity cannot be launched on a non-existent display.
Garfield Tan5423cf02019-12-06 17:02:38 -0800235 assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE));
Bryce Lee1533b2b2017-09-14 17:06:41 -0700236 }
237
chaviw82a0ba82018-03-15 14:26:29 -0700238 @Test
239 public void testsApplyOptionsLocked() {
240 ActivityOptions activityOptions = ActivityOptions.makeBasic();
241
242 // Set and apply options for ActivityRecord. Pending options should be cleared
243 mActivity.updateOptionsLocked(activityOptions);
244 mActivity.applyOptionsLocked();
245 assertNull(mActivity.pendingOptions);
246
247 // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
248 // Pending options should be cleared for both ActivityRecords
249 ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
250 activity2.updateOptionsLocked(activityOptions);
251 mActivity.updateOptionsLocked(activityOptions);
252 mActivity.applyOptionsLocked();
253 assertNull(mActivity.pendingOptions);
254 assertNull(activity2.pendingOptions);
255
256 // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
257 // Pending options should be cleared for only ActivityRecord that was applied
Louis Changcdec0802019-11-11 11:45:07 +0800258 Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
chaviw82a0ba82018-03-15 14:26:29 -0700259 activity2 = new ActivityBuilder(mService).setTask(task2).build();
260 activity2.updateOptionsLocked(activityOptions);
261 mActivity.updateOptionsLocked(activityOptions);
262 mActivity.applyOptionsLocked();
263 assertNull(mActivity.pendingOptions);
264 assertNotNull(activity2.pendingOptions);
265 }
Garfield Tan0443b372019-01-04 15:00:13 -0800266
267 @Test
268 public void testNewOverrideConfigurationIncrementsSeq() {
269 final Configuration newConfig = new Configuration();
270
271 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
272 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
273 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
274 }
275
276 @Test
277 public void testNewParentConfigurationIncrementsSeq() {
278 final Configuration newConfig = new Configuration(
279 mTask.getRequestedOverrideConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700280 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
281 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
Garfield Tan0443b372019-01-04 15:00:13 -0800282
283 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
284 mTask.onRequestedOverrideConfigurationChanged(newConfig);
285 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
286 }
287
288 @Test
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800289 public void testSetsRelaunchReason_NotDragResizing() {
290 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
291
292 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
293 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
294 mActivity.getConfiguration()));
295
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700296 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800297 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700298 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
299 ? ORIENTATION_LANDSCAPE
300 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800301 mTask.onRequestedOverrideConfigurationChanged(newConfig);
302
303 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
304
Riddle Hsu0a343c32018-12-21 00:40:48 +0800305 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800306
307 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
308 mActivity.mRelaunchReason);
309 }
310
311 @Test
312 public void testSetsRelaunchReason_DragResizing() {
313 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
314
315 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
316 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
317 mActivity.getConfiguration()));
318
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700319 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800320 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700321 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
322 ? ORIENTATION_LANDSCAPE
323 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800324 mTask.onRequestedOverrideConfigurationChanged(newConfig);
325
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200326 doReturn(true).when(mTask).isDragResizing();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800327
328 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
329
Riddle Hsu0a343c32018-12-21 00:40:48 +0800330 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800331
332 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
333 mActivity.mRelaunchReason);
334 }
335
336 @Test
337 public void testSetsRelaunchReason_NonResizeConfigChanges() {
338 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
339
340 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
341 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
342 mActivity.getConfiguration()));
343
344 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
345 final Configuration newConfig = new Configuration(mTask.getConfiguration());
346 newConfig.fontScale = 5;
347 mTask.onRequestedOverrideConfigurationChanged(newConfig);
348
349 mActivity.mRelaunchReason =
350 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
351
Riddle Hsu0a343c32018-12-21 00:40:48 +0800352 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800353
354 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
355 mActivity.mRelaunchReason);
356 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800357
358 @Test
359 public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700360 mActivity = new ActivityBuilder(mService)
361 .setTask(mTask)
362 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
363 .build();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800364 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
365
Garfield Tan36a69ad2019-01-16 17:08:23 -0800366 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
367 mActivity.getConfiguration()));
368
Garfield Tan36a69ad2019-01-16 17:08:23 -0800369 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700370 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
371 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
372 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
373 newConfig.orientation = ORIENTATION_LANDSCAPE;
374 newConfig.screenWidthDp = longSide;
375 newConfig.screenHeightDp = shortSide;
376 } else {
377 newConfig.orientation = ORIENTATION_PORTRAIT;
378 newConfig.screenWidthDp = shortSide;
379 newConfig.screenHeightDp = longSide;
380 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800381
382 // Mimic the behavior that display doesn't handle app's requested orientation.
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200383 final DisplayContent dc = mTask.getDisplayContent();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700384 doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
385 doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800386
387 final int requestedOrientation;
388 switch (newConfig.orientation) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700389 case ORIENTATION_LANDSCAPE:
390 requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE;
Garfield Tan36a69ad2019-01-16 17:08:23 -0800391 break;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700392 case ORIENTATION_PORTRAIT:
Garfield Tan36a69ad2019-01-16 17:08:23 -0800393 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
394 break;
395 default:
396 throw new IllegalStateException("Orientation in new config should be either"
397 + "landscape or portrait.");
398 }
399 mActivity.setRequestedOrientation(requestedOrientation);
400
401 final ActivityConfigurationChangeItem expected =
402 ActivityConfigurationChangeItem.obtain(newConfig);
403 verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
404 eq(mActivity.appToken), eq(expected));
405 }
Andrii Kulianf2195362019-01-31 18:20:11 -0800406
407 @Test
Garfield Tan966c0412019-11-19 11:34:27 -0800408 public void ignoreRequestedOrientationInFreeformWindows() {
409 mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
410 final Rect stableRect = new Rect();
411 mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
Garfield Tan972bbd92020-03-25 18:28:12 -0700412
413 // Carve out non-decor insets from stableRect
414 final Rect insets = new Rect();
415 final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo();
416 final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy();
417 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
418 displayInfo.logicalHeight, displayInfo.displayCutout, insets);
419 policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
420 Task.intersectWithInsetsIfFits(stableRect, stableRect, insets);
421
Garfield Tan966c0412019-11-19 11:34:27 -0800422 final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
423 final Rect bounds = new Rect(stableRect);
424 if (isScreenPortrait) {
425 // Landscape bounds
426 final int newHeight = stableRect.width() - 10;
427 bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
428 bounds.bottom = bounds.top + newHeight;
429 } else {
430 // Portrait bounds
431 final int newWidth = stableRect.height() - 10;
432 bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
433 bounds.right = bounds.left + newWidth;
434 }
435 mTask.setBounds(bounds);
436
437 // Requests orientation that's different from its bounds.
438 mActivity.setRequestedOrientation(
439 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
440
441 // Asserts it has orientation derived from bounds.
442 assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
443 mActivity.getConfiguration().orientation);
444 }
445
446 @Test
447 public void ignoreRequestedOrientationInSplitWindows() {
448 mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
449 final Rect stableRect = new Rect();
Garfield Tan972bbd92020-03-25 18:28:12 -0700450 mStack.getDisplay().getStableRect(stableRect);
451
452 // Carve out non-decor insets from stableRect
453 final Rect insets = new Rect();
454 final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo();
455 final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy();
456 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
457 displayInfo.logicalHeight, displayInfo.displayCutout, insets);
458 policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
459 Task.intersectWithInsetsIfFits(stableRect, stableRect, insets);
460
Garfield Tan966c0412019-11-19 11:34:27 -0800461 final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
462 final Rect bounds = new Rect(stableRect);
463 if (isScreenPortrait) {
464 // Landscape bounds
465 final int newHeight = stableRect.width() - 10;
466 bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
467 bounds.bottom = bounds.top + newHeight;
468 } else {
469 // Portrait bounds
470 final int newWidth = stableRect.height() - 10;
471 bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
472 bounds.right = bounds.left + newWidth;
473 }
474 mTask.setBounds(bounds);
475
476 // Requests orientation that's different from its bounds.
477 mActivity.setRequestedOrientation(
478 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
479
480 // Asserts it has orientation derived from bounds.
481 assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
482 mActivity.getConfiguration().orientation);
483 }
484
485 @Test
Andrii Kulianf2195362019-01-31 18:20:11 -0800486 public void testShouldMakeActive_deferredResume() {
487 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
488
489 mSupervisor.beginDeferResume();
490 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
491
492 mSupervisor.endDeferResume();
493 assertEquals(true, mActivity.shouldMakeActive(null /* activeActivity */));
494 }
Garfield Tan40263302019-02-01 15:27:35 -0800495
496 @Test
Louis Changdfeea6d2020-05-11 12:22:58 +0800497 public void testShouldMakeActive_nonTopVisible() {
498 ActivityRecord finishingActivity = new ActivityBuilder(mService).setTask(mTask).build();
499 finishingActivity.finishing = true;
500 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
501 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
502
503 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
504 }
505
506 @Test
Andrii Kulian0c869cc2019-02-06 19:50:32 -0800507 public void testShouldResume_stackVisibility() {
508 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
509 spyOn(mStack);
510
511 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
512 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
513
514 doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
515 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
516
517 doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
518 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
519 }
520
521 @Test
wilsonshiha96aac62019-11-18 14:53:34 +0800522 public void testShouldResumeOrPauseWithResults() {
523 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
524 spyOn(mStack);
525
526 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
527 mActivity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
528 topActivity.finishing = true;
529
530 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
531 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
532 assertEquals(false, mActivity.shouldPauseActivity(null /*activeActivity */));
533 }
534
535 @Test
Garfield Tan40263302019-02-01 15:27:35 -0800536 public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700537 mActivity = new ActivityBuilder(mService)
538 .setTask(mTask)
539 .setLaunchTaskBehind(true)
540 .setConfigChanges(CONFIG_ORIENTATION)
541 .build();
Garfield Tan40263302019-02-01 15:27:35 -0800542 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
543
Louis Chang149d5c82019-12-30 09:47:39 +0800544 final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
Garfield Tan40263302019-02-01 15:27:35 -0800545 try {
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800546 doReturn(false).when(stack).isTranslucent(any());
Garfield Tan40263302019-02-01 15:27:35 -0800547 assertFalse(mStack.shouldBeVisible(null /* starting */));
548
Garfield Tan40263302019-02-01 15:27:35 -0800549 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
550 mActivity.getConfiguration()));
551
Garfield Tan40263302019-02-01 15:27:35 -0800552 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700553 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
554 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
555 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
556 newConfig.orientation = ORIENTATION_LANDSCAPE;
557 newConfig.screenWidthDp = longSide;
558 newConfig.screenHeightDp = shortSide;
559 } else {
560 newConfig.orientation = ORIENTATION_PORTRAIT;
561 newConfig.screenWidthDp = shortSide;
562 newConfig.screenHeightDp = longSide;
563 }
Garfield Tan40263302019-02-01 15:27:35 -0800564
565 mTask.onConfigurationChanged(newConfig);
566
567 mActivity.ensureActivityConfiguration(0 /* globalChanges */,
568 false /* preserveWindow */, true /* ignoreStopState */);
569
570 final ActivityConfigurationChangeItem expected =
571 ActivityConfigurationChangeItem.obtain(newConfig);
572 verify(mService.getLifecycleManager()).scheduleTransaction(
573 eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
574 } finally {
Andrii Kulian86d676c2020-03-27 19:34:54 -0700575 stack.getDisplayArea().removeChild(stack);
Garfield Tan40263302019-02-01 15:27:35 -0800576 }
577 }
Riddle Hsu0a343c32018-12-21 00:40:48 +0800578
579 @Test
Andrii Kulianb9faa032019-10-17 23:11:54 -0700580 public void testShouldStartWhenMakeClientActive() {
Louis Chang3d119a92019-04-22 10:45:37 +0800581 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700582 topActivity.setOccludesParent(false);
Louis Chang3d119a92019-04-22 10:45:37 +0800583 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
Andrii Kulianb9faa032019-10-17 23:11:54 -0700584 mActivity.setVisibility(true);
585 mActivity.makeActiveIfNeeded(null /* activeActivity */);
Louis Changeadb22f2019-06-19 12:09:23 +0800586 assertEquals(STARTED, mActivity.getState());
Louis Chang3d119a92019-04-22 10:45:37 +0800587 }
588
589 @Test
Jorim Jaggi346702a2019-05-08 17:49:33 +0200590 public void testTakeOptions() {
591 ActivityOptions opts = ActivityOptions.makeRemoteAnimation(
592 new RemoteAnimationAdapter(new Stub() {
593
594 @Override
595 public void onAnimationStart(RemoteAnimationTarget[] apps,
Winson Chungd5852192019-09-06 17:20:28 -0700596 RemoteAnimationTarget[] wallpapers,
Jorim Jaggi346702a2019-05-08 17:49:33 +0200597 IRemoteAnimationFinishedCallback finishedCallback) {
598
599 }
600
601 @Override
602 public void onAnimationCancelled() {
603
604 }
605 }, 0, 0));
606 mActivity.updateOptionsLocked(opts);
607 assertNotNull(mActivity.takeOptionsLocked(true /* fromClient */));
608 assertNotNull(mActivity.pendingOptions);
609
610 mActivity.updateOptionsLocked(ActivityOptions.makeBasic());
611 assertNotNull(mActivity.takeOptionsLocked(false /* fromClient */));
612 assertNull(mActivity.pendingOptions);
613 }
614
Louis Chang6a9be162019-07-15 10:41:32 +0800615 @Test
616 public void testCanLaunchHomeActivityFromChooser() {
617 ComponentName chooserComponent = ComponentName.unflattenFromString(
618 Resources.getSystem().getString(R.string.config_chooserActivity));
619 ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
620 chooserComponent).build();
621 assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
622 }
623
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700624 /**
625 * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and
626 * that it is cleared after activity is resumed.
627 */
628 @Test
629 public void testHasSavedState() {
630 assertTrue(mActivity.hasSavedState());
631
632 ActivityRecord.activityResumedLocked(mActivity.appToken);
633 assertFalse(mActivity.hasSavedState());
634 assertNull(mActivity.getSavedState());
635 }
636
637 /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */
638 @Test
639 public void testUpdateSavedState() {
640 mActivity.setSavedState(null /* savedState */);
641 assertFalse(mActivity.hasSavedState());
642 assertNull(mActivity.getSavedState());
643
644 final Bundle savedState = new Bundle();
645 savedState.putString("test", "string");
646 mActivity.setSavedState(savedState);
647 assertTrue(mActivity.hasSavedState());
648 assertEquals(savedState, mActivity.getSavedState());
649 }
650
651 /** Verify the correct updates of saved state when activity client reports stop. */
652 @Test
653 public void testUpdateSavedState_activityStopped() {
654 final Bundle savedState = new Bundle();
655 savedState.putString("test", "string");
656 final PersistableBundle persistentSavedState = new PersistableBundle();
657 persistentSavedState.putString("persist", "string");
658
659 // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored.
660 mActivity.setState(STOPPING, "test");
Wale Ogunwale196db712019-12-27 15:35:39 +0000661 mActivity.activityStopped(savedState, persistentSavedState, "desc");
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700662 assertTrue(mActivity.hasSavedState());
663 assertEquals(savedState, mActivity.getSavedState());
664 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
665
666 // Sending 'null' for saved state can only happen due to timeout, so previously stored saved
667 // states should not be overridden.
668 mActivity.setState(STOPPING, "test");
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800669 mActivity.activityStopped(null /* savedState */, null /* persistentSavedState */, "desc");
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700670 assertTrue(mActivity.hasSavedState());
671 assertEquals(savedState, mActivity.getSavedState());
672 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
673 }
674
Andrii Kulian057a6512019-07-15 16:15:51 -0700675 /**
676 * Verify that activity finish request is not performed if activity is finishing or is in
677 * incorrect state.
678 */
679 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700680 public void testFinishActivityIfPossible_cancelled() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700681 // Mark activity as finishing
682 mActivity.finishing = true;
683 assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700684 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700685 assertTrue(mActivity.finishing);
686 assertTrue(mActivity.isInStackLocked());
687
688 // Remove activity from task
689 mActivity.finishing = false;
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200690 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
Andrii Kulian057a6512019-07-15 16:15:51 -0700691 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700692 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700693 assertFalse(mActivity.finishing);
694 }
695
696 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700697 * Verify that activity finish request is placed, but not executed immediately if activity is
Andrii Kulian057a6512019-07-15 16:15:51 -0700698 * not ready yet.
699 */
700 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700701 public void testFinishActivityIfPossible_requested() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700702 mActivity.finishing = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700703 assertEquals("Currently resumed activity must be prepared removal", FINISH_RESULT_REQUESTED,
704 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700705 assertTrue(mActivity.finishing);
706 assertTrue(mActivity.isInStackLocked());
707
708 // First request to finish activity must schedule a "destroy" request to the client.
709 // Activity must be removed from history after the client reports back or after timeout.
710 mActivity.finishing = false;
711 mActivity.setState(STOPPED, "test");
712 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700713 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700714 assertTrue(mActivity.finishing);
715 assertTrue(mActivity.isInStackLocked());
716 }
717
718 /**
719 * Verify that activity finish request removes activity immediately if it's ready.
720 */
721 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700722 public void testFinishActivityIfPossible_removed() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700723 // Prepare the activity record to be ready for immediate removal. It should be invisible and
724 // have no process. Otherwise, request to finish it will send a message to client first.
725 mActivity.setState(STOPPED, "test");
Issei Suzuki1669ea42019-11-06 14:20:59 +0100726 mActivity.mVisibleRequested = false;
Andrii Kulian057a6512019-07-15 16:15:51 -0700727 mActivity.nowVisible = false;
728 // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
729 // this will cause NPE when updating task's process.
730 mActivity.app = null;
wilsonshih4c9824a2019-10-25 18:47:50 +0800731
732 // Put a visible activity on top, so the finishing activity doesn't have to wait until the
733 // next activity reports idle to destroy it.
734 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100735 topActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +0800736 topActivity.nowVisible = true;
737 topActivity.setState(RESUMED, "test");
738
Andrii Kulian057a6512019-07-15 16:15:51 -0700739 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REMOVED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700740 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700741 assertTrue(mActivity.finishing);
742 assertFalse(mActivity.isInStackLocked());
743 }
744
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700745 /**
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800746 * Verify that when finishing the top focused activity on top display, the stack order will be
747 * changed by adjusting focus.
748 */
749 @Test
750 public void testFinishActivityIfPossible_adjustStackOrder() {
751 // Prepare the stacks with order (top to bottom): mStack, stack1, stack2.
Louis Chang149d5c82019-12-30 09:47:39 +0800752 final ActivityStack stack1 = new StackBuilder(mRootWindowContainer).build();
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800753 mStack.moveToFront("test");
754 // The stack2 is needed here for moving back to simulate the
Louis Chang677921f2019-12-06 16:44:24 +0800755 // {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so
756 // {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800757 // stacks. Then when mActivity is finishing, its stack will be invisible (no running
758 // activities in the stack) that is the key condition to verify.
Louis Chang149d5c82019-12-30 09:47:39 +0800759 final ActivityStack stack2 = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900760 stack2.moveToBack("test", stack2.getBottomMostTask());
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800761
Andrii Kulian86d676c2020-03-27 19:34:54 -0700762 assertTrue(mStack.isTopStackInDisplayArea());
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800763
764 mActivity.setState(RESUMED, "test");
765 mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test",
Louis Chang7b03ad92019-08-21 12:32:33 +0800766 false /* oomAdj */);
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800767
Andrii Kulian86d676c2020-03-27 19:34:54 -0700768 assertTrue(stack1.isTopStackInDisplayArea());
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800769 }
770
771 /**
Louis Chang6434be42020-04-10 17:39:35 +0800772 * Verify that when finishing the top focused activity while root task was created by organizer,
773 * the stack order will be changed by adjusting focus.
774 */
775 @Test
776 public void testFinishActivityIfPossible_adjustStackOrderOrganizedRoot() {
777 // Make mStack be a the root task that created by task organizer
778 mStack.mCreatedByOrganizer = true;
779
780 // Have two tasks (topRootableTask and mTask) as the children of mStack.
781 ActivityRecord topActivity = new ActivityBuilder(mActivity.mAtmService)
782 .setCreateTask(true)
783 .setStack(mStack)
784 .build();
785 ActivityStack topRootableTask = (ActivityStack) topActivity.getTask();
786 topRootableTask.moveToFront("test");
787 assertTrue(mStack.isTopStackInDisplayArea());
788
789 // Finish top activity and verify the next focusable rootable task has adjusted to top.
790 topActivity.setState(RESUMED, "test");
791 topActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test",
792 false /* oomAdj */);
793 assertEquals(mTask, mStack.getTopMostTask());
794 }
795
796 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700797 * Verify that resumed activity is paused due to finish request.
798 */
799 @Test
800 public void testFinishActivityIfPossible_resumedStartsPausing() {
801 mActivity.finishing = false;
802 mActivity.setState(RESUMED, "test");
803 assertEquals("Currently resumed activity must be paused before removal",
804 FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */));
805 assertEquals(PAUSING, mActivity.getState());
806 verify(mActivity).setVisibility(eq(false));
807 verify(mActivity.getDisplay().mDisplayContent)
808 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
809 }
810
811 /**
812 * Verify that finish request will be completed immediately for non-resumed activity.
813 */
814 @Test
815 public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() {
816 final ActivityState[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED};
817 for (ActivityState state : states) {
818 mActivity.finishing = false;
819 mActivity.setState(state, "test");
820 reset(mActivity);
821 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
822 mActivity.finishIfPossible("test", false /* oomAdj */));
823 verify(mActivity).completeFinishing(anyString());
824 }
825 }
826
827 /**
828 * Verify that finishing will not be completed in PAUSING state.
829 */
830 @Test
831 public void testFinishActivityIfPossible_pausing() {
832 mActivity.finishing = false;
833 mActivity.setState(PAUSING, "test");
834 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
835 mActivity.finishIfPossible("test", false /* oomAdj */));
836 verify(mActivity, never()).completeFinishing(anyString());
837 }
838
839 /**
840 * Verify that finish request for resumed activity will prepare an app transition but not
841 * execute it immediately.
842 */
843 @Test
844 public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() {
845 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100846 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700847 mActivity.setState(RESUMED, "test");
848 mActivity.finishIfPossible("test", false /* oomAdj */);
849
850 verify(mActivity).setVisibility(eq(false));
851 verify(mActivity.getDisplay().mDisplayContent)
852 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
853 verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition();
854 }
855
856 /**
857 * Verify that finish request for paused activity will prepare and execute an app transition.
858 */
859 @Test
860 public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() {
861 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100862 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700863 mActivity.setState(PAUSED, "test");
864 mActivity.finishIfPossible("test", false /* oomAdj */);
865
Andrii Kulian149d9ad32019-08-23 15:04:17 -0700866 verify(mActivity, atLeast(1)).setVisibility(eq(false));
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700867 verify(mActivity.getDisplay().mDisplayContent)
868 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
869 verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
870 }
871
872 /**
873 * Verify that finish request for non-visible activity will not prepare any transitions.
874 */
875 @Test
876 public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
877 // Put an activity on top of test activity to make it invisible and prevent us from
878 // accidentally resuming the topmost one again.
879 new ActivityBuilder(mService).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100880 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700881 mActivity.setState(STOPPED, "test");
882
883 mActivity.finishIfPossible("test", false /* oomAdj */);
884
885 verify(mActivity.getDisplay().mDisplayContent, never())
886 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
887 }
888
889 /**
890 * Verify that complete finish request for non-finishing activity is invalid.
891 */
892 @Test(expected = IllegalArgumentException.class)
893 public void testCompleteFinishing_failNotFinishing() {
894 mActivity.finishing = false;
895 mActivity.completeFinishing("test");
896 }
897
898 /**
899 * Verify that complete finish request for resumed activity is invalid.
900 */
901 @Test(expected = IllegalArgumentException.class)
902 public void testCompleteFinishing_failResumed() {
903 mActivity.setState(RESUMED, "test");
904 mActivity.completeFinishing("test");
905 }
906
907 /**
908 * Verify that finish request for pausing activity must be a no-op - activity will finish
909 * once it completes pausing.
910 */
911 @Test
912 public void testCompleteFinishing_pausing() {
913 mActivity.setState(PAUSING, "test");
914 mActivity.finishing = true;
915
916 assertEquals("Activity must not be removed immediately - waiting for paused",
917 mActivity, mActivity.completeFinishing("test"));
918 assertEquals(PAUSING, mActivity.getState());
919 verify(mActivity, never()).destroyIfPossible(anyString());
920 }
921
922 /**
Riddle Hsucf920232019-10-04 19:05:36 +0800923 * Verify that finish request won't change the state of next top activity if the current
924 * finishing activity doesn't need to be destroyed immediately. The case is usually like
925 * from {@link ActivityStack#completePauseLocked(boolean, ActivityRecord)} to
926 * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the
927 * responsibility to resume the next activity with updating the state.
928 */
929 @Test
930 public void testCompleteFinishing_keepStateOfNextInvisible() {
931 final ActivityRecord currentTop = mActivity;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100932 currentTop.mVisibleRequested = currentTop.nowVisible = true;
Riddle Hsucf920232019-10-04 19:05:36 +0800933
934 // Simulates that {@code currentTop} starts an existing activity from background (so its
935 // state is stopped) and the starting flow just goes to place it at top.
Louis Chang149d5c82019-12-30 09:47:39 +0800936 final ActivityStack nextStack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800937 final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity();
Riddle Hsucf920232019-10-04 19:05:36 +0800938 nextTop.setState(STOPPED, "test");
939
940 mStack.mPausingActivity = currentTop;
941 currentTop.finishing = true;
942 currentTop.setState(PAUSED, "test");
943 currentTop.completeFinishing("completePauseLocked");
944
945 // Current top becomes stopping because it is visible and the next is invisible.
946 assertEquals(STOPPING, currentTop.getState());
947 // The state of next activity shouldn't be changed.
948 assertEquals(STOPPED, nextTop.getState());
949 }
950
951 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700952 * Verify that complete finish request for visible activity must be delayed before the next one
953 * becomes visible.
954 */
955 @Test
956 public void testCompleteFinishing_waitForNextVisible() {
957 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100958 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700959 topActivity.nowVisible = true;
960 topActivity.finishing = true;
961 topActivity.setState(PAUSED, "true");
962 // Mark the bottom activity as not visible, so that we will wait for it before removing
963 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100964 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700965 mActivity.nowVisible = false;
966 mActivity.setState(STOPPED, "test");
967
968 assertEquals("Activity must not be removed immediately - waiting for next visible",
969 topActivity, topActivity.completeFinishing("test"));
970 assertEquals("Activity must be stopped to make next one visible", STOPPING,
971 topActivity.getState());
972 assertTrue("Activity must be stopped to make next one visible",
973 topActivity.mStackSupervisor.mStoppingActivities.contains(topActivity));
974 verify(topActivity, never()).destroyIfPossible(anyString());
975 }
976
977 /**
978 * Verify that complete finish request for invisible activity must not be delayed.
979 */
980 @Test
981 public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
982 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100983 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700984 topActivity.nowVisible = false;
985 topActivity.finishing = true;
Issei Suzukid0c14f32019-12-19 12:42:13 +0100986 topActivity.setState(STOPPED, "true");
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700987 // Mark the bottom activity as not visible, so that we would wait for it before removing
988 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100989 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700990 mActivity.nowVisible = false;
991 mActivity.setState(STOPPED, "test");
992
993 topActivity.completeFinishing("test");
994
995 verify(topActivity).destroyIfPossible(anyString());
996 }
997
998 /**
999 * Verify that paused finishing activity will be added to finishing list and wait for next one
1000 * to idle.
1001 */
1002 @Test
1003 public void testCompleteFinishing_waitForIdle() {
1004 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +01001005 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001006 topActivity.nowVisible = true;
1007 topActivity.finishing = true;
1008 topActivity.setState(PAUSED, "true");
1009 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +01001010 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001011 mActivity.nowVisible = true;
1012 mActivity.setState(RESUMED, "test");
1013
1014 topActivity.completeFinishing("test");
1015
1016 verify(topActivity).addToFinishingAndWaitForIdle();
1017 }
1018
1019 /**
1020 * Verify that complete finish request for visible activity must not be delayed if the next one
1021 * is already visible and it's not the focused stack.
1022 */
1023 @Test
1024 public void testCompleteFinishing_noWaitForNextVisible_stopped() {
1025 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +01001026 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001027 topActivity.nowVisible = false;
1028 topActivity.finishing = true;
1029 topActivity.setState(STOPPED, "true");
1030 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +01001031 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001032 mActivity.nowVisible = true;
1033 mActivity.setState(RESUMED, "test");
1034
1035 topActivity.completeFinishing("test");
1036
1037 verify(topActivity).destroyIfPossible(anyString());
1038 }
1039
1040 /**
1041 * Verify that complete finish request for visible activity must not be delayed if the next one
1042 * is already visible and it's not the focused stack.
1043 */
1044 @Test
1045 public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
1046 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +01001047 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001048 topActivity.nowVisible = true;
1049 topActivity.finishing = true;
1050 topActivity.setState(PAUSED, "true");
1051 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +01001052 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001053 mActivity.nowVisible = true;
1054 mActivity.setState(RESUMED, "test");
1055
1056 // Add another stack to become focused and make the activity there visible. This way it
1057 // simulates finishing in non-focused stack in split-screen.
Louis Chang149d5c82019-12-30 09:47:39 +08001058 final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001059 final ActivityRecord focusedActivity = stack.getTopMostActivity();
wilsonshih4c9824a2019-10-25 18:47:50 +08001060 focusedActivity.nowVisible = true;
Issei Suzuki1669ea42019-11-06 14:20:59 +01001061 focusedActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +08001062 focusedActivity.setState(RESUMED, "test");
1063 stack.mResumedActivity = focusedActivity;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001064
1065 topActivity.completeFinishing("test");
1066
1067 verify(topActivity).destroyIfPossible(anyString());
1068 }
1069
1070 /**
Louis Chang3d718c32020-04-09 16:51:02 +08001071 * Verify that complete finish request for a show-when-locked activity must ensure the
1072 * keyguard occluded state being updated.
1073 */
1074 @Test
1075 public void testCompleteFinishing_showWhenLocked() {
1076 // Make keyguard locked and set the top activity show-when-locked.
1077 KeyguardController keyguardController = mActivity.mStackSupervisor.getKeyguardController();
1078 doReturn(true).when(keyguardController).isKeyguardLocked();
1079 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
1080 topActivity.mVisibleRequested = true;
1081 topActivity.nowVisible = true;
1082 topActivity.setState(RESUMED, "true");
1083 doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
1084 any() /* starting */, anyInt() /* configChanges */,
1085 anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
1086 topActivity.setShowWhenLocked(true);
1087
1088 // Verify the stack-top activity is occluded keyguard.
1089 assertEquals(topActivity, mStack.topRunningActivity());
1090 assertTrue(mStack.topActivityOccludesKeyguard());
1091
1092 // Finish the top activity
1093 topActivity.setState(PAUSED, "true");
1094 topActivity.finishing = true;
1095 topActivity.completeFinishing("test");
1096
1097 // Verify new top activity does not occlude keyguard.
1098 assertEquals(mActivity, mStack.topRunningActivity());
1099 assertFalse(mStack.topActivityOccludesKeyguard());
1100 }
1101
1102 /**
Jeff Changde2c5f12020-04-10 17:23:43 +08001103 * Verify that complete finish request for an activity which the resume activity is translucent
1104 * must ensure the visibilities of activities being updated.
1105 */
1106 @Test
1107 public void testCompleteFinishing_ensureActivitiesVisible() {
1108 final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
1109 firstActivity.mVisibleRequested = false;
1110 firstActivity.nowVisible = false;
1111 firstActivity.setState(STOPPED, "true");
1112
1113 final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
1114 secondActivity.mVisibleRequested = true;
1115 secondActivity.nowVisible = true;
1116 secondActivity.setState(PAUSED, "true");
1117
1118 final ActivityRecord translucentActivity =
1119 new ActivityBuilder(mService).setTask(mTask).build();
1120 translucentActivity.mVisibleRequested = true;
1121 translucentActivity.nowVisible = true;
1122 translucentActivity.setState(RESUMED, "true");
1123
1124 doReturn(false).when(translucentActivity).occludesParent();
1125
1126 // Finish the second activity
1127 secondActivity.finishing = true;
1128 secondActivity.completeFinishing("test");
1129 verify(secondActivity.getDisplay()).ensureActivitiesVisible(null /* starting */,
1130 0 /* configChanges */ , false /* preserveWindows */,
1131 true /* notifyClients */);
1132
1133 // Finish the first activity
1134 firstActivity.finishing = true;
1135 firstActivity.mVisibleRequested = true;
1136 firstActivity.completeFinishing("test");
1137 verify(firstActivity.getDisplay(), times(2)).ensureActivitiesVisible(null /* starting */,
1138 0 /* configChanges */ , false /* preserveWindows */,
1139 true /* notifyClients */);
1140 }
1141
1142 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001143 * Verify destroy activity request completes successfully.
1144 */
1145 @Test
1146 public void testDestroyIfPossible() {
Louis Chang149d5c82019-12-30 09:47:39 +08001147 doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001148 spyOn(mStack);
1149 mActivity.destroyIfPossible("test");
1150
1151 assertEquals(DESTROYING, mActivity.getState());
1152 assertTrue(mActivity.finishing);
Andrii Kulian79d67982019-08-19 11:56:16 -07001153 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001154 }
1155
1156 /**
1157 * Verify that complete finish request for visible activity must not destroy it immediately if
1158 * it is the last running activity on a display with a home stack. We must wait for home
1159 * activity to come up to avoid a black flash in this case.
1160 */
1161 @Test
1162 public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
1163 // Empty the home stack.
Andrii Kulian86d676c2020-03-27 19:34:54 -07001164 final ActivityStack homeStack = mActivity.getDisplayArea().getRootHomeTask();
Wale Ogunwale0d465192020-01-23 19:14:44 -08001165 homeStack.forAllLeafTasks((t) -> {
Wale Ogunwale8f93b642019-12-26 12:10:52 -08001166 homeStack.removeChild(t, "test");
Wale Ogunwale0d465192020-01-23 19:14:44 -08001167 }, true /* traverseTopToBottom */);
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001168 mActivity.finishing = true;
Louis Chang149d5c82019-12-30 09:47:39 +08001169 doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001170 spyOn(mStack);
1171
1172 // Try to destroy the last activity above the home stack.
1173 mActivity.destroyIfPossible("test");
1174
1175 // Verify that the activity was not actually destroyed, but waits for next one to come up
1176 // instead.
Andrii Kulian79d67982019-08-19 11:56:16 -07001177 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001178 assertEquals(FINISHING, mActivity.getState());
1179 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1180 }
1181
Andrii Kulian79d67982019-08-19 11:56:16 -07001182 /**
wilsonshih4c9824a2019-10-25 18:47:50 +08001183 * Verify that complete finish request for visible activity must resume next home stack before
1184 * destroying it immediately if it is the last running activity on a display with a home stack.
1185 * We must wait for home activity to come up to avoid a black flash in this case.
1186 */
1187 @Test
1188 public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
1189 // Empty the home stack.
Andrii Kulian86d676c2020-03-27 19:34:54 -07001190 final ActivityStack homeStack = mActivity.getDisplayArea().getRootHomeTask();
Wale Ogunwale0d465192020-01-23 19:14:44 -08001191 homeStack.forAllLeafTasks((t) -> {
Wale Ogunwale8f93b642019-12-26 12:10:52 -08001192 homeStack.removeChild(t, "test");
Wale Ogunwale0d465192020-01-23 19:14:44 -08001193 }, true /* traverseTopToBottom */);
wilsonshih4c9824a2019-10-25 18:47:50 +08001194 mActivity.finishing = true;
1195 spyOn(mStack);
1196
1197 // Try to finish the last activity above the home stack.
1198 mActivity.completeFinishing("test");
1199
1200 // Verify that the activity is not destroyed immediately, but waits for next one to come up.
1201 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1202 assertEquals(FINISHING, mActivity.getState());
1203 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1204 }
1205
1206 /**
Andrii Kulian79d67982019-08-19 11:56:16 -07001207 * Test that the activity will be moved to destroying state and the message to destroy will be
1208 * sent to the client.
1209 */
1210 @Test
1211 public void testDestroyImmediately_hadApp_finishing() {
1212 mActivity.finishing = true;
1213 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1214
1215 assertEquals(DESTROYING, mActivity.getState());
1216 }
1217
1218 /**
1219 * Test that the activity will be moved to destroyed state immediately if it was not marked as
1220 * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
1221 */
1222 @Test
1223 public void testDestroyImmediately_hadApp_notFinishing() {
1224 mActivity.finishing = false;
1225 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1226
1227 assertEquals(DESTROYED, mActivity.getState());
1228 }
1229
1230 /**
1231 * Test that an activity with no process attached and that is marked as finishing will be
1232 * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
1233 */
1234 @Test
1235 public void testDestroyImmediately_noApp_finishing() {
1236 mActivity.app = null;
1237 mActivity.finishing = true;
Louis Changcdec0802019-11-11 11:45:07 +08001238 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001239
1240 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1241
1242 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001243 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001244 assertEquals(0, task.getChildCount());
1245 }
1246
1247 /**
1248 * Test that an activity with no process attached and that is not marked as finishing will be
1249 * marked as DESTROYED but not removed from task.
1250 */
1251 @Test
1252 public void testDestroyImmediately_noApp_notFinishing() {
1253 mActivity.app = null;
1254 mActivity.finishing = false;
Louis Changcdec0802019-11-11 11:45:07 +08001255 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001256
1257 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1258
1259 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001260 assertEquals(task, mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001261 assertEquals(1, task.getChildCount());
1262 }
1263
1264 /**
1265 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1266 */
1267 @Test
1268 public void testSafelyDestroy_nonDestroyable() {
1269 doReturn(false).when(mActivity).isDestroyable();
1270
1271 mActivity.safelyDestroy("test");
1272
1273 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1274 }
1275
1276 /**
1277 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1278 */
1279 @Test
1280 public void testSafelyDestroy_destroyable() {
1281 doReturn(true).when(mActivity).isDestroyable();
1282
1283 mActivity.safelyDestroy("test");
1284
1285 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1286 }
1287
1288 @Test
1289 public void testRemoveFromHistory() {
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -08001290 final ActivityStack stack = mActivity.getRootTask();
Louis Changcdec0802019-11-11 11:45:07 +08001291 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001292
1293 mActivity.removeFromHistory("test");
1294
1295 assertEquals(DESTROYED, mActivity.getState());
1296 assertNull(mActivity.app);
Louis Changcdec0802019-11-11 11:45:07 +08001297 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001298 assertEquals(0, task.getChildCount());
Wale Ogunwale8f93b642019-12-26 12:10:52 -08001299 assertEquals(task.getStack(), task);
Andrii Kulian79d67982019-08-19 11:56:16 -07001300 assertEquals(0, stack.getChildCount());
1301 }
1302
1303 /**
1304 * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is
1305 * not in destroying or destroyed state.
1306 */
1307 @Test(expected = IllegalStateException.class)
1308 public void testDestroyed_notDestroying() {
1309 mActivity.setState(STOPPED, "test");
1310 mActivity.destroyed("test");
1311 }
1312
1313 /**
1314 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying
1315 */
1316 @Test
1317 public void testDestroyed_destroying() {
1318 mActivity.setState(DESTROYING, "test");
1319 mActivity.destroyed("test");
1320
1321 verify(mActivity).removeFromHistory(anyString());
1322 }
1323
1324 /**
1325 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed.
1326 */
1327 @Test
1328 public void testDestroyed_destroyed() {
1329 mActivity.setState(DESTROYED, "test");
1330 mActivity.destroyed("test");
1331
1332 verify(mActivity).removeFromHistory(anyString());
1333 }
Andrii Kulianfa23a9e2019-10-10 15:15:36 -07001334
1335 @Test
1336 public void testActivityOverridesProcessConfig() {
1337 final WindowProcessController wpc = mActivity.app;
1338 assertTrue(wpc.registeredForActivityConfigChanges());
1339 assertFalse(wpc.registeredForDisplayConfigChanges());
1340
1341 final ActivityRecord secondaryDisplayActivity =
1342 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1343
1344 assertTrue(wpc.registeredForActivityConfigChanges());
1345 assertEquals(0, mActivity.getMergedOverrideConfiguration()
1346 .diff(wpc.getRequestedOverrideConfiguration()));
1347 assertNotEquals(mActivity.getConfiguration(),
1348 secondaryDisplayActivity.getConfiguration());
1349 }
1350
1351 @Test
1352 public void testActivityOverridesProcessConfig_TwoActivities() {
1353 final WindowProcessController wpc = mActivity.app;
1354 assertTrue(wpc.registeredForActivityConfigChanges());
1355
1356 final Task firstTaskRecord = mActivity.getTask();
1357 final ActivityRecord secondActivityRecord =
1358 new ActivityBuilder(mService).setTask(firstTaskRecord).setUseProcess(wpc).build();
1359
1360 assertTrue(wpc.registeredForActivityConfigChanges());
1361 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1362 .diff(wpc.getRequestedOverrideConfiguration()));
1363 }
1364
1365 @Test
1366 public void testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay() {
1367 final WindowProcessController wpc = mActivity.app;
1368 assertTrue(wpc.registeredForActivityConfigChanges());
1369
1370 final ActivityRecord secondActivityRecord =
1371 new ActivityBuilder(mService).setTask(mTask).setUseProcess(wpc).build();
1372
1373 assertTrue(wpc.registeredForActivityConfigChanges());
1374 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1375 .diff(wpc.getRequestedOverrideConfiguration()));
1376 }
1377
1378 @Test
1379 public void testActivityOverridesProcessConfig_TwoActivities_DifferentTasks() {
1380 final WindowProcessController wpc = mActivity.app;
1381 assertTrue(wpc.registeredForActivityConfigChanges());
1382
1383 final ActivityRecord secondActivityRecord =
1384 createActivityOnDisplay(true /* defaultDisplay */, wpc);
1385
1386 assertTrue(wpc.registeredForActivityConfigChanges());
1387 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1388 .diff(wpc.getRequestedOverrideConfiguration()));
1389 }
1390
1391 @Test
Riddle Hsud16620e2020-04-06 20:48:06 +08001392 public void testActivityOnCancelFixedRotationTransform() {
1393 mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
1394 final DisplayRotation displayRotation = mActivity.mDisplayContent.getDisplayRotation();
1395 spyOn(displayRotation);
1396
1397 final DisplayContent display = mActivity.mDisplayContent;
1398 final int originalRotation = display.getRotation();
1399
1400 // Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately.
1401 doReturn(true).when(displayRotation).isWaitingForRemoteRotation();
1402 doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation(
1403 anyInt() /* orientation */, anyInt() /* lastRotation */);
1404 // Set to visible so the activity can freeze the screen.
1405 mActivity.setVisibility(true);
1406
1407 display.rotateInDifferentOrientationIfNeeded(mActivity);
1408 display.mFixedRotationLaunchingApp = mActivity;
Riddle Hsu3d0aa4f2020-04-09 17:58:50 +08001409 displayRotation.updateRotationUnchecked(true /* forceUpdate */);
Riddle Hsud16620e2020-04-06 20:48:06 +08001410
1411 assertTrue(displayRotation.isRotatingSeamlessly());
1412
Riddle Hsu742313e2020-05-05 17:20:32 +08001413 // The launching rotated app should not be cleared when waiting for remote rotation.
1414 display.continueUpdateOrientationForDiffOrienLaunchingApp();
1415 assertNotNull(display.mFixedRotationLaunchingApp);
1416
Riddle Hsud16620e2020-04-06 20:48:06 +08001417 // Simulate the rotation has been updated to previous one, e.g. sensor updates before the
1418 // remote rotation is completed.
1419 doReturn(originalRotation).when(displayRotation).rotationForOrientation(
1420 anyInt() /* orientation */, anyInt() /* lastRotation */);
1421 display.updateOrientation();
1422
1423 final DisplayInfo rotatedInfo = mActivity.getFixedRotationTransformDisplayInfo();
1424 mActivity.finishFixedRotationTransform();
1425 final ScreenRotationAnimation rotationAnim = display.getRotationAnimation();
Riddle Hsub40f9662020-04-25 01:58:23 +08001426 assertNotNull(rotationAnim);
Riddle Hsud16620e2020-04-06 20:48:06 +08001427 rotationAnim.setRotation(display.getPendingTransaction(), originalRotation);
1428
1429 // Because the display doesn't rotate, the rotated activity needs to cancel the fixed
1430 // rotation. There should be a rotation animation to cover the change of activity.
1431 verify(mActivity).onCancelFixedRotationTransform(rotatedInfo.rotation);
1432 assertTrue(mActivity.isFreezingScreen());
1433 assertFalse(displayRotation.isRotatingSeamlessly());
Riddle Hsud16620e2020-04-06 20:48:06 +08001434 assertTrue(rotationAnim.isRotating());
Riddle Hsub40f9662020-04-25 01:58:23 +08001435
1436 // Simulate the remote rotation has completed and the configuration doesn't change, then
1437 // the rotated activity should also be restored by clearing the transform.
1438 displayRotation.updateRotationUnchecked(true /* forceUpdate */);
1439 doReturn(false).when(displayRotation).isWaitingForRemoteRotation();
1440 clearInvocations(mActivity);
1441 display.mFixedRotationLaunchingApp = mActivity;
1442 display.sendNewConfiguration();
1443
1444 assertNull(display.mFixedRotationLaunchingApp);
1445 assertFalse(mActivity.hasFixedRotationTransform());
Riddle Hsud16620e2020-04-06 20:48:06 +08001446 }
1447
1448 @Test
Riddle Hsueae6ef3e2020-05-13 01:07:33 +08001449 public void testIsSnapshotCompatible() {
1450 mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
1451 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
1452 .setRotation(mActivity.getWindowConfiguration().getRotation())
1453 .build();
1454
1455 assertTrue(mActivity.isSnapshotCompatible(snapshot));
1456
1457 setRotatedScreenOrientationSilently(mActivity);
1458
1459 assertFalse(mActivity.isSnapshotCompatible(snapshot));
1460 }
1461
Riddle Hsudb94bfd2020-05-13 01:50:17 +08001462 @Test
1463 public void testFixedRotationSnapshotStartingWindow() {
1464 mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
1465 // TaskSnapshotSurface requires a fullscreen opaque window.
1466 final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
1467 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
1468 params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
1469 final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
1470 mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
1471 mActivity.addWindow(w);
1472
1473 // Assume the activity is launching in different rotation, and there was an available
1474 // snapshot accepted by {@link Activity#isSnapshotCompatible}.
1475 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
1476 .setRotation((mActivity.getWindowConfiguration().getRotation() + 1) % 4)
1477 .build();
1478 setRotatedScreenOrientationSilently(mActivity);
1479
1480 final IWindowSession session = WindowManagerGlobal.getWindowSession();
1481 spyOn(session);
1482 try {
1483 // Return error to skip unnecessary operation.
1484 doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
1485 any() /* window */, anyInt() /* seq */, any() /* attrs */,
1486 anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */,
1487 any() /* outContentInsets */, any() /* outStableInsets */,
1488 any() /* outDisplayCutout */, any() /* outInputChannel */,
1489 any() /* outInsetsState */, any() /* outActiveControls */);
1490 TaskSnapshotSurface.create(mService.mWindowManager, mActivity, snapshot);
1491 } catch (RemoteException ignored) {
1492 } finally {
1493 reset(session);
1494 }
1495
1496 // Because the rotation of snapshot and the corresponding top activity are different, fixed
1497 // rotation should be applied when creating snapshot surface if the display rotation may be
1498 // changed according to the activity orientation.
1499 assertTrue(mActivity.hasFixedRotationTransform());
1500 assertEquals(mActivity, mActivity.mDisplayContent.mFixedRotationLaunchingApp);
1501 }
1502
Riddle Hsueae6ef3e2020-05-13 01:07:33 +08001503 /**
1504 * Sets orientation without notifying the parent to simulate that the display has not applied
1505 * the requested orientation yet.
1506 */
1507 private static void setRotatedScreenOrientationSilently(ActivityRecord r) {
1508 final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT
1509 ? SCREEN_ORIENTATION_LANDSCAPE
1510 : SCREEN_ORIENTATION_PORTRAIT;
1511 doReturn(false).when(r).onDescendantOrientationChanged(any(), any());
1512 r.setOrientation(rotatedOrentation);
1513 }
1514
1515 @Test
Andrii Kulianfa23a9e2019-10-10 15:15:36 -07001516 public void testActivityOnDifferentDisplayUpdatesProcessOverride() {
1517 final ActivityRecord secondaryDisplayActivity =
1518 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1519 final WindowProcessController wpc = secondaryDisplayActivity.app;
1520 assertTrue(wpc.registeredForActivityConfigChanges());
1521
1522 final ActivityRecord secondActivityRecord =
1523 createActivityOnDisplay(true /* defaultDisplay */, wpc);
1524
1525 assertTrue(wpc.registeredForActivityConfigChanges());
1526 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1527 .diff(wpc.getRequestedOverrideConfiguration()));
1528 assertFalse(wpc.registeredForDisplayConfigChanges());
1529 }
1530
1531 @Test
1532 public void testActivityReparentChangesProcessOverride() {
1533 final WindowProcessController wpc = mActivity.app;
1534 final Task initialTask = mActivity.getTask();
1535 final Configuration initialConf =
1536 new Configuration(mActivity.getMergedOverrideConfiguration());
1537 assertEquals(0, mActivity.getMergedOverrideConfiguration()
1538 .diff(wpc.getRequestedOverrideConfiguration()));
1539 assertTrue(wpc.registeredForActivityConfigChanges());
1540
1541 // Create a new task with custom config to reparent the activity to.
1542 final Task newTask =
1543 new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build();
1544 final Configuration newConfig = newTask.getConfiguration();
1545 newConfig.densityDpi += 100;
1546 newTask.onRequestedOverrideConfigurationChanged(newConfig);
1547 assertEquals(newTask.getConfiguration().densityDpi, newConfig.densityDpi);
1548
1549 // Reparent the activity and verify that config override changed.
1550 mActivity.reparent(newTask, 0 /* top */, "test");
1551 assertEquals(mActivity.getConfiguration().densityDpi, newConfig.densityDpi);
1552 assertEquals(mActivity.getMergedOverrideConfiguration().densityDpi, newConfig.densityDpi);
1553
1554 assertTrue(wpc.registeredForActivityConfigChanges());
1555 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1556 assertEquals(0, mActivity.getMergedOverrideConfiguration()
1557 .diff(wpc.getRequestedOverrideConfiguration()));
1558 }
1559
1560 @Test
1561 public void testActivityReparentDoesntClearProcessOverride_TwoActivities() {
1562 final WindowProcessController wpc = mActivity.app;
1563 final Configuration initialConf =
1564 new Configuration(mActivity.getMergedOverrideConfiguration());
1565 final Task initialTask = mActivity.getTask();
1566 final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(initialTask)
1567 .setUseProcess(wpc).build();
1568
1569 assertTrue(wpc.registeredForActivityConfigChanges());
1570 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1571 .diff(wpc.getRequestedOverrideConfiguration()));
1572
1573 // Create a new task with custom config to reparent the second activity to.
1574 final Task newTask =
1575 new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build();
1576 final Configuration newConfig = newTask.getConfiguration();
1577 newConfig.densityDpi += 100;
1578 newTask.onRequestedOverrideConfigurationChanged(newConfig);
1579
1580 // Reparent the activity and verify that config override changed.
1581 secondActivity.reparent(newTask, 0 /* top */, "test");
1582
1583 assertTrue(wpc.registeredForActivityConfigChanges());
1584 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1585 .diff(wpc.getRequestedOverrideConfiguration()));
1586 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1587
1588 // Reparent the first activity and verify that config override didn't change.
1589 mActivity.reparent(newTask, 1 /* top */, "test");
1590 assertTrue(wpc.registeredForActivityConfigChanges());
1591 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1592 .diff(wpc.getRequestedOverrideConfiguration()));
1593 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1594 }
1595
Darryl L Johnson2c8ae2d2020-03-11 15:25:28 -07001596 @Test
1597 public void testActivityDestroyDoesntChangeProcessOverride() {
1598 final ActivityRecord firstActivity =
1599 createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
1600 final WindowProcessController wpc = firstActivity.app;
1601 assertTrue(wpc.registeredForActivityConfigChanges());
1602 assertEquals(0, firstActivity.getMergedOverrideConfiguration()
1603 .diff(wpc.getRequestedOverrideConfiguration()));
1604
1605 final ActivityRecord secondActivity =
1606 createActivityOnDisplay(false /* defaultDisplay */, wpc);
1607 assertTrue(wpc.registeredForActivityConfigChanges());
1608 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1609 .diff(wpc.getRequestedOverrideConfiguration()));
1610
1611 final ActivityRecord thirdActivity =
1612 createActivityOnDisplay(false /* defaultDisplay */, wpc);
1613 assertTrue(wpc.registeredForActivityConfigChanges());
1614 assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
1615 .diff(wpc.getRequestedOverrideConfiguration()));
1616
1617 secondActivity.destroyImmediately(true, "");
1618
1619 assertTrue(wpc.registeredForActivityConfigChanges());
1620 assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
1621 .diff(wpc.getRequestedOverrideConfiguration()));
1622
1623 firstActivity.destroyImmediately(true, "");
1624
1625 assertTrue(wpc.registeredForActivityConfigChanges());
1626 assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
1627 .diff(wpc.getRequestedOverrideConfiguration()));
1628 }
1629
Andrii Kulianfa23a9e2019-10-10 15:15:36 -07001630 /**
1631 * Creates an activity on display. For non-default display request it will also create a new
1632 * display with custom DisplayInfo.
1633 */
1634 private ActivityRecord createActivityOnDisplay(boolean defaultDisplay,
1635 WindowProcessController process) {
1636 final DisplayContent display;
1637 if (defaultDisplay) {
1638 display = mRootWindowContainer.getDefaultDisplay();
1639 } else {
1640 display = new TestDisplayContent.Builder(mService, 2000, 1000).setDensityDpi(300)
1641 .setPosition(DisplayContent.POSITION_TOP).build();
1642 }
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -07001643 final ActivityStack stack = display.getDefaultTaskDisplayArea()
1644 .createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Andrii Kulianfa23a9e2019-10-10 15:15:36 -07001645 final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
1646 return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build();
1647 }
Bryce Leeaf691c02017-03-20 14:20:22 -07001648}