blob: 7a449b37224a51c2258cf270946716c84cb9fde4 [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;
wilsonshiha96aac62019-11-18 14:53:34 +080069import android.content.Intent;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080070import android.content.pm.ActivityInfo;
Garfield Tan0443b372019-01-04 15:00:13 -080071import android.content.res.Configuration;
Louis Chang6a9be162019-07-15 10:41:32 +080072import android.content.res.Resources;
Andrii Kulian06b8dcb2019-07-10 21:09:38 -070073import android.os.Bundle;
74import android.os.PersistableBundle;
Bryce Leeaf691c02017-03-20 14:20:22 -070075import android.platform.test.annotations.Presubmit;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080076import android.util.MergedConfiguration;
Andrii Kulian04470682018-01-10 15:32:31 -080077import android.util.MutableBoolean;
Jorim Jaggi346702a2019-05-08 17:49:33 +020078import android.view.IRemoteAnimationFinishedCallback;
79import android.view.IRemoteAnimationRunner.Stub;
80import android.view.RemoteAnimationAdapter;
81import android.view.RemoteAnimationTarget;
Bryce Leeaf691c02017-03-20 14:20:22 -070082
Brett Chabota26eda92018-07-23 13:08:30 -070083import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070084
Louis Chang6a9be162019-07-15 10:41:32 +080085import com.android.internal.R;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -070086import com.android.server.wm.ActivityStack.ActivityState;
Riddle Hsu74826262019-04-17 14:57:42 +080087
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070088import org.junit.Before;
Bryce Leeaf691c02017-03-20 14:20:22 -070089import org.junit.Test;
Riddle Hsu2da2d032019-08-28 21:08:58 +080090import org.junit.runner.RunWith;
Andrii Kulian04470682018-01-10 15:32:31 -080091import org.mockito.invocation.InvocationOnMock;
Bryce Lee0bd8d422018-01-09 09:45:57 -080092
Bryce Leeaf691c02017-03-20 14:20:22 -070093/**
94 * Tests for the {@link ActivityRecord} class.
95 *
96 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090097 * atest WmTests:ActivityRecordTests
Bryce Leeaf691c02017-03-20 14:20:22 -070098 */
99@MediumTest
Bryce Lee3115bdf2017-04-05 08:39:40 -0700100@Presubmit
Riddle Hsu2da2d032019-08-28 21:08:58 +0800101@RunWith(WindowTestRunner.class)
Bryce Leeaf691c02017-03-20 14:20:22 -0700102public class ActivityRecordTests extends ActivityTestsBase {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700103 private ActivityStack mStack;
Louis Changcdec0802019-11-11 11:45:07 +0800104 private Task mTask;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700105 private ActivityRecord mActivity;
106
107 @Before
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700108 public void setUp() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700109 mStack = new StackBuilder(mRootActivityContainer).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900110 mTask = mStack.getBottomMostTask();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800111 mActivity = mTask.getTopNonFinishingActivity();
Andrii Kulian6b321512019-01-23 06:37:00 +0000112
113 doReturn(false).when(mService).isBooting();
114 doReturn(true).when(mService).isBooted();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700115 }
116
Bryce Leeaf691c02017-03-20 14:20:22 -0700117 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900118 public void testStackCleanupOnClearingTask() {
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200119 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700120 verify(mStack, times(1)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700121 }
122
123 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900124 public void testStackCleanupOnActivityRemoval() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200125 mTask.removeChild(mActivity);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700126 verify(mStack, times(1)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700127 }
128
129 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900130 public void testStackCleanupOnTaskRemoval() {
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200131 mStack.removeChild(mTask, null /*reason*/);
Bryce Lee04ab3462017-04-10 15:06:33 -0700132 // Stack should be gone on task removal.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800133 assertNull(mService.mRootActivityContainer.getStack(mStack.mStackId));
Bryce Leeaf691c02017-03-20 14:20:22 -0700134 }
135
136 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900137 public void testNoCleanupMovingActivityInSameStack() {
Louis Changcdec0802019-11-11 11:45:07 +0800138 final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
Bryce Lee18d51592017-10-25 10:22:19 -0700139 .build();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700140 mActivity.reparent(newTask, 0, null /*reason*/);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700141 verify(mStack, times(0)).onActivityRemovedFromStack(any());
Bryce Leeaf691c02017-03-20 14:20:22 -0700142 }
Andrii Kulian3a1619d2017-07-07 14:38:09 -0700143
Andreas Gampecea9e6d2018-02-22 18:06:44 -0800144 @Test
Bryce Lee0bd8d422018-01-09 09:45:57 -0800145 public void testPausingWhenVisibleFromStopped() throws Exception {
Andrii Kulian04470682018-01-10 15:32:31 -0800146 final MutableBoolean pauseFound = new MutableBoolean(false);
147 doAnswer((InvocationOnMock invocationOnMock) -> {
148 final ClientTransaction transaction = invocationOnMock.getArgument(0);
149 if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
150 pauseFound.value = true;
Bryce Lee0bd8d422018-01-09 09:45:57 -0800151 }
Andrii Kulian04470682018-01-10 15:32:31 -0800152 return null;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700153 }).when(mActivity.app.getThread()).scheduleTransaction(any());
Bryce Leed939cf02018-03-12 09:04:44 -0700154
Bryce Lee7ace3952018-02-16 14:34:32 -0800155 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
Bryce Lee0bd8d422018-01-09 09:45:57 -0800156
Andrii Kulian6b321512019-01-23 06:37:00 +0000157 // The activity is in the focused stack so it should be resumed.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700158 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Andrii Kulian6b321512019-01-23 06:37:00 +0000159 assertTrue(mActivity.isState(RESUMED));
Bryce Leed939cf02018-03-12 09:04:44 -0700160 assertFalse(pauseFound.value);
Andrii Kulian04470682018-01-10 15:32:31 -0800161
Andrii Kulian6b321512019-01-23 06:37:00 +0000162 // Make the activity non focusable
163 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
164 doReturn(false).when(mActivity).isFocusable();
Bryce Leed939cf02018-03-12 09:04:44 -0700165
Andrii Kulian6b321512019-01-23 06:37:00 +0000166 // If the activity is not focusable, it should move to paused.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700167 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee7ace3952018-02-16 14:34:32 -0800168 assertTrue(mActivity.isState(PAUSING));
Andrii Kulian04470682018-01-10 15:32:31 -0800169 assertTrue(pauseFound.value);
Bryce Lee052957b2018-01-16 11:13:30 -0800170
171 // Make sure that the state does not change for current non-stopping states.
Bryce Lee7ace3952018-02-16 14:34:32 -0800172 mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
Andrii Kulian6b321512019-01-23 06:37:00 +0000173 doReturn(true).when(mActivity).isFocusable();
Bryce Lee052957b2018-01-16 11:13:30 -0800174
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700175 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee052957b2018-01-16 11:13:30 -0800176
Bryce Lee7ace3952018-02-16 14:34:32 -0800177 assertTrue(mActivity.isState(INITIALIZING));
Bryce Leea0fb8e02018-02-28 14:21:07 -0800178
179 // Make sure the state does not change if we are not the current top activity.
180 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
181
Bryce Leea0fb8e02018-02-28 14:21:07 -0800182 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
183 mStack.mTranslucentActivityWaiting = topActivity;
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700184 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Louis Changeadb22f2019-06-19 12:09:23 +0800185 assertTrue(mActivity.isState(STARTED));
186
187 mStack.mTranslucentActivityWaiting = null;
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700188 topActivity.setOccludesParent(false);
Louis Changeadb22f2019-06-19 12:09:23 +0800189 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
190 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
191 assertTrue(mActivity.isState(STARTED));
Bryce Lee0bd8d422018-01-09 09:45:57 -0800192 }
193
Riddle Hsu0a343c32018-12-21 00:40:48 +0800194 private void ensureActivityConfiguration() {
195 mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
196 }
197
Bryce Lee1533b2b2017-09-14 17:06:41 -0700198 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900199 public void testCanBeLaunchedOnDisplay() {
Riddle Hsu16567132018-08-16 21:37:47 +0800200 mService.mSupportsMultiWindow = true;
201 final ActivityRecord activity = new ActivityBuilder(mService).build();
Bryce Lee1533b2b2017-09-14 17:06:41 -0700202
Riddle Hsu16567132018-08-16 21:37:47 +0800203 // An activity can be launched on default display.
204 assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
205 // An activity cannot be launched on a non-existent display.
Garfield Tan5423cf02019-12-06 17:02:38 -0800206 assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE));
Bryce Lee1533b2b2017-09-14 17:06:41 -0700207 }
208
chaviw82a0ba82018-03-15 14:26:29 -0700209 @Test
210 public void testsApplyOptionsLocked() {
211 ActivityOptions activityOptions = ActivityOptions.makeBasic();
212
213 // Set and apply options for ActivityRecord. Pending options should be cleared
214 mActivity.updateOptionsLocked(activityOptions);
215 mActivity.applyOptionsLocked();
216 assertNull(mActivity.pendingOptions);
217
218 // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
219 // Pending options should be cleared for both ActivityRecords
220 ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
221 activity2.updateOptionsLocked(activityOptions);
222 mActivity.updateOptionsLocked(activityOptions);
223 mActivity.applyOptionsLocked();
224 assertNull(mActivity.pendingOptions);
225 assertNull(activity2.pendingOptions);
226
227 // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
228 // Pending options should be cleared for only ActivityRecord that was applied
Louis Changcdec0802019-11-11 11:45:07 +0800229 Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
chaviw82a0ba82018-03-15 14:26:29 -0700230 activity2 = new ActivityBuilder(mService).setTask(task2).build();
231 activity2.updateOptionsLocked(activityOptions);
232 mActivity.updateOptionsLocked(activityOptions);
233 mActivity.applyOptionsLocked();
234 assertNull(mActivity.pendingOptions);
235 assertNotNull(activity2.pendingOptions);
236 }
Garfield Tan0443b372019-01-04 15:00:13 -0800237
238 @Test
239 public void testNewOverrideConfigurationIncrementsSeq() {
240 final Configuration newConfig = new Configuration();
241
242 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
243 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
244 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
245 }
246
247 @Test
248 public void testNewParentConfigurationIncrementsSeq() {
249 final Configuration newConfig = new Configuration(
250 mTask.getRequestedOverrideConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700251 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
252 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
Garfield Tan0443b372019-01-04 15:00:13 -0800253
254 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
255 mTask.onRequestedOverrideConfigurationChanged(newConfig);
256 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
257 }
258
259 @Test
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800260 public void testSetsRelaunchReason_NotDragResizing() {
261 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
262
263 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
264 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
265 mActivity.getConfiguration()));
266
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700267 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800268 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700269 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
270 ? ORIENTATION_LANDSCAPE
271 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800272 mTask.onRequestedOverrideConfigurationChanged(newConfig);
273
274 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
275
Riddle Hsu0a343c32018-12-21 00:40:48 +0800276 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800277
278 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
279 mActivity.mRelaunchReason);
280 }
281
282 @Test
283 public void testSetsRelaunchReason_DragResizing() {
284 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
285
286 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
287 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
288 mActivity.getConfiguration()));
289
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700290 mActivity.info.configChanges &= ~CONFIG_ORIENTATION;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800291 final Configuration newConfig = new Configuration(mTask.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700292 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT
293 ? ORIENTATION_LANDSCAPE
294 : ORIENTATION_PORTRAIT;
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800295 mTask.onRequestedOverrideConfigurationChanged(newConfig);
296
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200297 doReturn(true).when(mTask).isDragResizing();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800298
299 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
300
Riddle Hsu0a343c32018-12-21 00:40:48 +0800301 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800302
303 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
304 mActivity.mRelaunchReason);
305 }
306
307 @Test
308 public void testSetsRelaunchReason_NonResizeConfigChanges() {
309 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
310
311 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
312 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
313 mActivity.getConfiguration()));
314
315 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
316 final Configuration newConfig = new Configuration(mTask.getConfiguration());
317 newConfig.fontScale = 5;
318 mTask.onRequestedOverrideConfigurationChanged(newConfig);
319
320 mActivity.mRelaunchReason =
321 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
322
Riddle Hsu0a343c32018-12-21 00:40:48 +0800323 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800324
325 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
326 mActivity.mRelaunchReason);
327 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800328
329 @Test
330 public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700331 mActivity = new ActivityBuilder(mService)
332 .setTask(mTask)
333 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)
334 .build();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800335 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
336
Garfield Tan36a69ad2019-01-16 17:08:23 -0800337 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
338 mActivity.getConfiguration()));
339
Garfield Tan36a69ad2019-01-16 17:08:23 -0800340 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700341 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
342 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
343 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
344 newConfig.orientation = ORIENTATION_LANDSCAPE;
345 newConfig.screenWidthDp = longSide;
346 newConfig.screenHeightDp = shortSide;
347 } else {
348 newConfig.orientation = ORIENTATION_PORTRAIT;
349 newConfig.screenWidthDp = shortSide;
350 newConfig.screenHeightDp = longSide;
351 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800352
353 // Mimic the behavior that display doesn't handle app's requested orientation.
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200354 final DisplayContent dc = mTask.getDisplayContent();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700355 doReturn(false).when(dc).onDescendantOrientationChanged(any(), any());
356 doReturn(false).when(dc).handlesOrientationChangeFromDescendant();
Garfield Tan36a69ad2019-01-16 17:08:23 -0800357
358 final int requestedOrientation;
359 switch (newConfig.orientation) {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700360 case ORIENTATION_LANDSCAPE:
361 requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE;
Garfield Tan36a69ad2019-01-16 17:08:23 -0800362 break;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700363 case ORIENTATION_PORTRAIT:
Garfield Tan36a69ad2019-01-16 17:08:23 -0800364 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
365 break;
366 default:
367 throw new IllegalStateException("Orientation in new config should be either"
368 + "landscape or portrait.");
369 }
370 mActivity.setRequestedOrientation(requestedOrientation);
371
372 final ActivityConfigurationChangeItem expected =
373 ActivityConfigurationChangeItem.obtain(newConfig);
374 verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
375 eq(mActivity.appToken), eq(expected));
376 }
Andrii Kulianf2195362019-01-31 18:20:11 -0800377
378 @Test
379 public void testShouldMakeActive_deferredResume() {
380 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
381
382 mSupervisor.beginDeferResume();
383 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
384
385 mSupervisor.endDeferResume();
386 assertEquals(true, mActivity.shouldMakeActive(null /* activeActivity */));
387 }
Garfield Tan40263302019-02-01 15:27:35 -0800388
389 @Test
Andrii Kulian0c869cc2019-02-06 19:50:32 -0800390 public void testShouldResume_stackVisibility() {
391 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
392 spyOn(mStack);
393
394 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
395 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
396
397 doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
398 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
399
400 doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
401 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
402 }
403
404 @Test
wilsonshiha96aac62019-11-18 14:53:34 +0800405 public void testShouldResumeOrPauseWithResults() {
406 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
407 spyOn(mStack);
408
409 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
410 mActivity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent());
411 topActivity.finishing = true;
412
413 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
414 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
415 assertEquals(false, mActivity.shouldPauseActivity(null /*activeActivity */));
416 }
417
418 @Test
Garfield Tan40263302019-02-01 15:27:35 -0800419 public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700420 mActivity = new ActivityBuilder(mService)
421 .setTask(mTask)
422 .setLaunchTaskBehind(true)
423 .setConfigChanges(CONFIG_ORIENTATION)
424 .build();
Garfield Tan40263302019-02-01 15:27:35 -0800425 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
426
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700427 final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
Garfield Tan40263302019-02-01 15:27:35 -0800428 try {
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700429 doReturn(false).when(stack).isStackTranslucent(any());
Garfield Tan40263302019-02-01 15:27:35 -0800430 assertFalse(mStack.shouldBeVisible(null /* starting */));
431
Garfield Tan40263302019-02-01 15:27:35 -0800432 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
433 mActivity.getConfiguration()));
434
Garfield Tan40263302019-02-01 15:27:35 -0800435 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700436 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp);
437 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp);
438 if (newConfig.orientation == ORIENTATION_PORTRAIT) {
439 newConfig.orientation = ORIENTATION_LANDSCAPE;
440 newConfig.screenWidthDp = longSide;
441 newConfig.screenHeightDp = shortSide;
442 } else {
443 newConfig.orientation = ORIENTATION_PORTRAIT;
444 newConfig.screenWidthDp = shortSide;
445 newConfig.screenHeightDp = longSide;
446 }
Garfield Tan40263302019-02-01 15:27:35 -0800447
448 mTask.onConfigurationChanged(newConfig);
449
450 mActivity.ensureActivityConfiguration(0 /* globalChanges */,
451 false /* preserveWindow */, true /* ignoreStopState */);
452
453 final ActivityConfigurationChangeItem expected =
454 ActivityConfigurationChangeItem.obtain(newConfig);
455 verify(mService.getLifecycleManager()).scheduleTransaction(
456 eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
457 } finally {
Louis Chang2453d062019-11-19 22:30:48 +0800458 stack.getDisplay().removeStack(stack);
Garfield Tan40263302019-02-01 15:27:35 -0800459 }
460 }
Riddle Hsu0a343c32018-12-21 00:40:48 +0800461
462 @Test
Louis Chang3d119a92019-04-22 10:45:37 +0800463 public void testShouldPauseWhenMakeClientVisible() {
464 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Wale Ogunwale83b8a6b2019-06-27 20:15:15 -0700465 topActivity.setOccludesParent(false);
Louis Chang3d119a92019-04-22 10:45:37 +0800466 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
467 mActivity.makeClientVisible();
Louis Changeadb22f2019-06-19 12:09:23 +0800468 assertEquals(STARTED, mActivity.getState());
Louis Chang3d119a92019-04-22 10:45:37 +0800469 }
470
471 @Test
Jorim Jaggi346702a2019-05-08 17:49:33 +0200472 public void testTakeOptions() {
473 ActivityOptions opts = ActivityOptions.makeRemoteAnimation(
474 new RemoteAnimationAdapter(new Stub() {
475
476 @Override
477 public void onAnimationStart(RemoteAnimationTarget[] apps,
Winson Chungd5852192019-09-06 17:20:28 -0700478 RemoteAnimationTarget[] wallpapers,
Jorim Jaggi346702a2019-05-08 17:49:33 +0200479 IRemoteAnimationFinishedCallback finishedCallback) {
480
481 }
482
483 @Override
484 public void onAnimationCancelled() {
485
486 }
487 }, 0, 0));
488 mActivity.updateOptionsLocked(opts);
489 assertNotNull(mActivity.takeOptionsLocked(true /* fromClient */));
490 assertNotNull(mActivity.pendingOptions);
491
492 mActivity.updateOptionsLocked(ActivityOptions.makeBasic());
493 assertNotNull(mActivity.takeOptionsLocked(false /* fromClient */));
494 assertNull(mActivity.pendingOptions);
495 }
496
Louis Chang6a9be162019-07-15 10:41:32 +0800497 @Test
498 public void testCanLaunchHomeActivityFromChooser() {
499 ComponentName chooserComponent = ComponentName.unflattenFromString(
500 Resources.getSystem().getString(R.string.config_chooserActivity));
501 ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent(
502 chooserComponent).build();
503 assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue();
504 }
505
Andrii Kulian06b8dcb2019-07-10 21:09:38 -0700506 /**
507 * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and
508 * that it is cleared after activity is resumed.
509 */
510 @Test
511 public void testHasSavedState() {
512 assertTrue(mActivity.hasSavedState());
513
514 ActivityRecord.activityResumedLocked(mActivity.appToken);
515 assertFalse(mActivity.hasSavedState());
516 assertNull(mActivity.getSavedState());
517 }
518
519 /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */
520 @Test
521 public void testUpdateSavedState() {
522 mActivity.setSavedState(null /* savedState */);
523 assertFalse(mActivity.hasSavedState());
524 assertNull(mActivity.getSavedState());
525
526 final Bundle savedState = new Bundle();
527 savedState.putString("test", "string");
528 mActivity.setSavedState(savedState);
529 assertTrue(mActivity.hasSavedState());
530 assertEquals(savedState, mActivity.getSavedState());
531 }
532
533 /** Verify the correct updates of saved state when activity client reports stop. */
534 @Test
535 public void testUpdateSavedState_activityStopped() {
536 final Bundle savedState = new Bundle();
537 savedState.putString("test", "string");
538 final PersistableBundle persistentSavedState = new PersistableBundle();
539 persistentSavedState.putString("persist", "string");
540
541 // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored.
542 mActivity.setState(STOPPING, "test");
543 mActivity.activityStoppedLocked(savedState, persistentSavedState, "desc");
544 assertTrue(mActivity.hasSavedState());
545 assertEquals(savedState, mActivity.getSavedState());
546 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
547
548 // Sending 'null' for saved state can only happen due to timeout, so previously stored saved
549 // states should not be overridden.
550 mActivity.setState(STOPPING, "test");
551 mActivity.activityStoppedLocked(null /* savedState */, null /* persistentSavedState */,
552 "desc");
553 assertTrue(mActivity.hasSavedState());
554 assertEquals(savedState, mActivity.getSavedState());
555 assertEquals(persistentSavedState, mActivity.getPersistentSavedState());
556 }
557
Andrii Kulian057a6512019-07-15 16:15:51 -0700558 /**
559 * Verify that activity finish request is not performed if activity is finishing or is in
560 * incorrect state.
561 */
562 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700563 public void testFinishActivityIfPossible_cancelled() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700564 // Mark activity as finishing
565 mActivity.finishing = true;
566 assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700567 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700568 assertTrue(mActivity.finishing);
569 assertTrue(mActivity.isInStackLocked());
570
571 // Remove activity from task
572 mActivity.finishing = false;
Wale Ogunwalec17418e2019-10-13 23:00:40 +0200573 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask());
Andrii Kulian057a6512019-07-15 16:15:51 -0700574 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700575 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700576 assertFalse(mActivity.finishing);
577 }
578
579 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700580 * Verify that activity finish request is placed, but not executed immediately if activity is
Andrii Kulian057a6512019-07-15 16:15:51 -0700581 * not ready yet.
582 */
583 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700584 public void testFinishActivityIfPossible_requested() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700585 mActivity.finishing = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700586 assertEquals("Currently resumed activity must be prepared removal", FINISH_RESULT_REQUESTED,
587 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700588 assertTrue(mActivity.finishing);
589 assertTrue(mActivity.isInStackLocked());
590
591 // First request to finish activity must schedule a "destroy" request to the client.
592 // Activity must be removed from history after the client reports back or after timeout.
593 mActivity.finishing = false;
594 mActivity.setState(STOPPED, "test");
595 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700596 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700597 assertTrue(mActivity.finishing);
598 assertTrue(mActivity.isInStackLocked());
599 }
600
601 /**
602 * Verify that activity finish request removes activity immediately if it's ready.
603 */
604 @Test
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700605 public void testFinishActivityIfPossible_removed() {
Andrii Kulian057a6512019-07-15 16:15:51 -0700606 // Prepare the activity record to be ready for immediate removal. It should be invisible and
607 // have no process. Otherwise, request to finish it will send a message to client first.
608 mActivity.setState(STOPPED, "test");
Issei Suzuki1669ea42019-11-06 14:20:59 +0100609 mActivity.mVisibleRequested = false;
Andrii Kulian057a6512019-07-15 16:15:51 -0700610 mActivity.nowVisible = false;
611 // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() -
612 // this will cause NPE when updating task's process.
613 mActivity.app = null;
wilsonshih4c9824a2019-10-25 18:47:50 +0800614
615 // Put a visible activity on top, so the finishing activity doesn't have to wait until the
616 // next activity reports idle to destroy it.
617 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100618 topActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +0800619 topActivity.nowVisible = true;
620 topActivity.setState(RESUMED, "test");
621
Andrii Kulian057a6512019-07-15 16:15:51 -0700622 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REMOVED,
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700623 mActivity.finishIfPossible("test", false /* oomAdj */));
Andrii Kulian057a6512019-07-15 16:15:51 -0700624 assertTrue(mActivity.finishing);
625 assertFalse(mActivity.isInStackLocked());
626 }
627
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700628 /**
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800629 * Verify that when finishing the top focused activity on top display, the stack order will be
630 * changed by adjusting focus.
631 */
632 @Test
633 public void testFinishActivityIfPossible_adjustStackOrder() {
634 // Prepare the stacks with order (top to bottom): mStack, stack1, stack2.
635 final ActivityStack stack1 = new StackBuilder(mRootActivityContainer).build();
636 mStack.moveToFront("test");
637 // The stack2 is needed here for moving back to simulate the
638 // {@link ActivityDisplay#mPreferredTopFocusableStack} is cleared, so
639 // {@link ActivityDisplay#getFocusedStack} will rely on the order of focusable-and-visible
640 // stacks. Then when mActivity is finishing, its stack will be invisible (no running
641 // activities in the stack) that is the key condition to verify.
642 final ActivityStack stack2 = new StackBuilder(mRootActivityContainer).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900643 stack2.moveToBack("test", stack2.getBottomMostTask());
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800644
645 assertTrue(mStack.isTopStackOnDisplay());
646
647 mActivity.setState(RESUMED, "test");
648 mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, "test",
Louis Chang7b03ad92019-08-21 12:32:33 +0800649 false /* oomAdj */);
Riddle Hsu1e7ba582019-08-26 19:18:34 +0800650
651 assertTrue(stack1.isTopStackOnDisplay());
652 }
653
654 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700655 * Verify that resumed activity is paused due to finish request.
656 */
657 @Test
658 public void testFinishActivityIfPossible_resumedStartsPausing() {
659 mActivity.finishing = false;
660 mActivity.setState(RESUMED, "test");
661 assertEquals("Currently resumed activity must be paused before removal",
662 FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */));
663 assertEquals(PAUSING, mActivity.getState());
664 verify(mActivity).setVisibility(eq(false));
665 verify(mActivity.getDisplay().mDisplayContent)
666 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
667 }
668
669 /**
670 * Verify that finish request will be completed immediately for non-resumed activity.
671 */
672 @Test
673 public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() {
674 final ActivityState[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED};
675 for (ActivityState state : states) {
676 mActivity.finishing = false;
677 mActivity.setState(state, "test");
678 reset(mActivity);
679 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
680 mActivity.finishIfPossible("test", false /* oomAdj */));
681 verify(mActivity).completeFinishing(anyString());
682 }
683 }
684
685 /**
686 * Verify that finishing will not be completed in PAUSING state.
687 */
688 @Test
689 public void testFinishActivityIfPossible_pausing() {
690 mActivity.finishing = false;
691 mActivity.setState(PAUSING, "test");
692 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED,
693 mActivity.finishIfPossible("test", false /* oomAdj */));
694 verify(mActivity, never()).completeFinishing(anyString());
695 }
696
697 /**
698 * Verify that finish request for resumed activity will prepare an app transition but not
699 * execute it immediately.
700 */
701 @Test
702 public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() {
703 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100704 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700705 mActivity.setState(RESUMED, "test");
706 mActivity.finishIfPossible("test", false /* oomAdj */);
707
708 verify(mActivity).setVisibility(eq(false));
709 verify(mActivity.getDisplay().mDisplayContent)
710 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
711 verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition();
712 }
713
714 /**
715 * Verify that finish request for paused activity will prepare and execute an app transition.
716 */
717 @Test
718 public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() {
719 mActivity.finishing = false;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100720 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700721 mActivity.setState(PAUSED, "test");
722 mActivity.finishIfPossible("test", false /* oomAdj */);
723
Andrii Kulian149d9ad32019-08-23 15:04:17 -0700724 verify(mActivity, atLeast(1)).setVisibility(eq(false));
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700725 verify(mActivity.getDisplay().mDisplayContent)
726 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
727 verify(mActivity.getDisplay().mDisplayContent).executeAppTransition();
728 }
729
730 /**
731 * Verify that finish request for non-visible activity will not prepare any transitions.
732 */
733 @Test
734 public void testFinishActivityIfPossible_nonVisibleNoAppTransition() {
735 // Put an activity on top of test activity to make it invisible and prevent us from
736 // accidentally resuming the topmost one again.
737 new ActivityBuilder(mService).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100738 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700739 mActivity.setState(STOPPED, "test");
740
741 mActivity.finishIfPossible("test", false /* oomAdj */);
742
743 verify(mActivity.getDisplay().mDisplayContent, never())
744 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */);
745 }
746
747 /**
748 * Verify that complete finish request for non-finishing activity is invalid.
749 */
750 @Test(expected = IllegalArgumentException.class)
751 public void testCompleteFinishing_failNotFinishing() {
752 mActivity.finishing = false;
753 mActivity.completeFinishing("test");
754 }
755
756 /**
757 * Verify that complete finish request for resumed activity is invalid.
758 */
759 @Test(expected = IllegalArgumentException.class)
760 public void testCompleteFinishing_failResumed() {
761 mActivity.setState(RESUMED, "test");
762 mActivity.completeFinishing("test");
763 }
764
765 /**
766 * Verify that finish request for pausing activity must be a no-op - activity will finish
767 * once it completes pausing.
768 */
769 @Test
770 public void testCompleteFinishing_pausing() {
771 mActivity.setState(PAUSING, "test");
772 mActivity.finishing = true;
773
774 assertEquals("Activity must not be removed immediately - waiting for paused",
775 mActivity, mActivity.completeFinishing("test"));
776 assertEquals(PAUSING, mActivity.getState());
777 verify(mActivity, never()).destroyIfPossible(anyString());
778 }
779
780 /**
Riddle Hsucf920232019-10-04 19:05:36 +0800781 * Verify that finish request won't change the state of next top activity if the current
782 * finishing activity doesn't need to be destroyed immediately. The case is usually like
783 * from {@link ActivityStack#completePauseLocked(boolean, ActivityRecord)} to
784 * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the
785 * responsibility to resume the next activity with updating the state.
786 */
787 @Test
788 public void testCompleteFinishing_keepStateOfNextInvisible() {
789 final ActivityRecord currentTop = mActivity;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100790 currentTop.mVisibleRequested = currentTop.nowVisible = true;
Riddle Hsucf920232019-10-04 19:05:36 +0800791
792 // Simulates that {@code currentTop} starts an existing activity from background (so its
793 // state is stopped) and the starting flow just goes to place it at top.
794 final ActivityStack nextStack = new StackBuilder(mRootActivityContainer).build();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800795 final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity();
Riddle Hsucf920232019-10-04 19:05:36 +0800796 nextTop.setState(STOPPED, "test");
797
798 mStack.mPausingActivity = currentTop;
799 currentTop.finishing = true;
800 currentTop.setState(PAUSED, "test");
801 currentTop.completeFinishing("completePauseLocked");
802
803 // Current top becomes stopping because it is visible and the next is invisible.
804 assertEquals(STOPPING, currentTop.getState());
805 // The state of next activity shouldn't be changed.
806 assertEquals(STOPPED, nextTop.getState());
807 }
808
809 /**
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700810 * Verify that complete finish request for visible activity must be delayed before the next one
811 * becomes visible.
812 */
813 @Test
814 public void testCompleteFinishing_waitForNextVisible() {
815 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100816 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700817 topActivity.nowVisible = true;
818 topActivity.finishing = true;
819 topActivity.setState(PAUSED, "true");
820 // Mark the bottom activity as not visible, so that we will wait for it before removing
821 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100822 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700823 mActivity.nowVisible = false;
824 mActivity.setState(STOPPED, "test");
825
826 assertEquals("Activity must not be removed immediately - waiting for next visible",
827 topActivity, topActivity.completeFinishing("test"));
828 assertEquals("Activity must be stopped to make next one visible", STOPPING,
829 topActivity.getState());
830 assertTrue("Activity must be stopped to make next one visible",
831 topActivity.mStackSupervisor.mStoppingActivities.contains(topActivity));
832 verify(topActivity, never()).destroyIfPossible(anyString());
833 }
834
835 /**
836 * Verify that complete finish request for invisible activity must not be delayed.
837 */
838 @Test
839 public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() {
840 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100841 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700842 topActivity.nowVisible = false;
843 topActivity.finishing = true;
844 topActivity.setState(PAUSED, "true");
845 // Mark the bottom activity as not visible, so that we would wait for it before removing
846 // the top one.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100847 mActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700848 mActivity.nowVisible = false;
849 mActivity.setState(STOPPED, "test");
850
851 topActivity.completeFinishing("test");
852
853 verify(topActivity).destroyIfPossible(anyString());
854 }
855
856 /**
857 * Verify that paused finishing activity will be added to finishing list and wait for next one
858 * to idle.
859 */
860 @Test
861 public void testCompleteFinishing_waitForIdle() {
862 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100863 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700864 topActivity.nowVisible = true;
865 topActivity.finishing = true;
866 topActivity.setState(PAUSED, "true");
867 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100868 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700869 mActivity.nowVisible = true;
870 mActivity.setState(RESUMED, "test");
871
872 topActivity.completeFinishing("test");
873
874 verify(topActivity).addToFinishingAndWaitForIdle();
875 }
876
877 /**
878 * Verify that complete finish request for visible activity must not be delayed if the next one
879 * is already visible and it's not the focused stack.
880 */
881 @Test
882 public void testCompleteFinishing_noWaitForNextVisible_stopped() {
883 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100884 topActivity.mVisibleRequested = false;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700885 topActivity.nowVisible = false;
886 topActivity.finishing = true;
887 topActivity.setState(STOPPED, "true");
888 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100889 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700890 mActivity.nowVisible = true;
891 mActivity.setState(RESUMED, "test");
892
893 topActivity.completeFinishing("test");
894
895 verify(topActivity).destroyIfPossible(anyString());
896 }
897
898 /**
899 * Verify that complete finish request for visible activity must not be delayed if the next one
900 * is already visible and it's not the focused stack.
901 */
902 @Test
903 public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() {
904 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
Issei Suzuki1669ea42019-11-06 14:20:59 +0100905 topActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700906 topActivity.nowVisible = true;
907 topActivity.finishing = true;
908 topActivity.setState(PAUSED, "true");
909 // Mark the bottom activity as already visible, so that there is no need to wait for it.
Issei Suzuki1669ea42019-11-06 14:20:59 +0100910 mActivity.mVisibleRequested = true;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700911 mActivity.nowVisible = true;
912 mActivity.setState(RESUMED, "test");
913
914 // Add another stack to become focused and make the activity there visible. This way it
915 // simulates finishing in non-focused stack in split-screen.
916 final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800917 final ActivityRecord focusedActivity = stack.getTopMostActivity();
wilsonshih4c9824a2019-10-25 18:47:50 +0800918 focusedActivity.nowVisible = true;
Issei Suzuki1669ea42019-11-06 14:20:59 +0100919 focusedActivity.mVisibleRequested = true;
wilsonshih4c9824a2019-10-25 18:47:50 +0800920 focusedActivity.setState(RESUMED, "test");
921 stack.mResumedActivity = focusedActivity;
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700922
923 topActivity.completeFinishing("test");
924
925 verify(topActivity).destroyIfPossible(anyString());
926 }
927
928 /**
929 * Verify destroy activity request completes successfully.
930 */
931 @Test
932 public void testDestroyIfPossible() {
933 doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities();
934 spyOn(mStack);
935 mActivity.destroyIfPossible("test");
936
937 assertEquals(DESTROYING, mActivity.getState());
938 assertTrue(mActivity.finishing);
Andrii Kulian79d67982019-08-19 11:56:16 -0700939 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700940 }
941
942 /**
943 * Verify that complete finish request for visible activity must not destroy it immediately if
944 * it is the last running activity on a display with a home stack. We must wait for home
945 * activity to come up to avoid a black flash in this case.
946 */
947 @Test
948 public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
949 // Empty the home stack.
950 final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900951 homeStack.forAllTasks((t) -> { homeStack.removeChild(t, "test"); });
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700952 mActivity.finishing = true;
953 doReturn(false).when(mRootActivityContainer).resumeFocusedStacksTopActivities();
954 spyOn(mStack);
955
956 // Try to destroy the last activity above the home stack.
957 mActivity.destroyIfPossible("test");
958
959 // Verify that the activity was not actually destroyed, but waits for next one to come up
960 // instead.
Andrii Kulian79d67982019-08-19 11:56:16 -0700961 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
Andrii Kulian7dd39bb2019-07-22 13:11:10 -0700962 assertEquals(FINISHING, mActivity.getState());
963 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
964 }
965
Andrii Kulian79d67982019-08-19 11:56:16 -0700966 /**
wilsonshih4c9824a2019-10-25 18:47:50 +0800967 * Verify that complete finish request for visible activity must resume next home stack before
968 * destroying it immediately if it is the last running activity on a display with a home stack.
969 * We must wait for home activity to come up to avoid a black flash in this case.
970 */
971 @Test
972 public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
973 // Empty the home stack.
974 final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900975 homeStack.forAllTasks((t) -> { homeStack.removeChild(t, "test"); });
wilsonshih4c9824a2019-10-25 18:47:50 +0800976 mActivity.finishing = true;
977 spyOn(mStack);
978
979 // Try to finish the last activity above the home stack.
980 mActivity.completeFinishing("test");
981
982 // Verify that the activity is not destroyed immediately, but waits for next one to come up.
983 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
984 assertEquals(FINISHING, mActivity.getState());
985 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity));
986 }
987
988 /**
Andrii Kulian79d67982019-08-19 11:56:16 -0700989 * Test that the activity will be moved to destroying state and the message to destroy will be
990 * sent to the client.
991 */
992 @Test
993 public void testDestroyImmediately_hadApp_finishing() {
994 mActivity.finishing = true;
995 mActivity.destroyImmediately(false /* removeFromApp */, "test");
996
997 assertEquals(DESTROYING, mActivity.getState());
998 }
999
1000 /**
1001 * Test that the activity will be moved to destroyed state immediately if it was not marked as
1002 * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}.
1003 */
1004 @Test
1005 public void testDestroyImmediately_hadApp_notFinishing() {
1006 mActivity.finishing = false;
1007 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1008
1009 assertEquals(DESTROYED, mActivity.getState());
1010 }
1011
1012 /**
1013 * Test that an activity with no process attached and that is marked as finishing will be
1014 * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called.
1015 */
1016 @Test
1017 public void testDestroyImmediately_noApp_finishing() {
1018 mActivity.app = null;
1019 mActivity.finishing = true;
Louis Changcdec0802019-11-11 11:45:07 +08001020 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001021
1022 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1023
1024 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001025 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001026 assertEquals(0, task.getChildCount());
1027 }
1028
1029 /**
1030 * Test that an activity with no process attached and that is not marked as finishing will be
1031 * marked as DESTROYED but not removed from task.
1032 */
1033 @Test
1034 public void testDestroyImmediately_noApp_notFinishing() {
1035 mActivity.app = null;
1036 mActivity.finishing = false;
Louis Changcdec0802019-11-11 11:45:07 +08001037 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001038
1039 mActivity.destroyImmediately(false /* removeFromApp */, "test");
1040
1041 assertEquals(DESTROYED, mActivity.getState());
Louis Changcdec0802019-11-11 11:45:07 +08001042 assertEquals(task, mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001043 assertEquals(1, task.getChildCount());
1044 }
1045
1046 /**
1047 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1048 */
1049 @Test
1050 public void testSafelyDestroy_nonDestroyable() {
1051 doReturn(false).when(mActivity).isDestroyable();
1052
1053 mActivity.safelyDestroy("test");
1054
1055 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1056 }
1057
1058 /**
1059 * Test that an activity will not be destroyed if it is marked as non-destroyable.
1060 */
1061 @Test
1062 public void testSafelyDestroy_destroyable() {
1063 doReturn(true).when(mActivity).isDestroyable();
1064
1065 mActivity.safelyDestroy("test");
1066
1067 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString());
1068 }
1069
1070 @Test
1071 public void testRemoveFromHistory() {
1072 final ActivityStack stack = mActivity.getActivityStack();
Louis Changcdec0802019-11-11 11:45:07 +08001073 final Task task = mActivity.getTask();
Andrii Kulian79d67982019-08-19 11:56:16 -07001074
1075 mActivity.removeFromHistory("test");
1076
1077 assertEquals(DESTROYED, mActivity.getState());
1078 assertNull(mActivity.app);
Louis Changcdec0802019-11-11 11:45:07 +08001079 assertNull(mActivity.getTask());
Andrii Kulian79d67982019-08-19 11:56:16 -07001080 assertEquals(0, task.getChildCount());
1081 assertNull(task.getStack());
1082 assertEquals(0, stack.getChildCount());
1083 }
1084
1085 /**
1086 * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is
1087 * not in destroying or destroyed state.
1088 */
1089 @Test(expected = IllegalStateException.class)
1090 public void testDestroyed_notDestroying() {
1091 mActivity.setState(STOPPED, "test");
1092 mActivity.destroyed("test");
1093 }
1094
1095 /**
1096 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying
1097 */
1098 @Test
1099 public void testDestroyed_destroying() {
1100 mActivity.setState(DESTROYING, "test");
1101 mActivity.destroyed("test");
1102
1103 verify(mActivity).removeFromHistory(anyString());
1104 }
1105
1106 /**
1107 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed.
1108 */
1109 @Test
1110 public void testDestroyed_destroyed() {
1111 mActivity.setState(DESTROYED, "test");
1112 mActivity.destroyed("test");
1113
1114 verify(mActivity).removeFromHistory(anyString());
1115 }
Bryce Leeaf691c02017-03-20 14:20:22 -07001116}