blob: 29b96ebdc0904a8b0f5a28c7c85d483aadb3815e [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");
Jeff Sharkey307ea7a2020-04-13 10:24:49 -0600765 mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */,
766 null /* resultGrants */, "test", 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");
Jeff Sharkey307ea7a2020-04-13 10:24:49 -0600791 topActivity.finishIfPossible(0 /* resultCode */, null /* resultData */,
792 null /* resultGrants */, "test", false /* oomAdj */);
Louis Chang6434be42020-04-10 17:39:35 +0800793 assertEquals(mTask, mStack.getTopMostTask());
794 }
795
796 /**
wilsonshih046523c2020-06-02 12:28:26 +0800797 * Verify that when top focused activity is on secondary display, when finishing the top focused
798 * activity on default display, the preferred top stack on default display should be changed by
799 * adjusting focus.
800 */
801 @Test
802 public void testFinishActivityIfPossible_PreferredTopStackChanged() {
803 final ActivityRecord topActivityOnNonTopDisplay =
804 createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
805 ActivityStack topRootableTask = topActivityOnNonTopDisplay.getRootTask();
806 topRootableTask.moveToFront("test");
807 assertTrue(topRootableTask.isTopStackInDisplayArea());
808 assertEquals(topRootableTask, topActivityOnNonTopDisplay.getDisplayArea()
809 .mPreferredTopFocusableStack);
810
811 final ActivityRecord secondaryDisplayActivity =
812 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
813 topRootableTask = secondaryDisplayActivity.getRootTask();
814 topRootableTask.moveToFront("test");
815 assertTrue(topRootableTask.isTopStackInDisplayArea());
816 assertEquals(topRootableTask,
817 secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableStack);
818
819 // The global top focus activity is on secondary display now.
820 // Finish top activity on default display and verify the next preferred top focusable stack
821 // on default display has changed.
822 topActivityOnNonTopDisplay.setState(RESUMED, "test");
823 topActivityOnNonTopDisplay.finishIfPossible(0 /* resultCode */, null /* resultData */,
824 null /* resultGrants */, "test", false /* oomAdj */);
825 assertEquals(mTask, mStack.getTopMostTask());
826 assertEquals(mStack, mActivity.getDisplayArea().mPreferredTopFocusableStack);
827 }
828
829 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700830 * Verify that resumed activity is paused due to finish request.
831 */
832 @Test
833 public void testFinishActivityIfPossible_resumedStartsPausing() {
834 mActivity.finishing = false;
835 mActivity.setState(RESUMED, "test");
836 assertEquals("Currently resumed activity must be paused before removal",
837 FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */));
838 assertEquals(PAUSING, mActivity.getState());
839 verify(mActivity).setVisibility(eq(false));
840 verify(mActivity.getDisplay().mDisplayContent)
841 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
842 }
843
844 /**
845 * Verify that finish request will be completed immediately for non-resumed activity.
846 */
847 @Test
848 public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() {
849 final ActivityState[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED};
850 for (ActivityState state : states) {
851 mActivity.finishing = false;
852 mActivity.setState(state, "test");
853 reset(mActivity);
854 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
855 mActivity.finishIfPossible("test", false /* oomAdj */));
856 verify(mActivity).completeFinishing(anyString());
857 }
858 }
859
860 /**
861 * Verify that finishing will not be completed in PAUSING state.
862 */
863 @Test
864 public void testFinishActivityIfPossible_pausing() {
865 mActivity.finishing = false;
866 mActivity.setState(PAUSING, "test");
867 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
868 mActivity.finishIfPossible("test", false /* oomAdj */));
869 verify(mActivity, never()).completeFinishing(anyString());
870 }
871
872 /**
873 * Verify that finish request for resumed activity will prepare an app transition but not
874 * execute it immediately.
875 */
876 @Test
877 public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() {
878 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100879 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700880 mActivity.setState(RESUMED, "test");
881 mActivity.finishIfPossible("test", false /* oomAdj */);
882
883 verify(mActivity).setVisibility(eq(false));
884 verify(mActivity.getDisplay().mDisplayContent)
885 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
886 verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition();
887 }
888
889 /**
890 * Verify that finish request for paused activity will prepare and execute an app transition.
891 */
892 @Test
893 public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() {
894 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100895 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700896 mActivity.setState(PAUSED, "test");
897 mActivity.finishIfPossible("test", false /* oomAdj */);
898
Andrii Kulian149d9ad32019-08-23 15:04:17 -0700899 verify(mActivity, atLeast(1)).setVisibility(eq(false));
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700900 verify(mActivity.getDisplay().mDisplayContent)
901 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
902 verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
903 }
904
905 /**
906 * Verify that finish request for non-visible activity will not prepare any transitions.
907 */
908 @Test
909 public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
910 // Put an activity on top of test activity to make it invisible and prevent us from
911 // accidentally resuming the topmost one again.
912 new ActivityBuilder(mService).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100913 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700914 mActivity.setState(STOPPED, "test");
915
916 mActivity.finishIfPossible("test", false /* oomAdj */);
917
918 verify(mActivity.getDisplay().mDisplayContent, never())
919 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
920 }
921
922 /**
923 * Verify that complete finish request for non-finishing activity is invalid.
924 */
925 @Test(expected = IllegalArgumentException.class)
926 public void testCompleteFinishing_failNotFinishing() {
927 mActivity.finishing = false;
928 mActivity.completeFinishing("test");
929 }
930
931 /**
932 * Verify that complete finish request for resumed activity is invalid.
933 */
934 @Test(expected = IllegalArgumentException.class)
935 public void testCompleteFinishing_failResumed() {
936 mActivity.setState(RESUMED, "test");
937 mActivity.completeFinishing("test");
938 }
939
940 /**
941 * Verify that finish request for pausing activity must be a no-op - activity will finish
942 * once it completes pausing.
943 */
944 @Test
945 public void testCompleteFinishing_pausing() {
946 mActivity.setState(PAUSING, "test");
947 mActivity.finishing = true;
948
949 assertEquals("Activity must not be removed immediately - waiting for paused",
950 mActivity, mActivity.completeFinishing("test"));
951 assertEquals(PAUSING, mActivity.getState());
952 verify(mActivity, never()).destroyIfPossible(anyString());
953 }
954
955 /**
Riddle Hsucf920232019-10-04 19:05:36 +0800956 * Verify that finish request won't change the state of next top activity if the current
957 * finishing activity doesn't need to be destroyed immediately. The case is usually like
958 * from {@link ActivityStack#completePauseLocked(boolean, ActivityRecord)} to
959 * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the
960 * responsibility to resume the next activity with updating the state.
961 */
962 @Test
963 public void testCompleteFinishing_keepStateOfNextInvisible() {
964 final ActivityRecord currentTop = mActivity;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100965 currentTop.mVisibleRequested = currentTop.nowVisible = true;
Riddle Hsucf920232019-10-04 19:05:36 +0800966
967 // Simulates that {@code currentTop} starts an existing activity from background (so its
968 // state is stopped) and the starting flow just goes to place it at top.
Louis Chang149d5c82019-12-30 09:47:39 +0800969 final ActivityStack nextStack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800970 final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity();
Riddle Hsucf920232019-10-04 19:05:36 +0800971 nextTop.setState(STOPPED, "test");
972
973 mStack.mPausingActivity = currentTop;
974 currentTop.finishing = true;
975 currentTop.setState(PAUSED, "test");
976 currentTop.completeFinishing("completePauseLocked");
977
978 // Current top becomes stopping because it is visible and the next is invisible.
979 assertEquals(STOPPING, currentTop.getState());
980 // The state of next activity shouldn't be changed.
981 assertEquals(STOPPED, nextTop.getState());
982 }
983
984 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700985 * Verify that complete finish request for visible activity must be delayed before the next one
986 * becomes visible.
987 */
988 @Test
989 public void testCompleteFinishing_waitForNextVisible() {
990 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100991 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700992 topActivity.nowVisible = true;
993 topActivity.finishing = true;
994 topActivity.setState(PAUSED, "true");
995 // Mark the bottom activity as not visible, so that we will wait for it before removing
996 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100997 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700998 mActivity.nowVisible = false;
999 mActivity.setState(STOPPED, "test");
1000
1001 assertEquals("Activity must not be removed immediately - waiting for next visible",
1002 topActivity, topActivity.completeFinishing("test"));
1003 assertEquals("Activity must be stopped to make next one visible", STOPPING,
1004 topActivity.getState());
1005 assertTrue("Activity must be stopped to make next one visible",
1006 topActivity.mStackSupervisor.mStoppingActivities.contains(topActivity));
1007 verify(topActivity, never()).destroyIfPossible(anyString());
1008 }
1009
1010 /**
1011 * Verify that complete finish request for invisible activity must not be delayed.
1012 */
1013 @Test
1014 public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
1015 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +01001016 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001017 topActivity.nowVisible = false;
1018 topActivity.finishing = true;
Issei Suzukid0c14f32019-12-19 12:42:13 +01001019 topActivity.setState(STOPPED, "true");
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001020 // Mark the bottom activity as not visible, so that we would wait for it before removing
1021 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +01001022 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001023 mActivity.nowVisible = false;
1024 mActivity.setState(STOPPED, "test");
1025
1026 topActivity.completeFinishing("test");
1027
1028 verify(topActivity).destroyIfPossible(anyString());
1029 }
1030
1031 /**
1032 * Verify that paused finishing activity will be added to finishing list and wait for next one
1033 * to idle.
1034 */
1035 @Test
1036 public void testCompleteFinishing_waitForIdle() {
1037 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +01001038 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001039 topActivity.nowVisible = true;
1040 topActivity.finishing = true;
1041 topActivity.setState(PAUSED, "true");
1042 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +01001043 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001044 mActivity.nowVisible = true;
1045 mActivity.setState(RESUMED, "test");
1046
1047 topActivity.completeFinishing("test");
1048
1049 verify(topActivity).addToFinishingAndWaitForIdle();
1050 }
1051
1052 /**
1053 * Verify that complete finish request for visible activity must not be delayed if the next one
1054 * is already visible and it's not the focused stack.
1055 */
1056 @Test
1057 public void testCompleteFinishing_noWaitForNextVisible_stopped() {
1058 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +01001059 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001060 topActivity.nowVisible = false;
1061 topActivity.finishing = true;
1062 topActivity.setState(STOPPED, "true");
1063 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +01001064 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001065 mActivity.nowVisible = true;
1066 mActivity.setState(RESUMED, "test");
1067
1068 topActivity.completeFinishing("test");
1069
1070 verify(topActivity).destroyIfPossible(anyString());
1071 }
1072
1073 /**
1074 * Verify that complete finish request for visible activity must not be delayed if the next one
1075 * is already visible and it's not the focused stack.
1076 */
1077 @Test
1078 public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
1079 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +01001080 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001081 topActivity.nowVisible = true;
1082 topActivity.finishing = true;
1083 topActivity.setState(PAUSED, "true");
1084 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +01001085 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001086 mActivity.nowVisible = true;
1087 mActivity.setState(RESUMED, "test");
1088
1089 // Add another stack to become focused and make the activity there visible. This way it
1090 // simulates finishing in non-focused stack in split-screen.
Louis Chang149d5c82019-12-30 09:47:39 +08001091 final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwalea38654f2019-11-17 20:37:15 -08001092 final ActivityRecord focusedActivity = stack.getTopMostActivity();
wilsonshih4c9824a2019-10-25 18:47:50 +08001093 focusedActivity.nowVisible = true;
Issei Suzuki1669ea42019-11-06 14:20:59 +01001094 focusedActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +08001095 focusedActivity.setState(RESUMED, "test");
1096 stack.mResumedActivity = focusedActivity;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001097
1098 topActivity.completeFinishing("test");
1099
1100 verify(topActivity).destroyIfPossible(anyString());
1101 }
1102
1103 /**
Louis Chang3d718c32020-04-09 16:51:02 +08001104 * Verify that complete finish request for a show-when-locked activity must ensure the
1105 * keyguard occluded state being updated.
1106 */
1107 @Test
1108 public void testCompleteFinishing_showWhenLocked() {
1109 // Make keyguard locked and set the top activity show-when-locked.
1110 KeyguardController keyguardController = mActivity.mStackSupervisor.getKeyguardController();
1111 doReturn(true).when(keyguardController).isKeyguardLocked();
1112 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
1113 topActivity.mVisibleRequested = true;
1114 topActivity.nowVisible = true;
1115 topActivity.setState(RESUMED, "true");
1116 doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
1117 any() /* starting */, anyInt() /* configChanges */,
1118 anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
1119 topActivity.setShowWhenLocked(true);
1120
1121 // Verify the stack-top activity is occluded keyguard.
1122 assertEquals(topActivity, mStack.topRunningActivity());
1123 assertTrue(mStack.topActivityOccludesKeyguard());
1124
1125 // Finish the top activity
1126 topActivity.setState(PAUSED, "true");
1127 topActivity.finishing = true;
1128 topActivity.completeFinishing("test");
1129
1130 // Verify new top activity does not occlude keyguard.
1131 assertEquals(mActivity, mStack.topRunningActivity());
1132 assertFalse(mStack.topActivityOccludesKeyguard());
1133 }
1134
1135 /**
Jeff Changde2c5f12020-04-10 17:23:43 +08001136 * Verify that complete finish request for an activity which the resume activity is translucent
1137 * must ensure the visibilities of activities being updated.
1138 */
1139 @Test
1140 public void testCompleteFinishing_ensureActivitiesVisible() {
1141 final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build();
1142 firstActivity.mVisibleRequested = false;
1143 firstActivity.nowVisible = false;
1144 firstActivity.setState(STOPPED, "true");
1145
1146 final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build();
1147 secondActivity.mVisibleRequested = true;
1148 secondActivity.nowVisible = true;
1149 secondActivity.setState(PAUSED, "true");
1150
1151 final ActivityRecord translucentActivity =
1152 new ActivityBuilder(mService).setTask(mTask).build();
1153 translucentActivity.mVisibleRequested = true;
1154 translucentActivity.nowVisible = true;
1155 translucentActivity.setState(RESUMED, "true");
1156
1157 doReturn(false).when(translucentActivity).occludesParent();
1158
1159 // Finish the second activity
1160 secondActivity.finishing = true;
1161 secondActivity.completeFinishing("test");
1162 verify(secondActivity.getDisplay()).ensureActivitiesVisible(null /* starting */,
1163 0 /* configChanges */ , false /* preserveWindows */,
1164 true /* notifyClients */);
1165
1166 // Finish the first activity
1167 firstActivity.finishing = true;
1168 firstActivity.mVisibleRequested = true;
1169 firstActivity.completeFinishing("test");
1170 verify(firstActivity.getDisplay(), times(2)).ensureActivitiesVisible(null /* starting */,
1171 0 /* configChanges */ , false /* preserveWindows */,
1172 true /* notifyClients */);
1173 }
1174
1175 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001176 * Verify destroy activity request completes successfully.
1177 */
1178 @Test
1179 public void testDestroyIfPossible() {
Louis Chang149d5c82019-12-30 09:47:39 +08001180 doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001181 spyOn(mStack);
1182 mActivity.destroyIfPossible("test");
1183
1184 assertEquals(DESTROYING, mActivity.getState());
1185 assertTrue(mActivity.finishing);
Andrii Kulian79d67982019-08-19 11:56:16 -07001186 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001187 }
1188
1189 /**
1190 * Verify that complete finish request for visible activity must not destroy it immediately if
1191 * it is the last running activity on a display with a home stack. We must wait for home
1192 * activity to come up to avoid a black flash in this case.
1193 */
1194 @Test
1195 public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
1196 // Empty the home stack.
Andrii Kulian86d676c2020-03-27 19:34:54 -07001197 final ActivityStack homeStack = mActivity.getDisplayArea().getRootHomeTask();
Wale Ogunwale0d465192020-01-23 19:14:44 -08001198 homeStack.forAllLeafTasks((t) -> {
Wale Ogunwale8f93b642019-12-26 12:10:52 -08001199 homeStack.removeChild(t, "test");
Wale Ogunwale0d465192020-01-23 19:14:44 -08001200 }, true /* traverseTopToBottom */);
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001201 mActivity.finishing = true;
Louis Chang149d5c82019-12-30 09:47:39 +08001202 doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001203 spyOn(mStack);
1204
1205 // Try to destroy the last activity above the home stack.
1206 mActivity.destroyIfPossible("test");
1207
1208 // Verify that the activity was not actually destroyed, but waits for next one to come up
1209 // instead.
Andrii Kulian79d67982019-08-19 11:56:16 -07001210 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001211 assertEquals(FINISHING, mActivity.getState());
1212 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1213 }
1214
Andrii Kulian79d67982019-08-19 11:56:16 -07001215 /**
wilsonshih4c9824a2019-10-25 18:47:50 +08001216 * Verify that complete finish request for visible activity must resume next home stack before
1217 * destroying it immediately if it is the last running activity on a display with a home stack.
1218 * We must wait for home activity to come up to avoid a black flash in this case.
1219 */
1220 @Test
1221 public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
1222 // Empty the home stack.
Andrii Kulian86d676c2020-03-27 19:34:54 -07001223 final ActivityStack homeStack = mActivity.getDisplayArea().getRootHomeTask();
Wale Ogunwale0d465192020-01-23 19:14:44 -08001224 homeStack.forAllLeafTasks((t) -> {
Wale Ogunwale8f93b642019-12-26 12:10:52 -08001225 homeStack.removeChild(t, "test");
Wale Ogunwale0d465192020-01-23 19:14:44 -08001226 }, true /* traverseTopToBottom */);
wilsonshih4c9824a2019-10-25 18:47:50 +08001227 mActivity.finishing = true;
1228 spyOn(mStack);
1229
1230 // Try to finish the last activity above the home stack.
1231 mActivity.completeFinishing("test");
1232
1233 // Verify that the activity is not destroyed immediately, but waits for next one to come up.
1234 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1235 assertEquals(FINISHING, mActivity.getState());
1236 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1237 }
1238
1239 /**
Andrii Kulian79d67982019-08-19 11:56:16 -07001240 * Test that the activity will be moved to destroying state and the message to destroy will be
1241 * sent to the client.
1242 */
1243 @Test
1244 public void testDestroyImmediately_hadApp_finishing() {
1245 mActivity.finishing = true;
1246 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1247
1248 assertEquals(DESTROYING, mActivity.getState());
1249 }
1250
1251 /**
1252 * Test that the activity will be moved to destroyed state immediately if it was not marked as
1253 * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
1254 */
1255 @Test
1256 public void testDestroyImmediately_hadApp_notFinishing() {
1257 mActivity.finishing = false;
1258 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1259
1260 assertEquals(DESTROYED, mActivity.getState());
1261 }
1262
1263 /**
1264 * Test that an activity with no process attached and that is marked as finishing will be
1265 * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
1266 */
1267 @Test
1268 public void testDestroyImmediately_noApp_finishing() {
1269 mActivity.app = null;
1270 mActivity.finishing = true;
Louis Changcdec0802019-11-11 11:45:07 +08001271 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001272
1273 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1274
1275 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001276 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001277 assertEquals(0, task.getChildCount());
1278 }
1279
1280 /**
1281 * Test that an activity with no process attached and that is not marked as finishing will be
1282 * marked as DESTROYED but not removed from task.
1283 */
1284 @Test
1285 public void testDestroyImmediately_noApp_notFinishing() {
1286 mActivity.app = null;
1287 mActivity.finishing = false;
Louis Changcdec0802019-11-11 11:45:07 +08001288 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001289
1290 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1291
1292 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001293 assertEquals(task, mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001294 assertEquals(1, task.getChildCount());
1295 }
1296
1297 /**
1298 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1299 */
1300 @Test
1301 public void testSafelyDestroy_nonDestroyable() {
1302 doReturn(false).when(mActivity).isDestroyable();
1303
1304 mActivity.safelyDestroy("test");
1305
1306 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1307 }
1308
1309 /**
1310 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1311 */
1312 @Test
1313 public void testSafelyDestroy_destroyable() {
1314 doReturn(true).when(mActivity).isDestroyable();
1315
1316 mActivity.safelyDestroy("test");
1317
1318 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1319 }
1320
1321 @Test
1322 public void testRemoveFromHistory() {
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -08001323 final ActivityStack stack = mActivity.getRootTask();
Louis Changcdec0802019-11-11 11:45:07 +08001324 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001325
1326 mActivity.removeFromHistory("test");
1327
1328 assertEquals(DESTROYED, mActivity.getState());
1329 assertNull(mActivity.app);
Louis Changcdec0802019-11-11 11:45:07 +08001330 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001331 assertEquals(0, task.getChildCount());
Wale Ogunwale8f93b642019-12-26 12:10:52 -08001332 assertEquals(task.getStack(), task);
Andrii Kulian79d67982019-08-19 11:56:16 -07001333 assertEquals(0, stack.getChildCount());
1334 }
1335
1336 /**
1337 * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is
1338 * not in destroying or destroyed state.
1339 */
1340 @Test(expected = IllegalStateException.class)
1341 public void testDestroyed_notDestroying() {
1342 mActivity.setState(STOPPED, "test");
1343 mActivity.destroyed("test");
1344 }
1345
1346 /**
1347 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying
1348 */
1349 @Test
1350 public void testDestroyed_destroying() {
1351 mActivity.setState(DESTROYING, "test");
1352 mActivity.destroyed("test");
1353
1354 verify(mActivity).removeFromHistory(anyString());
1355 }
1356
1357 /**
1358 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed.
1359 */
1360 @Test
1361 public void testDestroyed_destroyed() {
1362 mActivity.setState(DESTROYED, "test");
1363 mActivity.destroyed("test");
1364
1365 verify(mActivity).removeFromHistory(anyString());
1366 }
Andrii Kulianfa23a9e2019-10-10 15:15:36 -07001367
1368 @Test
1369 public void testActivityOverridesProcessConfig() {
1370 final WindowProcessController wpc = mActivity.app;
1371 assertTrue(wpc.registeredForActivityConfigChanges());
1372 assertFalse(wpc.registeredForDisplayConfigChanges());
1373
1374 final ActivityRecord secondaryDisplayActivity =
1375 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1376
1377 assertTrue(wpc.registeredForActivityConfigChanges());
1378 assertEquals(0, mActivity.getMergedOverrideConfiguration()
1379 .diff(wpc.getRequestedOverrideConfiguration()));
1380 assertNotEquals(mActivity.getConfiguration(),
1381 secondaryDisplayActivity.getConfiguration());
1382 }
1383
1384 @Test
1385 public void testActivityOverridesProcessConfig_TwoActivities() {
1386 final WindowProcessController wpc = mActivity.app;
1387 assertTrue(wpc.registeredForActivityConfigChanges());
1388
1389 final Task firstTaskRecord = mActivity.getTask();
1390 final ActivityRecord secondActivityRecord =
1391 new ActivityBuilder(mService).setTask(firstTaskRecord).setUseProcess(wpc).build();
1392
1393 assertTrue(wpc.registeredForActivityConfigChanges());
1394 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1395 .diff(wpc.getRequestedOverrideConfiguration()));
1396 }
1397
1398 @Test
1399 public void testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay() {
1400 final WindowProcessController wpc = mActivity.app;
1401 assertTrue(wpc.registeredForActivityConfigChanges());
1402
1403 final ActivityRecord secondActivityRecord =
1404 new ActivityBuilder(mService).setTask(mTask).setUseProcess(wpc).build();
1405
1406 assertTrue(wpc.registeredForActivityConfigChanges());
1407 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1408 .diff(wpc.getRequestedOverrideConfiguration()));
1409 }
1410
1411 @Test
1412 public void testActivityOverridesProcessConfig_TwoActivities_DifferentTasks() {
1413 final WindowProcessController wpc = mActivity.app;
1414 assertTrue(wpc.registeredForActivityConfigChanges());
1415
1416 final ActivityRecord secondActivityRecord =
1417 createActivityOnDisplay(true /* defaultDisplay */, wpc);
1418
1419 assertTrue(wpc.registeredForActivityConfigChanges());
1420 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1421 .diff(wpc.getRequestedOverrideConfiguration()));
1422 }
1423
1424 @Test
Riddle Hsud16620e2020-04-06 20:48:06 +08001425 public void testActivityOnCancelFixedRotationTransform() {
1426 mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
1427 final DisplayRotation displayRotation = mActivity.mDisplayContent.getDisplayRotation();
1428 spyOn(displayRotation);
1429
1430 final DisplayContent display = mActivity.mDisplayContent;
1431 final int originalRotation = display.getRotation();
1432
1433 // Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately.
1434 doReturn(true).when(displayRotation).isWaitingForRemoteRotation();
1435 doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation(
1436 anyInt() /* orientation */, anyInt() /* lastRotation */);
1437 // Set to visible so the activity can freeze the screen.
1438 mActivity.setVisibility(true);
1439
1440 display.rotateInDifferentOrientationIfNeeded(mActivity);
Hongwei Wangf4e4bab2020-05-19 11:28:32 -07001441 display.setFixedRotationLaunchingAppUnchecked(mActivity);
Riddle Hsu3d0aa4f2020-04-09 17:58:50 +08001442 displayRotation.updateRotationUnchecked(true /* forceUpdate */);
Riddle Hsud16620e2020-04-06 20:48:06 +08001443
1444 assertTrue(displayRotation.isRotatingSeamlessly());
1445
Riddle Hsu742313e2020-05-05 17:20:32 +08001446 // The launching rotated app should not be cleared when waiting for remote rotation.
1447 display.continueUpdateOrientationForDiffOrienLaunchingApp();
Riddle Hsu08bc4ed2020-05-26 18:32:18 +08001448 assertTrue(display.isFixedRotationLaunchingApp(mActivity));
Riddle Hsu742313e2020-05-05 17:20:32 +08001449
Riddle Hsud16620e2020-04-06 20:48:06 +08001450 // Simulate the rotation has been updated to previous one, e.g. sensor updates before the
1451 // remote rotation is completed.
1452 doReturn(originalRotation).when(displayRotation).rotationForOrientation(
1453 anyInt() /* orientation */, anyInt() /* lastRotation */);
1454 display.updateOrientation();
1455
1456 final DisplayInfo rotatedInfo = mActivity.getFixedRotationTransformDisplayInfo();
1457 mActivity.finishFixedRotationTransform();
1458 final ScreenRotationAnimation rotationAnim = display.getRotationAnimation();
Riddle Hsub40f9662020-04-25 01:58:23 +08001459 assertNotNull(rotationAnim);
Riddle Hsud16620e2020-04-06 20:48:06 +08001460 rotationAnim.setRotation(display.getPendingTransaction(), originalRotation);
1461
1462 // Because the display doesn't rotate, the rotated activity needs to cancel the fixed
1463 // rotation. There should be a rotation animation to cover the change of activity.
1464 verify(mActivity).onCancelFixedRotationTransform(rotatedInfo.rotation);
1465 assertTrue(mActivity.isFreezingScreen());
1466 assertFalse(displayRotation.isRotatingSeamlessly());
Riddle Hsud16620e2020-04-06 20:48:06 +08001467 assertTrue(rotationAnim.isRotating());
Riddle Hsub40f9662020-04-25 01:58:23 +08001468
1469 // Simulate the remote rotation has completed and the configuration doesn't change, then
1470 // the rotated activity should also be restored by clearing the transform.
1471 displayRotation.updateRotationUnchecked(true /* forceUpdate */);
1472 doReturn(false).when(displayRotation).isWaitingForRemoteRotation();
1473 clearInvocations(mActivity);
Hongwei Wangf4e4bab2020-05-19 11:28:32 -07001474 display.setFixedRotationLaunchingAppUnchecked(mActivity);
Riddle Hsub40f9662020-04-25 01:58:23 +08001475 display.sendNewConfiguration();
1476
Riddle Hsu08bc4ed2020-05-26 18:32:18 +08001477 assertFalse(display.hasTopFixedRotationLaunchingApp());
Riddle Hsub40f9662020-04-25 01:58:23 +08001478 assertFalse(mActivity.hasFixedRotationTransform());
Riddle Hsud16620e2020-04-06 20:48:06 +08001479 }
1480
1481 @Test
Riddle Hsueae6ef3e2020-05-13 01:07:33 +08001482 public void testIsSnapshotCompatible() {
1483 mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
1484 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
1485 .setRotation(mActivity.getWindowConfiguration().getRotation())
1486 .build();
1487
1488 assertTrue(mActivity.isSnapshotCompatible(snapshot));
1489
1490 setRotatedScreenOrientationSilently(mActivity);
1491
1492 assertFalse(mActivity.isSnapshotCompatible(snapshot));
1493 }
1494
Riddle Hsudb94bfd2020-05-13 01:50:17 +08001495 @Test
1496 public void testFixedRotationSnapshotStartingWindow() {
1497 mService.mWindowManager.mIsFixedRotationTransformEnabled = true;
1498 // TaskSnapshotSurface requires a fullscreen opaque window.
1499 final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
1500 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
1501 params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT;
1502 final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState(
1503 mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity);
1504 mActivity.addWindow(w);
1505
1506 // Assume the activity is launching in different rotation, and there was an available
1507 // snapshot accepted by {@link Activity#isSnapshotCompatible}.
1508 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder()
1509 .setRotation((mActivity.getWindowConfiguration().getRotation() + 1) % 4)
1510 .build();
1511 setRotatedScreenOrientationSilently(mActivity);
1512
1513 final IWindowSession session = WindowManagerGlobal.getWindowSession();
1514 spyOn(session);
1515 try {
1516 // Return error to skip unnecessary operation.
1517 doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay(
1518 any() /* window */, anyInt() /* seq */, any() /* attrs */,
1519 anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */,
1520 any() /* outContentInsets */, any() /* outStableInsets */,
1521 any() /* outDisplayCutout */, any() /* outInputChannel */,
1522 any() /* outInsetsState */, any() /* outActiveControls */);
1523 TaskSnapshotSurface.create(mService.mWindowManager, mActivity, snapshot);
1524 } catch (RemoteException ignored) {
1525 } finally {
1526 reset(session);
1527 }
1528
1529 // Because the rotation of snapshot and the corresponding top activity are different, fixed
1530 // rotation should be applied when creating snapshot surface if the display rotation may be
1531 // changed according to the activity orientation.
1532 assertTrue(mActivity.hasFixedRotationTransform());
Riddle Hsu08bc4ed2020-05-26 18:32:18 +08001533 assertTrue(mActivity.mDisplayContent.isFixedRotationLaunchingApp(mActivity));
Riddle Hsudb94bfd2020-05-13 01:50:17 +08001534 }
1535
Riddle Hsueae6ef3e2020-05-13 01:07:33 +08001536 /**
1537 * Sets orientation without notifying the parent to simulate that the display has not applied
1538 * the requested orientation yet.
1539 */
1540 private static void setRotatedScreenOrientationSilently(ActivityRecord r) {
1541 final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT
1542 ? SCREEN_ORIENTATION_LANDSCAPE
1543 : SCREEN_ORIENTATION_PORTRAIT;
1544 doReturn(false).when(r).onDescendantOrientationChanged(any(), any());
1545 r.setOrientation(rotatedOrentation);
1546 }
1547
1548 @Test
Andrii Kulianfa23a9e2019-10-10 15:15:36 -07001549 public void testActivityOnDifferentDisplayUpdatesProcessOverride() {
1550 final ActivityRecord secondaryDisplayActivity =
1551 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1552 final WindowProcessController wpc = secondaryDisplayActivity.app;
1553 assertTrue(wpc.registeredForActivityConfigChanges());
1554
1555 final ActivityRecord secondActivityRecord =
1556 createActivityOnDisplay(true /* defaultDisplay */, wpc);
1557
1558 assertTrue(wpc.registeredForActivityConfigChanges());
1559 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1560 .diff(wpc.getRequestedOverrideConfiguration()));
1561 assertFalse(wpc.registeredForDisplayConfigChanges());
1562 }
1563
1564 @Test
1565 public void testActivityReparentChangesProcessOverride() {
1566 final WindowProcessController wpc = mActivity.app;
1567 final Task initialTask = mActivity.getTask();
1568 final Configuration initialConf =
1569 new Configuration(mActivity.getMergedOverrideConfiguration());
1570 assertEquals(0, mActivity.getMergedOverrideConfiguration()
1571 .diff(wpc.getRequestedOverrideConfiguration()));
1572 assertTrue(wpc.registeredForActivityConfigChanges());
1573
1574 // Create a new task with custom config to reparent the activity to.
1575 final Task newTask =
1576 new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build();
1577 final Configuration newConfig = newTask.getConfiguration();
1578 newConfig.densityDpi += 100;
1579 newTask.onRequestedOverrideConfigurationChanged(newConfig);
1580 assertEquals(newTask.getConfiguration().densityDpi, newConfig.densityDpi);
1581
1582 // Reparent the activity and verify that config override changed.
1583 mActivity.reparent(newTask, 0 /* top */, "test");
1584 assertEquals(mActivity.getConfiguration().densityDpi, newConfig.densityDpi);
1585 assertEquals(mActivity.getMergedOverrideConfiguration().densityDpi, newConfig.densityDpi);
1586
1587 assertTrue(wpc.registeredForActivityConfigChanges());
1588 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1589 assertEquals(0, mActivity.getMergedOverrideConfiguration()
1590 .diff(wpc.getRequestedOverrideConfiguration()));
1591 }
1592
1593 @Test
1594 public void testActivityReparentDoesntClearProcessOverride_TwoActivities() {
1595 final WindowProcessController wpc = mActivity.app;
1596 final Configuration initialConf =
1597 new Configuration(mActivity.getMergedOverrideConfiguration());
1598 final Task initialTask = mActivity.getTask();
1599 final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(initialTask)
1600 .setUseProcess(wpc).build();
1601
1602 assertTrue(wpc.registeredForActivityConfigChanges());
1603 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1604 .diff(wpc.getRequestedOverrideConfiguration()));
1605
1606 // Create a new task with custom config to reparent the second activity to.
1607 final Task newTask =
1608 new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build();
1609 final Configuration newConfig = newTask.getConfiguration();
1610 newConfig.densityDpi += 100;
1611 newTask.onRequestedOverrideConfigurationChanged(newConfig);
1612
1613 // Reparent the activity and verify that config override changed.
1614 secondActivity.reparent(newTask, 0 /* top */, "test");
1615
1616 assertTrue(wpc.registeredForActivityConfigChanges());
1617 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1618 .diff(wpc.getRequestedOverrideConfiguration()));
1619 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1620
1621 // Reparent the first activity and verify that config override didn't change.
1622 mActivity.reparent(newTask, 1 /* top */, "test");
1623 assertTrue(wpc.registeredForActivityConfigChanges());
1624 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1625 .diff(wpc.getRequestedOverrideConfiguration()));
1626 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1627 }
1628
Darryl L Johnson2c8ae2d2020-03-11 15:25:28 -07001629 @Test
1630 public void testActivityDestroyDoesntChangeProcessOverride() {
1631 final ActivityRecord firstActivity =
1632 createActivityOnDisplay(true /* defaultDisplay */, null /* process */);
1633 final WindowProcessController wpc = firstActivity.app;
1634 assertTrue(wpc.registeredForActivityConfigChanges());
1635 assertEquals(0, firstActivity.getMergedOverrideConfiguration()
1636 .diff(wpc.getRequestedOverrideConfiguration()));
1637
1638 final ActivityRecord secondActivity =
1639 createActivityOnDisplay(false /* defaultDisplay */, wpc);
1640 assertTrue(wpc.registeredForActivityConfigChanges());
1641 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1642 .diff(wpc.getRequestedOverrideConfiguration()));
1643
1644 final ActivityRecord thirdActivity =
1645 createActivityOnDisplay(false /* defaultDisplay */, wpc);
1646 assertTrue(wpc.registeredForActivityConfigChanges());
1647 assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
1648 .diff(wpc.getRequestedOverrideConfiguration()));
1649
1650 secondActivity.destroyImmediately(true, "");
1651
1652 assertTrue(wpc.registeredForActivityConfigChanges());
1653 assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
1654 .diff(wpc.getRequestedOverrideConfiguration()));
1655
1656 firstActivity.destroyImmediately(true, "");
1657
1658 assertTrue(wpc.registeredForActivityConfigChanges());
1659 assertEquals(0, thirdActivity.getMergedOverrideConfiguration()
1660 .diff(wpc.getRequestedOverrideConfiguration()));
1661 }
1662
Andrii Kulianfa23a9e2019-10-10 15:15:36 -07001663 /**
1664 * Creates an activity on display. For non-default display request it will also create a new
1665 * display with custom DisplayInfo.
1666 */
1667 private ActivityRecord createActivityOnDisplay(boolean defaultDisplay,
1668 WindowProcessController process) {
1669 final DisplayContent display;
1670 if (defaultDisplay) {
1671 display = mRootWindowContainer.getDefaultDisplay();
1672 } else {
1673 display = new TestDisplayContent.Builder(mService, 2000, 1000).setDensityDpi(300)
1674 .setPosition(DisplayContent.POSITION_TOP).build();
1675 }
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -07001676 final ActivityStack stack = display.getDefaultTaskDisplayArea()
1677 .createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
Andrii Kulianfa23a9e2019-10-10 15:15:36 -07001678 final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
1679 return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build();
1680 }
Bryce Leeaf691c02017-03-20 14:20:22 -07001681}