blob: 30c8eb36f34a6a5ce35eb0004b4a5cf494131810 [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
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070019import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
20import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
21import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
22import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
23import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
24import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
Louis Chang6a9be162019-07-15 10:41:32 +080025import static android.os.Process.NOBODY_UID;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070026import static android.view.Display.DEFAULT_DISPLAY;
Riddle Hsu74826262019-04-17 14:57:42 +080027import static android.view.Surface.ROTATION_0;
28import static android.view.Surface.ROTATION_90;
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;
Garfield Tan36a69ad2019-01-16 17:08:23 -080032import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
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;
Riddle Hsu7b766fd2019-01-28 21:14:59 +080035import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
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;
Garfield Tan0443b372019-01-04 15:00:13 -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;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090043import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
Andrii Kulian057a6512019-07-15 16:15:51 -070044import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
45import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
46import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
Andrii Kulian79d67982019-08-19 11:56:16 -070047import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070048import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
49import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
Wale Ogunwale59507092018-10-29 09:00:30 -070050import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070051import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
Wale Ogunwale59507092018-10-29 09:00:30 -070052import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
Andrii Kulian6b321512019-01-23 06:37:00 +000053import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
Louis Changeadb22f2019-06-19 12:09:23 +080054import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
Wale Ogunwale59507092018-10-29 09:00:30 -070055import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070056import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070057import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
Wale Ogunwale59507092018-10-29 09:00:30 -070058import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080059import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
60import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
61import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
Adrian Roose99bc052017-11-20 17:55:31 +010062
Louis Chang6a9be162019-07-15 10:41:32 +080063import static com.google.common.truth.Truth.assertThat;
64
Bryce Lee04ab3462017-04-10 15:06:33 -070065import static org.junit.Assert.assertEquals;
Bryce Lee1533b2b2017-09-14 17:06:41 -070066import static org.junit.Assert.assertFalse;
Riddle Hsu7b766fd2019-01-28 21:14:59 +080067import static org.junit.Assert.assertNotEquals;
Yunfan Chen1ee84ea2018-11-13 16:03:37 -080068import static org.junit.Assert.assertNotNull;
Bryce Lee04ab3462017-04-10 15:06:33 -070069import static org.junit.Assert.assertNull;
Bryce Lee1533b2b2017-09-14 17:06:41 -070070import static org.junit.Assert.assertTrue;
Riddle Hsuaec55442019-03-12 17:25:35 +080071import static org.mockito.ArgumentMatchers.anyString;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070072import static org.mockito.Mockito.never;
chaviw82a0ba82018-03-15 14:26:29 -070073
Riddle Hsuaec55442019-03-12 17:25:35 +080074import android.app.ActivityManager;
75import android.app.ActivityManagerInternal;
chaviw82a0ba82018-03-15 14:26:29 -070076import android.app.ActivityOptions;
Garfield Tan36a69ad2019-01-16 17:08:23 -080077import android.app.servertransaction.ActivityConfigurationChangeItem;
Bryce Lee0bd8d422018-01-09 09:45:57 -080078import android.app.servertransaction.ClientTransaction;
79import android.app.servertransaction.PauseActivityItem;
Louis Chang6a9be162019-07-15 10:41:32 +080080import android.content.ComponentName;
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;
Andrii Kulian3a1619d2017-07-07 14:38:09 -070084import android.graphics.Rect;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070085import android.os.Bundle;
86import android.os.PersistableBundle;
Bryce Leeaf691c02017-03-20 14:20:22 -070087import android.platform.test.annotations.Presubmit;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080088import android.util.MergedConfiguration;
Andrii Kulian04470682018-01-10 15:32:31 -080089import android.util.MutableBoolean;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070090import android.view.DisplayInfo;
Jorim Jaggi346702a2019-05-08 17:49:33 +020091import android.view.IRemoteAnimationFinishedCallback;
92import android.view.IRemoteAnimationRunner.Stub;
93import android.view.RemoteAnimationAdapter;
94import android.view.RemoteAnimationTarget;
Bryce Leeaf691c02017-03-20 14:20:22 -070095
Brett Chabota26eda92018-07-23 13:08:30 -070096import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070097
Louis Chang6a9be162019-07-15 10:41:32 +080098import com.android.internal.R;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070099import com.android.server.wm.ActivityStack.ActivityState;
Riddle Hsu74826262019-04-17 14:57:42 +0800100
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700101import org.junit.Before;
Bryce Leeaf691c02017-03-20 14:20:22 -0700102import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +0800103import org.junit.runner.RunWith;
Andrii Kulian04470682018-01-10 15:32:31 -0800104import org.mockito.invocation.InvocationOnMock;
Bryce Lee0bd8d422018-01-09 09:45:57 -0800105
Riddle Hsuaec55442019-03-12 17:25:35 +0800106import java.util.concurrent.TimeUnit;
107
Bryce Leeaf691c02017-03-20 14:20:22 -0700108/**
109 * Tests for the {@link ActivityRecord} class.
110 *
111 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900112 * atest WmTests:ActivityRecordTests
Bryce Leeaf691c02017-03-20 14:20:22 -0700113 */
114@MediumTest
Bryce Lee3115bdf2017-04-05 08:39:40 -0700115@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +0800116@RunWith(WindowTestRunner.class)
Bryce Leeaf691c02017-03-20 14:20:22 -0700117public class ActivityRecordTests extends ActivityTestsBase {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700118 private ActivityStack mStack;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700119 private TaskRecord mTask;
120 private ActivityRecord mActivity;
121
122 @Before
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700123 public void setUp() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700124 mStack = new StackBuilder(mRootActivityContainer).build();
Louis Changf2835df2018-10-17 15:14:45 +0800125 mTask = mStack.getChildAt(0);
126 mActivity = mTask.getTopActivity();
Andrii Kulian6b321512019-01-23 06:37:00 +0000127
128 doReturn(false).when(mService).isBooting();
129 doReturn(true).when(mService).isBooted();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700130 }
131
Bryce Leeaf691c02017-03-20 14:20:22 -0700132 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900133 public void testStackCleanupOnClearingTask() {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700134 mActivity.setTask(null);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700135 verify(mStack, times(1)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700136 }
137
138 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900139 public void testStackCleanupOnActivityRemoval() {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700140 mTask.removeActivity(mActivity);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700141 verify(mStack, times(1)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700142 }
143
144 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900145 public void testStackCleanupOnTaskRemoval() {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700146 mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING);
Bryce Lee04ab3462017-04-10 15:06:33 -0700147 // Stack should be gone on task removal.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800148 assertNull(mService.mRootActivityContainer.getStack(mStack.mStackId));
Bryce Leeaf691c02017-03-20 14:20:22 -0700149 }
150
151 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900152 public void testNoCleanupMovingActivityInSameStack() {
Bryce Lee18d51592017-10-25 10:22:19 -0700153 final TaskRecord newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
154 .build();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700155 mActivity.reparent(newTask, 0, null /*reason*/);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700156 verify(mStack, times(0)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700157 }
Andrii Kulian3a1619d2017-07-07 14:38:09 -0700158
Andreas Gampecea9e6d2018-02-22 18:06:44 -0800159 @Test
Bryce Lee0bd8d422018-01-09 09:45:57 -0800160 public void testPausingWhenVisibleFromStopped() throws Exception {
Andrii Kulian04470682018-01-10 15:32:31 -0800161 final MutableBoolean pauseFound = new MutableBoolean(false);
162 doAnswer((InvocationOnMock invocationOnMock) -> {
163 final ClientTransaction transaction = invocationOnMock.getArgument(0);
164 if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
165 pauseFound.value = true;
Bryce Lee0bd8d422018-01-09 09:45:57 -0800166 }
Andrii Kulian04470682018-01-10 15:32:31 -0800167 return null;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700168 }).when(mActivity.app.getThread()).scheduleTransaction(any());
Bryce Leed939cf02018-03-12 09:04:44 -0700169
Bryce Lee7ace3952018-02-16 14:34:32 -0800170 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
Bryce Lee0bd8d422018-01-09 09:45:57 -0800171
Andrii Kulian6b321512019-01-23 06:37:00 +0000172 // The activity is in the focused stack so it should be resumed.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700173 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Andrii Kulian6b321512019-01-23 06:37:00 +0000174 assertTrue(mActivity.isState(RESUMED));
Bryce Leed939cf02018-03-12 09:04:44 -0700175 assertFalse(pauseFound.value);
Andrii Kulian04470682018-01-10 15:32:31 -0800176
Andrii Kulian6b321512019-01-23 06:37:00 +0000177 // Make the activity non focusable
178 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
179 doReturn(false).when(mActivity).isFocusable();
Bryce Leed939cf02018-03-12 09:04:44 -0700180
Andrii Kulian6b321512019-01-23 06:37:00 +0000181 // If the activity is not focusable, it should move to paused.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700182 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee7ace3952018-02-16 14:34:32 -0800183 assertTrue(mActivity.isState(PAUSING));
Andrii Kulian04470682018-01-10 15:32:31 -0800184 assertTrue(pauseFound.value);
Bryce Lee052957b2018-01-16 11:13:30 -0800185
186 // Make sure that the state does not change for current non-stopping states.
Bryce Lee7ace3952018-02-16 14:34:32 -0800187 mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
Andrii Kulian6b321512019-01-23 06:37:00 +0000188 doReturn(true).when(mActivity).isFocusable();
Bryce Lee052957b2018-01-16 11:13:30 -0800189
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700190 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee052957b2018-01-16 11:13:30 -0800191
Bryce Lee7ace3952018-02-16 14:34:32 -0800192 assertTrue(mActivity.isState(INITIALIZING));
Bryce Leea0fb8e02018-02-28 14:21:07 -0800193
194 // Make sure the state does not change if we are not the current top activity.
195 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
196
Bryce Leea0fb8e02018-02-28 14:21:07 -0800197 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
198 mStack.mTranslucentActivityWaiting = topActivity;
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700199 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Louis Changeadb22f2019-06-19 12:09:23 +0800200 assertTrue(mActivity.isState(STARTED));
201
202 mStack.mTranslucentActivityWaiting = null;
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700203 topActivity.setOccludesParent(false);
Louis Changeadb22f2019-06-19 12:09:23 +0800204 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
205 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
206 assertTrue(mActivity.isState(STARTED));
Bryce Lee0bd8d422018-01-09 09:45:57 -0800207 }
208
Riddle Hsu0a343c32018-12-21 00:40:48 +0800209 private void ensureActivityConfiguration() {
210 mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
211 }
212
Bryce Lee1533b2b2017-09-14 17:06:41 -0700213 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900214 public void testCanBeLaunchedOnDisplay() {
Riddle Hsu16567132018-08-16 21:37:47 +0800215 mService.mSupportsMultiWindow = true;
216 final ActivityRecord activity = new ActivityBuilder(mService).build();
Bryce Lee1533b2b2017-09-14 17:06:41 -0700217
Riddle Hsu16567132018-08-16 21:37:47 +0800218 // An activity can be launched on default display.
219 assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
220 // An activity cannot be launched on a non-existent display.
221 assertFalse(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY + 1));
Bryce Lee1533b2b2017-09-14 17:06:41 -0700222 }
223
chaviw82a0ba82018-03-15 14:26:29 -0700224 @Test
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800225 public void testRestartProcessIfVisible() {
226 doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800227 mActivity.visible = true;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700228 mActivity.setSavedState(null /* savedState */);
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800229 mActivity.setState(ActivityStack.ActivityState.RESUMED, "testRestart");
Riddle Hsuaec55442019-03-12 17:25:35 +0800230 prepareFixedAspectRatioUnresizableActivity();
231
Riddle Hsu04164182019-03-07 18:03:27 +0800232 final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
Riddle Hsu74826262019-04-17 14:57:42 +0800233 setupDisplayAndParentSize(600, 1200);
Riddle Hsu04164182019-03-07 18:03:27 +0800234 // The visible activity should recompute configuration according to the last parent bounds.
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800235 mService.restartActivityProcessIfVisible(mActivity.appToken);
236
237 assertEquals(ActivityStack.ActivityState.RESTARTING_PROCESS, mActivity.getState());
238 assertNotEquals(originalOverrideBounds, mActivity.getBounds());
239 }
240
241 @Test
chaviw82a0ba82018-03-15 14:26:29 -0700242 public void testsApplyOptionsLocked() {
243 ActivityOptions activityOptions = ActivityOptions.makeBasic();
244
245 // Set and apply options for ActivityRecord. Pending options should be cleared
246 mActivity.updateOptionsLocked(activityOptions);
247 mActivity.applyOptionsLocked();
248 assertNull(mActivity.pendingOptions);
249
250 // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
251 // Pending options should be cleared for both ActivityRecords
252 ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
253 activity2.updateOptionsLocked(activityOptions);
254 mActivity.updateOptionsLocked(activityOptions);
255 mActivity.applyOptionsLocked();
256 assertNull(mActivity.pendingOptions);
257 assertNull(activity2.pendingOptions);
258
259 // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
260 // Pending options should be cleared for only ActivityRecord that was applied
261 TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
262 activity2 = new ActivityBuilder(mService).setTask(task2).build();
263 activity2.updateOptionsLocked(activityOptions);
264 mActivity.updateOptionsLocked(activityOptions);
265 mActivity.applyOptionsLocked();
266 assertNull(mActivity.pendingOptions);
267 assertNotNull(activity2.pendingOptions);
268 }
Garfield Tan0443b372019-01-04 15:00:13 -0800269
270 @Test
271 public void testNewOverrideConfigurationIncrementsSeq() {
272 final Configuration newConfig = new Configuration();
273
274 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
275 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
276 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
277 }
278
279 @Test
280 public void testNewParentConfigurationIncrementsSeq() {
281 final Configuration newConfig = new Configuration(
282 mTask.getRequestedOverrideConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700283 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
284 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
Garfield Tan0443b372019-01-04 15:00:13 -0800285
286 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
287 mTask.onRequestedOverrideConfigurationChanged(newConfig);
288 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
289 }
290
291 @Test
292 public void testNotifiesSeqIncrementToAppToken() {
293 final Configuration appWindowTokenRequestedOrientation = mock(Configuration.class);
294 mActivity.mAppWindowToken = mock(AppWindowToken.class);
295 doReturn(appWindowTokenRequestedOrientation).when(mActivity.mAppWindowToken)
296 .getRequestedOverrideConfiguration();
297
298 final Configuration newConfig = new Configuration();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700299 newConfig.orientation = ORIENTATION_PORTRAIT;
Garfield Tan0443b372019-01-04 15:00:13 -0800300
301 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
302 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
303 assertEquals(prevSeq + 1, appWindowTokenRequestedOrientation.seq);
304 verify(mActivity.mAppWindowToken).onMergedOverrideConfigurationChanged();
305 }
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800306
307 @Test
308 public void testSetsRelaunchReason_NotDragResizing() {
309 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
310
311 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
312 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
313 mActivity.getConfiguration()));
314
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700315 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800316 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700317 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
318 ? ORIENTATION_LANDSCAPE
319 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800320 mTask.onRequestedOverrideConfigurationChanged(newConfig);
321
322 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
323
Riddle Hsu0a343c32018-12-21 00:40:48 +0800324 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800325
326 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
327 mActivity.mRelaunchReason);
328 }
329
330 @Test
331 public void testSetsRelaunchReason_DragResizing() {
332 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
333
334 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
335 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
336 mActivity.getConfiguration()));
337
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700338 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800339 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700340 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
341 ? ORIENTATION_LANDSCAPE
342 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800343 mTask.onRequestedOverrideConfigurationChanged(newConfig);
344
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700345 doReturn(true).when(mTask.mTask).isDragResizing();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800346
347 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
348
Riddle Hsu0a343c32018-12-21 00:40:48 +0800349 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800350
351 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
352 mActivity.mRelaunchReason);
353 }
354
355 @Test
356 public void testSetsRelaunchReason_NonResizeConfigChanges() {
357 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
358
359 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
360 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
361 mActivity.getConfiguration()));
362
363 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
364 final Configuration newConfig = new Configuration(mTask.getConfiguration());
365 newConfig.fontScale = 5;
366 mTask.onRequestedOverrideConfigurationChanged(newConfig);
367
368 mActivity.mRelaunchReason =
369 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
370
Riddle Hsu0a343c32018-12-21 00:40:48 +0800371 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800372
373 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
374 mActivity.mRelaunchReason);
375 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800376
377 @Test
378 public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700379 mActivity = new ActivityBuilder(mService)
380 .setTask(mTask)
381 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
382 .build();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800383 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
384
Garfield Tan36a69ad2019-01-16 17:08:23 -0800385 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
386 mActivity.getConfiguration()));
387
Garfield Tan36a69ad2019-01-16 17:08:23 -0800388 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700389 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
390 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
391 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
392 newConfig.orientation = ORIENTATION_LANDSCAPE;
393 newConfig.screenWidthDp = longSide;
394 newConfig.screenHeightDp = shortSide;
395 } else {
396 newConfig.orientation = ORIENTATION_PORTRAIT;
397 newConfig.screenWidthDp = shortSide;
398 newConfig.screenHeightDp = longSide;
399 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800400
401 // Mimic the behavior that display doesn't handle app's requested orientation.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700402 final DisplayContent dc = mTask.mTask.getDisplayContent();
403 doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
404 doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800405
406 final int requestedOrientation;
407 switch (newConfig.orientation) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700408 case ORIENTATION_LANDSCAPE:
409 requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE;
Garfield Tan36a69ad2019-01-16 17:08:23 -0800410 break;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700411 case ORIENTATION_PORTRAIT:
Garfield Tan36a69ad2019-01-16 17:08:23 -0800412 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
413 break;
414 default:
415 throw new IllegalStateException("Orientation in new config should be either"
416 + "landscape or portrait.");
417 }
418 mActivity.setRequestedOrientation(requestedOrientation);
419
420 final ActivityConfigurationChangeItem expected =
421 ActivityConfigurationChangeItem.obtain(newConfig);
422 verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
423 eq(mActivity.appToken), eq(expected));
424 }
Andrii Kulianf2195362019-01-31 18:20:11 -0800425
426 @Test
427 public void testShouldMakeActive_deferredResume() {
428 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
429
430 mSupervisor.beginDeferResume();
431 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
432
433 mSupervisor.endDeferResume();
434 assertEquals(true, mActivity.shouldMakeActive(null /* activeActivity */));
435 }
Garfield Tan40263302019-02-01 15:27:35 -0800436
437 @Test
Andrii Kulian0c869cc2019-02-06 19:50:32 -0800438 public void testShouldResume_stackVisibility() {
439 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
440 spyOn(mStack);
441
442 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
443 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
444
445 doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
446 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
447
448 doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
449 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
450 }
451
452 @Test
Garfield Tan40263302019-02-01 15:27:35 -0800453 public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700454 mActivity = new ActivityBuilder(mService)
455 .setTask(mTask)
456 .setLaunchTaskBehind(true)
457 .setConfigChanges(CONFIG_ORIENTATION)
458 .build();
Garfield Tan40263302019-02-01 15:27:35 -0800459 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
460
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700461 final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
Garfield Tan40263302019-02-01 15:27:35 -0800462 try {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700463 doReturn(false).when(stack).isStackTranslucent(any());
Garfield Tan40263302019-02-01 15:27:35 -0800464 assertFalse(mStack.shouldBeVisible(null /* starting */));
465
Garfield Tan40263302019-02-01 15:27:35 -0800466 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
467 mActivity.getConfiguration()));
468
Garfield Tan40263302019-02-01 15:27:35 -0800469 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700470 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
471 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
472 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
473 newConfig.orientation = ORIENTATION_LANDSCAPE;
474 newConfig.screenWidthDp = longSide;
475 newConfig.screenHeightDp = shortSide;
476 } else {
477 newConfig.orientation = ORIENTATION_PORTRAIT;
478 newConfig.screenWidthDp = shortSide;
479 newConfig.screenHeightDp = longSide;
480 }
Garfield Tan40263302019-02-01 15:27:35 -0800481
482 mTask.onConfigurationChanged(newConfig);
483
484 mActivity.ensureActivityConfiguration(0 /* globalChanges */,
485 false /* preserveWindow */, true /* ignoreStopState */);
486
487 final ActivityConfigurationChangeItem expected =
488 ActivityConfigurationChangeItem.obtain(newConfig);
489 verify(mService.getLifecycleManager()).scheduleTransaction(
490 eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
491 } finally {
492 stack.getDisplay().removeChild(stack);
493 }
494 }
Riddle Hsu0a343c32018-12-21 00:40:48 +0800495
496 @Test
Louis Chang3d119a92019-04-22 10:45:37 +0800497 public void testShouldPauseWhenMakeClientVisible() {
498 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700499 topActivity.setOccludesParent(false);
Louis Chang3d119a92019-04-22 10:45:37 +0800500 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
501 mActivity.makeClientVisible();
Louis Changeadb22f2019-06-19 12:09:23 +0800502 assertEquals(STARTED, mActivity.getState());
Louis Chang3d119a92019-04-22 10:45:37 +0800503 }
504
505 @Test
Riddle Hsu04164182019-03-07 18:03:27 +0800506 public void testSizeCompatMode_FixedAspectRatioBoundsWithDecor() {
Riddle Hsu74826262019-04-17 14:57:42 +0800507 setupDisplayContentForCompatDisplayInsets();
Riddle Hsu04164182019-03-07 18:03:27 +0800508 final int decorHeight = 200; // e.g. The device has cutout.
Riddle Hsu74826262019-04-17 14:57:42 +0800509 final DisplayPolicy policy = setupDisplayAndParentSize(600, 800).getDisplayPolicy();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700510 spyOn(policy);
Riddle Hsu74826262019-04-17 14:57:42 +0800511 doAnswer(invocationOnMock -> {
512 final int rotation = invocationOnMock.<Integer>getArgument(0);
513 final Rect insets = invocationOnMock.<Rect>getArgument(4);
514 if (rotation == ROTATION_0) {
515 insets.top = decorHeight;
516 } else if (rotation == ROTATION_90) {
517 insets.left = decorHeight;
518 }
519 return null;
520 }).when(policy).getNonDecorInsetsLw(anyInt() /* rotation */, anyInt() /* width */,
521 anyInt() /* height */, any() /* displayCutout */, any() /* outInsets */);
522
Riddle Hsu04164182019-03-07 18:03:27 +0800523 doReturn(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
524 .when(mActivity.mAppWindowToken).getOrientationIgnoreVisibility();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700525 mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
Riddle Hsu9ad1785102019-03-26 00:26:54 +0800526 mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
Riddle Hsu04164182019-03-07 18:03:27 +0800527 ensureActivityConfiguration();
Riddle Hsu9ad1785102019-03-26 00:26:54 +0800528 // The parent configuration doesn't change since the first resolved configuration, so the
529 // activity shouldn't be in the size compatibility mode.
530 assertFalse(mActivity.inSizeCompatMode());
Riddle Hsu04164182019-03-07 18:03:27 +0800531
532 final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
533 // Ensure the app bounds keep the declared aspect ratio.
534 assertEquals(appBounds.width(), appBounds.height());
535 // The decor height should be a part of the effective bounds.
536 assertEquals(mActivity.getBounds().height(), appBounds.height() + decorHeight);
537
Riddle Hsu74826262019-04-17 14:57:42 +0800538 mTask.getConfiguration().windowConfiguration.setRotation(ROTATION_90);
Riddle Hsu04164182019-03-07 18:03:27 +0800539 mActivity.onConfigurationChanged(mTask.getConfiguration());
540 // After changing orientation, the aspect ratio should be the same.
541 assertEquals(appBounds.width(), appBounds.height());
542 // The decor height will be included in width.
543 assertEquals(mActivity.getBounds().width(), appBounds.width() + decorHeight);
544 }
545
546 @Test
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800547 public void testSizeCompatMode_FixedScreenConfigurationWhenMovingToDisplay() {
Riddle Hsu0a343c32018-12-21 00:40:48 +0800548 // Initialize different bounds on a new display.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700549 final Rect newDisplayBounds = new Rect(0, 0, 1000, 2000);
550 DisplayInfo info = new DisplayInfo();
551 mService.mContext.getDisplay().getDisplayInfo(info);
552 info.logicalWidth = newDisplayBounds.width();
553 info.logicalHeight = newDisplayBounds.height();
554 info.logicalDensityDpi = 300;
555
556 final ActivityDisplay newDisplay =
557 addNewActivityDisplayAt(info, ActivityDisplay.POSITION_TOP);
Riddle Hsu0a343c32018-12-21 00:40:48 +0800558
Evan Rosky55729532019-08-09 20:01:00 -0700559 final Configuration c =
560 new Configuration(mStack.getDisplay().getRequestedOverrideConfiguration());
561 c.densityDpi = 200;
562 mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700563 mActivity = new ActivityBuilder(mService)
564 .setTask(mTask)
565 .setResizeMode(RESIZE_MODE_UNRESIZEABLE)
566 .setMaxAspectRatio(1.5f)
567 .build();
Evan Rosky55729532019-08-09 20:01:00 -0700568 mActivity.visible = true;
Riddle Hsuaec55442019-03-12 17:25:35 +0800569
Riddle Hsu0a343c32018-12-21 00:40:48 +0800570 final Rect originalBounds = new Rect(mActivity.getBounds());
571 final int originalDpi = mActivity.getConfiguration().densityDpi;
572
573 // Move the non-resizable activity to the new display.
574 mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */);
Riddle Hsu0a343c32018-12-21 00:40:48 +0800575
576 assertEquals(originalBounds, mActivity.getBounds());
577 assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
Riddle Hsuaec55442019-03-12 17:25:35 +0800578 assertTrue(mActivity.inSizeCompatMode());
Riddle Hsu0a343c32018-12-21 00:40:48 +0800579 }
580
581 @Test
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800582 public void testSizeCompatMode_FixedScreenBoundsWhenDisplaySizeChanged() {
Riddle Hsu74826262019-04-17 14:57:42 +0800583 setupDisplayContentForCompatDisplayInsets();
Riddle Hsu0a343c32018-12-21 00:40:48 +0800584 when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
Riddle Hsuaec55442019-03-12 17:25:35 +0800585 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Riddle Hsu0a343c32018-12-21 00:40:48 +0800586 mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700587 mTask.getConfiguration().orientation = ORIENTATION_PORTRAIT;
Riddle Hsuaec55442019-03-12 17:25:35 +0800588 mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700589 mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
Riddle Hsu0a343c32018-12-21 00:40:48 +0800590 ensureActivityConfiguration();
591 final Rect originalBounds = new Rect(mActivity.getBounds());
592
593 // Change the size of current display.
Riddle Hsu74826262019-04-17 14:57:42 +0800594 setupDisplayAndParentSize(1000, 2000);
Riddle Hsu0a343c32018-12-21 00:40:48 +0800595 ensureActivityConfiguration();
596
597 assertEquals(originalBounds, mActivity.getBounds());
Riddle Hsuaec55442019-03-12 17:25:35 +0800598 assertTrue(mActivity.inSizeCompatMode());
Riddle Hsu0a343c32018-12-21 00:40:48 +0800599 }
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800600
601 @Test
602 public void testSizeCompatMode_FixedScreenLayoutSizeBits() {
603 final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO
604 | Configuration.SCREENLAYOUT_SIZE_NORMAL;
Evan Rosky55729532019-08-09 20:01:00 -0700605 mTask.getRequestedOverrideConfiguration().screenLayout = fixedScreenLayout
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800606 | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR;
Riddle Hsuaec55442019-03-12 17:25:35 +0800607 prepareFixedAspectRatioUnresizableActivity();
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800608
609 // The initial configuration should inherit from parent.
610 assertEquals(mTask.getConfiguration().screenLayout,
611 mActivity.getConfiguration().screenLayout);
612
613 mTask.getConfiguration().screenLayout = Configuration.SCREENLAYOUT_LAYOUTDIR_RTL
614 | Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_LARGE;
615 mActivity.onConfigurationChanged(mTask.getConfiguration());
616
617 // The size and aspect ratio bits don't change, but the layout direction should be updated.
618 assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_RTL,
619 mActivity.getConfiguration().screenLayout);
620 }
Riddle Hsuaec55442019-03-12 17:25:35 +0800621
622 @Test
623 public void testSizeCompatMode_ResetNonVisibleActivity() {
624 final ActivityDisplay display = mStack.getDisplay();
625 spyOn(display);
626
627 prepareFixedAspectRatioUnresizableActivity();
628 mActivity.setState(STOPPED, "testSizeCompatMode");
629 mActivity.visible = false;
630 mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
631 // Make the parent bounds to be different so the activity is in size compatibility mode.
632 mTask.getWindowConfiguration().setAppBounds(new Rect(0, 0, 600, 1200));
633
634 // Simulate the display changes orientation.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700635 doReturn(ActivityInfo.CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION
Riddle Hsuaec55442019-03-12 17:25:35 +0800636 | ActivityInfo.CONFIG_WINDOW_CONFIGURATION)
637 .when(display).getLastOverrideConfigurationChanges();
638 mActivity.onConfigurationChanged(mTask.getConfiguration());
639 // The override configuration should not change so it is still in size compatibility mode.
640 assertTrue(mActivity.inSizeCompatMode());
641
642 // Simulate the display changes density.
643 doReturn(ActivityInfo.CONFIG_DENSITY).when(display).getLastOverrideConfigurationChanges();
644 mService.mAmInternal = mock(ActivityManagerInternal.class);
645 mActivity.onConfigurationChanged(mTask.getConfiguration());
646 // The override configuration should be reset and the activity's process will be killed.
647 assertFalse(mActivity.inSizeCompatMode());
648 verify(mActivity).restartProcessIfVisible();
Riddle Hsu2da2d032019-08-28 21:08:58 +0800649 mLockRule.runWithScissors(mService.mH, () -> { }, TimeUnit.SECONDS.toMillis(3));
Riddle Hsuaec55442019-03-12 17:25:35 +0800650 verify(mService.mAmInternal).killProcess(
651 eq(mActivity.app.mName), eq(mActivity.app.mUid), anyString());
652 }
653
Jorim Jaggi346702a2019-05-08 17:49:33 +0200654 @Test
655 public void testTakeOptions() {
656 ActivityOptions opts = ActivityOptions.makeRemoteAnimation(
657 new RemoteAnimationAdapter(new Stub() {
658
659 @Override
660 public void onAnimationStart(RemoteAnimationTarget[] apps,
Winson Chungd5852192019-09-06 17:20:28 -0700661 RemoteAnimationTarget[] wallpapers,
Jorim Jaggi346702a2019-05-08 17:49:33 +0200662 IRemoteAnimationFinishedCallback finishedCallback) {
663
664 }
665
666 @Override
667 public void onAnimationCancelled() {
668
669 }
670 }, 0, 0));
671 mActivity.updateOptionsLocked(opts);
672 assertNotNull(mActivity.takeOptionsLocked(true /* fromClient */));
673 assertNotNull(mActivity.pendingOptions);
674
675 mActivity.updateOptionsLocked(ActivityOptions.makeBasic());
676 assertNotNull(mActivity.takeOptionsLocked(false /* fromClient */));
677 assertNull(mActivity.pendingOptions);
678 }
679
Louis Chang6a9be162019-07-15 10:41:32 +0800680 @Test
681 public void testCanLaunchHomeActivityFromChooser() {
682 ComponentName chooserComponent = ComponentName.unflattenFromString(
683 Resources.getSystem().getString(R.string.config_chooserActivity));
684 ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
685 chooserComponent).build();
686 assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
687 }
688
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700689 /**
690 * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and
691 * that it is cleared after activity is resumed.
692 */
693 @Test
694 public void testHasSavedState() {
695 assertTrue(mActivity.hasSavedState());
696
697 ActivityRecord.activityResumedLocked(mActivity.appToken);
698 assertFalse(mActivity.hasSavedState());
699 assertNull(mActivity.getSavedState());
700 }
701
702 /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */
703 @Test
704 public void testUpdateSavedState() {
705 mActivity.setSavedState(null /* savedState */);
706 assertFalse(mActivity.hasSavedState());
707 assertNull(mActivity.getSavedState());
708
709 final Bundle savedState = new Bundle();
710 savedState.putString("test", "string");
711 mActivity.setSavedState(savedState);
712 assertTrue(mActivity.hasSavedState());
713 assertEquals(savedState, mActivity.getSavedState());
714 }
715
716 /** Verify the correct updates of saved state when activity client reports stop. */
717 @Test
718 public void testUpdateSavedState_activityStopped() {
719 final Bundle savedState = new Bundle();
720 savedState.putString("test", "string");
721 final PersistableBundle persistentSavedState = new PersistableBundle();
722 persistentSavedState.putString("persist", "string");
723
724 // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored.
725 mActivity.setState(STOPPING, "test");
726 mActivity.activityStoppedLocked(savedState, persistentSavedState, "desc");
727 assertTrue(mActivity.hasSavedState());
728 assertEquals(savedState, mActivity.getSavedState());
729 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
730
731 // Sending 'null' for saved state can only happen due to timeout, so previously stored saved
732 // states should not be overridden.
733 mActivity.setState(STOPPING, "test");
734 mActivity.activityStoppedLocked(null /* savedState */, null /* persistentSavedState */,
735 "desc");
736 assertTrue(mActivity.hasSavedState());
737 assertEquals(savedState, mActivity.getSavedState());
738 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
739 }
740
Andrii Kulian057a6512019-07-15 16:15:51 -0700741 /**
742 * Verify that activity finish request is not performed if activity is finishing or is in
743 * incorrect state.
744 */
745 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700746 public void testFinishActivityIfPossible_cancelled() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700747 // Mark activity as finishing
748 mActivity.finishing = true;
749 assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700750 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700751 assertTrue(mActivity.finishing);
752 assertTrue(mActivity.isInStackLocked());
753
754 // Remove activity from task
755 mActivity.finishing = false;
756 mActivity.setTask(null);
757 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700758 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700759 assertFalse(mActivity.finishing);
760 }
761
762 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700763 * Verify that activity finish request is placed, but not executed immediately if activity is
Andrii Kulian057a6512019-07-15 16:15:51 -0700764 * not ready yet.
765 */
766 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700767 public void testFinishActivityIfPossible_requested() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700768 mActivity.finishing = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700769 assertEquals("Currently resumed activity must be prepared removal", FINISH_RESULT_REQUESTED,
770 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700771 assertTrue(mActivity.finishing);
772 assertTrue(mActivity.isInStackLocked());
773
774 // First request to finish activity must schedule a "destroy" request to the client.
775 // Activity must be removed from history after the client reports back or after timeout.
776 mActivity.finishing = false;
777 mActivity.setState(STOPPED, "test");
778 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700779 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700780 assertTrue(mActivity.finishing);
781 assertTrue(mActivity.isInStackLocked());
782 }
783
784 /**
785 * Verify that activity finish request removes activity immediately if it's ready.
786 */
787 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700788 public void testFinishActivityIfPossible_removed() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700789 // Prepare the activity record to be ready for immediate removal. It should be invisible and
790 // have no process. Otherwise, request to finish it will send a message to client first.
791 mActivity.setState(STOPPED, "test");
792 mActivity.visible = false;
793 mActivity.nowVisible = false;
794 // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
795 // this will cause NPE when updating task's process.
796 mActivity.app = null;
797 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REMOVED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700798 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700799 assertTrue(mActivity.finishing);
800 assertFalse(mActivity.isInStackLocked());
801 }
802
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700803 /**
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800804 * Verify that when finishing the top focused activity on top display, the stack order will be
805 * changed by adjusting focus.
806 */
807 @Test
808 public void testFinishActivityIfPossible_adjustStackOrder() {
809 // Prepare the stacks with order (top to bottom): mStack, stack1, stack2.
810 final ActivityStack stack1 = new StackBuilder(mRootActivityContainer).build();
811 mStack.moveToFront("test");
812 // The stack2 is needed here for moving back to simulate the
813 // {@link ActivityDisplay#mPreferredTopFocusableStack} is cleared, so
814 // {@link ActivityDisplay#getFocusedStack} will rely on the order of focusable-and-visible
815 // stacks. Then when mActivity is finishing, its stack will be invisible (no running
816 // activities in the stack) that is the key condition to verify.
817 final ActivityStack stack2 = new StackBuilder(mRootActivityContainer).build();
818 stack2.moveToBack("test", stack2.getChildAt(0));
819
820 assertTrue(mStack.isTopStackOnDisplay());
821
822 mActivity.setState(RESUMED, "test");
823 mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test",
Louis Chang7b03ad92019-08-21 12:32:33 +0800824 false /* oomAdj */);
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800825
826 assertTrue(stack1.isTopStackOnDisplay());
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;
879 mActivity.visible = true;
880 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;
895 mActivity.visible = true;
896 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();
913 mActivity.visible = false;
914 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 /**
956 * Verify that complete finish request for visible activity must be delayed before the next one
957 * becomes visible.
958 */
959 @Test
960 public void testCompleteFinishing_waitForNextVisible() {
961 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
962 topActivity.visible = true;
963 topActivity.nowVisible = true;
964 topActivity.finishing = true;
965 topActivity.setState(PAUSED, "true");
966 // Mark the bottom activity as not visible, so that we will wait for it before removing
967 // the top one.
968 mActivity.visible = false;
969 mActivity.nowVisible = false;
970 mActivity.setState(STOPPED, "test");
971
972 assertEquals("Activity must not be removed immediately - waiting for next visible",
973 topActivity, topActivity.completeFinishing("test"));
974 assertEquals("Activity must be stopped to make next one visible", STOPPING,
975 topActivity.getState());
976 assertTrue("Activity must be stopped to make next one visible",
977 topActivity.mStackSupervisor.mStoppingActivities.contains(topActivity));
978 verify(topActivity, never()).destroyIfPossible(anyString());
979 }
980
981 /**
982 * Verify that complete finish request for invisible activity must not be delayed.
983 */
984 @Test
985 public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
986 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
987 topActivity.visible = false;
988 topActivity.nowVisible = false;
989 topActivity.finishing = true;
990 topActivity.setState(PAUSED, "true");
991 // Mark the bottom activity as not visible, so that we would wait for it before removing
992 // the top one.
993 mActivity.visible = false;
994 mActivity.nowVisible = false;
995 mActivity.setState(STOPPED, "test");
996
997 topActivity.completeFinishing("test");
998
999 verify(topActivity).destroyIfPossible(anyString());
1000 }
1001
1002 /**
1003 * Verify that paused finishing activity will be added to finishing list and wait for next one
1004 * to idle.
1005 */
1006 @Test
1007 public void testCompleteFinishing_waitForIdle() {
1008 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
1009 topActivity.visible = true;
1010 topActivity.nowVisible = true;
1011 topActivity.finishing = true;
1012 topActivity.setState(PAUSED, "true");
1013 // Mark the bottom activity as already visible, so that there is no need to wait for it.
1014 mActivity.visible = true;
1015 mActivity.nowVisible = true;
1016 mActivity.setState(RESUMED, "test");
1017
1018 topActivity.completeFinishing("test");
1019
1020 verify(topActivity).addToFinishingAndWaitForIdle();
1021 }
1022
1023 /**
1024 * Verify that complete finish request for visible activity must not be delayed if the next one
1025 * is already visible and it's not the focused stack.
1026 */
1027 @Test
1028 public void testCompleteFinishing_noWaitForNextVisible_stopped() {
1029 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
1030 topActivity.visible = false;
1031 topActivity.nowVisible = false;
1032 topActivity.finishing = true;
1033 topActivity.setState(STOPPED, "true");
1034 // Mark the bottom activity as already visible, so that there is no need to wait for it.
1035 mActivity.visible = true;
1036 mActivity.nowVisible = true;
1037 mActivity.setState(RESUMED, "test");
1038
1039 topActivity.completeFinishing("test");
1040
1041 verify(topActivity).destroyIfPossible(anyString());
1042 }
1043
1044 /**
1045 * Verify that complete finish request for visible activity must not be delayed if the next one
1046 * is already visible and it's not the focused stack.
1047 */
1048 @Test
1049 public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
1050 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
1051 topActivity.visible = true;
1052 topActivity.nowVisible = true;
1053 topActivity.finishing = true;
1054 topActivity.setState(PAUSED, "true");
1055 // Mark the bottom activity as already visible, so that there is no need to wait for it.
1056 mActivity.visible = true;
1057 mActivity.nowVisible = true;
1058 mActivity.setState(RESUMED, "test");
1059
1060 // Add another stack to become focused and make the activity there visible. This way it
1061 // simulates finishing in non-focused stack in split-screen.
1062 final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
1063 stack.getChildAt(0).getChildAt(0).nowVisible = true;
lumark50b81542019-09-01 23:11:49 +08001064 stack.getChildAt(0).getChildAt(0).visible = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001065
1066 topActivity.completeFinishing("test");
1067
1068 verify(topActivity).destroyIfPossible(anyString());
1069 }
1070
1071 /**
1072 * Verify destroy activity request completes successfully.
1073 */
1074 @Test
1075 public void testDestroyIfPossible() {
1076 doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities();
1077 spyOn(mStack);
1078 mActivity.destroyIfPossible("test");
1079
1080 assertEquals(DESTROYING, mActivity.getState());
1081 assertTrue(mActivity.finishing);
Andrii Kulian79d67982019-08-19 11:56:16 -07001082 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001083 }
1084
1085 /**
1086 * Verify that complete finish request for visible activity must not destroy it immediately if
1087 * it is the last running activity on a display with a home stack. We must wait for home
1088 * activity to come up to avoid a black flash in this case.
1089 */
1090 @Test
1091 public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
1092 // Empty the home stack.
1093 final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
1094 for (TaskRecord t : homeStack.getAllTasks()) {
1095 homeStack.removeTask(t, "test", REMOVE_TASK_MODE_DESTROYING);
1096 }
1097 mActivity.finishing = true;
1098 doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities();
1099 spyOn(mStack);
1100
1101 // Try to destroy the last activity above the home stack.
1102 mActivity.destroyIfPossible("test");
1103
1104 // Verify that the activity was not actually destroyed, but waits for next one to come up
1105 // instead.
Andrii Kulian79d67982019-08-19 11:56:16 -07001106 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001107 assertEquals(FINISHING, mActivity.getState());
1108 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1109 }
1110
Andrii Kulian79d67982019-08-19 11:56:16 -07001111 /**
1112 * Test that the activity will be moved to destroying state and the message to destroy will be
1113 * sent to the client.
1114 */
1115 @Test
1116 public void testDestroyImmediately_hadApp_finishing() {
1117 mActivity.finishing = true;
1118 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1119
1120 assertEquals(DESTROYING, mActivity.getState());
1121 }
1122
1123 /**
1124 * Test that the activity will be moved to destroyed state immediately if it was not marked as
1125 * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
1126 */
1127 @Test
1128 public void testDestroyImmediately_hadApp_notFinishing() {
1129 mActivity.finishing = false;
1130 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1131
1132 assertEquals(DESTROYED, mActivity.getState());
1133 }
1134
1135 /**
1136 * Test that an activity with no process attached and that is marked as finishing will be
1137 * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
1138 */
1139 @Test
1140 public void testDestroyImmediately_noApp_finishing() {
1141 mActivity.app = null;
1142 mActivity.finishing = true;
1143 final TaskRecord task = mActivity.getTaskRecord();
1144
1145 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1146
1147 assertEquals(DESTROYED, mActivity.getState());
1148 assertNull(mActivity.getTaskRecord());
1149 assertEquals(0, task.getChildCount());
1150 }
1151
1152 /**
1153 * Test that an activity with no process attached and that is not marked as finishing will be
1154 * marked as DESTROYED but not removed from task.
1155 */
1156 @Test
1157 public void testDestroyImmediately_noApp_notFinishing() {
1158 mActivity.app = null;
1159 mActivity.finishing = false;
1160 final TaskRecord task = mActivity.getTaskRecord();
1161
1162 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1163
1164 assertEquals(DESTROYED, mActivity.getState());
1165 assertEquals(task, mActivity.getTaskRecord());
1166 assertEquals(1, task.getChildCount());
1167 }
1168
1169 /**
1170 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1171 */
1172 @Test
1173 public void testSafelyDestroy_nonDestroyable() {
1174 doReturn(false).when(mActivity).isDestroyable();
1175
1176 mActivity.safelyDestroy("test");
1177
1178 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1179 }
1180
1181 /**
1182 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1183 */
1184 @Test
1185 public void testSafelyDestroy_destroyable() {
1186 doReturn(true).when(mActivity).isDestroyable();
1187
1188 mActivity.safelyDestroy("test");
1189
1190 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1191 }
1192
1193 @Test
1194 public void testRemoveFromHistory() {
1195 final ActivityStack stack = mActivity.getActivityStack();
1196 final TaskRecord task = mActivity.getTaskRecord();
1197
1198 mActivity.removeFromHistory("test");
1199
1200 assertEquals(DESTROYED, mActivity.getState());
1201 assertNull(mActivity.app);
1202 assertNull(mActivity.getTaskRecord());
1203 assertEquals(0, task.getChildCount());
1204 assertNull(task.getStack());
1205 assertEquals(0, stack.getChildCount());
1206 }
1207
1208 /**
1209 * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is
1210 * not in destroying or destroyed state.
1211 */
1212 @Test(expected = IllegalStateException.class)
1213 public void testDestroyed_notDestroying() {
1214 mActivity.setState(STOPPED, "test");
1215 mActivity.destroyed("test");
1216 }
1217
1218 /**
1219 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying
1220 */
1221 @Test
1222 public void testDestroyed_destroying() {
1223 mActivity.setState(DESTROYING, "test");
1224 mActivity.destroyed("test");
1225
1226 verify(mActivity).removeFromHistory(anyString());
1227 }
1228
1229 /**
1230 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed.
1231 */
1232 @Test
1233 public void testDestroyed_destroyed() {
1234 mActivity.setState(DESTROYED, "test");
1235 mActivity.destroyed("test");
1236
1237 verify(mActivity).removeFromHistory(anyString());
1238 }
1239
Riddle Hsuaec55442019-03-12 17:25:35 +08001240 /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
1241 private void prepareFixedAspectRatioUnresizableActivity() {
Riddle Hsu74826262019-04-17 14:57:42 +08001242 setupDisplayContentForCompatDisplayInsets();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001243 mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
Riddle Hsuaec55442019-03-12 17:25:35 +08001244 mActivity.info.maxAspectRatio = 1.5f;
Evan Rosky55729532019-08-09 20:01:00 -07001245 mActivity.visible = true;
Riddle Hsuaec55442019-03-12 17:25:35 +08001246 ensureActivityConfiguration();
1247 }
Riddle Hsu74826262019-04-17 14:57:42 +08001248
1249 private void setupDisplayContentForCompatDisplayInsets() {
1250 final Rect displayBounds = mStack.getDisplay().getBounds();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001251 setupDisplayAndParentSize(displayBounds.width(), displayBounds.height());
Riddle Hsu74826262019-04-17 14:57:42 +08001252 }
1253
1254 private DisplayContent setupDisplayAndParentSize(int width, int height) {
Riddle Hsu74826262019-04-17 14:57:42 +08001255 final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
1256 displayContent.mBaseDisplayWidth = width;
1257 displayContent.mBaseDisplayHeight = height;
Evan Rosky55729532019-08-09 20:01:00 -07001258 final Configuration c =
1259 new Configuration(mStack.getDisplay().getRequestedOverrideConfiguration());
1260 c.windowConfiguration.setBounds(new Rect(0, 0, width, height));
1261 c.windowConfiguration.setAppBounds(0, 0, width, height);
1262 c.windowConfiguration.setRotation(ROTATION_0);
1263 mStack.getDisplay().onRequestedOverrideConfigurationChanged(c);
Riddle Hsu74826262019-04-17 14:57:42 +08001264 return displayContent;
1265 }
Bryce Leeaf691c02017-03-20 14:20:22 -07001266}