blob: 73b2f6b2dc370602a3d3ceb8c78124fd99961bf6 [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;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070021import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
Garfield Tan966c0412019-11-19 11:34:27 -080022import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070023import 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;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070027import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
Bryce Lee0bd8d422018-01-09 09:45:57 -080028
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090029import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
Andrii Kulian149d9ad32019-08-23 15:04:17 -070030import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090031import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
Garfield Tan0443b372019-01-04 15:00:13 -080032import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
Garfield Tan36a69ad2019-01-16 17:08:23 -080033import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070034import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080035import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070036import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
Garfield Tan0443b372019-01-04 15:00:13 -080037import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Andrii Kulian057a6512019-07-15 16:15:51 -070038import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
39import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
40import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
Andrii Kulian79d67982019-08-19 11:56:16 -070041import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070042import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
43import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
Wale Ogunwale59507092018-10-29 09:00:30 -070044import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070045import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
Wale Ogunwale59507092018-10-29 09:00:30 -070046import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
Andrii Kulian6b321512019-01-23 06:37:00 +000047import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
Louis Changeadb22f2019-06-19 12:09:23 +080048import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
Wale Ogunwale59507092018-10-29 09:00:30 -070049import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070050import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080051import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
52import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
53import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
Adrian Roose99bc052017-11-20 17:55:31 +010054
Louis Chang6a9be162019-07-15 10:41:32 +080055import static com.google.common.truth.Truth.assertThat;
56
Bryce Lee04ab3462017-04-10 15:06:33 -070057import static org.junit.Assert.assertEquals;
Bryce Lee1533b2b2017-09-14 17:06:41 -070058import static org.junit.Assert.assertFalse;
Yunfan Chen1ee84ea2018-11-13 16:03:37 -080059import static org.junit.Assert.assertNotNull;
Bryce Lee04ab3462017-04-10 15:06:33 -070060import static org.junit.Assert.assertNull;
Bryce Lee1533b2b2017-09-14 17:06:41 -070061import static org.junit.Assert.assertTrue;
Riddle Hsuaec55442019-03-12 17:25:35 +080062import static org.mockito.ArgumentMatchers.anyString;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070063import static org.mockito.Mockito.never;
chaviw82a0ba82018-03-15 14:26:29 -070064
65import android.app.ActivityOptions;
Garfield Tan966c0412019-11-19 11:34:27 -080066import android.app.WindowConfiguration;
Garfield Tan36a69ad2019-01-16 17:08:23 -080067import android.app.servertransaction.ActivityConfigurationChangeItem;
Bryce Lee0bd8d422018-01-09 09:45:57 -080068import android.app.servertransaction.ClientTransaction;
69import android.app.servertransaction.PauseActivityItem;
Louis Chang6a9be162019-07-15 10:41:32 +080070import android.content.ComponentName;
wilsonshiha96aac62019-11-18 14:53:34 +080071import android.content.Intent;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080072import android.content.pm.ActivityInfo;
Garfield Tan0443b372019-01-04 15:00:13 -080073import android.content.res.Configuration;
Louis Chang6a9be162019-07-15 10:41:32 +080074import android.content.res.Resources;
Garfield Tan966c0412019-11-19 11:34:27 -080075import android.graphics.Rect;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070076import android.os.Bundle;
77import android.os.PersistableBundle;
Bryce Leeaf691c02017-03-20 14:20:22 -070078import android.platform.test.annotations.Presubmit;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080079import android.util.MergedConfiguration;
Andrii Kulian04470682018-01-10 15:32:31 -080080import android.util.MutableBoolean;
Jorim Jaggi346702a2019-05-08 17:49:33 +020081import android.view.IRemoteAnimationFinishedCallback;
82import android.view.IRemoteAnimationRunner.Stub;
83import android.view.RemoteAnimationAdapter;
84import android.view.RemoteAnimationTarget;
Bryce Leeaf691c02017-03-20 14:20:22 -070085
Brett Chabota26eda92018-07-23 13:08:30 -070086import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070087
Louis Chang6a9be162019-07-15 10:41:32 +080088import com.android.internal.R;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070089import com.android.server.wm.ActivityStack.ActivityState;
Riddle Hsu74826262019-04-17 14:57:42 +080090
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070091import org.junit.Before;
Bryce Leeaf691c02017-03-20 14:20:22 -070092import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +080093import org.junit.runner.RunWith;
Andrii Kulian04470682018-01-10 15:32:31 -080094import org.mockito.invocation.InvocationOnMock;
Bryce Lee0bd8d422018-01-09 09:45:57 -080095
Bryce Leeaf691c02017-03-20 14:20:22 -070096/**
97 * Tests for the {@link ActivityRecord} class.
98 *
99 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900100 * atest WmTests:ActivityRecordTests
Bryce Leeaf691c02017-03-20 14:20:22 -0700101 */
102@MediumTest
Bryce Lee3115bdf2017-04-05 08:39:40 -0700103@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +0800104@RunWith(WindowTestRunner.class)
Bryce Leeaf691c02017-03-20 14:20:22 -0700105public class ActivityRecordTests extends ActivityTestsBase {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700106 private ActivityStack mStack;
Louis Changcdec0802019-11-11 11:45:07 +0800107 private Task mTask;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700108 private ActivityRecord mActivity;
109
110 @Before
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700111 public void setUp() throws Exception {
Louis Chang149d5c82019-12-30 09:47:39 +0800112 mStack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900113 mTask = mStack.getBottomMostTask();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800114 mActivity = mTask.getTopNonFinishingActivity();
Andrii Kulian6b321512019-01-23 06:37:00 +0000115
116 doReturn(false).when(mService).isBooting();
117 doReturn(true).when(mService).isBooted();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700118 }
119
Bryce Leeaf691c02017-03-20 14:20:22 -0700120 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900121 public void testStackCleanupOnClearingTask() {
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200122 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700123 verify(mStack, times(1)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700124 }
125
126 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900127 public void testStackCleanupOnActivityRemoval() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200128 mTask.removeChild(mActivity);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700129 verify(mStack, times(1)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700130 }
131
132 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900133 public void testStackCleanupOnTaskRemoval() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200134 mStack.removeChild(mTask, null /*reason*/);
Bryce Lee04ab3462017-04-10 15:06:33 -0700135 // Stack should be gone on task removal.
Louis Chang149d5c82019-12-30 09:47:39 +0800136 assertNull(mService.mRootWindowContainer.getStack(mStack.mStackId));
Bryce Leeaf691c02017-03-20 14:20:22 -0700137 }
138
139 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900140 public void testNoCleanupMovingActivityInSameStack() {
Louis Changcdec0802019-11-11 11:45:07 +0800141 final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
Bryce Lee18d51592017-10-25 10:22:19 -0700142 .build();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700143 mActivity.reparent(newTask, 0, null /*reason*/);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700144 verify(mStack, times(0)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700145 }
Andrii Kulian3a1619d2017-07-07 14:38:09 -0700146
Andreas Gampecea9e6d2018-02-22 18:06:44 -0800147 @Test
Bryce Lee0bd8d422018-01-09 09:45:57 -0800148 public void testPausingWhenVisibleFromStopped() throws Exception {
Andrii Kulian04470682018-01-10 15:32:31 -0800149 final MutableBoolean pauseFound = new MutableBoolean(false);
150 doAnswer((InvocationOnMock invocationOnMock) -> {
151 final ClientTransaction transaction = invocationOnMock.getArgument(0);
152 if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
153 pauseFound.value = true;
Bryce Lee0bd8d422018-01-09 09:45:57 -0800154 }
Andrii Kulian04470682018-01-10 15:32:31 -0800155 return null;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700156 }).when(mActivity.app.getThread()).scheduleTransaction(any());
Bryce Leed939cf02018-03-12 09:04:44 -0700157
Bryce Lee7ace3952018-02-16 14:34:32 -0800158 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
Bryce Lee0bd8d422018-01-09 09:45:57 -0800159
Andrii Kulian6b321512019-01-23 06:37:00 +0000160 // The activity is in the focused stack so it should be resumed.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700161 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Andrii Kulian6b321512019-01-23 06:37:00 +0000162 assertTrue(mActivity.isState(RESUMED));
Bryce Leed939cf02018-03-12 09:04:44 -0700163 assertFalse(pauseFound.value);
Andrii Kulian04470682018-01-10 15:32:31 -0800164
Andrii Kulian6b321512019-01-23 06:37:00 +0000165 // Make the activity non focusable
166 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
167 doReturn(false).when(mActivity).isFocusable();
Bryce Leed939cf02018-03-12 09:04:44 -0700168
Andrii Kulian6b321512019-01-23 06:37:00 +0000169 // If the activity is not focusable, it should move to paused.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700170 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee7ace3952018-02-16 14:34:32 -0800171 assertTrue(mActivity.isState(PAUSING));
Andrii Kulian04470682018-01-10 15:32:31 -0800172 assertTrue(pauseFound.value);
Bryce Lee052957b2018-01-16 11:13:30 -0800173
174 // Make sure that the state does not change for current non-stopping states.
Bryce Lee7ace3952018-02-16 14:34:32 -0800175 mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
Andrii Kulian6b321512019-01-23 06:37:00 +0000176 doReturn(true).when(mActivity).isFocusable();
Bryce Lee052957b2018-01-16 11:13:30 -0800177
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700178 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee052957b2018-01-16 11:13:30 -0800179
Bryce Lee7ace3952018-02-16 14:34:32 -0800180 assertTrue(mActivity.isState(INITIALIZING));
Bryce Leea0fb8e02018-02-28 14:21:07 -0800181
182 // Make sure the state does not change if we are not the current top activity.
183 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
184
Bryce Leea0fb8e02018-02-28 14:21:07 -0800185 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
186 mStack.mTranslucentActivityWaiting = topActivity;
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700187 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Louis Changeadb22f2019-06-19 12:09:23 +0800188 assertTrue(mActivity.isState(STARTED));
189
190 mStack.mTranslucentActivityWaiting = null;
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700191 topActivity.setOccludesParent(false);
Louis Changeadb22f2019-06-19 12:09:23 +0800192 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
193 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
194 assertTrue(mActivity.isState(STARTED));
Bryce Lee0bd8d422018-01-09 09:45:57 -0800195 }
196
Riddle Hsu0a343c32018-12-21 00:40:48 +0800197 private void ensureActivityConfiguration() {
198 mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
199 }
200
Bryce Lee1533b2b2017-09-14 17:06:41 -0700201 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900202 public void testCanBeLaunchedOnDisplay() {
Riddle Hsu16567132018-08-16 21:37:47 +0800203 mService.mSupportsMultiWindow = true;
204 final ActivityRecord activity = new ActivityBuilder(mService).build();
Bryce Lee1533b2b2017-09-14 17:06:41 -0700205
Riddle Hsu16567132018-08-16 21:37:47 +0800206 // An activity can be launched on default display.
207 assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
208 // An activity cannot be launched on a non-existent display.
Garfield Tan5423cf02019-12-06 17:02:38 -0800209 assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE));
Bryce Lee1533b2b2017-09-14 17:06:41 -0700210 }
211
chaviw82a0ba82018-03-15 14:26:29 -0700212 @Test
213 public void testsApplyOptionsLocked() {
214 ActivityOptions activityOptions = ActivityOptions.makeBasic();
215
216 // Set and apply options for ActivityRecord. Pending options should be cleared
217 mActivity.updateOptionsLocked(activityOptions);
218 mActivity.applyOptionsLocked();
219 assertNull(mActivity.pendingOptions);
220
221 // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
222 // Pending options should be cleared for both ActivityRecords
223 ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
224 activity2.updateOptionsLocked(activityOptions);
225 mActivity.updateOptionsLocked(activityOptions);
226 mActivity.applyOptionsLocked();
227 assertNull(mActivity.pendingOptions);
228 assertNull(activity2.pendingOptions);
229
230 // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
231 // Pending options should be cleared for only ActivityRecord that was applied
Louis Changcdec0802019-11-11 11:45:07 +0800232 Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
chaviw82a0ba82018-03-15 14:26:29 -0700233 activity2 = new ActivityBuilder(mService).setTask(task2).build();
234 activity2.updateOptionsLocked(activityOptions);
235 mActivity.updateOptionsLocked(activityOptions);
236 mActivity.applyOptionsLocked();
237 assertNull(mActivity.pendingOptions);
238 assertNotNull(activity2.pendingOptions);
239 }
Garfield Tan0443b372019-01-04 15:00:13 -0800240
241 @Test
242 public void testNewOverrideConfigurationIncrementsSeq() {
243 final Configuration newConfig = new Configuration();
244
245 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
246 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
247 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
248 }
249
250 @Test
251 public void testNewParentConfigurationIncrementsSeq() {
252 final Configuration newConfig = new Configuration(
253 mTask.getRequestedOverrideConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700254 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
255 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
Garfield Tan0443b372019-01-04 15:00:13 -0800256
257 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
258 mTask.onRequestedOverrideConfigurationChanged(newConfig);
259 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
260 }
261
262 @Test
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800263 public void testSetsRelaunchReason_NotDragResizing() {
264 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
265
266 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
267 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
268 mActivity.getConfiguration()));
269
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700270 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800271 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700272 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
273 ? ORIENTATION_LANDSCAPE
274 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800275 mTask.onRequestedOverrideConfigurationChanged(newConfig);
276
277 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
278
Riddle Hsu0a343c32018-12-21 00:40:48 +0800279 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800280
281 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
282 mActivity.mRelaunchReason);
283 }
284
285 @Test
286 public void testSetsRelaunchReason_DragResizing() {
287 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
288
289 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
290 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
291 mActivity.getConfiguration()));
292
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700293 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800294 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700295 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
296 ? ORIENTATION_LANDSCAPE
297 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800298 mTask.onRequestedOverrideConfigurationChanged(newConfig);
299
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200300 doReturn(true).when(mTask).isDragResizing();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800301
302 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
303
Riddle Hsu0a343c32018-12-21 00:40:48 +0800304 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800305
306 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
307 mActivity.mRelaunchReason);
308 }
309
310 @Test
311 public void testSetsRelaunchReason_NonResizeConfigChanges() {
312 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
313
314 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
315 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
316 mActivity.getConfiguration()));
317
318 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
319 final Configuration newConfig = new Configuration(mTask.getConfiguration());
320 newConfig.fontScale = 5;
321 mTask.onRequestedOverrideConfigurationChanged(newConfig);
322
323 mActivity.mRelaunchReason =
324 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
325
Riddle Hsu0a343c32018-12-21 00:40:48 +0800326 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800327
328 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
329 mActivity.mRelaunchReason);
330 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800331
332 @Test
333 public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700334 mActivity = new ActivityBuilder(mService)
335 .setTask(mTask)
336 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
337 .build();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800338 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
339
Garfield Tan36a69ad2019-01-16 17:08:23 -0800340 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
341 mActivity.getConfiguration()));
342
Garfield Tan36a69ad2019-01-16 17:08:23 -0800343 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700344 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
345 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
346 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
347 newConfig.orientation = ORIENTATION_LANDSCAPE;
348 newConfig.screenWidthDp = longSide;
349 newConfig.screenHeightDp = shortSide;
350 } else {
351 newConfig.orientation = ORIENTATION_PORTRAIT;
352 newConfig.screenWidthDp = shortSide;
353 newConfig.screenHeightDp = longSide;
354 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800355
356 // Mimic the behavior that display doesn't handle app's requested orientation.
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200357 final DisplayContent dc = mTask.getDisplayContent();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700358 doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
359 doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800360
361 final int requestedOrientation;
362 switch (newConfig.orientation) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700363 case ORIENTATION_LANDSCAPE:
364 requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE;
Garfield Tan36a69ad2019-01-16 17:08:23 -0800365 break;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700366 case ORIENTATION_PORTRAIT:
Garfield Tan36a69ad2019-01-16 17:08:23 -0800367 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
368 break;
369 default:
370 throw new IllegalStateException("Orientation in new config should be either"
371 + "landscape or portrait.");
372 }
373 mActivity.setRequestedOrientation(requestedOrientation);
374
375 final ActivityConfigurationChangeItem expected =
376 ActivityConfigurationChangeItem.obtain(newConfig);
377 verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
378 eq(mActivity.appToken), eq(expected));
379 }
Andrii Kulianf2195362019-01-31 18:20:11 -0800380
381 @Test
Garfield Tan966c0412019-11-19 11:34:27 -0800382 public void ignoreRequestedOrientationInFreeformWindows() {
383 mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
384 final Rect stableRect = new Rect();
385 mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
386 final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
387 final Rect bounds = new Rect(stableRect);
388 if (isScreenPortrait) {
389 // Landscape bounds
390 final int newHeight = stableRect.width() - 10;
391 bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
392 bounds.bottom = bounds.top + newHeight;
393 } else {
394 // Portrait bounds
395 final int newWidth = stableRect.height() - 10;
396 bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
397 bounds.right = bounds.left + newWidth;
398 }
399 mTask.setBounds(bounds);
400
401 // Requests orientation that's different from its bounds.
402 mActivity.setRequestedOrientation(
403 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
404
405 // Asserts it has orientation derived from bounds.
406 assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
407 mActivity.getConfiguration().orientation);
408 }
409
410 @Test
411 public void ignoreRequestedOrientationInSplitWindows() {
412 mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
413 final Rect stableRect = new Rect();
414 mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
415 final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
416 final Rect bounds = new Rect(stableRect);
417 if (isScreenPortrait) {
418 // Landscape bounds
419 final int newHeight = stableRect.width() - 10;
420 bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2;
421 bounds.bottom = bounds.top + newHeight;
422 } else {
423 // Portrait bounds
424 final int newWidth = stableRect.height() - 10;
425 bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2;
426 bounds.right = bounds.left + newWidth;
427 }
428 mTask.setBounds(bounds);
429
430 // Requests orientation that's different from its bounds.
431 mActivity.setRequestedOrientation(
432 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE);
433
434 // Asserts it has orientation derived from bounds.
435 assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT,
436 mActivity.getConfiguration().orientation);
437 }
438
439 @Test
Andrii Kulianf2195362019-01-31 18:20:11 -0800440 public void testShouldMakeActive_deferredResume() {
441 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
442
443 mSupervisor.beginDeferResume();
444 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
445
446 mSupervisor.endDeferResume();
447 assertEquals(true, mActivity.shouldMakeActive(null /* activeActivity */));
448 }
Garfield Tan40263302019-02-01 15:27:35 -0800449
450 @Test
Andrii Kulian0c869cc2019-02-06 19:50:32 -0800451 public void testShouldResume_stackVisibility() {
452 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
453 spyOn(mStack);
454
455 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
456 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
457
458 doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
459 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
460
461 doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
462 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
463 }
464
465 @Test
wilsonshiha96aac62019-11-18 14:53:34 +0800466 public void testShouldResumeOrPauseWithResults() {
467 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
468 spyOn(mStack);
469
470 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
471 mActivity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
472 topActivity.finishing = true;
473
474 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
475 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
476 assertEquals(false, mActivity.shouldPauseActivity(null /*activeActivity */));
477 }
478
479 @Test
Garfield Tan40263302019-02-01 15:27:35 -0800480 public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700481 mActivity = new ActivityBuilder(mService)
482 .setTask(mTask)
483 .setLaunchTaskBehind(true)
484 .setConfigChanges(CONFIG_ORIENTATION)
485 .build();
Garfield Tan40263302019-02-01 15:27:35 -0800486 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
487
Louis Chang149d5c82019-12-30 09:47:39 +0800488 final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
Garfield Tan40263302019-02-01 15:27:35 -0800489 try {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700490 doReturn(false).when(stack).isStackTranslucent(any());
Garfield Tan40263302019-02-01 15:27:35 -0800491 assertFalse(mStack.shouldBeVisible(null /* starting */));
492
Garfield Tan40263302019-02-01 15:27:35 -0800493 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
494 mActivity.getConfiguration()));
495
Garfield Tan40263302019-02-01 15:27:35 -0800496 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700497 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
498 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
499 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
500 newConfig.orientation = ORIENTATION_LANDSCAPE;
501 newConfig.screenWidthDp = longSide;
502 newConfig.screenHeightDp = shortSide;
503 } else {
504 newConfig.orientation = ORIENTATION_PORTRAIT;
505 newConfig.screenWidthDp = shortSide;
506 newConfig.screenHeightDp = longSide;
507 }
Garfield Tan40263302019-02-01 15:27:35 -0800508
509 mTask.onConfigurationChanged(newConfig);
510
511 mActivity.ensureActivityConfiguration(0 /* globalChanges */,
512 false /* preserveWindow */, true /* ignoreStopState */);
513
514 final ActivityConfigurationChangeItem expected =
515 ActivityConfigurationChangeItem.obtain(newConfig);
516 verify(mService.getLifecycleManager()).scheduleTransaction(
517 eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
518 } finally {
Louis Chang2453d062019-11-19 22:30:48 +0800519 stack.getDisplay().removeStack(stack);
Garfield Tan40263302019-02-01 15:27:35 -0800520 }
521 }
Riddle Hsu0a343c32018-12-21 00:40:48 +0800522
523 @Test
Louis Chang3d119a92019-04-22 10:45:37 +0800524 public void testShouldPauseWhenMakeClientVisible() {
525 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700526 topActivity.setOccludesParent(false);
Louis Chang3d119a92019-04-22 10:45:37 +0800527 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
528 mActivity.makeClientVisible();
Louis Changeadb22f2019-06-19 12:09:23 +0800529 assertEquals(STARTED, mActivity.getState());
Louis Chang3d119a92019-04-22 10:45:37 +0800530 }
531
532 @Test
Jorim Jaggi346702a2019-05-08 17:49:33 +0200533 public void testTakeOptions() {
534 ActivityOptions opts = ActivityOptions.makeRemoteAnimation(
535 new RemoteAnimationAdapter(new Stub() {
536
537 @Override
538 public void onAnimationStart(RemoteAnimationTarget[] apps,
Winson Chungd5852192019-09-06 17:20:28 -0700539 RemoteAnimationTarget[] wallpapers,
Jorim Jaggi346702a2019-05-08 17:49:33 +0200540 IRemoteAnimationFinishedCallback finishedCallback) {
541
542 }
543
544 @Override
545 public void onAnimationCancelled() {
546
547 }
548 }, 0, 0));
549 mActivity.updateOptionsLocked(opts);
550 assertNotNull(mActivity.takeOptionsLocked(true /* fromClient */));
551 assertNotNull(mActivity.pendingOptions);
552
553 mActivity.updateOptionsLocked(ActivityOptions.makeBasic());
554 assertNotNull(mActivity.takeOptionsLocked(false /* fromClient */));
555 assertNull(mActivity.pendingOptions);
556 }
557
Louis Chang6a9be162019-07-15 10:41:32 +0800558 @Test
559 public void testCanLaunchHomeActivityFromChooser() {
560 ComponentName chooserComponent = ComponentName.unflattenFromString(
561 Resources.getSystem().getString(R.string.config_chooserActivity));
562 ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
563 chooserComponent).build();
564 assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
565 }
566
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700567 /**
568 * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and
569 * that it is cleared after activity is resumed.
570 */
571 @Test
572 public void testHasSavedState() {
573 assertTrue(mActivity.hasSavedState());
574
575 ActivityRecord.activityResumedLocked(mActivity.appToken);
576 assertFalse(mActivity.hasSavedState());
577 assertNull(mActivity.getSavedState());
578 }
579
580 /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */
581 @Test
582 public void testUpdateSavedState() {
583 mActivity.setSavedState(null /* savedState */);
584 assertFalse(mActivity.hasSavedState());
585 assertNull(mActivity.getSavedState());
586
587 final Bundle savedState = new Bundle();
588 savedState.putString("test", "string");
589 mActivity.setSavedState(savedState);
590 assertTrue(mActivity.hasSavedState());
591 assertEquals(savedState, mActivity.getSavedState());
592 }
593
594 /** Verify the correct updates of saved state when activity client reports stop. */
595 @Test
596 public void testUpdateSavedState_activityStopped() {
597 final Bundle savedState = new Bundle();
598 savedState.putString("test", "string");
599 final PersistableBundle persistentSavedState = new PersistableBundle();
600 persistentSavedState.putString("persist", "string");
601
602 // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored.
603 mActivity.setState(STOPPING, "test");
Wale Ogunwale196db712019-12-27 15:35:39 +0000604 mActivity.activityStopped(savedState, persistentSavedState, "desc");
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700605 assertTrue(mActivity.hasSavedState());
606 assertEquals(savedState, mActivity.getSavedState());
607 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
608
609 // Sending 'null' for saved state can only happen due to timeout, so previously stored saved
610 // states should not be overridden.
611 mActivity.setState(STOPPING, "test");
Wale Ogunwale196db712019-12-27 15:35:39 +0000612 mActivity.activityStopped(null /* savedState */, null /* persistentSavedState */,
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700613 "desc");
614 assertTrue(mActivity.hasSavedState());
615 assertEquals(savedState, mActivity.getSavedState());
616 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
617 }
618
Andrii Kulian057a6512019-07-15 16:15:51 -0700619 /**
620 * Verify that activity finish request is not performed if activity is finishing or is in
621 * incorrect state.
622 */
623 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700624 public void testFinishActivityIfPossible_cancelled() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700625 // Mark activity as finishing
626 mActivity.finishing = true;
627 assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700628 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700629 assertTrue(mActivity.finishing);
630 assertTrue(mActivity.isInStackLocked());
631
632 // Remove activity from task
633 mActivity.finishing = false;
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200634 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
Andrii Kulian057a6512019-07-15 16:15:51 -0700635 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700636 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700637 assertFalse(mActivity.finishing);
638 }
639
640 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700641 * Verify that activity finish request is placed, but not executed immediately if activity is
Andrii Kulian057a6512019-07-15 16:15:51 -0700642 * not ready yet.
643 */
644 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700645 public void testFinishActivityIfPossible_requested() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700646 mActivity.finishing = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700647 assertEquals("Currently resumed activity must be prepared removal", FINISH_RESULT_REQUESTED,
648 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700649 assertTrue(mActivity.finishing);
650 assertTrue(mActivity.isInStackLocked());
651
652 // First request to finish activity must schedule a "destroy" request to the client.
653 // Activity must be removed from history after the client reports back or after timeout.
654 mActivity.finishing = false;
655 mActivity.setState(STOPPED, "test");
656 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700657 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700658 assertTrue(mActivity.finishing);
659 assertTrue(mActivity.isInStackLocked());
660 }
661
662 /**
663 * Verify that activity finish request removes activity immediately if it's ready.
664 */
665 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700666 public void testFinishActivityIfPossible_removed() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700667 // Prepare the activity record to be ready for immediate removal. It should be invisible and
668 // have no process. Otherwise, request to finish it will send a message to client first.
669 mActivity.setState(STOPPED, "test");
Issei Suzuki1669ea42019-11-06 14:20:59 +0100670 mActivity.mVisibleRequested = false;
Andrii Kulian057a6512019-07-15 16:15:51 -0700671 mActivity.nowVisible = false;
672 // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
673 // this will cause NPE when updating task's process.
674 mActivity.app = null;
wilsonshih4c9824a2019-10-25 18:47:50 +0800675
676 // Put a visible activity on top, so the finishing activity doesn't have to wait until the
677 // next activity reports idle to destroy it.
678 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100679 topActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +0800680 topActivity.nowVisible = true;
681 topActivity.setState(RESUMED, "test");
682
Andrii Kulian057a6512019-07-15 16:15:51 -0700683 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REMOVED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700684 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700685 assertTrue(mActivity.finishing);
686 assertFalse(mActivity.isInStackLocked());
687 }
688
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700689 /**
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800690 * Verify that when finishing the top focused activity on top display, the stack order will be
691 * changed by adjusting focus.
692 */
693 @Test
694 public void testFinishActivityIfPossible_adjustStackOrder() {
695 // Prepare the stacks with order (top to bottom): mStack, stack1, stack2.
Louis Chang149d5c82019-12-30 09:47:39 +0800696 final ActivityStack stack1 = new StackBuilder(mRootWindowContainer).build();
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800697 mStack.moveToFront("test");
698 // The stack2 is needed here for moving back to simulate the
Louis Chang677921f2019-12-06 16:44:24 +0800699 // {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so
700 // {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800701 // stacks. Then when mActivity is finishing, its stack will be invisible (no running
702 // activities in the stack) that is the key condition to verify.
Louis Chang149d5c82019-12-30 09:47:39 +0800703 final ActivityStack stack2 = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900704 stack2.moveToBack("test", stack2.getBottomMostTask());
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800705
706 assertTrue(mStack.isTopStackOnDisplay());
707
708 mActivity.setState(RESUMED, "test");
709 mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test",
Louis Chang7b03ad92019-08-21 12:32:33 +0800710 false /* oomAdj */);
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800711
712 assertTrue(stack1.isTopStackOnDisplay());
713 }
714
715 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700716 * Verify that resumed activity is paused due to finish request.
717 */
718 @Test
719 public void testFinishActivityIfPossible_resumedStartsPausing() {
720 mActivity.finishing = false;
721 mActivity.setState(RESUMED, "test");
722 assertEquals("Currently resumed activity must be paused before removal",
723 FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */));
724 assertEquals(PAUSING, mActivity.getState());
725 verify(mActivity).setVisibility(eq(false));
726 verify(mActivity.getDisplay().mDisplayContent)
727 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
728 }
729
730 /**
731 * Verify that finish request will be completed immediately for non-resumed activity.
732 */
733 @Test
734 public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() {
735 final ActivityState[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED};
736 for (ActivityState state : states) {
737 mActivity.finishing = false;
738 mActivity.setState(state, "test");
739 reset(mActivity);
740 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
741 mActivity.finishIfPossible("test", false /* oomAdj */));
742 verify(mActivity).completeFinishing(anyString());
743 }
744 }
745
746 /**
747 * Verify that finishing will not be completed in PAUSING state.
748 */
749 @Test
750 public void testFinishActivityIfPossible_pausing() {
751 mActivity.finishing = false;
752 mActivity.setState(PAUSING, "test");
753 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
754 mActivity.finishIfPossible("test", false /* oomAdj */));
755 verify(mActivity, never()).completeFinishing(anyString());
756 }
757
758 /**
759 * Verify that finish request for resumed activity will prepare an app transition but not
760 * execute it immediately.
761 */
762 @Test
763 public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() {
764 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100765 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700766 mActivity.setState(RESUMED, "test");
767 mActivity.finishIfPossible("test", false /* oomAdj */);
768
769 verify(mActivity).setVisibility(eq(false));
770 verify(mActivity.getDisplay().mDisplayContent)
771 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
772 verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition();
773 }
774
775 /**
776 * Verify that finish request for paused activity will prepare and execute an app transition.
777 */
778 @Test
779 public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() {
780 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100781 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700782 mActivity.setState(PAUSED, "test");
783 mActivity.finishIfPossible("test", false /* oomAdj */);
784
Andrii Kulian149d9ad32019-08-23 15:04:17 -0700785 verify(mActivity, atLeast(1)).setVisibility(eq(false));
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700786 verify(mActivity.getDisplay().mDisplayContent)
787 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
788 verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
789 }
790
791 /**
792 * Verify that finish request for non-visible activity will not prepare any transitions.
793 */
794 @Test
795 public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
796 // Put an activity on top of test activity to make it invisible and prevent us from
797 // accidentally resuming the topmost one again.
798 new ActivityBuilder(mService).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100799 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700800 mActivity.setState(STOPPED, "test");
801
802 mActivity.finishIfPossible("test", false /* oomAdj */);
803
804 verify(mActivity.getDisplay().mDisplayContent, never())
805 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
806 }
807
808 /**
809 * Verify that complete finish request for non-finishing activity is invalid.
810 */
811 @Test(expected = IllegalArgumentException.class)
812 public void testCompleteFinishing_failNotFinishing() {
813 mActivity.finishing = false;
814 mActivity.completeFinishing("test");
815 }
816
817 /**
818 * Verify that complete finish request for resumed activity is invalid.
819 */
820 @Test(expected = IllegalArgumentException.class)
821 public void testCompleteFinishing_failResumed() {
822 mActivity.setState(RESUMED, "test");
823 mActivity.completeFinishing("test");
824 }
825
826 /**
827 * Verify that finish request for pausing activity must be a no-op - activity will finish
828 * once it completes pausing.
829 */
830 @Test
831 public void testCompleteFinishing_pausing() {
832 mActivity.setState(PAUSING, "test");
833 mActivity.finishing = true;
834
835 assertEquals("Activity must not be removed immediately - waiting for paused",
836 mActivity, mActivity.completeFinishing("test"));
837 assertEquals(PAUSING, mActivity.getState());
838 verify(mActivity, never()).destroyIfPossible(anyString());
839 }
840
841 /**
Riddle Hsucf920232019-10-04 19:05:36 +0800842 * Verify that finish request won't change the state of next top activity if the current
843 * finishing activity doesn't need to be destroyed immediately. The case is usually like
844 * from {@link ActivityStack#completePauseLocked(boolean, ActivityRecord)} to
845 * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the
846 * responsibility to resume the next activity with updating the state.
847 */
848 @Test
849 public void testCompleteFinishing_keepStateOfNextInvisible() {
850 final ActivityRecord currentTop = mActivity;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100851 currentTop.mVisibleRequested = currentTop.nowVisible = true;
Riddle Hsucf920232019-10-04 19:05:36 +0800852
853 // Simulates that {@code currentTop} starts an existing activity from background (so its
854 // state is stopped) and the starting flow just goes to place it at top.
Louis Chang149d5c82019-12-30 09:47:39 +0800855 final ActivityStack nextStack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800856 final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity();
Riddle Hsucf920232019-10-04 19:05:36 +0800857 nextTop.setState(STOPPED, "test");
858
859 mStack.mPausingActivity = currentTop;
860 currentTop.finishing = true;
861 currentTop.setState(PAUSED, "test");
862 currentTop.completeFinishing("completePauseLocked");
863
864 // Current top becomes stopping because it is visible and the next is invisible.
865 assertEquals(STOPPING, currentTop.getState());
866 // The state of next activity shouldn't be changed.
867 assertEquals(STOPPED, nextTop.getState());
868 }
869
870 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700871 * Verify that complete finish request for visible activity must be delayed before the next one
872 * becomes visible.
873 */
874 @Test
875 public void testCompleteFinishing_waitForNextVisible() {
876 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100877 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700878 topActivity.nowVisible = true;
879 topActivity.finishing = true;
880 topActivity.setState(PAUSED, "true");
881 // Mark the bottom activity as not visible, so that we will wait for it before removing
882 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100883 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700884 mActivity.nowVisible = false;
885 mActivity.setState(STOPPED, "test");
886
887 assertEquals("Activity must not be removed immediately - waiting for next visible",
888 topActivity, topActivity.completeFinishing("test"));
889 assertEquals("Activity must be stopped to make next one visible", STOPPING,
890 topActivity.getState());
891 assertTrue("Activity must be stopped to make next one visible",
892 topActivity.mStackSupervisor.mStoppingActivities.contains(topActivity));
893 verify(topActivity, never()).destroyIfPossible(anyString());
894 }
895
896 /**
897 * Verify that complete finish request for invisible activity must not be delayed.
898 */
899 @Test
900 public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
901 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100902 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700903 topActivity.nowVisible = false;
904 topActivity.finishing = true;
Issei Suzukid0c14f32019-12-19 12:42:13 +0100905 topActivity.setState(STOPPED, "true");
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700906 // Mark the bottom activity as not visible, so that we would wait for it before removing
907 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100908 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700909 mActivity.nowVisible = false;
910 mActivity.setState(STOPPED, "test");
911
912 topActivity.completeFinishing("test");
913
914 verify(topActivity).destroyIfPossible(anyString());
915 }
916
917 /**
918 * Verify that paused finishing activity will be added to finishing list and wait for next one
919 * to idle.
920 */
921 @Test
922 public void testCompleteFinishing_waitForIdle() {
923 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100924 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700925 topActivity.nowVisible = true;
926 topActivity.finishing = true;
927 topActivity.setState(PAUSED, "true");
928 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100929 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700930 mActivity.nowVisible = true;
931 mActivity.setState(RESUMED, "test");
932
933 topActivity.completeFinishing("test");
934
935 verify(topActivity).addToFinishingAndWaitForIdle();
936 }
937
938 /**
939 * Verify that complete finish request for visible activity must not be delayed if the next one
940 * is already visible and it's not the focused stack.
941 */
942 @Test
943 public void testCompleteFinishing_noWaitForNextVisible_stopped() {
944 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100945 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700946 topActivity.nowVisible = false;
947 topActivity.finishing = true;
948 topActivity.setState(STOPPED, "true");
949 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100950 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700951 mActivity.nowVisible = true;
952 mActivity.setState(RESUMED, "test");
953
954 topActivity.completeFinishing("test");
955
956 verify(topActivity).destroyIfPossible(anyString());
957 }
958
959 /**
960 * Verify that complete finish request for visible activity must not be delayed if the next one
961 * is already visible and it's not the focused stack.
962 */
963 @Test
964 public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
965 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100966 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700967 topActivity.nowVisible = true;
968 topActivity.finishing = true;
969 topActivity.setState(PAUSED, "true");
970 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100971 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700972 mActivity.nowVisible = true;
973 mActivity.setState(RESUMED, "test");
974
975 // Add another stack to become focused and make the activity there visible. This way it
976 // simulates finishing in non-focused stack in split-screen.
Louis Chang149d5c82019-12-30 09:47:39 +0800977 final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800978 final ActivityRecord focusedActivity = stack.getTopMostActivity();
wilsonshih4c9824a2019-10-25 18:47:50 +0800979 focusedActivity.nowVisible = true;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100980 focusedActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +0800981 focusedActivity.setState(RESUMED, "test");
982 stack.mResumedActivity = focusedActivity;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700983
984 topActivity.completeFinishing("test");
985
986 verify(topActivity).destroyIfPossible(anyString());
987 }
988
989 /**
990 * Verify destroy activity request completes successfully.
991 */
992 @Test
993 public void testDestroyIfPossible() {
Louis Chang149d5c82019-12-30 09:47:39 +0800994 doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700995 spyOn(mStack);
996 mActivity.destroyIfPossible("test");
997
998 assertEquals(DESTROYING, mActivity.getState());
999 assertTrue(mActivity.finishing);
Andrii Kulian79d67982019-08-19 11:56:16 -07001000 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001001 }
1002
1003 /**
1004 * Verify that complete finish request for visible activity must not destroy it immediately if
1005 * it is the last running activity on a display with a home stack. We must wait for home
1006 * activity to come up to avoid a black flash in this case.
1007 */
1008 @Test
1009 public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
1010 // Empty the home stack.
1011 final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +09001012 homeStack.forAllTasks((t) -> { homeStack.removeChild(t, "test"); });
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001013 mActivity.finishing = true;
Louis Chang149d5c82019-12-30 09:47:39 +08001014 doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities();
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001015 spyOn(mStack);
1016
1017 // Try to destroy the last activity above the home stack.
1018 mActivity.destroyIfPossible("test");
1019
1020 // Verify that the activity was not actually destroyed, but waits for next one to come up
1021 // instead.
Andrii Kulian79d67982019-08-19 11:56:16 -07001022 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -07001023 assertEquals(FINISHING, mActivity.getState());
1024 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1025 }
1026
Andrii Kulian79d67982019-08-19 11:56:16 -07001027 /**
wilsonshih4c9824a2019-10-25 18:47:50 +08001028 * Verify that complete finish request for visible activity must resume next home stack before
1029 * destroying it immediately if it is the last running activity on a display with a home stack.
1030 * We must wait for home activity to come up to avoid a black flash in this case.
1031 */
1032 @Test
1033 public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
1034 // Empty the home stack.
1035 final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +09001036 homeStack.forAllTasks((t) -> { homeStack.removeChild(t, "test"); });
wilsonshih4c9824a2019-10-25 18:47:50 +08001037 mActivity.finishing = true;
1038 spyOn(mStack);
1039
1040 // Try to finish the last activity above the home stack.
1041 mActivity.completeFinishing("test");
1042
1043 // Verify that the activity is not destroyed immediately, but waits for next one to come up.
1044 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1045 assertEquals(FINISHING, mActivity.getState());
1046 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
1047 }
1048
1049 /**
Andrii Kulian79d67982019-08-19 11:56:16 -07001050 * Test that the activity will be moved to destroying state and the message to destroy will be
1051 * sent to the client.
1052 */
1053 @Test
1054 public void testDestroyImmediately_hadApp_finishing() {
1055 mActivity.finishing = true;
1056 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1057
1058 assertEquals(DESTROYING, mActivity.getState());
1059 }
1060
1061 /**
1062 * Test that the activity will be moved to destroyed state immediately if it was not marked as
1063 * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
1064 */
1065 @Test
1066 public void testDestroyImmediately_hadApp_notFinishing() {
1067 mActivity.finishing = false;
1068 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1069
1070 assertEquals(DESTROYED, mActivity.getState());
1071 }
1072
1073 /**
1074 * Test that an activity with no process attached and that is marked as finishing will be
1075 * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
1076 */
1077 @Test
1078 public void testDestroyImmediately_noApp_finishing() {
1079 mActivity.app = null;
1080 mActivity.finishing = true;
Louis Changcdec0802019-11-11 11:45:07 +08001081 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001082
1083 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1084
1085 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001086 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001087 assertEquals(0, task.getChildCount());
1088 }
1089
1090 /**
1091 * Test that an activity with no process attached and that is not marked as finishing will be
1092 * marked as DESTROYED but not removed from task.
1093 */
1094 @Test
1095 public void testDestroyImmediately_noApp_notFinishing() {
1096 mActivity.app = null;
1097 mActivity.finishing = false;
Louis Changcdec0802019-11-11 11:45:07 +08001098 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001099
1100 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1101
1102 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001103 assertEquals(task, mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001104 assertEquals(1, task.getChildCount());
1105 }
1106
1107 /**
1108 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1109 */
1110 @Test
1111 public void testSafelyDestroy_nonDestroyable() {
1112 doReturn(false).when(mActivity).isDestroyable();
1113
1114 mActivity.safelyDestroy("test");
1115
1116 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1117 }
1118
1119 /**
1120 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1121 */
1122 @Test
1123 public void testSafelyDestroy_destroyable() {
1124 doReturn(true).when(mActivity).isDestroyable();
1125
1126 mActivity.safelyDestroy("test");
1127
1128 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1129 }
1130
1131 @Test
1132 public void testRemoveFromHistory() {
1133 final ActivityStack stack = mActivity.getActivityStack();
Louis Changcdec0802019-11-11 11:45:07 +08001134 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001135
1136 mActivity.removeFromHistory("test");
1137
1138 assertEquals(DESTROYED, mActivity.getState());
1139 assertNull(mActivity.app);
Louis Changcdec0802019-11-11 11:45:07 +08001140 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001141 assertEquals(0, task.getChildCount());
1142 assertNull(task.getStack());
1143 assertEquals(0, stack.getChildCount());
1144 }
1145
1146 /**
1147 * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is
1148 * not in destroying or destroyed state.
1149 */
1150 @Test(expected = IllegalStateException.class)
1151 public void testDestroyed_notDestroying() {
1152 mActivity.setState(STOPPED, "test");
1153 mActivity.destroyed("test");
1154 }
1155
1156 /**
1157 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying
1158 */
1159 @Test
1160 public void testDestroyed_destroying() {
1161 mActivity.setState(DESTROYING, "test");
1162 mActivity.destroyed("test");
1163
1164 verify(mActivity).removeFromHistory(anyString());
1165 }
1166
1167 /**
1168 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed.
1169 */
1170 @Test
1171 public void testDestroyed_destroyed() {
1172 mActivity.setState(DESTROYED, "test");
1173 mActivity.destroyed("test");
1174
1175 verify(mActivity).removeFromHistory(anyString());
1176 }
Bryce Leeaf691c02017-03-20 14:20:22 -07001177}