blob: 898ff4a4133ac876b5833aab630c00376264e7ae [file] [log] [blame]
Wale Ogunwaleb783fd82016-11-04 09:51:54 -07001/*
2 * Copyright (C) 2016 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
14 * limitations under the License
15 */
16
17package com.android.server.wm;
18
Wale Ogunwale68278562017-09-23 17:13:55 -070019import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Andrii Kulian92c9a942017-10-10 00:41:41 -070021import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
22import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
23import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Wale Ogunwale34247952017-02-19 11:57:53 -080024import static android.view.Display.DEFAULT_DISPLAY;
Adrian Roos24264212018-02-19 16:26:15 +010025import static android.view.DisplayCutout.fromBoundingRect;
Wale Ogunwale34247952017-02-19 11:57:53 -080026import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
27import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
28import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
Andrii Kulian92c9a942017-10-10 00:41:41 -070029import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
Wale Ogunwale34247952017-02-19 11:57:53 -080030import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
David Stevens46939562017-03-24 13:04:00 -070031import static com.android.server.wm.WindowContainer.POSITION_TOP;
chaviwebcbc342018-02-07 13:19:00 -080032
Adrian Roos5251b1d2018-03-23 18:57:43 +010033import static org.hamcrest.Matchers.is;
Wale Ogunwale34247952017-02-19 11:57:53 -080034import static org.junit.Assert.assertEquals;
Andrii Kulianf0379de2018-03-14 16:24:07 -070035import static org.junit.Assert.assertFalse;
Adrian Roos5251b1d2018-03-23 18:57:43 +010036import static org.junit.Assert.assertThat;
Wale Ogunwale34247952017-02-19 11:57:53 -080037import static org.junit.Assert.assertTrue;
Riddle Hsu654a6f92018-07-13 22:59:36 +080038import static org.mockito.Mockito.doNothing;
39import static org.mockito.Mockito.spy;
Andrii Kulianf0379de2018-03-14 16:24:07 -070040import static org.mockito.Mockito.times;
41import static org.mockito.Mockito.verify;
Wale Ogunwale34247952017-02-19 11:57:53 -080042
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070043import org.junit.Test;
44import org.junit.runner.RunWith;
45
Andrii Kulian92c9a942017-10-10 00:41:41 -070046import android.annotation.SuppressLint;
Andrii Kuliand68501e2017-01-10 22:57:27 -080047import android.content.res.Configuration;
Adrian Roos1cf585052018-01-03 18:43:27 +010048import android.graphics.Rect;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070049import android.os.SystemClock;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070050import android.platform.test.annotations.Presubmit;
Adrian Roos0f9368c2018-04-08 10:59:08 -070051import android.support.test.filters.FlakyTest;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070052import android.support.test.filters.SmallTest;
53import android.support.test.runner.AndroidJUnit4;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070054import android.util.DisplayMetrics;
Andrii Kulian0214ed92017-05-16 13:44:05 -070055import android.util.SparseIntArray;
Adrian Roos1cf585052018-01-03 18:43:27 +010056import android.view.DisplayCutout;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070057import android.view.MotionEvent;
Adrian Roos1cf585052018-01-03 18:43:27 +010058import android.view.Surface;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070059
Adrian Roos6a4fa0e2018-03-05 19:50:16 +010060import com.android.server.wm.utils.WmDisplayCutout;
61
Adrian Roos0f9368c2018-04-08 10:59:08 -070062import java.util.ArrayList;
Wale Ogunwale34247952017-02-19 11:57:53 -080063import java.util.Arrays;
Adrian Roos0f9368c2018-04-08 10:59:08 -070064import java.util.Collections;
Wale Ogunwale34247952017-02-19 11:57:53 -080065import java.util.LinkedList;
66import java.util.List;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070067
68/**
69 * Tests for the {@link DisplayContent} class.
70 *
71 * Build/Install/Run:
Adrian Roos1cf585052018-01-03 18:43:27 +010072 * atest com.android.server.wm.DisplayContentTests
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070073 */
74@SmallTest
75@Presubmit
76@RunWith(AndroidJUnit4.class)
Wale Ogunwale44fbdf52016-11-16 10:18:45 -080077public class DisplayContentTests extends WindowTestsBase {
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070078
79 @Test
Adrian Roos0f9368c2018-04-08 10:59:08 -070080 @FlakyTest(bugId = 77772044)
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070081 public void testForAllWindows() throws Exception {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -080082 final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070083 mDisplayContent, "exiting app");
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070084 final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
85 exitingAppToken.mIsExiting = true;
Bryce Lee6d410262017-02-28 15:30:17 -080086 exitingAppToken.getTask().mStack.mExitingAppTokens.add(exitingAppToken);
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070087
Wale Ogunwale34247952017-02-19 11:57:53 -080088 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -070089 mWallpaperWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -080090 exitingAppWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070091 mChildAppWindowBelow,
92 mAppWindow,
93 mChildAppWindowAbove,
94 mDockedDividerWindow,
95 mStatusBarWindow,
96 mNavBarWindow,
97 mImeWindow,
98 mImeDialogWindow));
Wale Ogunwale3c1170d2016-12-02 14:44:52 -080099 }
100
101 @Test
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800102 public void testForAllWindows_WithAppImeTarget() throws Exception {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800103 final WindowState imeAppTarget =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700104 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800105
106 sWm.mInputMethodTarget = imeAppTarget;
107
Wale Ogunwale34247952017-02-19 11:57:53 -0800108 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700109 mWallpaperWindow,
110 mChildAppWindowBelow,
111 mAppWindow,
112 mChildAppWindowAbove,
Wale Ogunwale34247952017-02-19 11:57:53 -0800113 imeAppTarget,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700114 mImeWindow,
115 mImeDialogWindow,
116 mDockedDividerWindow,
117 mStatusBarWindow,
118 mNavBarWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800119 }
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800120
Wale Ogunwale34247952017-02-19 11:57:53 -0800121 @Test
122 public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700123 sWm.mInputMethodTarget = mChildAppWindowAbove;
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800124
Wale Ogunwale34247952017-02-19 11:57:53 -0800125 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700126 mWallpaperWindow,
127 mChildAppWindowBelow,
128 mAppWindow,
129 mChildAppWindowAbove,
130 mImeWindow,
131 mImeDialogWindow,
132 mDockedDividerWindow,
133 mStatusBarWindow,
134 mNavBarWindow));
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700135 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800136
137 @Test
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800138 public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700139 sWm.mInputMethodTarget = mStatusBarWindow;
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800140
Wale Ogunwale34247952017-02-19 11:57:53 -0800141 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700142 mWallpaperWindow,
143 mChildAppWindowBelow,
144 mAppWindow,
145 mChildAppWindowAbove,
146 mDockedDividerWindow,
147 mStatusBarWindow,
148 mImeWindow,
149 mImeDialogWindow,
150 mNavBarWindow));
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800151 }
152
153 @Test
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800154 public void testForAllWindows_WithInBetweenWindowToken() throws Exception {
155 // This window is set-up to be z-ordered between some windows that go in the same token like
156 // the nav bar and status bar.
157 final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700158 mDisplayContent, "voiceInteractionWindow");
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800159
Wale Ogunwale34247952017-02-19 11:57:53 -0800160 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700161 mWallpaperWindow,
162 mChildAppWindowBelow,
163 mAppWindow,
164 mChildAppWindowAbove,
165 mDockedDividerWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -0800166 voiceInteractionWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700167 mStatusBarWindow,
168 mNavBarWindow,
169 mImeWindow,
170 mImeDialogWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800171 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800172
Wale Ogunwale34247952017-02-19 11:57:53 -0800173 @Test
174 public void testComputeImeTarget() throws Exception {
175 // Verify that an app window can be an ime target.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700176 final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
Wale Ogunwale34247952017-02-19 11:57:53 -0800177 appWin.setHasSurface(true);
178 assertTrue(appWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700179 WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800180 assertEquals(appWin, imeTarget);
chaviwebcbc342018-02-07 13:19:00 -0800181 appWin.mHidden = false;
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800182
Wale Ogunwale34247952017-02-19 11:57:53 -0800183 // Verify that an child window can be an ime target.
184 final WindowState childWin = createWindow(appWin,
185 TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
186 childWin.setHasSurface(true);
187 assertTrue(childWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700188 imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800189 assertEquals(childWin, imeTarget);
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800190 }
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800191
Andrii Kuliand68501e2017-01-10 22:57:27 -0800192 /**
193 * This tests stack movement between displays and proper stack's, task's and app token's display
194 * container references updates.
195 */
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800196 @Test
197 public void testMoveStackBetweenDisplays() throws Exception {
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800198 // Create a second display.
199 final DisplayContent dc = createNewDisplay();
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800200
201 // Add stack with activity.
202 final TaskStack stack = createTaskStackOnDisplay(dc);
203 assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
204 assertEquals(dc, stack.getParent().getParent());
205 assertEquals(dc, stack.getDisplayContent());
206
207 final Task task = createTaskInStack(stack, 0 /* userId */);
chaviw97d28202018-02-27 16:23:53 -0800208 final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
209 dc);
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800210 task.addChild(token, 0);
211 assertEquals(dc, task.getDisplayContent());
212 assertEquals(dc, token.getDisplayContent());
213
214 // Move stack to first display.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700215 mDisplayContent.moveStackToDisplay(stack, true /* onTop */);
216 assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
217 assertEquals(mDisplayContent, stack.getParent().getParent());
218 assertEquals(mDisplayContent, stack.getDisplayContent());
219 assertEquals(mDisplayContent, task.getDisplayContent());
220 assertEquals(mDisplayContent, token.getDisplayContent());
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800221 }
Andrii Kuliand68501e2017-01-10 22:57:27 -0800222
223 /**
224 * This tests override configuration updates for display content.
225 */
226 @Test
227 public void testDisplayOverrideConfigUpdate() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700228 final int displayId = mDisplayContent.getDisplayId();
229 final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800230
231 // Create new, slightly changed override configuration and apply it to the display.
232 final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
233 newOverrideConfig.densityDpi += 120;
234 newOverrideConfig.fontScale += 0.3;
235
236 sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
237
238 // Check that override config is applied.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700239 assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration());
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800240 }
241
242 /**
243 * This tests global configuration updates when default display config is updated.
244 */
245 @Test
246 public void testDefaultDisplayOverrideConfigUpdate() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700247 final Configuration currentConfig = mDisplayContent.getConfiguration();
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800248
249 // Create new, slightly changed override configuration and apply it to the display.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700250 final Configuration newOverrideConfig = new Configuration(currentConfig);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800251 newOverrideConfig.densityDpi += 120;
252 newOverrideConfig.fontScale += 0.3;
253
254 sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800255
256 // Check that global configuration is updated, as we've updated default display's config.
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800257 Configuration globalConfig = sWm.mRoot.getConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800258 assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
259 assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800260
261 // Return back to original values.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700262 sWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800263 globalConfig = sWm.mRoot.getConfiguration();
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700264 assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
265 assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800266 }
Wale Ogunwale34247952017-02-19 11:57:53 -0800267
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700268 /**
269 * Tests tapping on a stack in different display results in window gaining focus.
270 */
271 @Test
272 public void testInputEventBringsCorrectDisplayInFocus() throws Exception {
273 DisplayContent dc0 = sWm.getDefaultDisplayContentLocked();
274 // Create a second display
275 final DisplayContent dc1 = createNewDisplay();
276
277 // Add stack with activity.
278 final TaskStack stack0 = createTaskStackOnDisplay(dc0);
279 final Task task0 = createTaskInStack(stack0, 0 /* userId */);
280 final WindowTestUtils.TestAppWindowToken token =
chaviw97d28202018-02-27 16:23:53 -0800281 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700282 task0.addChild(token, 0);
283 dc0.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
284 sWm.registerPointerEventListener(dc0.mTapDetector);
285 final TaskStack stack1 = createTaskStackOnDisplay(dc1);
286 final Task task1 = createTaskInStack(stack1, 0 /* userId */);
287 final WindowTestUtils.TestAppWindowToken token1 =
chaviw97d28202018-02-27 16:23:53 -0800288 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700289 task1.addChild(token1, 0);
290 dc1.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
291 sWm.registerPointerEventListener(dc1.mTapDetector);
292
293 // tap on primary display (by sending ACTION_DOWN followed by ACTION_UP)
294 DisplayMetrics dm0 = dc0.getDisplayMetrics();
295 dc0.mTapDetector.onPointerEvent(
296 createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, true));
297 dc0.mTapDetector.onPointerEvent(
298 createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, false));
299
300 // Check focus is on primary display.
301 assertEquals(sWm.mCurrentFocus, dc0.findFocusedWindow());
302
303 // Tap on secondary display
304 DisplayMetrics dm1 = dc1.getDisplayMetrics();
305 dc1.mTapDetector.onPointerEvent(
306 createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, true));
307 dc1.mTapDetector.onPointerEvent(
308 createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, false));
309
310 // Check focus is on secondary.
311 assertEquals(sWm.mCurrentFocus, dc1.findFocusedWindow());
312 }
313
David Stevens46939562017-03-24 13:04:00 -0700314 @Test
315 public void testFocusedWindowMultipleDisplays() throws Exception {
Andrii Kulian0214ed92017-05-16 13:44:05 -0700316 // Create a focusable window and check that focus is calculated correctly
David Stevens46939562017-03-24 13:04:00 -0700317 final WindowState window1 =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700318 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
David Stevens46939562017-03-24 13:04:00 -0700319 assertEquals(window1, sWm.mRoot.computeFocusedWindow());
320
321 // Check that a new display doesn't affect focus
322 final DisplayContent dc = createNewDisplay();
323 assertEquals(window1, sWm.mRoot.computeFocusedWindow());
324
325 // Add a window to the second display, and it should be focused
326 final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
327 assertEquals(window2, sWm.mRoot.computeFocusedWindow());
328
329 // Move the first window to the to including parents, and make sure focus is updated
330 window1.getParent().positionChildAt(POSITION_TOP, window1, true);
331 assertEquals(window1, sWm.mRoot.computeFocusedWindow());
332 }
333
Adrian Roos4163d622018-05-22 16:56:35 +0200334 @Test
335 public void testKeyguard_preventsSecondaryDisplayFocus() throws Exception {
336 final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR,
337 sWm.getDefaultDisplayContentLocked(), "keyguard");
338 assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
339
340 // Add a window to a second display, and it should be focused
341 final DisplayContent dc = createNewDisplay();
342 final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
343 assertEquals(win, sWm.mRoot.computeFocusedWindow());
344
345 mWmRule.getWindowManagerPolicy().keyguardShowingAndNotOccluded = true;
346 assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
347 }
348
Bryce Lee27cec322017-03-21 09:41:37 -0700349 /**
350 * This tests setting the maximum ui width on a display.
351 */
352 @Test
353 public void testMaxUiWidth() throws Exception {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800354 // Prevent base display metrics for test from being updated to the value of real display.
355 final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
Bryce Lee27cec322017-03-21 09:41:37 -0700356 final int baseWidth = 1440;
357 final int baseHeight = 2560;
358 final int baseDensity = 300;
359
Riddle Hsu654a6f92018-07-13 22:59:36 +0800360 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700361
362 final int maxWidth = 300;
363 final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
364 final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
365
Riddle Hsu654a6f92018-07-13 22:59:36 +0800366 displayContent.setMaxUiWidth(maxWidth);
367 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700368
369 // Assert setting values again does not change;
Riddle Hsu654a6f92018-07-13 22:59:36 +0800370 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
371 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700372
373 final int smallerWidth = 200;
374 final int smallerHeight = 400;
375 final int smallerDensity = 100;
376
377 // Specify smaller dimension, verify that it is honored
Riddle Hsu654a6f92018-07-13 22:59:36 +0800378 displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
379 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700380
381 // Verify that setting the max width to a greater value than the base width has no effect
Riddle Hsu654a6f92018-07-13 22:59:36 +0800382 displayContent.setMaxUiWidth(maxWidth);
383 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700384 }
385
Bryce Lee48f4b572017-04-10 10:54:15 -0700386 /**
Kazuki Takise148d00a2018-05-31 15:32:19 +0900387 * This test enforces that alwaysOnTop stack is placed at proper position.
Bryce Lee48f4b572017-04-10 10:54:15 -0700388 */
389 @Test
Kazuki Takise148d00a2018-05-31 15:32:19 +0900390 public void testAlwaysOnTopStackLocation() {
391 final TaskStack alwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent);
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900392 final Task task = createTaskInStack(alwaysOnTopStack, 0 /* userId */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900393 alwaysOnTopStack.setAlwaysOnTop(true);
394 mDisplayContent.positionStackAt(POSITION_TOP, alwaysOnTopStack);
395 assertTrue(alwaysOnTopStack.isAlwaysOnTop());
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900396 // Ensure always on top state is synced to the children of the stack.
397 assertTrue(alwaysOnTopStack.getTopChild().isAlwaysOnTop());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900398 assertEquals(alwaysOnTopStack, mDisplayContent.getTopStack());
399
Wale Ogunwale61911492017-10-11 08:50:50 -0700400 final TaskStack pinnedStack = createStackControllerOnStackOnDisplay(
401 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Wale Ogunwale61911492017-10-11 08:50:50 -0700402 assertEquals(pinnedStack, mDisplayContent.getPinnedStack());
403 assertEquals(pinnedStack, mDisplayContent.getTopStack());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900404
405 final TaskStack anotherAlwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent);
406 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
407 mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack);
408 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
409 int topPosition = mDisplayContent.getStacks().size() - 1;
410 // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
411 // existing alwaysOnTop stack.
412 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
413
414 final TaskStack nonAlwaysOnTopStack = createTaskStackOnDisplay(mDisplayContent);
415 assertEquals(mDisplayContent, nonAlwaysOnTopStack.getDisplayContent());
416 topPosition = mDisplayContent.getStacks().size() - 1;
417 // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
418 // existing other non-alwaysOnTop stacks.
419 assertEquals(nonAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 3));
Kazuki Takisef85197b2018-06-18 18:18:36 +0900420
421 anotherAlwaysOnTopStack.setAlwaysOnTop(false);
422 mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack);
423 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
424 topPosition = mDisplayContent.getStacks().size() - 1;
425 // Ensure, when always on top is turned off for a stack, the stack is put just below all
426 // other always on top stacks.
427 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
Bryce Lee48f4b572017-04-10 10:54:15 -0700428 }
429
Andrii Kulian0214ed92017-05-16 13:44:05 -0700430 /**
431 * Test that WM does not report displays to AM that are pending to be removed.
432 */
433 @Test
434 public void testDontReportDeferredRemoval() {
435 // Create a display and add an animating window to it.
436 final DisplayContent dc = createNewDisplay();
437 final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
438 window.mAnimatingExit = true;
439 // Request display removal, it should be deferred.
440 dc.removeIfPossible();
441 // Request ordered display ids from WM.
442 final SparseIntArray orderedDisplayIds = new SparseIntArray();
443 sWm.getDisplaysInFocusOrder(orderedDisplayIds);
444 // Make sure that display that is marked for removal is not reported.
445 assertEquals(-1, orderedDisplayIds.indexOfValue(dc.getDisplayId()));
446 }
447
Andrii Kulian92c9a942017-10-10 00:41:41 -0700448 @Test
Adrian Roos1cf585052018-01-03 18:43:27 +0100449 public void testDisplayCutout_rot0() throws Exception {
450 synchronized (sWm.getWindowManagerLock()) {
451 final DisplayContent dc = createNewDisplay();
452 dc.mInitialDisplayWidth = 200;
453 dc.mInitialDisplayHeight = 400;
Adrian Roos24264212018-02-19 16:26:15 +0100454 Rect r = new Rect(80, 0, 120, 10);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100455 final DisplayCutout cutout = new WmDisplayCutout(
456 fromBoundingRect(r.left, r.top, r.right, r.bottom), null)
457 .computeSafeInsets(200, 400).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100458
459 dc.mInitialDisplayCutout = cutout;
460 dc.setRotation(Surface.ROTATION_0);
461 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
462
463 assertEquals(cutout, dc.getDisplayInfo().displayCutout);
464 }
465 }
466
467 @Test
468 public void testDisplayCutout_rot90() throws Exception {
469 synchronized (sWm.getWindowManagerLock()) {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800470 // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
471 // if the device has no cutout).
472 final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
473 // Rotation may use real display info to compute bound, so here also uses the
474 // same width and height.
475 final int displayWidth = dc.mInitialDisplayWidth;
476 final int displayHeight = dc.mInitialDisplayHeight;
477 final int cutoutWidth = 40;
478 final int cutoutHeight = 10;
479 final int left = (displayWidth - cutoutWidth) / 2;
480 final int top = 0;
481 final int right = (displayWidth + cutoutWidth) / 2;
482 final int bottom = cutoutHeight;
483
484 final Rect r1 = new Rect(left, top, right, bottom);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100485 final DisplayCutout cutout = new WmDisplayCutout(
486 fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800487 .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100488
489 dc.mInitialDisplayCutout = cutout;
490 dc.setRotation(Surface.ROTATION_90);
491 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
492
Riddle Hsu654a6f92018-07-13 22:59:36 +0800493 // ----o---------- -------------
494 // | | | | |
495 // | ------o | o---
496 // | | | |
497 // | | -> | |
498 // | | ---o
499 // | | |
500 // | | -------------
501 final Rect r = new Rect(top, left, bottom, right);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100502 assertEquals(new WmDisplayCutout(
503 fromBoundingRect(r.left, r.top, r.right, r.bottom), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800504 .computeSafeInsets(displayHeight, displayWidth)
505 .getDisplayCutout(), dc.getDisplayInfo().displayCutout);
Adrian Roos1cf585052018-01-03 18:43:27 +0100506 }
507 }
508
509 @Test
Adrian Roos5251b1d2018-03-23 18:57:43 +0100510 public void testLayoutSeq_assignedDuringLayout() throws Exception {
511 synchronized (sWm.getWindowManagerLock()) {
512
513 final DisplayContent dc = createNewDisplay();
514 final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
515
516 dc.setLayoutNeeded();
517 dc.performLayout(true /* initial */, false /* updateImeWindows */);
518
519 assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
520 }
521 }
522
523 @Test
Andrii Kulian92c9a942017-10-10 00:41:41 -0700524 @SuppressLint("InlinedApi")
525 public void testOrientationDefinedByKeyguard() {
526 final DisplayContent dc = createNewDisplay();
527 // Create a window that requests landscape orientation. It will define device orientation
528 // by default.
529 final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
530 window.mAppToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
531
532 final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, dc, "keyguard");
533 keyguard.mHasSurface = true;
534 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
535
536 assertEquals("Screen orientation must be defined by the app window by default",
537 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
538
539 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
540 assertEquals("Visible keyguard must influence device orientation",
541 SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
542
543 sWm.setKeyguardGoingAway(true);
544 assertEquals("Keyguard that is going away must not influence device orientation",
545 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
546 }
547
Andrii Kulianf0379de2018-03-14 16:24:07 -0700548 @Test
549 public void testDisableDisplayInfoOverrideFromWindowManager() {
550 final DisplayContent dc = createNewDisplay();
551
552 assertTrue(dc.mShouldOverrideDisplayConfiguration);
553 sWm.dontOverrideDisplayInfo(dc.getDisplayId());
554
555 assertFalse(dc.mShouldOverrideDisplayConfiguration);
556 verify(sWm.mDisplayManagerInternal, times(1))
557 .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
558 }
559
Bryce Lee27cec322017-03-21 09:41:37 -0700560 private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
561 int expectedBaseHeight, int expectedBaseDensity) {
562 assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
563 assertEquals(displayContent.mBaseDisplayHeight, expectedBaseHeight);
564 assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
565 }
566
Riddle Hsu654a6f92018-07-13 22:59:36 +0800567 /**
568 * Create DisplayContent that does not update display base/initial values from device to keep
569 * the values set by test.
570 */
571 private DisplayContent createDisplayNoUpdateDisplayInfo() {
572 final DisplayContent displayContent = spy(createNewDisplay());
573 doNothing().when(displayContent).updateDisplayInfo();
574 return displayContent;
575 }
576
Adrian Roos0f9368c2018-04-08 10:59:08 -0700577 private void assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop) {
578 final LinkedList<WindowState> actualWindows = new LinkedList<>();
Wale Ogunwale34247952017-02-19 11:57:53 -0800579
580 // Test forward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700581 mDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700582 assertThat("bottomToTop", actualWindows, is(expectedWindowsBottomToTop));
583
584 actualWindows.clear();
Wale Ogunwale34247952017-02-19 11:57:53 -0800585
586 // Test backward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700587 mDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700588 assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop)));
589 }
590
591 private static List<WindowState> reverseList(List<WindowState> list) {
592 final ArrayList<WindowState> result = new ArrayList<>(list);
593 Collections.reverse(result);
594 return result;
Wale Ogunwale34247952017-02-19 11:57:53 -0800595 }
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700596
597 private MotionEvent createTapEvent(float x, float y, boolean isDownEvent) {
598 final long downTime = SystemClock.uptimeMillis();
599 final long eventTime = SystemClock.uptimeMillis() + 100;
600 final int metaState = 0;
601
602 return MotionEvent.obtain(
603 downTime,
604 eventTime,
605 isDownEvent ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP,
606 x,
607 y,
608 metaState);
609 }
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700610}