blob: 56f4a8544f007bec249eb3c95c168be251d0a60d [file] [log] [blame]
Riddle Hsu75016992018-09-20 20:37:14 +08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
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
Riddle Hsu75016992018-09-20 20:37:14 +080015 */
16
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Riddle Hsu75016992018-09-20 20:37:14 +080018
Riddle Hsu402b4402018-11-06 17:23:15 +080019import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
Riddle Hsu75016992018-09-20 20:37:14 +080020import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
Evan Roskyc5abbd82018-10-05 16:02:19 -070021import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
Riddle Hsu75016992018-09-20 20:37:14 +080022import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
24import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
Riddle Hsue10cea52018-10-16 23:33:23 +080025import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
Riddle Hsu75016992018-09-20 20:37:14 +080026
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090027import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
28import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
29import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
30import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
31import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Wale Ogunwale59507092018-10-29 09:00:30 -070032import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
Riddle Hsu75016992018-09-20 20:37:14 +080033
Riddle Hsubbb63c22018-10-03 12:28:29 +080034import static org.junit.Assert.assertEquals;
Evan Roskyc5abbd82018-10-05 16:02:19 -070035import static org.junit.Assert.assertFalse;
Riddle Hsue10cea52018-10-16 23:33:23 +080036import static org.junit.Assert.assertNull;
Riddle Hsu75016992018-09-20 20:37:14 +080037import static org.junit.Assert.assertTrue;
Riddle Hsu402b4402018-11-06 17:23:15 +080038import static org.mockito.ArgumentMatchers.any;
Louis Changf787e532019-01-15 12:46:49 +080039import static org.mockito.ArgumentMatchers.anyBoolean;
40import static org.mockito.ArgumentMatchers.eq;
41import static org.mockito.Mockito.doAnswer;
Riddle Hsu75016992018-09-20 20:37:14 +080042
43import android.platform.test.annotations.Presubmit;
Wale Ogunwale38f72bd2018-11-20 02:53:49 +000044
Riddle Hsu75016992018-09-20 20:37:14 +080045import androidx.test.filters.SmallTest;
Riddle Hsu75016992018-09-20 20:37:14 +080046
47import org.junit.Before;
48import org.junit.Test;
Riddle Hsu75016992018-09-20 20:37:14 +080049
50/**
51 * Tests for the {@link ActivityDisplay} class.
52 *
53 * Build/Install/Run:
54 * atest WmTests:ActivityDisplayTests
55 */
56@SmallTest
57@Presubmit
Riddle Hsu75016992018-09-20 20:37:14 +080058public class ActivityDisplayTests extends ActivityTestsBase {
59
Riddle Hsubbb63c22018-10-03 12:28:29 +080060 @Test
61 public void testLastFocusedStackIsUpdatedWhenMovingStack() {
62 // Create a stack at bottom.
Wale Ogunwaled32da472018-11-16 07:19:28 -080063 final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
64 final ActivityStack stack =
65 new StackBuilder(mRootActivityContainer).setOnTop(!ON_TOP).build();
Riddle Hsubbb63c22018-10-03 12:28:29 +080066 final ActivityStack prevFocusedStack = display.getFocusedStack();
67
68 stack.moveToFront("moveStackToFront");
69 // After moving the stack to front, the previous focused should be the last focused.
70 assertTrue(stack.isFocusedStackOnDisplay());
71 assertEquals(prevFocusedStack, display.getLastFocusedStack());
72
73 stack.moveToBack("moveStackToBack", null /* task */);
74 // After moving the stack to back, the stack should be the last focused.
75 assertEquals(stack, display.getLastFocusedStack());
76 }
77
Riddle Hsu75016992018-09-20 20:37:14 +080078 /**
79 * This test simulates the picture-in-picture menu activity launches an activity to fullscreen
80 * stack. The fullscreen stack should be the top focused for resuming correctly.
81 */
82 @Test
83 public void testFullscreenStackCanBeFocusedWhenFocusablePinnedStackExists() {
84 // Create a pinned stack and move to front.
Wale Ogunwaled32da472018-11-16 07:19:28 -080085 final ActivityStack pinnedStack = mRootActivityContainer.getDefaultDisplay().createStack(
Riddle Hsu75016992018-09-20 20:37:14 +080086 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
87 final TaskRecord pinnedTask = new TaskBuilder(mService.mStackSupervisor)
88 .setStack(pinnedStack).build();
89 new ActivityBuilder(mService).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
90 .setTask(pinnedTask).build();
91 pinnedStack.moveToFront("movePinnedStackToFront");
92
93 // The focused stack should be the pinned stack.
94 assertTrue(pinnedStack.isFocusedStackOnDisplay());
95
96 // Create a fullscreen stack and move to front.
97 final ActivityStack fullscreenStack = createFullscreenStackWithSimpleActivityAt(
Wale Ogunwaled32da472018-11-16 07:19:28 -080098 mRootActivityContainer.getDefaultDisplay());
Riddle Hsu75016992018-09-20 20:37:14 +080099 fullscreenStack.moveToFront("moveFullscreenStackToFront");
100
101 // The focused stack should be the fullscreen stack.
102 assertTrue(fullscreenStack.isFocusedStackOnDisplay());
103 }
104
105 /**
106 * Test {@link ActivityDisplay#mPreferredTopFocusableStack} will be cleared when the stack is
107 * removed or moved to back, and the focused stack will be according to z-order.
108 */
109 @Test
110 public void testStackShouldNotBeFocusedAfterMovingToBackOrRemoving() {
111 // Create a display which only contains 2 stacks.
112 final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
113 final ActivityStack stack1 = createFullscreenStackWithSimpleActivityAt(display);
114 final ActivityStack stack2 = createFullscreenStackWithSimpleActivityAt(display);
115
116 // Put stack1 and stack2 on top.
117 stack1.moveToFront("moveStack1ToFront");
118 stack2.moveToFront("moveStack2ToFront");
119 assertTrue(stack2.isFocusedStackOnDisplay());
120
121 // Stack1 should be focused after moving stack2 to back.
122 stack2.moveToBack("moveStack2ToBack", null /* task */);
123 assertTrue(stack1.isFocusedStackOnDisplay());
124
125 // Stack2 should be focused after removing stack1.
126 display.removeChild(stack1);
127 assertTrue(stack2.isFocusedStackOnDisplay());
128 }
129
Riddle Hsu402b4402018-11-06 17:23:15 +0800130 /**
131 * Verifies {@link ActivityDisplay#remove} should not resume home stack on the removing display.
132 */
133 @Test
134 public void testNotResumeHomeStackOnRemovingDisplay() {
135 // Create a display which supports system decoration and allows reparenting stacks to
136 // another display when the display is removed.
137 final ActivityDisplay display = spy(createNewActivityDisplay());
138 doReturn(false).when(display).shouldDestroyContentOnRemove();
139 doReturn(true).when(display).supportsSystemDecorations();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800140 mRootActivityContainer.addChild(display, ActivityDisplay.POSITION_TOP);
Riddle Hsu402b4402018-11-06 17:23:15 +0800141
142 // Put home stack on the display.
143 final ActivityStack homeStack = display.createStack(
144 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
145 final TaskRecord task = new TaskBuilder(mSupervisor).setStack(homeStack).build();
146 new ActivityBuilder(mService).setTask(task).build();
147 display.removeChild(homeStack);
148 final ActivityStack spiedHomeStack = spy(homeStack);
149 display.addChild(spiedHomeStack, ActivityDisplay.POSITION_TOP);
150 reset(spiedHomeStack);
151
152 // Put a finishing standard activity which will be reparented.
153 final ActivityStack stack = createFullscreenStackWithSimpleActivityAt(display);
154 stack.topRunningActivityLocked().makeFinishingLocked();
155
156 display.remove();
157
158 // The removed display should have no focused stack and its home stack should never resume.
159 assertNull(display.getFocusedStack());
160 verify(spiedHomeStack, never()).resumeTopActivityUncheckedLocked(any(), any());
161 }
162
Riddle Hsu75016992018-09-20 20:37:14 +0800163 private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) {
164 final ActivityStack fullscreenStack = display.createStack(
165 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
166 final TaskRecord fullscreenTask = new TaskBuilder(mService.mStackSupervisor)
167 .setStack(fullscreenStack).build();
168 new ActivityBuilder(mService).setTask(fullscreenTask).build();
169 return fullscreenStack;
170 }
Riddle Hsue10cea52018-10-16 23:33:23 +0800171
172 /**
173 * Verifies the correct activity is returned when querying the top running activity.
174 */
175 @Test
176 public void testTopRunningActivity() {
Wale Ogunwaled32da472018-11-16 07:19:28 -0800177 final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
Riddle Hsue10cea52018-10-16 23:33:23 +0800178 final KeyguardController keyguard = mSupervisor.getKeyguardController();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800179 final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
Louis Changf2835df2018-10-17 15:14:45 +0800180 final ActivityRecord activity = stack.getTopActivity();
181
182 // Create empty stack on top.
183 final ActivityStack emptyStack =
Wale Ogunwaled32da472018-11-16 07:19:28 -0800184 new StackBuilder(mRootActivityContainer).setCreateActivity(false).build();
Riddle Hsue10cea52018-10-16 23:33:23 +0800185
186 // Make sure the top running activity is not affected when keyguard is not locked.
187 assertTopRunningActivity(activity, display);
188
189 // Check to make sure activity not reported when it cannot show on lock and lock is on.
190 doReturn(true).when(keyguard).isKeyguardLocked();
191 assertEquals(activity, display.topRunningActivity());
192 assertNull(display.topRunningActivity(true /* considerKeyguardState */));
193
Louis Changf2835df2018-10-17 15:14:45 +0800194 // Move stack with activity to top.
195 stack.moveToFront("testStackToFront");
Riddle Hsue10cea52018-10-16 23:33:23 +0800196 assertEquals(stack, display.getFocusedStack());
197 assertEquals(activity, display.topRunningActivity());
198 assertNull(display.topRunningActivity(true /* considerKeyguardState */));
199
200 // Add activity that should be shown on the keyguard.
201 final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService)
202 .setCreateTask(true)
203 .setStack(stack)
204 .setActivityFlags(FLAG_SHOW_WHEN_LOCKED)
205 .build();
206
207 // Ensure the show when locked activity is returned.
208 assertTopRunningActivity(showWhenLockedActivity, display);
209
Louis Changf2835df2018-10-17 15:14:45 +0800210 // Move empty stack to front. The running activity in focusable stack which below the
211 // empty stack should be returned.
212 emptyStack.moveToFront("emptyStackToFront");
213 assertEquals(stack, display.getFocusedStack());
Riddle Hsue10cea52018-10-16 23:33:23 +0800214 assertTopRunningActivity(showWhenLockedActivity, display);
215 }
216
217 private static void assertTopRunningActivity(ActivityRecord top, ActivityDisplay display) {
218 assertEquals(top, display.topRunningActivity());
219 assertEquals(top, display.topRunningActivity(true /* considerKeyguardState */));
220 }
Evan Roskyc5abbd82018-10-05 16:02:19 -0700221
222 /**
223 * This test enforces that alwaysOnTop stack is placed at proper position.
224 */
225 @Test
226 public void testAlwaysOnTopStackLocation() {
Wale Ogunwaled32da472018-11-16 07:19:28 -0800227 final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
Evan Roskyc5abbd82018-10-05 16:02:19 -0700228 final ActivityStack alwaysOnTopStack = display.createStack(WINDOWING_MODE_FREEFORM,
229 ACTIVITY_TYPE_STANDARD, true /* onTop */);
230 final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
231 .setStack(alwaysOnTopStack).build();
232 alwaysOnTopStack.setAlwaysOnTop(true);
233 display.positionChildAtTop(alwaysOnTopStack, false /* includingParents */);
234 assertTrue(alwaysOnTopStack.isAlwaysOnTop());
235 // Ensure always on top state is synced to the children of the stack.
236 assertTrue(alwaysOnTopStack.getTopActivity().isAlwaysOnTop());
237 assertEquals(alwaysOnTopStack, display.getTopStack());
238
239 final ActivityStack pinnedStack = display.createStack(
240 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
241 assertEquals(pinnedStack, display.getPinnedStack());
242 assertEquals(pinnedStack, display.getTopStack());
243
244 final ActivityStack anotherAlwaysOnTopStack = display.createStack(
245 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
246 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
247 display.positionChildAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
248 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
249 int topPosition = display.getChildCount() - 1;
250 // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
251 // existing alwaysOnTop stack.
252 assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 1));
253
254 final ActivityStack nonAlwaysOnTopStack = display.createStack(
255 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
256 assertEquals(display, nonAlwaysOnTopStack.getDisplay());
257 topPosition = display.getChildCount() - 1;
258 // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
259 // existing other non-alwaysOnTop stacks.
260 assertEquals(nonAlwaysOnTopStack, display.getChildAt(topPosition - 3));
261
262 anotherAlwaysOnTopStack.setAlwaysOnTop(false);
263 display.positionChildAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
264 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
265 // Ensure, when always on top is turned off for a stack, the stack is put just below all
266 // other always on top stacks.
267 assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 2));
268 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
269
270 // Ensure always on top state changes properly when windowing mode changes.
271 anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
272 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
273 assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 2));
274 anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
275 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
276 assertEquals(anotherAlwaysOnTopStack, display.getChildAt(topPosition - 1));
277 }
Louis Changf787e532019-01-15 12:46:49 +0800278
279 @Test
280 public void testRemoveStackInWindowingModes() {
281 removeStackTests(() -> mRootActivityContainer.removeStacksInWindowingModes(
282 WINDOWING_MODE_FULLSCREEN));
283 }
284
285 @Test
286 public void testRemoveStackWithActivityTypes() {
287 removeStackTests(
288 () -> mRootActivityContainer.removeStacksWithActivityTypes(ACTIVITY_TYPE_STANDARD));
289 }
290
291 private void removeStackTests(Runnable runnable) {
292 final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
293 final ActivityStack stack1 = display.createStack(WINDOWING_MODE_FULLSCREEN,
294 ACTIVITY_TYPE_STANDARD, ON_TOP);
295 final ActivityStack stack2 = display.createStack(WINDOWING_MODE_FULLSCREEN,
296 ACTIVITY_TYPE_STANDARD, ON_TOP);
297 final ActivityStack stack3 = display.createStack(WINDOWING_MODE_FULLSCREEN,
298 ACTIVITY_TYPE_STANDARD, ON_TOP);
299 final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN,
300 ACTIVITY_TYPE_STANDARD, ON_TOP);
301 final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor).setStack(
302 stack1).setTaskId(1).build();
303 final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(
304 stack2).setTaskId(2).build();
305 final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor).setStack(
306 stack3).setTaskId(3).build();
307 final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor).setStack(
308 stack4).setTaskId(4).build();
309
310 // Reordering stacks while removing stacks.
311 doAnswer(invocation -> {
312 display.positionChildAtTop(stack3, false);
313 return true;
314 }).when(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
315 any());
316
317 // Removing stacks from the display while removing stacks.
318 doAnswer(invocation -> {
319 display.removeChild(stack2);
320 return true;
321 }).when(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
322 any());
323
324 runnable.run();
325 verify(mSupervisor).removeTaskByIdLocked(eq(task4.taskId), anyBoolean(), anyBoolean(),
326 any());
327 verify(mSupervisor).removeTaskByIdLocked(eq(task3.taskId), anyBoolean(), anyBoolean(),
328 any());
329 verify(mSupervisor).removeTaskByIdLocked(eq(task2.taskId), anyBoolean(), anyBoolean(),
330 any());
331 verify(mSupervisor).removeTaskByIdLocked(eq(task1.taskId), anyBoolean(), anyBoolean(),
332 any());
333 }
Riddle Hsu75016992018-09-20 20:37:14 +0800334}