blob: 44390b0c8d433649817df052e0d6f872fb96dac2 [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 Ogunwale04a05ac2017-09-17 21:35:02 -070019import static android.view.Display.DEFAULT_DISPLAY;
Bryce Lee0bd8d422018-01-09 09:45:57 -080020
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090021import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
Garfield Tan36a69ad2019-01-16 17:08:23 -080022import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090023import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
Riddle Hsu7b766fd2019-01-28 21:14:59 +080024import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
Garfield Tan0443b372019-01-04 15:00:13 -080025import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
Garfield Tan36a69ad2019-01-16 17:08:23 -080026import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
Garfield Tan0443b372019-01-04 15:00:13 -080027import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080028import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
Garfield Tan0443b372019-01-04 15:00:13 -080029import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090030import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
Wale Ogunwale59507092018-10-29 09:00:30 -070031import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
32import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
Andrii Kulian6b321512019-01-23 06:37:00 +000033import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
Wale Ogunwale59507092018-10-29 09:00:30 -070034import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
35import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080036import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
37import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
38import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
Adrian Roose99bc052017-11-20 17:55:31 +010039
Bryce Lee04ab3462017-04-10 15:06:33 -070040import static org.junit.Assert.assertEquals;
Bryce Lee1533b2b2017-09-14 17:06:41 -070041import static org.junit.Assert.assertFalse;
Riddle Hsu7b766fd2019-01-28 21:14:59 +080042import static org.junit.Assert.assertNotEquals;
Yunfan Chen1ee84ea2018-11-13 16:03:37 -080043import static org.junit.Assert.assertNotNull;
Bryce Lee04ab3462017-04-10 15:06:33 -070044import static org.junit.Assert.assertNull;
Bryce Lee1533b2b2017-09-14 17:06:41 -070045import static org.junit.Assert.assertTrue;
Riddle Hsuaec55442019-03-12 17:25:35 +080046import static org.mockito.ArgumentMatchers.anyString;
chaviw82a0ba82018-03-15 14:26:29 -070047
Riddle Hsuaec55442019-03-12 17:25:35 +080048import android.app.ActivityManager;
49import android.app.ActivityManagerInternal;
chaviw82a0ba82018-03-15 14:26:29 -070050import android.app.ActivityOptions;
Garfield Tan36a69ad2019-01-16 17:08:23 -080051import android.app.servertransaction.ActivityConfigurationChangeItem;
Bryce Lee0bd8d422018-01-09 09:45:57 -080052import android.app.servertransaction.ClientTransaction;
53import android.app.servertransaction.PauseActivityItem;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080054import android.content.pm.ActivityInfo;
Garfield Tan0443b372019-01-04 15:00:13 -080055import android.content.res.Configuration;
Andrii Kulian3a1619d2017-07-07 14:38:09 -070056import android.graphics.Rect;
Bryce Leeaf691c02017-03-20 14:20:22 -070057import android.platform.test.annotations.Presubmit;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080058import android.util.MergedConfiguration;
Andrii Kulian04470682018-01-10 15:32:31 -080059import android.util.MutableBoolean;
Riddle Hsu61987bc2019-04-03 13:08:47 +080060import android.view.DisplayInfo;
Bryce Leeaf691c02017-03-20 14:20:22 -070061
Brett Chabota26eda92018-07-23 13:08:30 -070062import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070063
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070064import org.junit.Before;
Bryce Leeaf691c02017-03-20 14:20:22 -070065import org.junit.Test;
Andrii Kulian04470682018-01-10 15:32:31 -080066import org.mockito.invocation.InvocationOnMock;
Bryce Lee0bd8d422018-01-09 09:45:57 -080067
Riddle Hsuaec55442019-03-12 17:25:35 +080068import java.util.concurrent.TimeUnit;
69
Bryce Leeaf691c02017-03-20 14:20:22 -070070/**
71 * Tests for the {@link ActivityRecord} class.
72 *
73 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090074 * atest WmTests:ActivityRecordTests
Bryce Leeaf691c02017-03-20 14:20:22 -070075 */
76@MediumTest
Bryce Lee3115bdf2017-04-05 08:39:40 -070077@Presubmit
Bryce Leeaf691c02017-03-20 14:20:22 -070078public class ActivityRecordTests extends ActivityTestsBase {
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -070079 private TestActivityStack mStack;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070080 private TaskRecord mTask;
81 private ActivityRecord mActivity;
82
83 @Before
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070084 public void setUp() throws Exception {
Yunfan Chen279f5582018-12-12 15:24:50 -080085 mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
Louis Changf2835df2018-10-17 15:14:45 +080086 mTask = mStack.getChildAt(0);
87 mActivity = mTask.getTopActivity();
Andrii Kulian6b321512019-01-23 06:37:00 +000088
89 doReturn(false).when(mService).isBooting();
90 doReturn(true).when(mService).isBooted();
Riddle Hsu61987bc2019-04-03 13:08:47 +080091
92 final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
93 doReturn(mock(DisplayPolicy.class)).when(displayContent).getDisplayPolicy();
94 doReturn(mock(DisplayInfo.class)).when(displayContent).getDisplayInfo();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070095 }
96
Bryce Leeaf691c02017-03-20 14:20:22 -070097 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090098 public void testStackCleanupOnClearingTask() {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070099 mActivity.setTask(null);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700100 assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
Bryce Leeaf691c02017-03-20 14:20:22 -0700101 }
102
103 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900104 public void testStackCleanupOnActivityRemoval() {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700105 mTask.removeActivity(mActivity);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700106 assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
Bryce Leeaf691c02017-03-20 14:20:22 -0700107 }
108
109 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900110 public void testStackCleanupOnTaskRemoval() {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700111 mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING);
Bryce Lee04ab3462017-04-10 15:06:33 -0700112 // Stack should be gone on task removal.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800113 assertNull(mService.mRootActivityContainer.getStack(mStack.mStackId));
Bryce Leeaf691c02017-03-20 14:20:22 -0700114 }
115
116 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900117 public void testNoCleanupMovingActivityInSameStack() {
Bryce Lee18d51592017-10-25 10:22:19 -0700118 final TaskRecord newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
119 .build();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700120 mActivity.reparent(newTask, 0, null /*reason*/);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700121 assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 0);
Bryce Leeaf691c02017-03-20 14:20:22 -0700122 }
Andrii Kulian3a1619d2017-07-07 14:38:09 -0700123
Andreas Gampecea9e6d2018-02-22 18:06:44 -0800124 @Test
Bryce Lee0bd8d422018-01-09 09:45:57 -0800125 public void testPausingWhenVisibleFromStopped() throws Exception {
Andrii Kulian04470682018-01-10 15:32:31 -0800126 final MutableBoolean pauseFound = new MutableBoolean(false);
127 doAnswer((InvocationOnMock invocationOnMock) -> {
128 final ClientTransaction transaction = invocationOnMock.getArgument(0);
129 if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
130 pauseFound.value = true;
Bryce Lee0bd8d422018-01-09 09:45:57 -0800131 }
Andrii Kulian04470682018-01-10 15:32:31 -0800132 return null;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700133 }).when(mActivity.app.getThread()).scheduleTransaction(any());
Bryce Leed939cf02018-03-12 09:04:44 -0700134
Bryce Lee7ace3952018-02-16 14:34:32 -0800135 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
Bryce Lee0bd8d422018-01-09 09:45:57 -0800136
Andrii Kulian6b321512019-01-23 06:37:00 +0000137 // The activity is in the focused stack so it should be resumed.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700138 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Andrii Kulian6b321512019-01-23 06:37:00 +0000139 assertTrue(mActivity.isState(RESUMED));
Bryce Leed939cf02018-03-12 09:04:44 -0700140 assertFalse(pauseFound.value);
Andrii Kulian04470682018-01-10 15:32:31 -0800141
Andrii Kulian6b321512019-01-23 06:37:00 +0000142 // Make the activity non focusable
143 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
144 doReturn(false).when(mActivity).isFocusable();
Bryce Leed939cf02018-03-12 09:04:44 -0700145
Andrii Kulian6b321512019-01-23 06:37:00 +0000146 // If the activity is not focusable, it should move to paused.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700147 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee7ace3952018-02-16 14:34:32 -0800148 assertTrue(mActivity.isState(PAUSING));
Andrii Kulian04470682018-01-10 15:32:31 -0800149 assertTrue(pauseFound.value);
Bryce Lee052957b2018-01-16 11:13:30 -0800150
151 // Make sure that the state does not change for current non-stopping states.
Bryce Lee7ace3952018-02-16 14:34:32 -0800152 mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
Andrii Kulian6b321512019-01-23 06:37:00 +0000153 doReturn(true).when(mActivity).isFocusable();
Bryce Lee052957b2018-01-16 11:13:30 -0800154
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700155 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee052957b2018-01-16 11:13:30 -0800156
Bryce Lee7ace3952018-02-16 14:34:32 -0800157 assertTrue(mActivity.isState(INITIALIZING));
Bryce Leea0fb8e02018-02-28 14:21:07 -0800158
159 // Make sure the state does not change if we are not the current top activity.
160 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
161
162 // Make sure that the state does not change when we have an activity becoming translucent
163 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
164 mStack.mTranslucentActivityWaiting = topActivity;
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700165 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Leea0fb8e02018-02-28 14:21:07 -0800166
167 assertTrue(mActivity.isState(STOPPED));
Bryce Lee0bd8d422018-01-09 09:45:57 -0800168 }
169
Riddle Hsu0a343c32018-12-21 00:40:48 +0800170 private void ensureActivityConfiguration() {
171 mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
172 }
173
Bryce Lee1533b2b2017-09-14 17:06:41 -0700174 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900175 public void testCanBeLaunchedOnDisplay() {
Riddle Hsu16567132018-08-16 21:37:47 +0800176 mService.mSupportsMultiWindow = true;
177 final ActivityRecord activity = new ActivityBuilder(mService).build();
Bryce Lee1533b2b2017-09-14 17:06:41 -0700178
Riddle Hsu16567132018-08-16 21:37:47 +0800179 // An activity can be launched on default display.
180 assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
181 // An activity cannot be launched on a non-existent display.
182 assertFalse(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY + 1));
Bryce Lee1533b2b2017-09-14 17:06:41 -0700183 }
184
chaviw82a0ba82018-03-15 14:26:29 -0700185 @Test
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800186 public void testRestartProcessIfVisible() {
187 doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800188 mActivity.visible = true;
189 mActivity.haveState = false;
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800190 mActivity.setState(ActivityStack.ActivityState.RESUMED, "testRestart");
Riddle Hsuaec55442019-03-12 17:25:35 +0800191 prepareFixedAspectRatioUnresizableActivity();
192
Riddle Hsu04164182019-03-07 18:03:27 +0800193 final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
194 mTask.getWindowConfiguration().setAppBounds(0, 0, 600, 1200);
195 // The visible activity should recompute configuration according to the last parent bounds.
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800196 mService.restartActivityProcessIfVisible(mActivity.appToken);
197
198 assertEquals(ActivityStack.ActivityState.RESTARTING_PROCESS, mActivity.getState());
199 assertNotEquals(originalOverrideBounds, mActivity.getBounds());
200 }
201
202 @Test
chaviw82a0ba82018-03-15 14:26:29 -0700203 public void testsApplyOptionsLocked() {
204 ActivityOptions activityOptions = ActivityOptions.makeBasic();
205
206 // Set and apply options for ActivityRecord. Pending options should be cleared
207 mActivity.updateOptionsLocked(activityOptions);
208 mActivity.applyOptionsLocked();
209 assertNull(mActivity.pendingOptions);
210
211 // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
212 // Pending options should be cleared for both ActivityRecords
213 ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
214 activity2.updateOptionsLocked(activityOptions);
215 mActivity.updateOptionsLocked(activityOptions);
216 mActivity.applyOptionsLocked();
217 assertNull(mActivity.pendingOptions);
218 assertNull(activity2.pendingOptions);
219
220 // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
221 // Pending options should be cleared for only ActivityRecord that was applied
222 TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
223 activity2 = new ActivityBuilder(mService).setTask(task2).build();
224 activity2.updateOptionsLocked(activityOptions);
225 mActivity.updateOptionsLocked(activityOptions);
226 mActivity.applyOptionsLocked();
227 assertNull(mActivity.pendingOptions);
228 assertNotNull(activity2.pendingOptions);
229 }
Garfield Tan0443b372019-01-04 15:00:13 -0800230
231 @Test
232 public void testNewOverrideConfigurationIncrementsSeq() {
233 final Configuration newConfig = new Configuration();
234
235 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
236 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
237 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
238 }
239
240 @Test
241 public void testNewParentConfigurationIncrementsSeq() {
242 final Configuration newConfig = new Configuration(
243 mTask.getRequestedOverrideConfiguration());
244 newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
245 ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
246
247 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
248 mTask.onRequestedOverrideConfigurationChanged(newConfig);
249 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
250 }
251
252 @Test
253 public void testNotifiesSeqIncrementToAppToken() {
254 final Configuration appWindowTokenRequestedOrientation = mock(Configuration.class);
255 mActivity.mAppWindowToken = mock(AppWindowToken.class);
256 doReturn(appWindowTokenRequestedOrientation).when(mActivity.mAppWindowToken)
257 .getRequestedOverrideConfiguration();
258
259 final Configuration newConfig = new Configuration();
260 newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
261
262 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
263 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
264 assertEquals(prevSeq + 1, appWindowTokenRequestedOrientation.seq);
265 verify(mActivity.mAppWindowToken).onMergedOverrideConfigurationChanged();
266 }
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800267
268 @Test
269 public void testSetsRelaunchReason_NotDragResizing() {
270 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
271
272 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
273 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
274 mActivity.getConfiguration()));
275
276 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
277 final Configuration newConfig = new Configuration(mTask.getConfiguration());
278 newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
279 ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
280 mTask.onRequestedOverrideConfigurationChanged(newConfig);
281
282 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
283
Riddle Hsu0a343c32018-12-21 00:40:48 +0800284 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800285
286 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
287 mActivity.mRelaunchReason);
288 }
289
290 @Test
291 public void testSetsRelaunchReason_DragResizing() {
292 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
293
294 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
295 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
296 mActivity.getConfiguration()));
297
298 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
299 final Configuration newConfig = new Configuration(mTask.getConfiguration());
300 newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
301 ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
302 mTask.onRequestedOverrideConfigurationChanged(newConfig);
303
304 doReturn(true).when(mTask.getTask()).isDragResizing();
305
306 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
307
Riddle Hsu0a343c32018-12-21 00:40:48 +0800308 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800309
310 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
311 mActivity.mRelaunchReason);
312 }
313
314 @Test
315 public void testSetsRelaunchReason_NonResizeConfigChanges() {
316 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
317
318 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
319 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
320 mActivity.getConfiguration()));
321
322 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
323 final Configuration newConfig = new Configuration(mTask.getConfiguration());
324 newConfig.fontScale = 5;
325 mTask.onRequestedOverrideConfigurationChanged(newConfig);
326
327 mActivity.mRelaunchReason =
328 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
329
Riddle Hsu0a343c32018-12-21 00:40:48 +0800330 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800331
332 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
333 mActivity.mRelaunchReason);
334 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800335
336 @Test
337 public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
338 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
339
340 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
341 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
342 mActivity.getConfiguration()));
343
344 mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
345 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
346 newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
347 ? Configuration.ORIENTATION_LANDSCAPE
348 : Configuration.ORIENTATION_PORTRAIT;
349
350 // Mimic the behavior that display doesn't handle app's requested orientation.
351 doAnswer(invocation -> {
352 mTask.onConfigurationChanged(newConfig);
353 return null;
354 }).when(mActivity.mAppWindowToken).setOrientation(anyInt(), any(), any());
355
356 final int requestedOrientation;
357 switch (newConfig.orientation) {
358 case Configuration.ORIENTATION_LANDSCAPE:
359 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
360 break;
361 case Configuration.ORIENTATION_PORTRAIT:
362 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
363 break;
364 default:
365 throw new IllegalStateException("Orientation in new config should be either"
366 + "landscape or portrait.");
367 }
368 mActivity.setRequestedOrientation(requestedOrientation);
369
370 final ActivityConfigurationChangeItem expected =
371 ActivityConfigurationChangeItem.obtain(newConfig);
372 verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
373 eq(mActivity.appToken), eq(expected));
374 }
Andrii Kulianf2195362019-01-31 18:20:11 -0800375
376 @Test
377 public void testShouldMakeActive_deferredResume() {
378 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
379
380 mSupervisor.beginDeferResume();
381 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
382
383 mSupervisor.endDeferResume();
384 assertEquals(true, mActivity.shouldMakeActive(null /* activeActivity */));
385 }
Garfield Tan40263302019-02-01 15:27:35 -0800386
387 @Test
Andrii Kulian0c869cc2019-02-06 19:50:32 -0800388 public void testShouldResume_stackVisibility() {
389 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
390 spyOn(mStack);
391
392 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
393 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
394
395 doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
396 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
397
398 doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
399 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
400 }
401
402 @Test
Garfield Tan40263302019-02-01 15:27:35 -0800403 public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
404 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
405
406 final TestActivityStack stack = (TestActivityStack) new StackBuilder(mRootActivityContainer)
407 .build();
408 try {
409 stack.setIsTranslucent(false);
410 assertFalse(mStack.shouldBeVisible(null /* starting */));
411
412 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
413 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
414 mActivity.getConfiguration()));
415
416 mActivity.mLaunchTaskBehind = true;
417 mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
418 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
419 newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
420 ? Configuration.ORIENTATION_LANDSCAPE
421 : Configuration.ORIENTATION_PORTRAIT;
422
423 mTask.onConfigurationChanged(newConfig);
424
425 mActivity.ensureActivityConfiguration(0 /* globalChanges */,
426 false /* preserveWindow */, true /* ignoreStopState */);
427
428 final ActivityConfigurationChangeItem expected =
429 ActivityConfigurationChangeItem.obtain(newConfig);
430 verify(mService.getLifecycleManager()).scheduleTransaction(
431 eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
432 } finally {
433 stack.getDisplay().removeChild(stack);
434 }
435 }
Riddle Hsu0a343c32018-12-21 00:40:48 +0800436
437 @Test
Riddle Hsu04164182019-03-07 18:03:27 +0800438 public void testSizeCompatMode_FixedAspectRatioBoundsWithDecor() {
439 final int decorHeight = 200; // e.g. The device has cutout.
440 final Rect parentAppBounds = new Rect(0, decorHeight, 600, 1000);
441 mTask.getWindowConfiguration().setAppBounds(parentAppBounds);
442 mTask.getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
443 doReturn(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
444 .when(mActivity.mAppWindowToken).getOrientationIgnoreVisibility();
445 mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
Riddle Hsu9ad1785102019-03-26 00:26:54 +0800446 mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
Riddle Hsu04164182019-03-07 18:03:27 +0800447 ensureActivityConfiguration();
Riddle Hsu9ad1785102019-03-26 00:26:54 +0800448 // The parent configuration doesn't change since the first resolved configuration, so the
449 // activity shouldn't be in the size compatibility mode.
450 assertFalse(mActivity.inSizeCompatMode());
Riddle Hsu04164182019-03-07 18:03:27 +0800451
452 final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
453 // Ensure the app bounds keep the declared aspect ratio.
454 assertEquals(appBounds.width(), appBounds.height());
455 // The decor height should be a part of the effective bounds.
456 assertEquals(mActivity.getBounds().height(), appBounds.height() + decorHeight);
457
458 mTask.getConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE;
459 mActivity.onConfigurationChanged(mTask.getConfiguration());
460 // After changing orientation, the aspect ratio should be the same.
461 assertEquals(appBounds.width(), appBounds.height());
462 // The decor height will be included in width.
463 assertEquals(mActivity.getBounds().width(), appBounds.width() + decorHeight);
464 }
465
466 @Test
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800467 public void testSizeCompatMode_FixedScreenConfigurationWhenMovingToDisplay() {
Riddle Hsu0a343c32018-12-21 00:40:48 +0800468 // Initialize different bounds on a new display.
469 final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
Riddle Hsu04164182019-03-07 18:03:27 +0800470 newDisplay.getWindowConfiguration().setAppBounds(new Rect(0, 0, 1000, 2000));
Riddle Hsu0a343c32018-12-21 00:40:48 +0800471 newDisplay.getConfiguration().densityDpi = 300;
472
Riddle Hsu0a343c32018-12-21 00:40:48 +0800473 mTask.getConfiguration().densityDpi = 200;
Riddle Hsuaec55442019-03-12 17:25:35 +0800474 prepareFixedAspectRatioUnresizableActivity();
475
Riddle Hsu0a343c32018-12-21 00:40:48 +0800476 final Rect originalBounds = new Rect(mActivity.getBounds());
477 final int originalDpi = mActivity.getConfiguration().densityDpi;
478
479 // Move the non-resizable activity to the new display.
480 mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */);
481 ensureActivityConfiguration();
482
483 assertEquals(originalBounds, mActivity.getBounds());
484 assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
Riddle Hsuaec55442019-03-12 17:25:35 +0800485 assertTrue(mActivity.inSizeCompatMode());
Riddle Hsu0a343c32018-12-21 00:40:48 +0800486 }
487
488 @Test
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800489 public void testSizeCompatMode_FixedScreenBoundsWhenDisplaySizeChanged() {
Riddle Hsu0a343c32018-12-21 00:40:48 +0800490 when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
Riddle Hsuaec55442019-03-12 17:25:35 +0800491 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Riddle Hsu0a343c32018-12-21 00:40:48 +0800492 mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
Riddle Hsuaec55442019-03-12 17:25:35 +0800493 mTask.getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
494 mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
Riddle Hsu0a343c32018-12-21 00:40:48 +0800495 mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
496 ensureActivityConfiguration();
497 final Rect originalBounds = new Rect(mActivity.getBounds());
498
499 // Change the size of current display.
500 mStack.getDisplay().setBounds(0, 0, 1000, 2000);
501 ensureActivityConfiguration();
502
503 assertEquals(originalBounds, mActivity.getBounds());
Riddle Hsuaec55442019-03-12 17:25:35 +0800504 assertTrue(mActivity.inSizeCompatMode());
Riddle Hsu0a343c32018-12-21 00:40:48 +0800505 }
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800506
507 @Test
508 public void testSizeCompatMode_FixedScreenLayoutSizeBits() {
509 final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO
510 | Configuration.SCREENLAYOUT_SIZE_NORMAL;
511 mTask.getConfiguration().screenLayout = fixedScreenLayout
512 | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR;
Riddle Hsuaec55442019-03-12 17:25:35 +0800513 prepareFixedAspectRatioUnresizableActivity();
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800514
515 // The initial configuration should inherit from parent.
516 assertEquals(mTask.getConfiguration().screenLayout,
517 mActivity.getConfiguration().screenLayout);
518
519 mTask.getConfiguration().screenLayout = Configuration.SCREENLAYOUT_LAYOUTDIR_RTL
520 | Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_LARGE;
521 mActivity.onConfigurationChanged(mTask.getConfiguration());
522
523 // The size and aspect ratio bits don't change, but the layout direction should be updated.
524 assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_RTL,
525 mActivity.getConfiguration().screenLayout);
526 }
Riddle Hsuaec55442019-03-12 17:25:35 +0800527
528 @Test
529 public void testSizeCompatMode_ResetNonVisibleActivity() {
530 final ActivityDisplay display = mStack.getDisplay();
531 spyOn(display);
532
533 prepareFixedAspectRatioUnresizableActivity();
534 mActivity.setState(STOPPED, "testSizeCompatMode");
535 mActivity.visible = false;
536 mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
537 // Make the parent bounds to be different so the activity is in size compatibility mode.
538 mTask.getWindowConfiguration().setAppBounds(new Rect(0, 0, 600, 1200));
539
540 // Simulate the display changes orientation.
541 doReturn(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION
542 | ActivityInfo.CONFIG_WINDOW_CONFIGURATION)
543 .when(display).getLastOverrideConfigurationChanges();
544 mActivity.onConfigurationChanged(mTask.getConfiguration());
545 // The override configuration should not change so it is still in size compatibility mode.
546 assertTrue(mActivity.inSizeCompatMode());
547
548 // Simulate the display changes density.
549 doReturn(ActivityInfo.CONFIG_DENSITY).when(display).getLastOverrideConfigurationChanges();
550 mService.mAmInternal = mock(ActivityManagerInternal.class);
551 mActivity.onConfigurationChanged(mTask.getConfiguration());
552 // The override configuration should be reset and the activity's process will be killed.
553 assertFalse(mActivity.inSizeCompatMode());
554 verify(mActivity).restartProcessIfVisible();
555 mService.mH.runWithScissors(() -> { }, TimeUnit.SECONDS.toMillis(3));
556 verify(mService.mAmInternal).killProcess(
557 eq(mActivity.app.mName), eq(mActivity.app.mUid), anyString());
558 }
559
560 /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
561 private void prepareFixedAspectRatioUnresizableActivity() {
562 when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
563 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
564 mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
565 mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
566 mActivity.info.maxAspectRatio = 1.5f;
567 ensureActivityConfiguration();
568 }
Bryce Leeaf691c02017-03-20 14:20:22 -0700569}