blob: af3a3fe5f77e15d6c9766f94899af34480f62521 [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;
Andrii Kulian149d9ad32019-08-23 15:04:17 -070032import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090033import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
Garfield Tan0443b372019-01-04 15:00:13 -080034import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
Garfield Tan36a69ad2019-01-16 17:08:23 -080035import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070036import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080037import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070038import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
Garfield Tan0443b372019-01-04 15:00:13 -080039import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Andrii Kulian057a6512019-07-15 16:15:51 -070040import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
41import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
42import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
Andrii Kulian79d67982019-08-19 11:56:16 -070043import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070044import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
45import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
Wale Ogunwale59507092018-10-29 09:00:30 -070046import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070047import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
Wale Ogunwale59507092018-10-29 09:00:30 -070048import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
Andrii Kulian6b321512019-01-23 06:37:00 +000049import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
Louis Changeadb22f2019-06-19 12:09:23 +080050import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
Wale Ogunwale59507092018-10-29 09:00:30 -070051import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070052import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080053import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
54import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
55import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
Adrian Roose99bc052017-11-20 17:55:31 +010056
Louis Chang6a9be162019-07-15 10:41:32 +080057import static com.google.common.truth.Truth.assertThat;
58
Bryce Lee04ab3462017-04-10 15:06:33 -070059import static org.junit.Assert.assertEquals;
Bryce Lee1533b2b2017-09-14 17:06:41 -070060import static org.junit.Assert.assertFalse;
Andrii Kulianfa23a9e2019-10-10 15:15:36 -070061import static org.junit.Assert.assertNotEquals;
Yunfan Chen1ee84ea2018-11-13 16:03:37 -080062import static org.junit.Assert.assertNotNull;
Bryce Lee04ab3462017-04-10 15:06:33 -070063import static org.junit.Assert.assertNull;
Bryce Lee1533b2b2017-09-14 17:06:41 -070064import static org.junit.Assert.assertTrue;
Riddle Hsuaec55442019-03-12 17:25:35 +080065import static org.mockito.ArgumentMatchers.anyString;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070066import static org.mockito.Mockito.never;
chaviw82a0ba82018-03-15 14:26:29 -070067
68import android.app.ActivityOptions;
Garfield Tan966c0412019-11-19 11:34:27 -080069import android.app.WindowConfiguration;
Garfield Tan36a69ad2019-01-16 17:08:23 -080070import android.app.servertransaction.ActivityConfigurationChangeItem;
Bryce Lee0bd8d422018-01-09 09:45:57 -080071import android.app.servertransaction.ClientTransaction;
72import android.app.servertransaction.PauseActivityItem;
Louis Chang6a9be162019-07-15 10:41:32 +080073import android.content.ComponentName;
wilsonshiha96aac62019-11-18 14:53:34 +080074import android.content.Intent;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080075import android.content.pm.ActivityInfo;
Garfield Tan0443b372019-01-04 15:00:13 -080076import android.content.res.Configuration;
Louis Chang6a9be162019-07-15 10:41:32 +080077import android.content.res.Resources;
Garfield Tan966c0412019-11-19 11:34:27 -080078import android.graphics.Rect;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070079import android.os.Bundle;
80import android.os.PersistableBundle;
Bryce Leeaf691c02017-03-20 14:20:22 -070081import android.platform.test.annotations.Presubmit;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080082import android.util.MergedConfiguration;
Andrii Kulian04470682018-01-10 15:32:31 -080083import android.util.MutableBoolean;
Jorim Jaggi346702a2019-05-08 17:49:33 +020084import android.view.IRemoteAnimationFinishedCallback;
85import android.view.IRemoteAnimationRunner.Stub;
86import android.view.RemoteAnimationAdapter;
87import android.view.RemoteAnimationTarget;
Bryce Leeaf691c02017-03-20 14:20:22 -070088
Brett Chabota26eda92018-07-23 13:08:30 -070089import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070090
Louis Chang6a9be162019-07-15 10:41:32 +080091import com.android.internal.R;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070092import com.android.server.wm.ActivityStack.ActivityState;
Riddle Hsu74826262019-04-17 14:57:42 +080093
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070094import org.junit.Before;
Bryce Leeaf691c02017-03-20 14:20:22 -070095import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +080096import org.junit.runner.RunWith;
Andrii Kulian04470682018-01-10 15:32:31 -080097import org.mockito.invocation.InvocationOnMock;
Bryce Lee0bd8d422018-01-09 09:45:57 -080098
Bryce Leeaf691c02017-03-20 14:20:22 -070099/**
100 * Tests for the {@link ActivityRecord} class.
101 *
102 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900103 * atest WmTests:ActivityRecordTests
Bryce Leeaf691c02017-03-20 14:20:22 -0700104 */
105@MediumTest
Bryce Lee3115bdf2017-04-05 08:39:40 -0700106@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +0800107@RunWith(WindowTestRunner.class)
Bryce Leeaf691c02017-03-20 14:20:22 -0700108public class ActivityRecordTests extends ActivityTestsBase {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700109 private ActivityStack mStack;
Louis Changcdec0802019-11-11 11:45:07 +0800110 private Task mTask;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700111 private ActivityRecord mActivity;
112
113 @Before
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700114 public void setUp() throws Exception {
Louis Chang149d5c82019-12-30 09:47:39 +0800115 mStack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900116 mTask = mStack.getBottomMostTask();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800117 mActivity = mTask.getTopNonFinishingActivity();
Andrii Kulian6b321512019-01-23 06:37:00 +0000118
119 doReturn(false).when(mService).isBooting();
120 doReturn(true).when(mService).isBooted();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700121 }
122
Bryce Leeaf691c02017-03-20 14:20:22 -0700123 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900124 public void testStackCleanupOnClearingTask() {
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200125 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800126 verify(mStack, times(1)).cleanUpActivityReferences(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700127 }
128
129 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900130 public void testStackCleanupOnActivityRemoval() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200131 mTask.removeChild(mActivity);
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800132 verify(mStack, times(1)).cleanUpActivityReferences(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700133 }
134
135 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900136 public void testStackCleanupOnTaskRemoval() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200137 mStack.removeChild(mTask, null /*reason*/);
Bryce Lee04ab3462017-04-10 15:06:33 -0700138 // Stack should be gone on task removal.
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -0800139 assertNull(mService.mRootWindowContainer.getStack(mStack.mTaskId));
Bryce Leeaf691c02017-03-20 14:20:22 -0700140 }
141
142 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900143 public void testNoCleanupMovingActivityInSameStack() {
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800144 final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700145 mActivity.reparent(newTask, 0, null /*reason*/);
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800146 verify(mStack, times(0)).cleanUpActivityReferences(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700147 }
Andrii Kulian3a1619d2017-07-07 14:38:09 -0700148
Andreas Gampecea9e6d2018-02-22 18:06:44 -0800149 @Test
Bryce Lee0bd8d422018-01-09 09:45:57 -0800150 public void testPausingWhenVisibleFromStopped() throws Exception {
Andrii Kulian04470682018-01-10 15:32:31 -0800151 final MutableBoolean pauseFound = new MutableBoolean(false);
152 doAnswer((InvocationOnMock invocationOnMock) -> {
153 final ClientTransaction transaction = invocationOnMock.getArgument(0);
154 if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
155 pauseFound.value = true;
Bryce Lee0bd8d422018-01-09 09:45:57 -0800156 }
Andrii Kulian04470682018-01-10 15:32:31 -0800157 return null;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700158 }).when(mActivity.app.getThread()).scheduleTransaction(any());
Bryce Leed939cf02018-03-12 09:04:44 -0700159
Bryce Lee7ace3952018-02-16 14:34:32 -0800160 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
Bryce Lee0bd8d422018-01-09 09:45:57 -0800161
Andrii Kulian6b321512019-01-23 06:37:00 +0000162 // The activity is in the focused stack so it should be resumed.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700163 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Andrii Kulian6b321512019-01-23 06:37:00 +0000164 assertTrue(mActivity.isState(RESUMED));
Bryce Leed939cf02018-03-12 09:04:44 -0700165 assertFalse(pauseFound.value);
Andrii Kulian04470682018-01-10 15:32:31 -0800166
Andrii Kulian6b321512019-01-23 06:37:00 +0000167 // Make the activity non focusable
168 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
169 doReturn(false).when(mActivity).isFocusable();
Bryce Leed939cf02018-03-12 09:04:44 -0700170
Andrii Kulian6b321512019-01-23 06:37:00 +0000171 // If the activity is not focusable, it should move to paused.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700172 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee7ace3952018-02-16 14:34:32 -0800173 assertTrue(mActivity.isState(PAUSING));
Andrii Kulian04470682018-01-10 15:32:31 -0800174 assertTrue(pauseFound.value);
Bryce Lee052957b2018-01-16 11:13:30 -0800175
176 // Make sure that the state does not change for current non-stopping states.
Bryce Lee7ace3952018-02-16 14:34:32 -0800177 mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
Andrii Kulian6b321512019-01-23 06:37:00 +0000178 doReturn(true).when(mActivity).isFocusable();
Bryce Lee052957b2018-01-16 11:13:30 -0800179
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700180 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee052957b2018-01-16 11:13:30 -0800181
Bryce Lee7ace3952018-02-16 14:34:32 -0800182 assertTrue(mActivity.isState(INITIALIZING));
Bryce Leea0fb8e02018-02-28 14:21:07 -0800183
184 // Make sure the state does not change if we are not the current top activity.
185 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
186
Bryce Leea0fb8e02018-02-28 14:21:07 -0800187 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
188 mStack.mTranslucentActivityWaiting = topActivity;
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700189 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Louis Changeadb22f2019-06-19 12:09:23 +0800190 assertTrue(mActivity.isState(STARTED));
191
192 mStack.mTranslucentActivityWaiting = null;
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700193 topActivity.setOccludesParent(false);
Louis Changeadb22f2019-06-19 12:09:23 +0800194 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
195 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
196 assertTrue(mActivity.isState(STARTED));
Bryce Lee0bd8d422018-01-09 09:45:57 -0800197 }
198
Riddle Hsu0a343c32018-12-21 00:40:48 +0800199 private void ensureActivityConfiguration() {
200 mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
201 }
202
Bryce Lee1533b2b2017-09-14 17:06:41 -0700203 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900204 public void testCanBeLaunchedOnDisplay() {
Riddle Hsu16567132018-08-16 21:37:47 +0800205 mService.mSupportsMultiWindow = true;
206 final ActivityRecord activity = new ActivityBuilder(mService).build();
Bryce Lee1533b2b2017-09-14 17:06:41 -0700207
Riddle Hsu16567132018-08-16 21:37:47 +0800208 // An activity can be launched on default display.
209 assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
210 // An activity cannot be launched on a non-existent display.
Garfield Tan5423cf02019-12-06 17:02:38 -0800211 assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE));
Bryce Lee1533b2b2017-09-14 17:06:41 -0700212 }
213
chaviw82a0ba82018-03-15 14:26:29 -0700214 @Test
215 public void testsApplyOptionsLocked() {
216 ActivityOptions activityOptions = ActivityOptions.makeBasic();
217
218 // Set and apply options for ActivityRecord. Pending options should be cleared
219 mActivity.updateOptionsLocked(activityOptions);
220 mActivity.applyOptionsLocked();
221 assertNull(mActivity.pendingOptions);
222
223 // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
224 // Pending options should be cleared for both ActivityRecords
225 ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
226 activity2.updateOptionsLocked(activityOptions);
227 mActivity.updateOptionsLocked(activityOptions);
228 mActivity.applyOptionsLocked();
229 assertNull(mActivity.pendingOptions);
230 assertNull(activity2.pendingOptions);
231
232 // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
233 // Pending options should be cleared for only ActivityRecord that was applied
Louis Changcdec0802019-11-11 11:45:07 +0800234 Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
chaviw82a0ba82018-03-15 14:26:29 -0700235 activity2 = new ActivityBuilder(mService).setTask(task2).build();
236 activity2.updateOptionsLocked(activityOptions);
237 mActivity.updateOptionsLocked(activityOptions);
238 mActivity.applyOptionsLocked();
239 assertNull(mActivity.pendingOptions);
240 assertNotNull(activity2.pendingOptions);
241 }
Garfield Tan0443b372019-01-04 15:00:13 -0800242
243 @Test
244 public void testNewOverrideConfigurationIncrementsSeq() {
245 final Configuration newConfig = new Configuration();
246
247 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
248 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
249 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
250 }
251
252 @Test
253 public void testNewParentConfigurationIncrementsSeq() {
254 final Configuration newConfig = new Configuration(
255 mTask.getRequestedOverrideConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700256 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
257 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
Garfield Tan0443b372019-01-04 15:00:13 -0800258
259 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
260 mTask.onRequestedOverrideConfigurationChanged(newConfig);
261 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
262 }
263
264 @Test
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800265 public void testSetsRelaunchReason_NotDragResizing() {
266 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
267
268 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
269 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
270 mActivity.getConfiguration()));
271
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700272 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800273 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700274 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
275 ? ORIENTATION_LANDSCAPE
276 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800277 mTask.onRequestedOverrideConfigurationChanged(newConfig);
278
279 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
280
Riddle Hsu0a343c32018-12-21 00:40:48 +0800281 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800282
283 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
284 mActivity.mRelaunchReason);
285 }
286
287 @Test
288 public void testSetsRelaunchReason_DragResizing() {
289 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
290
291 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
292 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
293 mActivity.getConfiguration()));
294
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700295 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800296 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700297 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
298 ? ORIENTATION_LANDSCAPE
299 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800300 mTask.onRequestedOverrideConfigurationChanged(newConfig);
301
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200302 doReturn(true).when(mTask).isDragResizing();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800303
304 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
305
Riddle Hsu0a343c32018-12-21 00:40:48 +0800306 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800307
308 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
309 mActivity.mRelaunchReason);
310 }
311
312 @Test
313 public void testSetsRelaunchReason_NonResizeConfigChanges() {
314 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
315
316 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
317 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
318 mActivity.getConfiguration()));
319
320 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
321 final Configuration newConfig = new Configuration(mTask.getConfiguration());
322 newConfig.fontScale = 5;
323 mTask.onRequestedOverrideConfigurationChanged(newConfig);
324
325 mActivity.mRelaunchReason =
326 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
327
Riddle Hsu0a343c32018-12-21 00:40:48 +0800328 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800329
330 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
331 mActivity.mRelaunchReason);
332 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800333
334 @Test
335 public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700336 mActivity = new ActivityBuilder(mService)
337 .setTask(mTask)
338 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
339 .build();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800340 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
341
Garfield Tan36a69ad2019-01-16 17:08:23 -0800342 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
343 mActivity.getConfiguration()));
344
Garfield Tan36a69ad2019-01-16 17:08:23 -0800345 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700346 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
347 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
348 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
349 newConfig.orientation = ORIENTATION_LANDSCAPE;
350 newConfig.screenWidthDp = longSide;
351 newConfig.screenHeightDp = shortSide;
352 } else {
353 newConfig.orientation = ORIENTATION_PORTRAIT;
354 newConfig.screenWidthDp = shortSide;
355 newConfig.screenHeightDp = longSide;
356 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800357
358 // Mimic the behavior that display doesn't handle app's requested orientation.
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200359 final DisplayContent dc = mTask.getDisplayContent();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700360 doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
361 doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800362
363 final int requestedOrientation;
364 switch (newConfig.orientation) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700365 case ORIENTATION_LANDSCAPE:
366 requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE;
Garfield Tan36a69ad2019-01-16 17:08:23 -0800367 break;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700368 case ORIENTATION_PORTRAIT:
Garfield Tan36a69ad2019-01-16 17:08:23 -0800369 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
370 break;
371 default:
372 throw new IllegalStateException("Orientation in new config should be either"
373 + "landscape or portrait.");
374 }
375 mActivity.setRequestedOrientation(requestedOrientation);
376
377 final ActivityConfigurationChangeItem expected =
378 ActivityConfigurationChangeItem.obtain(newConfig);
379 verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
380 eq(mActivity.appToken), eq(expected));
381 }
Andrii Kulianf2195362019-01-31 18:20:11 -0800382
383 @Test
Garfield Tan966c0412019-11-19 11:34:27 -0800384 public void ignoreRequestedOrientationInFreeformWindows() {
385 mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
386 final Rect stableRect = new Rect();
387 mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
388 final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
389 final Rect bounds = new Rect(stableRect);
390 if (isScreenPortrait) {
391 // Landscape bounds
392 final int newHeight = stableRect.width() - 10;
393 bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
394 bounds.bottom = bounds.top + newHeight;
395 } else {
396 // Portrait bounds
397 final int newWidth = stableRect.height() - 10;
398 bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
399 bounds.right = bounds.left + newWidth;
400 }
401 mTask.setBounds(bounds);
402
403 // Requests orientation that's different from its bounds.
404 mActivity.setRequestedOrientation(
405 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
406
407 // Asserts it has orientation derived from bounds.
408 assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
409 mActivity.getConfiguration().orientation);
410 }
411
412 @Test
413 public void ignoreRequestedOrientationInSplitWindows() {
414 mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
415 final Rect stableRect = new Rect();
416 mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
417 final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
418 final Rect bounds = new Rect(stableRect);
419 if (isScreenPortrait) {
420 // Landscape bounds
421 final int newHeight = stableRect.width() - 10;
422 bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
423 bounds.bottom = bounds.top + newHeight;
424 } else {
425 // Portrait bounds
426 final int newWidth = stableRect.height() - 10;
427 bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
428 bounds.right = bounds.left + newWidth;
429 }
430 mTask.setBounds(bounds);
431
432 // Requests orientation that's different from its bounds.
433 mActivity.setRequestedOrientation(
434 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
435
436 // Asserts it has orientation derived from bounds.
437 assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
438 mActivity.getConfiguration().orientation);
439 }
440
441 @Test
Andrii Kulianf2195362019-01-31 18:20:11 -0800442 public void testShouldMakeActive_deferredResume() {
443 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
444
445 mSupervisor.beginDeferResume();
446 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
447
448 mSupervisor.endDeferResume();
449 assertEquals(true, mActivity.shouldMakeActive(null /* activeActivity */));
450 }
Garfield Tan40263302019-02-01 15:27:35 -0800451
452 @Test
Andrii Kulian0c869cc2019-02-06 19:50:32 -0800453 public void testShouldResume_stackVisibility() {
454 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
455 spyOn(mStack);
456
457 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
458 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
459
460 doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
461 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
462
463 doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
464 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
465 }
466
467 @Test
wilsonshiha96aac62019-11-18 14:53:34 +0800468 public void testShouldResumeOrPauseWithResults() {
469 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
470 spyOn(mStack);
471
472 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
473 mActivity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
474 topActivity.finishing = true;
475
476 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
477 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
478 assertEquals(false, mActivity.shouldPauseActivity(null /*activeActivity */));
479 }
480
481 @Test
Garfield Tan40263302019-02-01 15:27:35 -0800482 public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700483 mActivity = new ActivityBuilder(mService)
484 .setTask(mTask)
485 .setLaunchTaskBehind(true)
486 .setConfigChanges(CONFIG_ORIENTATION)
487 .build();
Garfield Tan40263302019-02-01 15:27:35 -0800488 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
489
Louis Chang149d5c82019-12-30 09:47:39 +0800490 final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
Garfield Tan40263302019-02-01 15:27:35 -0800491 try {
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800492 doReturn(false).when(stack).isTranslucent(any());
Garfield Tan40263302019-02-01 15:27:35 -0800493 assertFalse(mStack.shouldBeVisible(null /* starting */));
494
Garfield Tan40263302019-02-01 15:27:35 -0800495 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
496 mActivity.getConfiguration()));
497
Garfield Tan40263302019-02-01 15:27:35 -0800498 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700499 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
500 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
501 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
502 newConfig.orientation = ORIENTATION_LANDSCAPE;
503 newConfig.screenWidthDp = longSide;
504 newConfig.screenHeightDp = shortSide;
505 } else {
506 newConfig.orientation = ORIENTATION_PORTRAIT;
507 newConfig.screenWidthDp = shortSide;
508 newConfig.screenHeightDp = longSide;
509 }
Garfield Tan40263302019-02-01 15:27:35 -0800510
511 mTask.onConfigurationChanged(newConfig);
512
513 mActivity.ensureActivityConfiguration(0 /* globalChanges */,
514 false /* preserveWindow */, true /* ignoreStopState */);
515
516 final ActivityConfigurationChangeItem expected =
517 ActivityConfigurationChangeItem.obtain(newConfig);
518 verify(mService.getLifecycleManager()).scheduleTransaction(
519 eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
520 } finally {
Louis Chang2453d062019-11-19 22:30:48 +0800521 stack.getDisplay().removeStack(stack);
Garfield Tan40263302019-02-01 15:27:35 -0800522 }
523 }
Riddle Hsu0a343c32018-12-21 00:40:48 +0800524
525 @Test
Andrii Kulianb9faa032019-10-17 23:11:54 -0700526 public void testShouldStartWhenMakeClientActive() {
Louis Chang3d119a92019-04-22 10:45:37 +0800527 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700528 topActivity.setOccludesParent(false);
Louis Chang3d119a92019-04-22 10:45:37 +0800529 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
Andrii Kulianb9faa032019-10-17 23:11:54 -0700530 mActivity.setVisibility(true);
531 mActivity.makeActiveIfNeeded(null /* activeActivity */);
Louis Changeadb22f2019-06-19 12:09:23 +0800532 assertEquals(STARTED, mActivity.getState());
Louis Chang3d119a92019-04-22 10:45:37 +0800533 }
534
535 @Test
Jorim Jaggi346702a2019-05-08 17:49:33 +0200536 public void testTakeOptions() {
537 ActivityOptions opts = ActivityOptions.makeRemoteAnimation(
538 new RemoteAnimationAdapter(new Stub() {
539
540 @Override
541 public void onAnimationStart(RemoteAnimationTarget[] apps,
Winson Chungd5852192019-09-06 17:20:28 -0700542 RemoteAnimationTarget[] wallpapers,
Jorim Jaggi346702a2019-05-08 17:49:33 +0200543 IRemoteAnimationFinishedCallback finishedCallback) {
544
545 }
546
547 @Override
548 public void onAnimationCancelled() {
549
550 }
551 }, 0, 0));
552 mActivity.updateOptionsLocked(opts);
553 assertNotNull(mActivity.takeOptionsLocked(true /* fromClient */));
554 assertNotNull(mActivity.pendingOptions);
555
556 mActivity.updateOptionsLocked(ActivityOptions.makeBasic());
557 assertNotNull(mActivity.takeOptionsLocked(false /* fromClient */));
558 assertNull(mActivity.pendingOptions);
559 }
560
Louis Chang6a9be162019-07-15 10:41:32 +0800561 @Test
562 public void testCanLaunchHomeActivityFromChooser() {
563 ComponentName chooserComponent = ComponentName.unflattenFromString(
564 Resources.getSystem().getString(R.string.config_chooserActivity));
565 ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
566 chooserComponent).build();
567 assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
568 }
569
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700570 /**
571 * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and
572 * that it is cleared after activity is resumed.
573 */
574 @Test
575 public void testHasSavedState() {
576 assertTrue(mActivity.hasSavedState());
577
578 ActivityRecord.activityResumedLocked(mActivity.appToken);
579 assertFalse(mActivity.hasSavedState());
580 assertNull(mActivity.getSavedState());
581 }
582
583 /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */
584 @Test
585 public void testUpdateSavedState() {
586 mActivity.setSavedState(null /* savedState */);
587 assertFalse(mActivity.hasSavedState());
588 assertNull(mActivity.getSavedState());
589
590 final Bundle savedState = new Bundle();
591 savedState.putString("test", "string");
592 mActivity.setSavedState(savedState);
593 assertTrue(mActivity.hasSavedState());
594 assertEquals(savedState, mActivity.getSavedState());
595 }
596
597 /** Verify the correct updates of saved state when activity client reports stop. */
598 @Test
599 public void testUpdateSavedState_activityStopped() {
600 final Bundle savedState = new Bundle();
601 savedState.putString("test", "string");
602 final PersistableBundle persistentSavedState = new PersistableBundle();
603 persistentSavedState.putString("persist", "string");
604
605 // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored.
606 mActivity.setState(STOPPING, "test");
Wale Ogunwale196db712019-12-27 15:35:39 +0000607 mActivity.activityStopped(savedState, persistentSavedState, "desc");
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700608 assertTrue(mActivity.hasSavedState());
609 assertEquals(savedState, mActivity.getSavedState());
610 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
611
612 // Sending 'null' for saved state can only happen due to timeout, so previously stored saved
613 // states should not be overridden.
614 mActivity.setState(STOPPING, "test");
Wale Ogunwale8f93b642019-12-26 12:10:52 -0800615 mActivity.activityStopped(null /* savedState */, null /* persistentSavedState */, "desc");
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700616 assertTrue(mActivity.hasSavedState());
617 assertEquals(savedState, mActivity.getSavedState());
618 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
619 }
620
Andrii Kulian057a6512019-07-15 16:15:51 -0700621 /**
622 * Verify that activity finish request is not performed if activity is finishing or is in
623 * incorrect state.
624 */
625 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700626 public void testFinishActivityIfPossible_cancelled() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700627 // Mark activity as finishing
628 mActivity.finishing = true;
629 assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700630 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700631 assertTrue(mActivity.finishing);
632 assertTrue(mActivity.isInStackLocked());
633
634 // Remove activity from task
635 mActivity.finishing = false;
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200636 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
Andrii Kulian057a6512019-07-15 16:15:51 -0700637 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700638 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700639 assertFalse(mActivity.finishing);
640 }
641
642 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700643 * Verify that activity finish request is placed, but not executed immediately if activity is
Andrii Kulian057a6512019-07-15 16:15:51 -0700644 * not ready yet.
645 */
646 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700647 public void testFinishActivityIfPossible_requested() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700648 mActivity.finishing = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700649 assertEquals("Currently resumed activity must be prepared removal", FINISH_RESULT_REQUESTED,
650 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700651 assertTrue(mActivity.finishing);
652 assertTrue(mActivity.isInStackLocked());
653
654 // First request to finish activity must schedule a "destroy" request to the client.
655 // Activity must be removed from history after the client reports back or after timeout.
656 mActivity.finishing = false;
657 mActivity.setState(STOPPED, "test");
658 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700659 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700660 assertTrue(mActivity.finishing);
661 assertTrue(mActivity.isInStackLocked());
662 }
663
664 /**
665 * Verify that activity finish request removes activity immediately if it's ready.
666 */
667 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700668 public void testFinishActivityIfPossible_removed() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700669 // Prepare the activity record to be ready for immediate removal. It should be invisible and
670 // have no process. Otherwise, request to finish it will send a message to client first.
671 mActivity.setState(STOPPED, "test");
Issei Suzuki1669ea42019-11-06 14:20:59 +0100672 mActivity.mVisibleRequested = false;
Andrii Kulian057a6512019-07-15 16:15:51 -0700673 mActivity.nowVisible = false;
674 // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
675 // this will cause NPE when updating task's process.
676 mActivity.app = null;
wilsonshih4c9824a2019-10-25 18:47:50 +0800677
678 // Put a visible activity on top, so the finishing activity doesn't have to wait until the
679 // next activity reports idle to destroy it.
680 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100681 topActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +0800682 topActivity.nowVisible = true;
683 topActivity.setState(RESUMED, "test");
684
Andrii Kulian057a6512019-07-15 16:15:51 -0700685 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REMOVED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700686 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700687 assertTrue(mActivity.finishing);
688 assertFalse(mActivity.isInStackLocked());
689 }
690
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700691 /**
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800692 * Verify that when finishing the top focused activity on top display, the stack order will be
693 * changed by adjusting focus.
694 */
695 @Test
696 public void testFinishActivityIfPossible_adjustStackOrder() {
697 // Prepare the stacks with order (top to bottom): mStack, stack1, stack2.
Louis Chang149d5c82019-12-30 09:47:39 +0800698 final ActivityStack stack1 = new StackBuilder(mRootWindowContainer).build();
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800699 mStack.moveToFront("test");
700 // The stack2 is needed here for moving back to simulate the
Louis Chang677921f2019-12-06 16:44:24 +0800701 // {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so
702 // {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800703 // stacks. Then when mActivity is finishing, its stack will be invisible (no running
704 // activities in the stack) that is the key condition to verify.
Louis Chang149d5c82019-12-30 09:47:39 +0800705 final ActivityStack stack2 = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900706 stack2.moveToBack("test", stack2.getBottomMostTask());
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800707
708 assertTrue(mStack.isTopStackOnDisplay());
709
710 mActivity.setState(RESUMED, "test");
711 mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test",
Louis Chang7b03ad92019-08-21 12:32:33 +0800712 false /* oomAdj */);
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800713
714 assertTrue(stack1.isTopStackOnDisplay());
715 }
716
717 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700718 * Verify that resumed activity is paused due to finish request.
719 */
720 @Test
721 public void testFinishActivityIfPossible_resumedStartsPausing() {
722 mActivity.finishing = false;
723 mActivity.setState(RESUMED, "test");
724 assertEquals("Currently resumed activity must be paused before removal",
725 FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */));
726 assertEquals(PAUSING, mActivity.getState());
727 verify(mActivity).setVisibility(eq(false));
728 verify(mActivity.getDisplay().mDisplayContent)
729 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
730 }
731
732 /**
733 * Verify that finish request will be completed immediately for non-resumed activity.
734 */
735 @Test
736 public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() {
737 final ActivityState[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED};
738 for (ActivityState state : states) {
739 mActivity.finishing = false;
740 mActivity.setState(state, "test");
741 reset(mActivity);
742 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
743 mActivity.finishIfPossible("test", false /* oomAdj */));
744 verify(mActivity).completeFinishing(anyString());
745 }
746 }
747
748 /**
749 * Verify that finishing will not be completed in PAUSING state.
750 */
751 @Test
752 public void testFinishActivityIfPossible_pausing() {
753 mActivity.finishing = false;
754 mActivity.setState(PAUSING, "test");
755 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
756 mActivity.finishIfPossible("test", false /* oomAdj */));
757 verify(mActivity, never()).completeFinishing(anyString());
758 }
759
760 /**
761 * Verify that finish request for resumed activity will prepare an app transition but not
762 * execute it immediately.
763 */
764 @Test
765 public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() {
766 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100767 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700768 mActivity.setState(RESUMED, "test");
769 mActivity.finishIfPossible("test", false /* oomAdj */);
770
771 verify(mActivity).setVisibility(eq(false));
772 verify(mActivity.getDisplay().mDisplayContent)
773 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
774 verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition();
775 }
776
777 /**
778 * Verify that finish request for paused activity will prepare and execute an app transition.
779 */
780 @Test
781 public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() {
782 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100783 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700784 mActivity.setState(PAUSED, "test");
785 mActivity.finishIfPossible("test", false /* oomAdj */);
786
Andrii Kulian149d9ad32019-08-23 15:04:17 -0700787 verify(mActivity, atLeast(1)).setVisibility(eq(false));
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700788 verify(mActivity.getDisplay().mDisplayContent)
789 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
790 verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
791 }
792
793 /**
794 * Verify that finish request for non-visible activity will not prepare any transitions.
795 */
796 @Test
797 public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
798 // Put an activity on top of test activity to make it invisible and prevent us from
799 // accidentally resuming the topmost one again.
800 new ActivityBuilder(mService).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100801 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700802 mActivity.setState(STOPPED, "test");
803
804 mActivity.finishIfPossible("test", false /* oomAdj */);
805
806 verify(mActivity.getDisplay().mDisplayContent, never())
807 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
808 }
809
810 /**
811 * Verify that complete finish request for non-finishing activity is invalid.
812 */
813 @Test(expected = IllegalArgumentException.class)
814 public void testCompleteFinishing_failNotFinishing() {
815 mActivity.finishing = false;
816 mActivity.completeFinishing("test");
817 }
818
819 /**
820 * Verify that complete finish request for resumed activity is invalid.
821 */
822 @Test(expected = IllegalArgumentException.class)
823 public void testCompleteFinishing_failResumed() {
824 mActivity.setState(RESUMED, "test");
825 mActivity.completeFinishing("test");
826 }
827
828 /**
829 * Verify that finish request for pausing activity must be a no-op - activity will finish
830 * once it completes pausing.
831 */
832 @Test
833 public void testCompleteFinishing_pausing() {
834 mActivity.setState(PAUSING, "test");
835 mActivity.finishing = true;
836
837 assertEquals("Activity must not be removed immediately - waiting for paused",
838 mActivity, mActivity.completeFinishing("test"));
839 assertEquals(PAUSING, mActivity.getState());
840 verify(mActivity, never()).destroyIfPossible(anyString());
841 }
842
843 /**
Riddle Hsucf920232019-10-04 19:05:36 +0800844 * Verify that finish request won't change the state of next top activity if the current
845 * finishing activity doesn't need to be destroyed immediately. The case is usually like
846 * from {@link ActivityStack#completePauseLocked(boolean, ActivityRecord)} to
847 * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the
848 * responsibility to resume the next activity with updating the state.
849 */
850 @Test
851 public void testCompleteFinishing_keepStateOfNextInvisible() {
852 final ActivityRecord currentTop = mActivity;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100853 currentTop.mVisibleRequested = currentTop.nowVisible = true;
Riddle Hsucf920232019-10-04 19:05:36 +0800854
855 // Simulates that {@code currentTop} starts an existing activity from background (so its
856 // state is stopped) and the starting flow just goes to place it at top.
Louis Chang149d5c82019-12-30 09:47:39 +0800857 final ActivityStack nextStack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800858 final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity();
Riddle Hsucf920232019-10-04 19:05:36 +0800859 nextTop.setState(STOPPED, "test");
860
861 mStack.mPausingActivity = currentTop;
862 currentTop.finishing = true;
863 currentTop.setState(PAUSED, "test");
864 currentTop.completeFinishing("completePauseLocked");
865
866 // Current top becomes stopping because it is visible and the next is invisible.
867 assertEquals(STOPPING, currentTop.getState());
868 // The state of next activity shouldn't be changed.
869 assertEquals(STOPPED, nextTop.getState());
870 }
871
872 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700873 * Verify that complete finish request for visible activity must be delayed before the next one
874 * becomes visible.
875 */
876 @Test
877 public void testCompleteFinishing_waitForNextVisible() {
878 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100879 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700880 topActivity.nowVisible = true;
881 topActivity.finishing = true;
882 topActivity.setState(PAUSED, "true");
883 // Mark the bottom activity as not visible, so that we will wait for it before removing
884 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100885 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700886 mActivity.nowVisible = false;
887 mActivity.setState(STOPPED, "test");
888
889 assertEquals("Activity must not be removed immediately - waiting for next visible",
890 topActivity, topActivity.completeFinishing("test"));
891 assertEquals("Activity must be stopped to make next one visible", STOPPING,
892 topActivity.getState());
893 assertTrue("Activity must be stopped to make next one visible",
894 topActivity.mStackSupervisor.mStoppingActivities.contains(topActivity));
895 verify(topActivity, never()).destroyIfPossible(anyString());
896 }
897
898 /**
899 * Verify that complete finish request for invisible activity must not be delayed.
900 */
901 @Test
902 public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
903 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100904 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700905 topActivity.nowVisible = false;
906 topActivity.finishing = true;
Issei Suzukid0c14f32019-12-19 12:42:13 +0100907 topActivity.setState(STOPPED, "true");
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700908 // Mark the bottom activity as not visible, so that we would wait for it before removing
909 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100910 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700911 mActivity.nowVisible = false;
912 mActivity.setState(STOPPED, "test");
913
914 topActivity.completeFinishing("test");
915
916 verify(topActivity).destroyIfPossible(anyString());
917 }
918
919 /**
920 * Verify that paused finishing activity will be added to finishing list and wait for next one
921 * to idle.
922 */
923 @Test
924 public void testCompleteFinishing_waitForIdle() {
925 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100926 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700927 topActivity.nowVisible = true;
928 topActivity.finishing = true;
929 topActivity.setState(PAUSED, "true");
930 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100931 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700932 mActivity.nowVisible = true;
933 mActivity.setState(RESUMED, "test");
934
935 topActivity.completeFinishing("test");
936
937 verify(topActivity).addToFinishingAndWaitForIdle();
938 }
939
940 /**
941 * Verify that complete finish request for visible activity must not be delayed if the next one
942 * is already visible and it's not the focused stack.
943 */
944 @Test
945 public void testCompleteFinishing_noWaitForNextVisible_stopped() {
946 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100947 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700948 topActivity.nowVisible = false;
949 topActivity.finishing = true;
950 topActivity.setState(STOPPED, "true");
951 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100952 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700953 mActivity.nowVisible = true;
954 mActivity.setState(RESUMED, "test");
955
956 topActivity.completeFinishing("test");
957
958 verify(topActivity).destroyIfPossible(anyString());
959 }
960
961 /**
962 * Verify that complete finish request for visible activity must not be delayed if the next one
963 * is already visible and it's not the focused stack.
964 */
965 @Test
966 public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
967 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100968 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700969 topActivity.nowVisible = true;
970 topActivity.finishing = true;
971 topActivity.setState(PAUSED, "true");
972 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100973 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700974 mActivity.nowVisible = true;
975 mActivity.setState(RESUMED, "test");
976
977 // Add another stack to become focused and make the activity there visible. This way it
978 // simulates finishing in non-focused stack in split-screen.
Louis Chang149d5c82019-12-30 09:47:39 +0800979 final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800980 final ActivityRecord focusedActivity = stack.getTopMostActivity();
wilsonshih4c9824a2019-10-25 18:47:50 +0800981 focusedActivity.nowVisible = true;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100982 focusedActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +0800983 focusedActivity.setState(RESUMED, "test");
984 stack.mResumedActivity = focusedActivity;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700985
986 topActivity.completeFinishing("test");
987
988 verify(topActivity).destroyIfPossible(anyString());
989 }
990
991 /**
992 * Verify destroy activity request completes successfully.
993 */
994 @Test
995 public void testDestroyIfPossible() {
Louis Chang149d5c82019-12-30 09:47:39 +0800996 doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700997 spyOn(mStack);
998 mActivity.destroyIfPossible("test");
999
1000 assertEquals(DESTROYING, mActivity.getState());
1001 assertTrue(mActivity.finishing);
Andrii Kulian79d67982019-08-19 11:56:16 -07001002 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001003 }
1004
1005 /**
1006 * Verify that complete finish request for visible activity must not destroy it immediately if
1007 * it is the last running activity on a display with a home stack. We must wait for home
1008 * activity to come up to avoid a black flash in this case.
1009 */
1010 @Test
1011 public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
1012 // Empty the home stack.
1013 final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
Wale Ogunwale8f93b642019-12-26 12:10:52 -08001014 homeStack.forAllTasks((t) -> {
1015 homeStack.removeChild(t, "test");
1016 }, true /* traverseTopToBottom */, homeStack);
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001017 mActivity.finishing = true;
Louis Chang149d5c82019-12-30 09:47:39 +08001018 doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001019 spyOn(mStack);
1020
1021 // Try to destroy the last activity above the home stack.
1022 mActivity.destroyIfPossible("test");
1023
1024 // Verify that the activity was not actually destroyed, but waits for next one to come up
1025 // instead.
Andrii Kulian79d67982019-08-19 11:56:16 -07001026 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001027 assertEquals(FINISHING, mActivity.getState());
1028 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1029 }
1030
Andrii Kulian79d67982019-08-19 11:56:16 -07001031 /**
wilsonshih4c9824a2019-10-25 18:47:50 +08001032 * Verify that complete finish request for visible activity must resume next home stack before
1033 * destroying it immediately if it is the last running activity on a display with a home stack.
1034 * We must wait for home activity to come up to avoid a black flash in this case.
1035 */
1036 @Test
1037 public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
1038 // Empty the home stack.
1039 final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
Wale Ogunwale8f93b642019-12-26 12:10:52 -08001040 homeStack.forAllTasks((t) -> {
1041 homeStack.removeChild(t, "test");
1042 }, true /* traverseTopToBottom */, homeStack);
wilsonshih4c9824a2019-10-25 18:47:50 +08001043 mActivity.finishing = true;
1044 spyOn(mStack);
1045
1046 // Try to finish the last activity above the home stack.
1047 mActivity.completeFinishing("test");
1048
1049 // Verify that the activity is not destroyed immediately, but waits for next one to come up.
1050 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1051 assertEquals(FINISHING, mActivity.getState());
1052 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1053 }
1054
1055 /**
Andrii Kulian79d67982019-08-19 11:56:16 -07001056 * Test that the activity will be moved to destroying state and the message to destroy will be
1057 * sent to the client.
1058 */
1059 @Test
1060 public void testDestroyImmediately_hadApp_finishing() {
1061 mActivity.finishing = true;
1062 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1063
1064 assertEquals(DESTROYING, mActivity.getState());
1065 }
1066
1067 /**
1068 * Test that the activity will be moved to destroyed state immediately if it was not marked as
1069 * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
1070 */
1071 @Test
1072 public void testDestroyImmediately_hadApp_notFinishing() {
1073 mActivity.finishing = false;
1074 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1075
1076 assertEquals(DESTROYED, mActivity.getState());
1077 }
1078
1079 /**
1080 * Test that an activity with no process attached and that is marked as finishing will be
1081 * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
1082 */
1083 @Test
1084 public void testDestroyImmediately_noApp_finishing() {
1085 mActivity.app = null;
1086 mActivity.finishing = true;
Louis Changcdec0802019-11-11 11:45:07 +08001087 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001088
1089 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1090
1091 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001092 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001093 assertEquals(0, task.getChildCount());
1094 }
1095
1096 /**
1097 * Test that an activity with no process attached and that is not marked as finishing will be
1098 * marked as DESTROYED but not removed from task.
1099 */
1100 @Test
1101 public void testDestroyImmediately_noApp_notFinishing() {
1102 mActivity.app = null;
1103 mActivity.finishing = false;
Louis Changcdec0802019-11-11 11:45:07 +08001104 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001105
1106 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1107
1108 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001109 assertEquals(task, mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001110 assertEquals(1, task.getChildCount());
1111 }
1112
1113 /**
1114 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1115 */
1116 @Test
1117 public void testSafelyDestroy_nonDestroyable() {
1118 doReturn(false).when(mActivity).isDestroyable();
1119
1120 mActivity.safelyDestroy("test");
1121
1122 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1123 }
1124
1125 /**
1126 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1127 */
1128 @Test
1129 public void testSafelyDestroy_destroyable() {
1130 doReturn(true).when(mActivity).isDestroyable();
1131
1132 mActivity.safelyDestroy("test");
1133
1134 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1135 }
1136
1137 @Test
1138 public void testRemoveFromHistory() {
Wale Ogunwale1ebcd8e2020-01-21 11:27:03 -08001139 final ActivityStack stack = mActivity.getRootTask();
Louis Changcdec0802019-11-11 11:45:07 +08001140 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001141
1142 mActivity.removeFromHistory("test");
1143
1144 assertEquals(DESTROYED, mActivity.getState());
1145 assertNull(mActivity.app);
Louis Changcdec0802019-11-11 11:45:07 +08001146 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001147 assertEquals(0, task.getChildCount());
Wale Ogunwale8f93b642019-12-26 12:10:52 -08001148 assertEquals(task.getStack(), task);
Andrii Kulian79d67982019-08-19 11:56:16 -07001149 assertEquals(0, stack.getChildCount());
1150 }
1151
1152 /**
1153 * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is
1154 * not in destroying or destroyed state.
1155 */
1156 @Test(expected = IllegalStateException.class)
1157 public void testDestroyed_notDestroying() {
1158 mActivity.setState(STOPPED, "test");
1159 mActivity.destroyed("test");
1160 }
1161
1162 /**
1163 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying
1164 */
1165 @Test
1166 public void testDestroyed_destroying() {
1167 mActivity.setState(DESTROYING, "test");
1168 mActivity.destroyed("test");
1169
1170 verify(mActivity).removeFromHistory(anyString());
1171 }
1172
1173 /**
1174 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed.
1175 */
1176 @Test
1177 public void testDestroyed_destroyed() {
1178 mActivity.setState(DESTROYED, "test");
1179 mActivity.destroyed("test");
1180
1181 verify(mActivity).removeFromHistory(anyString());
1182 }
Andrii Kulianfa23a9e2019-10-10 15:15:36 -07001183
1184 @Test
1185 public void testActivityOverridesProcessConfig() {
1186 final WindowProcessController wpc = mActivity.app;
1187 assertTrue(wpc.registeredForActivityConfigChanges());
1188 assertFalse(wpc.registeredForDisplayConfigChanges());
1189
1190 final ActivityRecord secondaryDisplayActivity =
1191 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1192
1193 assertTrue(wpc.registeredForActivityConfigChanges());
1194 assertEquals(0, mActivity.getMergedOverrideConfiguration()
1195 .diff(wpc.getRequestedOverrideConfiguration()));
1196 assertNotEquals(mActivity.getConfiguration(),
1197 secondaryDisplayActivity.getConfiguration());
1198 }
1199
1200 @Test
1201 public void testActivityOverridesProcessConfig_TwoActivities() {
1202 final WindowProcessController wpc = mActivity.app;
1203 assertTrue(wpc.registeredForActivityConfigChanges());
1204
1205 final Task firstTaskRecord = mActivity.getTask();
1206 final ActivityRecord secondActivityRecord =
1207 new ActivityBuilder(mService).setTask(firstTaskRecord).setUseProcess(wpc).build();
1208
1209 assertTrue(wpc.registeredForActivityConfigChanges());
1210 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1211 .diff(wpc.getRequestedOverrideConfiguration()));
1212 }
1213
1214 @Test
1215 public void testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay() {
1216 final WindowProcessController wpc = mActivity.app;
1217 assertTrue(wpc.registeredForActivityConfigChanges());
1218
1219 final ActivityRecord secondActivityRecord =
1220 new ActivityBuilder(mService).setTask(mTask).setUseProcess(wpc).build();
1221
1222 assertTrue(wpc.registeredForActivityConfigChanges());
1223 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1224 .diff(wpc.getRequestedOverrideConfiguration()));
1225 }
1226
1227 @Test
1228 public void testActivityOverridesProcessConfig_TwoActivities_DifferentTasks() {
1229 final WindowProcessController wpc = mActivity.app;
1230 assertTrue(wpc.registeredForActivityConfigChanges());
1231
1232 final ActivityRecord secondActivityRecord =
1233 createActivityOnDisplay(true /* defaultDisplay */, wpc);
1234
1235 assertTrue(wpc.registeredForActivityConfigChanges());
1236 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1237 .diff(wpc.getRequestedOverrideConfiguration()));
1238 }
1239
1240 @Test
1241 public void testActivityOnDifferentDisplayUpdatesProcessOverride() {
1242 final ActivityRecord secondaryDisplayActivity =
1243 createActivityOnDisplay(false /* defaultDisplay */, null /* process */);
1244 final WindowProcessController wpc = secondaryDisplayActivity.app;
1245 assertTrue(wpc.registeredForActivityConfigChanges());
1246
1247 final ActivityRecord secondActivityRecord =
1248 createActivityOnDisplay(true /* defaultDisplay */, wpc);
1249
1250 assertTrue(wpc.registeredForActivityConfigChanges());
1251 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration()
1252 .diff(wpc.getRequestedOverrideConfiguration()));
1253 assertFalse(wpc.registeredForDisplayConfigChanges());
1254 }
1255
1256 @Test
1257 public void testActivityReparentChangesProcessOverride() {
1258 final WindowProcessController wpc = mActivity.app;
1259 final Task initialTask = mActivity.getTask();
1260 final Configuration initialConf =
1261 new Configuration(mActivity.getMergedOverrideConfiguration());
1262 assertEquals(0, mActivity.getMergedOverrideConfiguration()
1263 .diff(wpc.getRequestedOverrideConfiguration()));
1264 assertTrue(wpc.registeredForActivityConfigChanges());
1265
1266 // Create a new task with custom config to reparent the activity to.
1267 final Task newTask =
1268 new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build();
1269 final Configuration newConfig = newTask.getConfiguration();
1270 newConfig.densityDpi += 100;
1271 newTask.onRequestedOverrideConfigurationChanged(newConfig);
1272 assertEquals(newTask.getConfiguration().densityDpi, newConfig.densityDpi);
1273
1274 // Reparent the activity and verify that config override changed.
1275 mActivity.reparent(newTask, 0 /* top */, "test");
1276 assertEquals(mActivity.getConfiguration().densityDpi, newConfig.densityDpi);
1277 assertEquals(mActivity.getMergedOverrideConfiguration().densityDpi, newConfig.densityDpi);
1278
1279 assertTrue(wpc.registeredForActivityConfigChanges());
1280 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1281 assertEquals(0, mActivity.getMergedOverrideConfiguration()
1282 .diff(wpc.getRequestedOverrideConfiguration()));
1283 }
1284
1285 @Test
1286 public void testActivityReparentDoesntClearProcessOverride_TwoActivities() {
1287 final WindowProcessController wpc = mActivity.app;
1288 final Configuration initialConf =
1289 new Configuration(mActivity.getMergedOverrideConfiguration());
1290 final Task initialTask = mActivity.getTask();
1291 final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(initialTask)
1292 .setUseProcess(wpc).build();
1293
1294 assertTrue(wpc.registeredForActivityConfigChanges());
1295 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1296 .diff(wpc.getRequestedOverrideConfiguration()));
1297
1298 // Create a new task with custom config to reparent the second activity to.
1299 final Task newTask =
1300 new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build();
1301 final Configuration newConfig = newTask.getConfiguration();
1302 newConfig.densityDpi += 100;
1303 newTask.onRequestedOverrideConfigurationChanged(newConfig);
1304
1305 // Reparent the activity and verify that config override changed.
1306 secondActivity.reparent(newTask, 0 /* top */, "test");
1307
1308 assertTrue(wpc.registeredForActivityConfigChanges());
1309 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1310 .diff(wpc.getRequestedOverrideConfiguration()));
1311 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1312
1313 // Reparent the first activity and verify that config override didn't change.
1314 mActivity.reparent(newTask, 1 /* top */, "test");
1315 assertTrue(wpc.registeredForActivityConfigChanges());
1316 assertEquals(0, secondActivity.getMergedOverrideConfiguration()
1317 .diff(wpc.getRequestedOverrideConfiguration()));
1318 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration());
1319 }
1320
1321 /**
1322 * Creates an activity on display. For non-default display request it will also create a new
1323 * display with custom DisplayInfo.
1324 */
1325 private ActivityRecord createActivityOnDisplay(boolean defaultDisplay,
1326 WindowProcessController process) {
1327 final DisplayContent display;
1328 if (defaultDisplay) {
1329 display = mRootWindowContainer.getDefaultDisplay();
1330 } else {
1331 display = new TestDisplayContent.Builder(mService, 2000, 1000).setDensityDpi(300)
1332 .setPosition(DisplayContent.POSITION_TOP).build();
1333 }
1334 final ActivityStack stack = display.createStack(WINDOWING_MODE_UNDEFINED,
1335 ACTIVITY_TYPE_STANDARD, true /* onTop */);
1336 final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
1337 return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build();
1338 }
Bryce Leeaf691c02017-03-20 14:20:22 -07001339}