blob: dc8b8857eb0e9c73d08f7da60172c359e29e7d03 [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;
Riddle Hsu74826262019-04-17 14:57:42 +080020import static android.view.Surface.ROTATION_0;
21import static android.view.Surface.ROTATION_90;
Bryce Lee0bd8d422018-01-09 09:45:57 -080022
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090023import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
Garfield Tan36a69ad2019-01-16 17:08:23 -080024import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090025import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
Riddle Hsu7b766fd2019-01-28 21:14:59 +080026import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
Garfield Tan0443b372019-01-04 15:00:13 -080027import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
Garfield Tan36a69ad2019-01-16 17:08:23 -080028import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
Garfield Tan0443b372019-01-04 15:00:13 -080029import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080030import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
Garfield Tan0443b372019-01-04 15:00:13 -080031import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090032import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
Wale Ogunwale59507092018-10-29 09:00:30 -070033import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
34import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
Andrii Kulian6b321512019-01-23 06:37:00 +000035import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
Wale Ogunwale59507092018-10-29 09:00:30 -070036import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
37import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080038import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
39import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
40import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
Adrian Roose99bc052017-11-20 17:55:31 +010041
Bryce Lee04ab3462017-04-10 15:06:33 -070042import static org.junit.Assert.assertEquals;
Bryce Lee1533b2b2017-09-14 17:06:41 -070043import static org.junit.Assert.assertFalse;
Riddle Hsu7b766fd2019-01-28 21:14:59 +080044import static org.junit.Assert.assertNotEquals;
Yunfan Chen1ee84ea2018-11-13 16:03:37 -080045import static org.junit.Assert.assertNotNull;
Bryce Lee04ab3462017-04-10 15:06:33 -070046import static org.junit.Assert.assertNull;
Bryce Lee1533b2b2017-09-14 17:06:41 -070047import static org.junit.Assert.assertTrue;
Riddle Hsuaec55442019-03-12 17:25:35 +080048import static org.mockito.ArgumentMatchers.anyString;
chaviw82a0ba82018-03-15 14:26:29 -070049
Riddle Hsuaec55442019-03-12 17:25:35 +080050import android.app.ActivityManager;
51import android.app.ActivityManagerInternal;
chaviw82a0ba82018-03-15 14:26:29 -070052import android.app.ActivityOptions;
Garfield Tan36a69ad2019-01-16 17:08:23 -080053import android.app.servertransaction.ActivityConfigurationChangeItem;
Bryce Lee0bd8d422018-01-09 09:45:57 -080054import android.app.servertransaction.ClientTransaction;
55import android.app.servertransaction.PauseActivityItem;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080056import android.content.pm.ActivityInfo;
Garfield Tan0443b372019-01-04 15:00:13 -080057import android.content.res.Configuration;
Andrii Kulian3a1619d2017-07-07 14:38:09 -070058import android.graphics.Rect;
Bryce Leeaf691c02017-03-20 14:20:22 -070059import android.platform.test.annotations.Presubmit;
Garfield Tanf6cc5c92019-01-15 13:54:12 -080060import android.util.MergedConfiguration;
Andrii Kulian04470682018-01-10 15:32:31 -080061import android.util.MutableBoolean;
Bryce Leeaf691c02017-03-20 14:20:22 -070062
Brett Chabota26eda92018-07-23 13:08:30 -070063import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070064
Riddle Hsu74826262019-04-17 14:57:42 +080065import com.android.server.wm.utils.WmDisplayCutout;
66
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070067import org.junit.Before;
Bryce Leeaf691c02017-03-20 14:20:22 -070068import org.junit.Test;
Andrii Kulian04470682018-01-10 15:32:31 -080069import org.mockito.invocation.InvocationOnMock;
Bryce Lee0bd8d422018-01-09 09:45:57 -080070
Riddle Hsuaec55442019-03-12 17:25:35 +080071import java.util.concurrent.TimeUnit;
72
Bryce Leeaf691c02017-03-20 14:20:22 -070073/**
74 * Tests for the {@link ActivityRecord} class.
75 *
76 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090077 * atest WmTests:ActivityRecordTests
Bryce Leeaf691c02017-03-20 14:20:22 -070078 */
79@MediumTest
Bryce Lee3115bdf2017-04-05 08:39:40 -070080@Presubmit
Bryce Leeaf691c02017-03-20 14:20:22 -070081public class ActivityRecordTests extends ActivityTestsBase {
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -070082 private TestActivityStack mStack;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070083 private TaskRecord mTask;
84 private ActivityRecord mActivity;
85
86 @Before
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070087 public void setUp() throws Exception {
Yunfan Chen279f5582018-12-12 15:24:50 -080088 mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
Louis Changf2835df2018-10-17 15:14:45 +080089 mTask = mStack.getChildAt(0);
90 mActivity = mTask.getTopActivity();
Andrii Kulian6b321512019-01-23 06:37:00 +000091
92 doReturn(false).when(mService).isBooting();
93 doReturn(true).when(mService).isBooted();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070094 }
95
Bryce Leeaf691c02017-03-20 14:20:22 -070096 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090097 public void testStackCleanupOnClearingTask() {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070098 mActivity.setTask(null);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -070099 assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
Bryce Leeaf691c02017-03-20 14:20:22 -0700100 }
101
102 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900103 public void testStackCleanupOnActivityRemoval() {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700104 mTask.removeActivity(mActivity);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700105 assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 1);
Bryce Leeaf691c02017-03-20 14:20:22 -0700106 }
107
108 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900109 public void testStackCleanupOnTaskRemoval() {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700110 mStack.removeTask(mTask, null /*reason*/, REMOVE_TASK_MODE_MOVING);
Bryce Lee04ab3462017-04-10 15:06:33 -0700111 // Stack should be gone on task removal.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800112 assertNull(mService.mRootActivityContainer.getStack(mStack.mStackId));
Bryce Leeaf691c02017-03-20 14:20:22 -0700113 }
114
115 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900116 public void testNoCleanupMovingActivityInSameStack() {
Bryce Lee18d51592017-10-25 10:22:19 -0700117 final TaskRecord newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
118 .build();
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700119 mActivity.reparent(newTask, 0, null /*reason*/);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700120 assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 0);
Bryce Leeaf691c02017-03-20 14:20:22 -0700121 }
Andrii Kulian3a1619d2017-07-07 14:38:09 -0700122
Andreas Gampecea9e6d2018-02-22 18:06:44 -0800123 @Test
Bryce Lee0bd8d422018-01-09 09:45:57 -0800124 public void testPausingWhenVisibleFromStopped() throws Exception {
Andrii Kulian04470682018-01-10 15:32:31 -0800125 final MutableBoolean pauseFound = new MutableBoolean(false);
126 doAnswer((InvocationOnMock invocationOnMock) -> {
127 final ClientTransaction transaction = invocationOnMock.getArgument(0);
128 if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) {
129 pauseFound.value = true;
Bryce Lee0bd8d422018-01-09 09:45:57 -0800130 }
Andrii Kulian04470682018-01-10 15:32:31 -0800131 return null;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700132 }).when(mActivity.app.getThread()).scheduleTransaction(any());
Bryce Leed939cf02018-03-12 09:04:44 -0700133
Bryce Lee7ace3952018-02-16 14:34:32 -0800134 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
Bryce Lee0bd8d422018-01-09 09:45:57 -0800135
Andrii Kulian6b321512019-01-23 06:37:00 +0000136 // The activity is in the focused stack so it should be resumed.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700137 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Andrii Kulian6b321512019-01-23 06:37:00 +0000138 assertTrue(mActivity.isState(RESUMED));
Bryce Leed939cf02018-03-12 09:04:44 -0700139 assertFalse(pauseFound.value);
Andrii Kulian04470682018-01-10 15:32:31 -0800140
Andrii Kulian6b321512019-01-23 06:37:00 +0000141 // Make the activity non focusable
142 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
143 doReturn(false).when(mActivity).isFocusable();
Bryce Leed939cf02018-03-12 09:04:44 -0700144
Andrii Kulian6b321512019-01-23 06:37:00 +0000145 // If the activity is not focusable, it should move to paused.
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700146 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee7ace3952018-02-16 14:34:32 -0800147 assertTrue(mActivity.isState(PAUSING));
Andrii Kulian04470682018-01-10 15:32:31 -0800148 assertTrue(pauseFound.value);
Bryce Lee052957b2018-01-16 11:13:30 -0800149
150 // Make sure that the state does not change for current non-stopping states.
Bryce Lee7ace3952018-02-16 14:34:32 -0800151 mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
Andrii Kulian6b321512019-01-23 06:37:00 +0000152 doReturn(true).when(mActivity).isFocusable();
Bryce Lee052957b2018-01-16 11:13:30 -0800153
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700154 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Lee052957b2018-01-16 11:13:30 -0800155
Bryce Lee7ace3952018-02-16 14:34:32 -0800156 assertTrue(mActivity.isState(INITIALIZING));
Bryce Leea0fb8e02018-02-28 14:21:07 -0800157
158 // Make sure the state does not change if we are not the current top activity.
159 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind");
160
161 // Make sure that the state does not change when we have an activity becoming translucent
162 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
163 mStack.mTranslucentActivityWaiting = topActivity;
Andrii Kuliana39ae3e2018-05-31 12:43:54 -0700164 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
Bryce Leea0fb8e02018-02-28 14:21:07 -0800165
166 assertTrue(mActivity.isState(STOPPED));
Bryce Lee0bd8d422018-01-09 09:45:57 -0800167 }
168
Riddle Hsu0a343c32018-12-21 00:40:48 +0800169 private void ensureActivityConfiguration() {
170 mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
171 }
172
Bryce Lee1533b2b2017-09-14 17:06:41 -0700173 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900174 public void testCanBeLaunchedOnDisplay() {
Riddle Hsu16567132018-08-16 21:37:47 +0800175 mService.mSupportsMultiWindow = true;
176 final ActivityRecord activity = new ActivityBuilder(mService).build();
Bryce Lee1533b2b2017-09-14 17:06:41 -0700177
Riddle Hsu16567132018-08-16 21:37:47 +0800178 // An activity can be launched on default display.
179 assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY));
180 // An activity cannot be launched on a non-existent display.
181 assertFalse(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY + 1));
Bryce Lee1533b2b2017-09-14 17:06:41 -0700182 }
183
chaviw82a0ba82018-03-15 14:26:29 -0700184 @Test
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800185 public void testRestartProcessIfVisible() {
186 doNothing().when(mSupervisor).scheduleRestartTimeout(mActivity);
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800187 mActivity.visible = true;
188 mActivity.haveState = false;
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800189 mActivity.setState(ActivityStack.ActivityState.RESUMED, "testRestart");
Riddle Hsuaec55442019-03-12 17:25:35 +0800190 prepareFixedAspectRatioUnresizableActivity();
191
Riddle Hsu04164182019-03-07 18:03:27 +0800192 final Rect originalOverrideBounds = new Rect(mActivity.getBounds());
Riddle Hsu74826262019-04-17 14:57:42 +0800193 setupDisplayAndParentSize(600, 1200);
Riddle Hsu04164182019-03-07 18:03:27 +0800194 // The visible activity should recompute configuration according to the last parent bounds.
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800195 mService.restartActivityProcessIfVisible(mActivity.appToken);
196
197 assertEquals(ActivityStack.ActivityState.RESTARTING_PROCESS, mActivity.getState());
198 assertNotEquals(originalOverrideBounds, mActivity.getBounds());
199 }
200
201 @Test
chaviw82a0ba82018-03-15 14:26:29 -0700202 public void testsApplyOptionsLocked() {
203 ActivityOptions activityOptions = ActivityOptions.makeBasic();
204
205 // Set and apply options for ActivityRecord. Pending options should be cleared
206 mActivity.updateOptionsLocked(activityOptions);
207 mActivity.applyOptionsLocked();
208 assertNull(mActivity.pendingOptions);
209
210 // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options.
211 // Pending options should be cleared for both ActivityRecords
212 ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build();
213 activity2.updateOptionsLocked(activityOptions);
214 mActivity.updateOptionsLocked(activityOptions);
215 mActivity.applyOptionsLocked();
216 assertNull(mActivity.pendingOptions);
217 assertNull(activity2.pendingOptions);
218
219 // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
220 // Pending options should be cleared for only ActivityRecord that was applied
221 TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
222 activity2 = new ActivityBuilder(mService).setTask(task2).build();
223 activity2.updateOptionsLocked(activityOptions);
224 mActivity.updateOptionsLocked(activityOptions);
225 mActivity.applyOptionsLocked();
226 assertNull(mActivity.pendingOptions);
227 assertNotNull(activity2.pendingOptions);
228 }
Garfield Tan0443b372019-01-04 15:00:13 -0800229
230 @Test
231 public void testNewOverrideConfigurationIncrementsSeq() {
232 final Configuration newConfig = new Configuration();
233
234 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
235 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
236 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
237 }
238
239 @Test
240 public void testNewParentConfigurationIncrementsSeq() {
241 final Configuration newConfig = new Configuration(
242 mTask.getRequestedOverrideConfiguration());
243 newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
244 ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
245
246 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
247 mTask.onRequestedOverrideConfigurationChanged(newConfig);
248 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq);
249 }
250
251 @Test
252 public void testNotifiesSeqIncrementToAppToken() {
253 final Configuration appWindowTokenRequestedOrientation = mock(Configuration.class);
254 mActivity.mAppWindowToken = mock(AppWindowToken.class);
255 doReturn(appWindowTokenRequestedOrientation).when(mActivity.mAppWindowToken)
256 .getRequestedOverrideConfiguration();
257
258 final Configuration newConfig = new Configuration();
259 newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
260
261 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq;
262 mActivity.onRequestedOverrideConfigurationChanged(newConfig);
263 assertEquals(prevSeq + 1, appWindowTokenRequestedOrientation.seq);
264 verify(mActivity.mAppWindowToken).onMergedOverrideConfigurationChanged();
265 }
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800266
267 @Test
268 public void testSetsRelaunchReason_NotDragResizing() {
269 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
270
271 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
272 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
273 mActivity.getConfiguration()));
274
275 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
276 final Configuration newConfig = new Configuration(mTask.getConfiguration());
277 newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
278 ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
279 mTask.onRequestedOverrideConfigurationChanged(newConfig);
280
281 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
282
Riddle Hsu0a343c32018-12-21 00:40:48 +0800283 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800284
285 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE,
286 mActivity.mRelaunchReason);
287 }
288
289 @Test
290 public void testSetsRelaunchReason_DragResizing() {
291 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
292
293 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
294 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
295 mActivity.getConfiguration()));
296
297 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_ORIENTATION;
298 final Configuration newConfig = new Configuration(mTask.getConfiguration());
299 newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
300 ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT;
301 mTask.onRequestedOverrideConfigurationChanged(newConfig);
302
303 doReturn(true).when(mTask.getTask()).isDragResizing();
304
305 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE;
306
Riddle Hsu0a343c32018-12-21 00:40:48 +0800307 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800308
309 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE,
310 mActivity.mRelaunchReason);
311 }
312
313 @Test
314 public void testSetsRelaunchReason_NonResizeConfigChanges() {
315 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
316
317 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
318 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
319 mActivity.getConfiguration()));
320
321 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE;
322 final Configuration newConfig = new Configuration(mTask.getConfiguration());
323 newConfig.fontScale = 5;
324 mTask.onRequestedOverrideConfigurationChanged(newConfig);
325
326 mActivity.mRelaunchReason =
327 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
328
Riddle Hsu0a343c32018-12-21 00:40:48 +0800329 ensureActivityConfiguration();
Garfield Tanf6cc5c92019-01-15 13:54:12 -0800330
331 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
332 mActivity.mRelaunchReason);
333 }
Garfield Tan36a69ad2019-01-16 17:08:23 -0800334
335 @Test
336 public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
337 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
338
339 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
340 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
341 mActivity.getConfiguration()));
342
343 mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
344 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
345 newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
346 ? Configuration.ORIENTATION_LANDSCAPE
347 : Configuration.ORIENTATION_PORTRAIT;
348
349 // Mimic the behavior that display doesn't handle app's requested orientation.
350 doAnswer(invocation -> {
351 mTask.onConfigurationChanged(newConfig);
352 return null;
353 }).when(mActivity.mAppWindowToken).setOrientation(anyInt(), any(), any());
354
355 final int requestedOrientation;
356 switch (newConfig.orientation) {
357 case Configuration.ORIENTATION_LANDSCAPE:
358 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
359 break;
360 case Configuration.ORIENTATION_PORTRAIT:
361 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
362 break;
363 default:
364 throw new IllegalStateException("Orientation in new config should be either"
365 + "landscape or portrait.");
366 }
367 mActivity.setRequestedOrientation(requestedOrientation);
368
369 final ActivityConfigurationChangeItem expected =
370 ActivityConfigurationChangeItem.obtain(newConfig);
371 verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
372 eq(mActivity.appToken), eq(expected));
373 }
Andrii Kulianf2195362019-01-31 18:20:11 -0800374
375 @Test
376 public void testShouldMakeActive_deferredResume() {
377 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
378
379 mSupervisor.beginDeferResume();
380 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */));
381
382 mSupervisor.endDeferResume();
383 assertEquals(true, mActivity.shouldMakeActive(null /* activeActivity */));
384 }
Garfield Tan40263302019-02-01 15:27:35 -0800385
386 @Test
Andrii Kulian0c869cc2019-02-06 19:50:32 -0800387 public void testShouldResume_stackVisibility() {
388 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
389 spyOn(mStack);
390
391 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
392 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
393
394 doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
395 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
396
397 doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
398 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
399 }
400
401 @Test
Garfield Tan40263302019-02-01 15:27:35 -0800402 public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
403 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
404
405 final TestActivityStack stack = (TestActivityStack) new StackBuilder(mRootActivityContainer)
406 .build();
407 try {
408 stack.setIsTranslucent(false);
409 assertFalse(mStack.shouldBeVisible(null /* starting */));
410
411 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
412 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
413 mActivity.getConfiguration()));
414
415 mActivity.mLaunchTaskBehind = true;
416 mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
417 final Configuration newConfig = new Configuration(mActivity.getConfiguration());
418 newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
419 ? Configuration.ORIENTATION_LANDSCAPE
420 : Configuration.ORIENTATION_PORTRAIT;
421
422 mTask.onConfigurationChanged(newConfig);
423
424 mActivity.ensureActivityConfiguration(0 /* globalChanges */,
425 false /* preserveWindow */, true /* ignoreStopState */);
426
427 final ActivityConfigurationChangeItem expected =
428 ActivityConfigurationChangeItem.obtain(newConfig);
429 verify(mService.getLifecycleManager()).scheduleTransaction(
430 eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected));
431 } finally {
432 stack.getDisplay().removeChild(stack);
433 }
434 }
Riddle Hsu0a343c32018-12-21 00:40:48 +0800435
436 @Test
Riddle Hsu04164182019-03-07 18:03:27 +0800437 public void testSizeCompatMode_FixedAspectRatioBoundsWithDecor() {
Riddle Hsu74826262019-04-17 14:57:42 +0800438 setupDisplayContentForCompatDisplayInsets();
Riddle Hsu04164182019-03-07 18:03:27 +0800439 final int decorHeight = 200; // e.g. The device has cutout.
Riddle Hsu74826262019-04-17 14:57:42 +0800440 final DisplayPolicy policy = setupDisplayAndParentSize(600, 800).getDisplayPolicy();
441 doAnswer(invocationOnMock -> {
442 final int rotation = invocationOnMock.<Integer>getArgument(0);
443 final Rect insets = invocationOnMock.<Rect>getArgument(4);
444 if (rotation == ROTATION_0) {
445 insets.top = decorHeight;
446 } else if (rotation == ROTATION_90) {
447 insets.left = decorHeight;
448 }
449 return null;
450 }).when(policy).getNonDecorInsetsLw(anyInt() /* rotation */, anyInt() /* width */,
451 anyInt() /* height */, any() /* displayCutout */, any() /* outInsets */);
452
Riddle Hsu04164182019-03-07 18:03:27 +0800453 doReturn(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)
454 .when(mActivity.mAppWindowToken).getOrientationIgnoreVisibility();
455 mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
Riddle Hsu9ad1785102019-03-26 00:26:54 +0800456 mActivity.info.minAspectRatio = mActivity.info.maxAspectRatio = 1;
Riddle Hsu04164182019-03-07 18:03:27 +0800457 ensureActivityConfiguration();
Riddle Hsu9ad1785102019-03-26 00:26:54 +0800458 // The parent configuration doesn't change since the first resolved configuration, so the
459 // activity shouldn't be in the size compatibility mode.
460 assertFalse(mActivity.inSizeCompatMode());
Riddle Hsu04164182019-03-07 18:03:27 +0800461
462 final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
463 // Ensure the app bounds keep the declared aspect ratio.
464 assertEquals(appBounds.width(), appBounds.height());
465 // The decor height should be a part of the effective bounds.
466 assertEquals(mActivity.getBounds().height(), appBounds.height() + decorHeight);
467
Riddle Hsu74826262019-04-17 14:57:42 +0800468 mTask.getConfiguration().windowConfiguration.setRotation(ROTATION_90);
Riddle Hsu04164182019-03-07 18:03:27 +0800469 mActivity.onConfigurationChanged(mTask.getConfiguration());
470 // After changing orientation, the aspect ratio should be the same.
471 assertEquals(appBounds.width(), appBounds.height());
472 // The decor height will be included in width.
473 assertEquals(mActivity.getBounds().width(), appBounds.width() + decorHeight);
474 }
475
476 @Test
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800477 public void testSizeCompatMode_FixedScreenConfigurationWhenMovingToDisplay() {
Riddle Hsu0a343c32018-12-21 00:40:48 +0800478 // Initialize different bounds on a new display.
479 final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
Riddle Hsu04164182019-03-07 18:03:27 +0800480 newDisplay.getWindowConfiguration().setAppBounds(new Rect(0, 0, 1000, 2000));
Riddle Hsu0a343c32018-12-21 00:40:48 +0800481 newDisplay.getConfiguration().densityDpi = 300;
482
Riddle Hsu0a343c32018-12-21 00:40:48 +0800483 mTask.getConfiguration().densityDpi = 200;
Riddle Hsuaec55442019-03-12 17:25:35 +0800484 prepareFixedAspectRatioUnresizableActivity();
485
Riddle Hsu0a343c32018-12-21 00:40:48 +0800486 final Rect originalBounds = new Rect(mActivity.getBounds());
487 final int originalDpi = mActivity.getConfiguration().densityDpi;
488
489 // Move the non-resizable activity to the new display.
490 mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */);
491 ensureActivityConfiguration();
492
493 assertEquals(originalBounds, mActivity.getBounds());
494 assertEquals(originalDpi, mActivity.getConfiguration().densityDpi);
Riddle Hsuaec55442019-03-12 17:25:35 +0800495 assertTrue(mActivity.inSizeCompatMode());
Riddle Hsu0a343c32018-12-21 00:40:48 +0800496 }
497
498 @Test
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800499 public void testSizeCompatMode_FixedScreenBoundsWhenDisplaySizeChanged() {
Riddle Hsu74826262019-04-17 14:57:42 +0800500 setupDisplayContentForCompatDisplayInsets();
Riddle Hsu0a343c32018-12-21 00:40:48 +0800501 when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
Riddle Hsuaec55442019-03-12 17:25:35 +0800502 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Riddle Hsu0a343c32018-12-21 00:40:48 +0800503 mTask.getWindowConfiguration().setAppBounds(mStack.getDisplay().getBounds());
Riddle Hsuaec55442019-03-12 17:25:35 +0800504 mTask.getConfiguration().orientation = Configuration.ORIENTATION_PORTRAIT;
505 mActivity.info.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
Riddle Hsu0a343c32018-12-21 00:40:48 +0800506 mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
507 ensureActivityConfiguration();
508 final Rect originalBounds = new Rect(mActivity.getBounds());
509
510 // Change the size of current display.
Riddle Hsu74826262019-04-17 14:57:42 +0800511 setupDisplayAndParentSize(1000, 2000);
Riddle Hsu0a343c32018-12-21 00:40:48 +0800512 ensureActivityConfiguration();
513
514 assertEquals(originalBounds, mActivity.getBounds());
Riddle Hsuaec55442019-03-12 17:25:35 +0800515 assertTrue(mActivity.inSizeCompatMode());
Riddle Hsu0a343c32018-12-21 00:40:48 +0800516 }
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800517
518 @Test
519 public void testSizeCompatMode_FixedScreenLayoutSizeBits() {
520 final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO
521 | Configuration.SCREENLAYOUT_SIZE_NORMAL;
522 mTask.getConfiguration().screenLayout = fixedScreenLayout
523 | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR;
Riddle Hsuaec55442019-03-12 17:25:35 +0800524 prepareFixedAspectRatioUnresizableActivity();
Riddle Hsu2560c3b2019-02-23 23:45:58 +0800525
526 // The initial configuration should inherit from parent.
527 assertEquals(mTask.getConfiguration().screenLayout,
528 mActivity.getConfiguration().screenLayout);
529
530 mTask.getConfiguration().screenLayout = Configuration.SCREENLAYOUT_LAYOUTDIR_RTL
531 | Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_LARGE;
532 mActivity.onConfigurationChanged(mTask.getConfiguration());
533
534 // The size and aspect ratio bits don't change, but the layout direction should be updated.
535 assertEquals(fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_RTL,
536 mActivity.getConfiguration().screenLayout);
537 }
Riddle Hsuaec55442019-03-12 17:25:35 +0800538
539 @Test
540 public void testSizeCompatMode_ResetNonVisibleActivity() {
541 final ActivityDisplay display = mStack.getDisplay();
542 spyOn(display);
543
544 prepareFixedAspectRatioUnresizableActivity();
545 mActivity.setState(STOPPED, "testSizeCompatMode");
546 mActivity.visible = false;
547 mActivity.app.setReportedProcState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY);
548 // Make the parent bounds to be different so the activity is in size compatibility mode.
549 mTask.getWindowConfiguration().setAppBounds(new Rect(0, 0, 600, 1200));
550
551 // Simulate the display changes orientation.
552 doReturn(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION
553 | ActivityInfo.CONFIG_WINDOW_CONFIGURATION)
554 .when(display).getLastOverrideConfigurationChanges();
555 mActivity.onConfigurationChanged(mTask.getConfiguration());
556 // The override configuration should not change so it is still in size compatibility mode.
557 assertTrue(mActivity.inSizeCompatMode());
558
559 // Simulate the display changes density.
560 doReturn(ActivityInfo.CONFIG_DENSITY).when(display).getLastOverrideConfigurationChanges();
561 mService.mAmInternal = mock(ActivityManagerInternal.class);
562 mActivity.onConfigurationChanged(mTask.getConfiguration());
563 // The override configuration should be reset and the activity's process will be killed.
564 assertFalse(mActivity.inSizeCompatMode());
565 verify(mActivity).restartProcessIfVisible();
566 mService.mH.runWithScissors(() -> { }, TimeUnit.SECONDS.toMillis(3));
567 verify(mService.mAmInternal).killProcess(
568 eq(mActivity.app.mName), eq(mActivity.app.mUid), anyString());
569 }
570
571 /** Setup {@link #mActivity} as a size-compat-mode-able activity without fixed orientation. */
572 private void prepareFixedAspectRatioUnresizableActivity() {
Riddle Hsu74826262019-04-17 14:57:42 +0800573 setupDisplayContentForCompatDisplayInsets();
Riddle Hsuaec55442019-03-12 17:25:35 +0800574 when(mActivity.mAppWindowToken.getOrientationIgnoreVisibility()).thenReturn(
575 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
Riddle Hsuaec55442019-03-12 17:25:35 +0800576 mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
577 mActivity.info.maxAspectRatio = 1.5f;
578 ensureActivityConfiguration();
579 }
Riddle Hsu74826262019-04-17 14:57:42 +0800580
581 private void setupDisplayContentForCompatDisplayInsets() {
582 final Rect displayBounds = mStack.getDisplay().getBounds();
583 final DisplayContent displayContent = setupDisplayAndParentSize(
584 displayBounds.width(), displayBounds.height());
585 doReturn(mock(DisplayPolicy.class)).when(displayContent).getDisplayPolicy();
586 doReturn(mock(WmDisplayCutout.class)).when(displayContent)
587 .calculateDisplayCutoutForRotation(anyInt());
588 }
589
590 private DisplayContent setupDisplayAndParentSize(int width, int height) {
591 // The DisplayContent is already a mocked object.
592 final DisplayContent displayContent = mStack.getDisplay().mDisplayContent;
593 displayContent.mBaseDisplayWidth = width;
594 displayContent.mBaseDisplayHeight = height;
595 mTask.getWindowConfiguration().setAppBounds(0, 0, width, height);
596 mTask.getWindowConfiguration().setRotation(ROTATION_0);
597 return displayContent;
598 }
Bryce Leeaf691c02017-03-20 14:20:22 -0700599}