blob: a2e423369fcd6a1fa19811deaaab60cc3e2a7389 [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;
22import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
23import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
Louis Chang6a9be162019-07-15 10:41:32 +080024import static android.os.Process.NOBODY_UID;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070025import static android.view.Display.DEFAULT_DISPLAY;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070026import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
Bryce Lee0bd8d422018-01-09 09:45:57 -080027
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090028import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
Andrii Kulian149d9ad32019-08-23 15:04:17 -070029import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090030import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
Garfield Tan0443b372019-01-04 15:00:13 -080031import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
Garfield Tan36a69ad2019-01-16 17:08:23 -080032import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070033import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080034import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070035import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
Garfield Tan0443b372019-01-04 15:00:13 -080036import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Andrii Kulian057a6512019-07-15 16:15:51 -070037import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED;
38import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
39import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED;
Andrii Kulian79d67982019-08-19 11:56:16 -070040import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070041import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
42import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
Wale Ogunwale59507092018-10-29 09:00:30 -070043import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070044import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
Wale Ogunwale59507092018-10-29 09:00:30 -070045import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
Andrii Kulian6b321512019-01-23 06:37:00 +000046import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
Louis Changeadb22f2019-06-19 12:09:23 +080047import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
Wale Ogunwale59507092018-10-29 09:00:30 -070048import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070049import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080050import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
51import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
52import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
Adrian Roose99bc052017-11-20 17:55:31 +010053
Louis Chang6a9be162019-07-15 10:41:32 +080054import static com.google.common.truth.Truth.assertThat;
55
Bryce Lee04ab3462017-04-10 15:06:33 -070056import static org.junit.Assert.assertEquals;
Bryce Lee1533b2b2017-09-14 17:06:41 -070057import static org.junit.Assert.assertFalse;
Yunfan Chen1ee84ea2018-11-13 16:03:37 -080058import static org.junit.Assert.assertNotNull;
Bryce Lee04ab3462017-04-10 15:06:33 -070059import static org.junit.Assert.assertNull;
Bryce Lee1533b2b2017-09-14 17:06:41 -070060import static org.junit.Assert.assertTrue;
Riddle Hsuaec55442019-03-12 17:25:35 +080061import static org.mockito.ArgumentMatchers.anyString;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070062import static org.mockito.Mockito.never;
chaviw82a0ba82018-03-15 14:26:29 -070063
64import android.app.ActivityOptions;
Garfield Tan36a69ad2019-01-16 17:08:23 -080065import android.app.servertransaction.ActivityConfigurationChangeItem;
Bryce Lee0bd8d422018-01-09 09:45:57 -080066import android.app.servertransaction.ClientTransaction;
67import android.app.servertransaction.PauseActivityItem;
Louis Chang6a9be162019-07-15 10:41:32 +080068import android.content.ComponentName;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080069import android.content.pm.ActivityInfo;
Garfield Tan0443b372019-01-04 15:00:13 -080070import android.content.res.Configuration;
Louis Chang6a9be162019-07-15 10:41:32 +080071import android.content.res.Resources;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070072import android.os.Bundle;
73import android.os.PersistableBundle;
Bryce Leeaf691c02017-03-20 14:20:22 -070074import android.platform.test.annotations.Presubmit;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080075import android.util.MergedConfiguration;
Andrii Kulian04470682018-01-10 15:32:31 -080076import android.util.MutableBoolean;
Jorim Jaggi346702a2019-05-08 17:49:33 +020077import android.view.IRemoteAnimationFinishedCallback;
78import android.view.IRemoteAnimationRunner.Stub;
79import android.view.RemoteAnimationAdapter;
80import android.view.RemoteAnimationTarget;
Bryce Leeaf691c02017-03-20 14:20:22 -070081
Brett Chabota26eda92018-07-23 13:08:30 -070082import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070083
Louis Chang6a9be162019-07-15 10:41:32 +080084import com.android.internal.R;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070085import com.android.server.wm.ActivityStack.ActivityState;
Riddle Hsu74826262019-04-17 14:57:42 +080086
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070087import org.junit.Before;
Bryce Leeaf691c02017-03-20 14:20:22 -070088import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +080089import org.junit.runner.RunWith;
Andrii Kulian04470682018-01-10 15:32:31 -080090import org.mockito.invocation.InvocationOnMock;
Bryce Lee0bd8d422018-01-09 09:45:57 -080091
Bryce Leeaf691c02017-03-20 14:20:22 -070092/**
93 * Tests for the {@link ActivityRecord} class.
94 *
95 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090096 * atest WmTests:ActivityRecordTests
Bryce Leeaf691c02017-03-20 14:20:22 -070097 */
98@MediumTest
Bryce Lee3115bdf2017-04-05 08:39:40 -070099@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +0800100@RunWith(WindowTestRunner.class)
Bryce Leeaf691c02017-03-20 14:20:22 -0700101public class ActivityRecordTests extends ActivityTestsBase {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700102 private ActivityStack mStack;
Louis Changcdec0802019-11-11 11:45:07 +0800103 private Task mTask;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700104 private ActivityRecord mActivity;
105
106 @Before
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700107 public void setUp() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700108 mStack = new StackBuilder(mRootActivityContainer).build();
Louis Changf2835df2018-10-17 15:14:45 +0800109 mTask = mStack.getChildAt(0);
Wale Ogunwale21e06482019-11-18 05:14:15 -0800110 mActivity = mTask.getTopNonFinishingActivity();
Andrii Kulian6b321512019-01-23 06:37:00 +0000111
112 doReturn(false).when(mService).isBooting();
113 doReturn(true).when(mService).isBooted();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700114 }
115
Bryce Leeaf691c02017-03-20 14:20:22 -0700116 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900117 public void testStackCleanupOnClearingTask() {
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200118 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700119 verify(mStack, times(1)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700120 }
121
122 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900123 public void testStackCleanupOnActivityRemoval() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200124 mTask.removeChild(mActivity);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700125 verify(mStack, times(1)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700126 }
127
128 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900129 public void testStackCleanupOnTaskRemoval() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200130 mStack.removeChild(mTask, null /*reason*/);
Bryce Lee04ab3462017-04-10 15:06:33 -0700131 // Stack should be gone on task removal.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800132 assertNull(mService.mRootActivityContainer.getStack(mStack.mStackId));
Bryce Leeaf691c02017-03-20 14:20:22 -0700133 }
134
135 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900136 public void testNoCleanupMovingActivityInSameStack() {
Louis Changcdec0802019-11-11 11:45:07 +0800137 final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
Bryce Lee18d51592017-10-25 10:22:19 -0700138 .build();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700139 mActivity.reparent(newTask, 0, null /*reason*/);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700140 verify(mStack, times(0)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700141 }
Andrii Kulian3a1619d2017-07-07 14:38:09 -0700142
Andreas Gampecea9e6d2018-02-22 18:06:44 -0800143 @Test
Bryce Lee0bd8d422018-01-09 09:45:57 -0800144 public void testPausingWhenVisibleFromStopped() throws Exception {
Andrii Kulian04470682018-01-10 15:32:31 -0800145 final MutableBoolean pauseFound = new MutableBoolean(false);
146 doAnswer((InvocationOnMock invocationOnMock) -> {
147 final ClientTransaction transaction = invocationOnMock.getArgument(0);
148 if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
149 pauseFound.value = true;
Bryce Lee0bd8d422018-01-09 09:45:57 -0800150 }
Andrii Kulian04470682018-01-10 15:32:31 -0800151 return null;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700152 }).when(mActivity.app.getThread()).scheduleTransaction(any());
Bryce Leed939cf02018-03-12 09:04:44 -0700153
Bryce Lee7ace3952018-02-16 14:34:32 -0800154 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
Bryce Lee0bd8d422018-01-09 09:45:57 -0800155
Andrii Kulian6b321512019-01-23 06:37:00 +0000156 // The activity is in the focused stack so it should be resumed.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700157 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Andrii Kulian6b321512019-01-23 06:37:00 +0000158 assertTrue(mActivity.isState(RESUMED));
Bryce Leed939cf02018-03-12 09:04:44 -0700159 assertFalse(pauseFound.value);
Andrii Kulian04470682018-01-10 15:32:31 -0800160
Andrii Kulian6b321512019-01-23 06:37:00 +0000161 // Make the activity non focusable
162 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
163 doReturn(false).when(mActivity).isFocusable();
Bryce Leed939cf02018-03-12 09:04:44 -0700164
Andrii Kulian6b321512019-01-23 06:37:00 +0000165 // If the activity is not focusable, it should move to paused.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700166 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee7ace3952018-02-16 14:34:32 -0800167 assertTrue(mActivity.isState(PAUSING));
Andrii Kulian04470682018-01-10 15:32:31 -0800168 assertTrue(pauseFound.value);
Bryce Lee052957b2018-01-16 11:13:30 -0800169
170 // Make sure that the state does not change for current non-stopping states.
Bryce Lee7ace3952018-02-16 14:34:32 -0800171 mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
Andrii Kulian6b321512019-01-23 06:37:00 +0000172 doReturn(true).when(mActivity).isFocusable();
Bryce Lee052957b2018-01-16 11:13:30 -0800173
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700174 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee052957b2018-01-16 11:13:30 -0800175
Bryce Lee7ace3952018-02-16 14:34:32 -0800176 assertTrue(mActivity.isState(INITIALIZING));
Bryce Leea0fb8e02018-02-28 14:21:07 -0800177
178 // Make sure the state does not change if we are not the current top activity.
179 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
180
Bryce Leea0fb8e02018-02-28 14:21:07 -0800181 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
182 mStack.mTranslucentActivityWaiting = topActivity;
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700183 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Louis Changeadb22f2019-06-19 12:09:23 +0800184 assertTrue(mActivity.isState(STARTED));
185
186 mStack.mTranslucentActivityWaiting = null;
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700187 topActivity.setOccludesParent(false);
Louis Changeadb22f2019-06-19 12:09:23 +0800188 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
189 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
190 assertTrue(mActivity.isState(STARTED));
Bryce Lee0bd8d422018-01-09 09:45:57 -0800191 }
192
Riddle Hsu0a343c32018-12-21 00:40:48 +0800193 private void ensureActivityConfiguration() {
194 mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
195 }
196
Bryce Lee1533b2b2017-09-14 17:06:41 -0700197 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900198 public void testCanBeLaunchedOnDisplay() {
Riddle Hsu16567132018-08-16 21:37:47 +0800199 mService.mSupportsMultiWindow = true;
200 final ActivityRecord activity = new ActivityBuilder(mService).build();
Bryce Lee1533b2b2017-09-14 17:06:41 -0700201
Riddle Hsu16567132018-08-16 21:37:47 +0800202 // An activity can be launched on default display.
203 assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
204 // An activity cannot be launched on a non-existent display.
205 assertFalse(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY + 1));
Bryce Lee1533b2b2017-09-14 17:06:41 -0700206 }
207
chaviw82a0ba82018-03-15 14:26:29 -0700208 @Test
209 public void testsApplyOptionsLocked() {
210 ActivityOptions activityOptions = ActivityOptions.makeBasic();
211
212 // Set and apply options for ActivityRecord. Pending options should be cleared
213 mActivity.updateOptionsLocked(activityOptions);
214 mActivity.applyOptionsLocked();
215 assertNull(mActivity.pendingOptions);
216
217 // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
218 // Pending options should be cleared for both ActivityRecords
219 ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
220 activity2.updateOptionsLocked(activityOptions);
221 mActivity.updateOptionsLocked(activityOptions);
222 mActivity.applyOptionsLocked();
223 assertNull(mActivity.pendingOptions);
224 assertNull(activity2.pendingOptions);
225
226 // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
227 // Pending options should be cleared for only ActivityRecord that was applied
Louis Changcdec0802019-11-11 11:45:07 +0800228 Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
chaviw82a0ba82018-03-15 14:26:29 -0700229 activity2 = new ActivityBuilder(mService).setTask(task2).build();
230 activity2.updateOptionsLocked(activityOptions);
231 mActivity.updateOptionsLocked(activityOptions);
232 mActivity.applyOptionsLocked();
233 assertNull(mActivity.pendingOptions);
234 assertNotNull(activity2.pendingOptions);
235 }
Garfield Tan0443b372019-01-04 15:00:13 -0800236
237 @Test
238 public void testNewOverrideConfigurationIncrementsSeq() {
239 final Configuration newConfig = new Configuration();
240
241 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
242 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
243 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
244 }
245
246 @Test
247 public void testNewParentConfigurationIncrementsSeq() {
248 final Configuration newConfig = new Configuration(
249 mTask.getRequestedOverrideConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700250 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
251 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
Garfield Tan0443b372019-01-04 15:00:13 -0800252
253 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
254 mTask.onRequestedOverrideConfigurationChanged(newConfig);
255 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
256 }
257
258 @Test
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800259 public void testSetsRelaunchReason_NotDragResizing() {
260 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
261
262 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
263 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
264 mActivity.getConfiguration()));
265
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700266 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800267 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700268 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
269 ? ORIENTATION_LANDSCAPE
270 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800271 mTask.onRequestedOverrideConfigurationChanged(newConfig);
272
273 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
274
Riddle Hsu0a343c32018-12-21 00:40:48 +0800275 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800276
277 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
278 mActivity.mRelaunchReason);
279 }
280
281 @Test
282 public void testSetsRelaunchReason_DragResizing() {
283 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
284
285 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
286 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
287 mActivity.getConfiguration()));
288
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700289 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800290 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700291 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
292 ? ORIENTATION_LANDSCAPE
293 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800294 mTask.onRequestedOverrideConfigurationChanged(newConfig);
295
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200296 doReturn(true).when(mTask).isDragResizing();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800297
298 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
299
Riddle Hsu0a343c32018-12-21 00:40:48 +0800300 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800301
302 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
303 mActivity.mRelaunchReason);
304 }
305
306 @Test
307 public void testSetsRelaunchReason_NonResizeConfigChanges() {
308 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
309
310 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
311 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
312 mActivity.getConfiguration()));
313
314 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
315 final Configuration newConfig = new Configuration(mTask.getConfiguration());
316 newConfig.fontScale = 5;
317 mTask.onRequestedOverrideConfigurationChanged(newConfig);
318
319 mActivity.mRelaunchReason =
320 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
321
Riddle Hsu0a343c32018-12-21 00:40:48 +0800322 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800323
324 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
325 mActivity.mRelaunchReason);
326 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800327
328 @Test
329 public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700330 mActivity = new ActivityBuilder(mService)
331 .setTask(mTask)
332 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
333 .build();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800334 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
335
Garfield Tan36a69ad2019-01-16 17:08:23 -0800336 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
337 mActivity.getConfiguration()));
338
Garfield Tan36a69ad2019-01-16 17:08:23 -0800339 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700340 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
341 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
342 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
343 newConfig.orientation = ORIENTATION_LANDSCAPE;
344 newConfig.screenWidthDp = longSide;
345 newConfig.screenHeightDp = shortSide;
346 } else {
347 newConfig.orientation = ORIENTATION_PORTRAIT;
348 newConfig.screenWidthDp = shortSide;
349 newConfig.screenHeightDp = longSide;
350 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800351
352 // Mimic the behavior that display doesn't handle app's requested orientation.
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200353 final DisplayContent dc = mTask.getDisplayContent();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700354 doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
355 doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800356
357 final int requestedOrientation;
358 switch (newConfig.orientation) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700359 case ORIENTATION_LANDSCAPE:
360 requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE;
Garfield Tan36a69ad2019-01-16 17:08:23 -0800361 break;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700362 case ORIENTATION_PORTRAIT:
Garfield Tan36a69ad2019-01-16 17:08:23 -0800363 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
364 break;
365 default:
366 throw new IllegalStateException("Orientation in new config should be either"
367 + "landscape or portrait.");
368 }
369 mActivity.setRequestedOrientation(requestedOrientation);
370
371 final ActivityConfigurationChangeItem expected =
372 ActivityConfigurationChangeItem.obtain(newConfig);
373 verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
374 eq(mActivity.appToken), eq(expected));
375 }
Andrii Kulianf2195362019-01-31 18:20:11 -0800376
377 @Test
378 public void testShouldMakeActive_deferredResume() {
379 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
380
381 mSupervisor.beginDeferResume();
382 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
383
384 mSupervisor.endDeferResume();
385 assertEquals(true, mActivity.shouldMakeActive(null /* activeActivity */));
386 }
Garfield Tan40263302019-02-01 15:27:35 -0800387
388 @Test
Andrii Kulian0c869cc2019-02-06 19:50:32 -0800389 public void testShouldResume_stackVisibility() {
390 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
391 spyOn(mStack);
392
393 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
394 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
395
396 doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
397 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
398
399 doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
400 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
401 }
402
403 @Test
Garfield Tan40263302019-02-01 15:27:35 -0800404 public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700405 mActivity = new ActivityBuilder(mService)
406 .setTask(mTask)
407 .setLaunchTaskBehind(true)
408 .setConfigChanges(CONFIG_ORIENTATION)
409 .build();
Garfield Tan40263302019-02-01 15:27:35 -0800410 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
411
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700412 final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
Garfield Tan40263302019-02-01 15:27:35 -0800413 try {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700414 doReturn(false).when(stack).isStackTranslucent(any());
Garfield Tan40263302019-02-01 15:27:35 -0800415 assertFalse(mStack.shouldBeVisible(null /* starting */));
416
Garfield Tan40263302019-02-01 15:27:35 -0800417 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
418 mActivity.getConfiguration()));
419
Garfield Tan40263302019-02-01 15:27:35 -0800420 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700421 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
422 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
423 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
424 newConfig.orientation = ORIENTATION_LANDSCAPE;
425 newConfig.screenWidthDp = longSide;
426 newConfig.screenHeightDp = shortSide;
427 } else {
428 newConfig.orientation = ORIENTATION_PORTRAIT;
429 newConfig.screenWidthDp = shortSide;
430 newConfig.screenHeightDp = longSide;
431 }
Garfield Tan40263302019-02-01 15:27:35 -0800432
433 mTask.onConfigurationChanged(newConfig);
434
435 mActivity.ensureActivityConfiguration(0 /* globalChanges */,
436 false /* preserveWindow */, true /* ignoreStopState */);
437
438 final ActivityConfigurationChangeItem expected =
439 ActivityConfigurationChangeItem.obtain(newConfig);
440 verify(mService.getLifecycleManager()).scheduleTransaction(
441 eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
442 } finally {
443 stack.getDisplay().removeChild(stack);
444 }
445 }
Riddle Hsu0a343c32018-12-21 00:40:48 +0800446
447 @Test
Louis Chang3d119a92019-04-22 10:45:37 +0800448 public void testShouldPauseWhenMakeClientVisible() {
449 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700450 topActivity.setOccludesParent(false);
Louis Chang3d119a92019-04-22 10:45:37 +0800451 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
452 mActivity.makeClientVisible();
Louis Changeadb22f2019-06-19 12:09:23 +0800453 assertEquals(STARTED, mActivity.getState());
Louis Chang3d119a92019-04-22 10:45:37 +0800454 }
455
456 @Test
Jorim Jaggi346702a2019-05-08 17:49:33 +0200457 public void testTakeOptions() {
458 ActivityOptions opts = ActivityOptions.makeRemoteAnimation(
459 new RemoteAnimationAdapter(new Stub() {
460
461 @Override
462 public void onAnimationStart(RemoteAnimationTarget[] apps,
Winson Chungd5852192019-09-06 17:20:28 -0700463 RemoteAnimationTarget[] wallpapers,
Jorim Jaggi346702a2019-05-08 17:49:33 +0200464 IRemoteAnimationFinishedCallback finishedCallback) {
465
466 }
467
468 @Override
469 public void onAnimationCancelled() {
470
471 }
472 }, 0, 0));
473 mActivity.updateOptionsLocked(opts);
474 assertNotNull(mActivity.takeOptionsLocked(true /* fromClient */));
475 assertNotNull(mActivity.pendingOptions);
476
477 mActivity.updateOptionsLocked(ActivityOptions.makeBasic());
478 assertNotNull(mActivity.takeOptionsLocked(false /* fromClient */));
479 assertNull(mActivity.pendingOptions);
480 }
481
Louis Chang6a9be162019-07-15 10:41:32 +0800482 @Test
483 public void testCanLaunchHomeActivityFromChooser() {
484 ComponentName chooserComponent = ComponentName.unflattenFromString(
485 Resources.getSystem().getString(R.string.config_chooserActivity));
486 ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
487 chooserComponent).build();
488 assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
489 }
490
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700491 /**
492 * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and
493 * that it is cleared after activity is resumed.
494 */
495 @Test
496 public void testHasSavedState() {
497 assertTrue(mActivity.hasSavedState());
498
499 ActivityRecord.activityResumedLocked(mActivity.appToken);
500 assertFalse(mActivity.hasSavedState());
501 assertNull(mActivity.getSavedState());
502 }
503
504 /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */
505 @Test
506 public void testUpdateSavedState() {
507 mActivity.setSavedState(null /* savedState */);
508 assertFalse(mActivity.hasSavedState());
509 assertNull(mActivity.getSavedState());
510
511 final Bundle savedState = new Bundle();
512 savedState.putString("test", "string");
513 mActivity.setSavedState(savedState);
514 assertTrue(mActivity.hasSavedState());
515 assertEquals(savedState, mActivity.getSavedState());
516 }
517
518 /** Verify the correct updates of saved state when activity client reports stop. */
519 @Test
520 public void testUpdateSavedState_activityStopped() {
521 final Bundle savedState = new Bundle();
522 savedState.putString("test", "string");
523 final PersistableBundle persistentSavedState = new PersistableBundle();
524 persistentSavedState.putString("persist", "string");
525
526 // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored.
527 mActivity.setState(STOPPING, "test");
528 mActivity.activityStoppedLocked(savedState, persistentSavedState, "desc");
529 assertTrue(mActivity.hasSavedState());
530 assertEquals(savedState, mActivity.getSavedState());
531 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
532
533 // Sending 'null' for saved state can only happen due to timeout, so previously stored saved
534 // states should not be overridden.
535 mActivity.setState(STOPPING, "test");
536 mActivity.activityStoppedLocked(null /* savedState */, null /* persistentSavedState */,
537 "desc");
538 assertTrue(mActivity.hasSavedState());
539 assertEquals(savedState, mActivity.getSavedState());
540 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
541 }
542
Andrii Kulian057a6512019-07-15 16:15:51 -0700543 /**
544 * Verify that activity finish request is not performed if activity is finishing or is in
545 * incorrect state.
546 */
547 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700548 public void testFinishActivityIfPossible_cancelled() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700549 // Mark activity as finishing
550 mActivity.finishing = true;
551 assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700552 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700553 assertTrue(mActivity.finishing);
554 assertTrue(mActivity.isInStackLocked());
555
556 // Remove activity from task
557 mActivity.finishing = false;
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200558 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
Andrii Kulian057a6512019-07-15 16:15:51 -0700559 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700560 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700561 assertFalse(mActivity.finishing);
562 }
563
564 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700565 * Verify that activity finish request is placed, but not executed immediately if activity is
Andrii Kulian057a6512019-07-15 16:15:51 -0700566 * not ready yet.
567 */
568 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700569 public void testFinishActivityIfPossible_requested() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700570 mActivity.finishing = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700571 assertEquals("Currently resumed activity must be prepared removal", FINISH_RESULT_REQUESTED,
572 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700573 assertTrue(mActivity.finishing);
574 assertTrue(mActivity.isInStackLocked());
575
576 // First request to finish activity must schedule a "destroy" request to the client.
577 // Activity must be removed from history after the client reports back or after timeout.
578 mActivity.finishing = false;
579 mActivity.setState(STOPPED, "test");
580 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700581 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700582 assertTrue(mActivity.finishing);
583 assertTrue(mActivity.isInStackLocked());
584 }
585
586 /**
587 * Verify that activity finish request removes activity immediately if it's ready.
588 */
589 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700590 public void testFinishActivityIfPossible_removed() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700591 // Prepare the activity record to be ready for immediate removal. It should be invisible and
592 // have no process. Otherwise, request to finish it will send a message to client first.
593 mActivity.setState(STOPPED, "test");
Issei Suzuki1669ea42019-11-06 14:20:59 +0100594 mActivity.mVisibleRequested = false;
Andrii Kulian057a6512019-07-15 16:15:51 -0700595 mActivity.nowVisible = false;
596 // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
597 // this will cause NPE when updating task's process.
598 mActivity.app = null;
wilsonshih4c9824a2019-10-25 18:47:50 +0800599
600 // Put a visible activity on top, so the finishing activity doesn't have to wait until the
601 // next activity reports idle to destroy it.
602 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100603 topActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +0800604 topActivity.nowVisible = true;
605 topActivity.setState(RESUMED, "test");
606
Andrii Kulian057a6512019-07-15 16:15:51 -0700607 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REMOVED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700608 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700609 assertTrue(mActivity.finishing);
610 assertFalse(mActivity.isInStackLocked());
611 }
612
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700613 /**
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800614 * Verify that when finishing the top focused activity on top display, the stack order will be
615 * changed by adjusting focus.
616 */
617 @Test
618 public void testFinishActivityIfPossible_adjustStackOrder() {
619 // Prepare the stacks with order (top to bottom): mStack, stack1, stack2.
620 final ActivityStack stack1 = new StackBuilder(mRootActivityContainer).build();
621 mStack.moveToFront("test");
622 // The stack2 is needed here for moving back to simulate the
623 // {@link ActivityDisplay#mPreferredTopFocusableStack} is cleared, so
624 // {@link ActivityDisplay#getFocusedStack} will rely on the order of focusable-and-visible
625 // stacks. Then when mActivity is finishing, its stack will be invisible (no running
626 // activities in the stack) that is the key condition to verify.
627 final ActivityStack stack2 = new StackBuilder(mRootActivityContainer).build();
628 stack2.moveToBack("test", stack2.getChildAt(0));
629
630 assertTrue(mStack.isTopStackOnDisplay());
631
632 mActivity.setState(RESUMED, "test");
633 mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test",
Louis Chang7b03ad92019-08-21 12:32:33 +0800634 false /* oomAdj */);
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800635
636 assertTrue(stack1.isTopStackOnDisplay());
637 }
638
639 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700640 * Verify that resumed activity is paused due to finish request.
641 */
642 @Test
643 public void testFinishActivityIfPossible_resumedStartsPausing() {
644 mActivity.finishing = false;
645 mActivity.setState(RESUMED, "test");
646 assertEquals("Currently resumed activity must be paused before removal",
647 FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */));
648 assertEquals(PAUSING, mActivity.getState());
649 verify(mActivity).setVisibility(eq(false));
650 verify(mActivity.getDisplay().mDisplayContent)
651 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
652 }
653
654 /**
655 * Verify that finish request will be completed immediately for non-resumed activity.
656 */
657 @Test
658 public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() {
659 final ActivityState[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED};
660 for (ActivityState state : states) {
661 mActivity.finishing = false;
662 mActivity.setState(state, "test");
663 reset(mActivity);
664 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
665 mActivity.finishIfPossible("test", false /* oomAdj */));
666 verify(mActivity).completeFinishing(anyString());
667 }
668 }
669
670 /**
671 * Verify that finishing will not be completed in PAUSING state.
672 */
673 @Test
674 public void testFinishActivityIfPossible_pausing() {
675 mActivity.finishing = false;
676 mActivity.setState(PAUSING, "test");
677 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
678 mActivity.finishIfPossible("test", false /* oomAdj */));
679 verify(mActivity, never()).completeFinishing(anyString());
680 }
681
682 /**
683 * Verify that finish request for resumed activity will prepare an app transition but not
684 * execute it immediately.
685 */
686 @Test
687 public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() {
688 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100689 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700690 mActivity.setState(RESUMED, "test");
691 mActivity.finishIfPossible("test", false /* oomAdj */);
692
693 verify(mActivity).setVisibility(eq(false));
694 verify(mActivity.getDisplay().mDisplayContent)
695 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
696 verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition();
697 }
698
699 /**
700 * Verify that finish request for paused activity will prepare and execute an app transition.
701 */
702 @Test
703 public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() {
704 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100705 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700706 mActivity.setState(PAUSED, "test");
707 mActivity.finishIfPossible("test", false /* oomAdj */);
708
Andrii Kulian149d9ad32019-08-23 15:04:17 -0700709 verify(mActivity, atLeast(1)).setVisibility(eq(false));
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700710 verify(mActivity.getDisplay().mDisplayContent)
711 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
712 verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
713 }
714
715 /**
716 * Verify that finish request for non-visible activity will not prepare any transitions.
717 */
718 @Test
719 public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
720 // Put an activity on top of test activity to make it invisible and prevent us from
721 // accidentally resuming the topmost one again.
722 new ActivityBuilder(mService).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100723 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700724 mActivity.setState(STOPPED, "test");
725
726 mActivity.finishIfPossible("test", false /* oomAdj */);
727
728 verify(mActivity.getDisplay().mDisplayContent, never())
729 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
730 }
731
732 /**
733 * Verify that complete finish request for non-finishing activity is invalid.
734 */
735 @Test(expected = IllegalArgumentException.class)
736 public void testCompleteFinishing_failNotFinishing() {
737 mActivity.finishing = false;
738 mActivity.completeFinishing("test");
739 }
740
741 /**
742 * Verify that complete finish request for resumed activity is invalid.
743 */
744 @Test(expected = IllegalArgumentException.class)
745 public void testCompleteFinishing_failResumed() {
746 mActivity.setState(RESUMED, "test");
747 mActivity.completeFinishing("test");
748 }
749
750 /**
751 * Verify that finish request for pausing activity must be a no-op - activity will finish
752 * once it completes pausing.
753 */
754 @Test
755 public void testCompleteFinishing_pausing() {
756 mActivity.setState(PAUSING, "test");
757 mActivity.finishing = true;
758
759 assertEquals("Activity must not be removed immediately - waiting for paused",
760 mActivity, mActivity.completeFinishing("test"));
761 assertEquals(PAUSING, mActivity.getState());
762 verify(mActivity, never()).destroyIfPossible(anyString());
763 }
764
765 /**
Riddle Hsucf920232019-10-04 19:05:36 +0800766 * Verify that finish request won't change the state of next top activity if the current
767 * finishing activity doesn't need to be destroyed immediately. The case is usually like
768 * from {@link ActivityStack#completePauseLocked(boolean, ActivityRecord)} to
769 * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the
770 * responsibility to resume the next activity with updating the state.
771 */
772 @Test
773 public void testCompleteFinishing_keepStateOfNextInvisible() {
774 final ActivityRecord currentTop = mActivity;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100775 currentTop.mVisibleRequested = currentTop.nowVisible = true;
Riddle Hsucf920232019-10-04 19:05:36 +0800776
777 // Simulates that {@code currentTop} starts an existing activity from background (so its
778 // state is stopped) and the starting flow just goes to place it at top.
779 final ActivityStack nextStack = new StackBuilder(mRootActivityContainer).build();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800780 final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity();
Riddle Hsucf920232019-10-04 19:05:36 +0800781 nextTop.setState(STOPPED, "test");
782
783 mStack.mPausingActivity = currentTop;
784 currentTop.finishing = true;
785 currentTop.setState(PAUSED, "test");
786 currentTop.completeFinishing("completePauseLocked");
787
788 // Current top becomes stopping because it is visible and the next is invisible.
789 assertEquals(STOPPING, currentTop.getState());
790 // The state of next activity shouldn't be changed.
791 assertEquals(STOPPED, nextTop.getState());
792 }
793
794 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700795 * Verify that complete finish request for visible activity must be delayed before the next one
796 * becomes visible.
797 */
798 @Test
799 public void testCompleteFinishing_waitForNextVisible() {
800 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100801 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700802 topActivity.nowVisible = true;
803 topActivity.finishing = true;
804 topActivity.setState(PAUSED, "true");
805 // Mark the bottom activity as not visible, so that we will wait for it before removing
806 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100807 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700808 mActivity.nowVisible = false;
809 mActivity.setState(STOPPED, "test");
810
811 assertEquals("Activity must not be removed immediately - waiting for next visible",
812 topActivity, topActivity.completeFinishing("test"));
813 assertEquals("Activity must be stopped to make next one visible", STOPPING,
814 topActivity.getState());
815 assertTrue("Activity must be stopped to make next one visible",
816 topActivity.mStackSupervisor.mStoppingActivities.contains(topActivity));
817 verify(topActivity, never()).destroyIfPossible(anyString());
818 }
819
820 /**
821 * Verify that complete finish request for invisible activity must not be delayed.
822 */
823 @Test
824 public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
825 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100826 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700827 topActivity.nowVisible = false;
828 topActivity.finishing = true;
829 topActivity.setState(PAUSED, "true");
830 // Mark the bottom activity as not visible, so that we would wait for it before removing
831 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100832 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700833 mActivity.nowVisible = false;
834 mActivity.setState(STOPPED, "test");
835
836 topActivity.completeFinishing("test");
837
838 verify(topActivity).destroyIfPossible(anyString());
839 }
840
841 /**
842 * Verify that paused finishing activity will be added to finishing list and wait for next one
843 * to idle.
844 */
845 @Test
846 public void testCompleteFinishing_waitForIdle() {
847 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100848 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700849 topActivity.nowVisible = true;
850 topActivity.finishing = true;
851 topActivity.setState(PAUSED, "true");
852 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100853 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700854 mActivity.nowVisible = true;
855 mActivity.setState(RESUMED, "test");
856
857 topActivity.completeFinishing("test");
858
859 verify(topActivity).addToFinishingAndWaitForIdle();
860 }
861
862 /**
863 * Verify that complete finish request for visible activity must not be delayed if the next one
864 * is already visible and it's not the focused stack.
865 */
866 @Test
867 public void testCompleteFinishing_noWaitForNextVisible_stopped() {
868 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100869 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700870 topActivity.nowVisible = false;
871 topActivity.finishing = true;
872 topActivity.setState(STOPPED, "true");
873 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100874 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700875 mActivity.nowVisible = true;
876 mActivity.setState(RESUMED, "test");
877
878 topActivity.completeFinishing("test");
879
880 verify(topActivity).destroyIfPossible(anyString());
881 }
882
883 /**
884 * Verify that complete finish request for visible activity must not be delayed if the next one
885 * is already visible and it's not the focused stack.
886 */
887 @Test
888 public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
889 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100890 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700891 topActivity.nowVisible = true;
892 topActivity.finishing = true;
893 topActivity.setState(PAUSED, "true");
894 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100895 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700896 mActivity.nowVisible = true;
897 mActivity.setState(RESUMED, "test");
898
899 // Add another stack to become focused and make the activity there visible. This way it
900 // simulates finishing in non-focused stack in split-screen.
901 final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
wilsonshih4c9824a2019-10-25 18:47:50 +0800902 final ActivityRecord focusedActivity = stack.getChildAt(0).getChildAt(0);
903 focusedActivity.nowVisible = true;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100904 focusedActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +0800905 focusedActivity.setState(RESUMED, "test");
906 stack.mResumedActivity = focusedActivity;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700907
908 topActivity.completeFinishing("test");
909
910 verify(topActivity).destroyIfPossible(anyString());
911 }
912
913 /**
914 * Verify destroy activity request completes successfully.
915 */
916 @Test
917 public void testDestroyIfPossible() {
918 doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities();
919 spyOn(mStack);
920 mActivity.destroyIfPossible("test");
921
922 assertEquals(DESTROYING, mActivity.getState());
923 assertTrue(mActivity.finishing);
Andrii Kulian79d67982019-08-19 11:56:16 -0700924 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700925 }
926
927 /**
928 * Verify that complete finish request for visible activity must not destroy it immediately if
929 * it is the last running activity on a display with a home stack. We must wait for home
930 * activity to come up to avoid a black flash in this case.
931 */
932 @Test
933 public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
934 // Empty the home stack.
935 final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
Louis Changcdec0802019-11-11 11:45:07 +0800936 for (Task t : homeStack.getAllTasks()) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200937 homeStack.removeChild(t, "test");
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700938 }
939 mActivity.finishing = true;
940 doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities();
941 spyOn(mStack);
942
943 // Try to destroy the last activity above the home stack.
944 mActivity.destroyIfPossible("test");
945
946 // Verify that the activity was not actually destroyed, but waits for next one to come up
947 // instead.
Andrii Kulian79d67982019-08-19 11:56:16 -0700948 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700949 assertEquals(FINISHING, mActivity.getState());
950 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
951 }
952
Andrii Kulian79d67982019-08-19 11:56:16 -0700953 /**
wilsonshih4c9824a2019-10-25 18:47:50 +0800954 * Verify that complete finish request for visible activity must resume next home stack before
955 * destroying it immediately if it is the last running activity on a display with a home stack.
956 * We must wait for home activity to come up to avoid a black flash in this case.
957 */
958 @Test
959 public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
960 // Empty the home stack.
961 final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
Louis Changcdec0802019-11-11 11:45:07 +0800962 for (Task t : homeStack.getAllTasks()) {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200963 homeStack.removeChild(t, "test");
wilsonshih4c9824a2019-10-25 18:47:50 +0800964 }
965 mActivity.finishing = true;
966 spyOn(mStack);
967
968 // Try to finish the last activity above the home stack.
969 mActivity.completeFinishing("test");
970
971 // Verify that the activity is not destroyed immediately, but waits for next one to come up.
972 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
973 assertEquals(FINISHING, mActivity.getState());
974 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
975 }
976
977 /**
Andrii Kulian79d67982019-08-19 11:56:16 -0700978 * Test that the activity will be moved to destroying state and the message to destroy will be
979 * sent to the client.
980 */
981 @Test
982 public void testDestroyImmediately_hadApp_finishing() {
983 mActivity.finishing = true;
984 mActivity.destroyImmediately(false /* removeFromApp */, "test");
985
986 assertEquals(DESTROYING, mActivity.getState());
987 }
988
989 /**
990 * Test that the activity will be moved to destroyed state immediately if it was not marked as
991 * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
992 */
993 @Test
994 public void testDestroyImmediately_hadApp_notFinishing() {
995 mActivity.finishing = false;
996 mActivity.destroyImmediately(false /* removeFromApp */, "test");
997
998 assertEquals(DESTROYED, mActivity.getState());
999 }
1000
1001 /**
1002 * Test that an activity with no process attached and that is marked as finishing will be
1003 * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
1004 */
1005 @Test
1006 public void testDestroyImmediately_noApp_finishing() {
1007 mActivity.app = null;
1008 mActivity.finishing = true;
Louis Changcdec0802019-11-11 11:45:07 +08001009 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001010
1011 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1012
1013 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001014 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001015 assertEquals(0, task.getChildCount());
1016 }
1017
1018 /**
1019 * Test that an activity with no process attached and that is not marked as finishing will be
1020 * marked as DESTROYED but not removed from task.
1021 */
1022 @Test
1023 public void testDestroyImmediately_noApp_notFinishing() {
1024 mActivity.app = null;
1025 mActivity.finishing = false;
Louis Changcdec0802019-11-11 11:45:07 +08001026 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001027
1028 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1029
1030 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001031 assertEquals(task, mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001032 assertEquals(1, task.getChildCount());
1033 }
1034
1035 /**
1036 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1037 */
1038 @Test
1039 public void testSafelyDestroy_nonDestroyable() {
1040 doReturn(false).when(mActivity).isDestroyable();
1041
1042 mActivity.safelyDestroy("test");
1043
1044 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1045 }
1046
1047 /**
1048 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1049 */
1050 @Test
1051 public void testSafelyDestroy_destroyable() {
1052 doReturn(true).when(mActivity).isDestroyable();
1053
1054 mActivity.safelyDestroy("test");
1055
1056 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1057 }
1058
1059 @Test
1060 public void testRemoveFromHistory() {
1061 final ActivityStack stack = mActivity.getActivityStack();
Louis Changcdec0802019-11-11 11:45:07 +08001062 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001063
1064 mActivity.removeFromHistory("test");
1065
1066 assertEquals(DESTROYED, mActivity.getState());
1067 assertNull(mActivity.app);
Louis Changcdec0802019-11-11 11:45:07 +08001068 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001069 assertEquals(0, task.getChildCount());
1070 assertNull(task.getStack());
1071 assertEquals(0, stack.getChildCount());
1072 }
1073
1074 /**
1075 * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is
1076 * not in destroying or destroyed state.
1077 */
1078 @Test(expected = IllegalStateException.class)
1079 public void testDestroyed_notDestroying() {
1080 mActivity.setState(STOPPED, "test");
1081 mActivity.destroyed("test");
1082 }
1083
1084 /**
1085 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying
1086 */
1087 @Test
1088 public void testDestroyed_destroying() {
1089 mActivity.setState(DESTROYING, "test");
1090 mActivity.destroyed("test");
1091
1092 verify(mActivity).removeFromHistory(anyString());
1093 }
1094
1095 /**
1096 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed.
1097 */
1098 @Test
1099 public void testDestroyed_destroyed() {
1100 mActivity.setState(DESTROYED, "test");
1101 mActivity.destroyed("test");
1102
1103 verify(mActivity).removeFromHistory(anyString());
1104 }
Bryce Leeaf691c02017-03-20 14:20:22 -07001105}