blob: cfef51c88838f5e6ad771d436ec6ae98f8793c3f [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;
Kazuki Takise048e2662018-06-27 17:05:11 +090020import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
21import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
Wale Ogunwale68278562017-09-23 17:13:55 -070022import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Andrii Kulian92c9a942017-10-10 00:41:41 -070023import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
24import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
25import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Wale Ogunwale34247952017-02-19 11:57:53 -080026import static android.view.Display.DEFAULT_DISPLAY;
Adrian Roos24264212018-02-19 16:26:15 +010027import static android.view.DisplayCutout.fromBoundingRect;
Wale Ogunwale34247952017-02-19 11:57:53 -080028import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
29import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
30import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
Andrii Kulian92c9a942017-10-10 00:41:41 -070031import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
Wale Ogunwale34247952017-02-19 11:57:53 -080032import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
Brett Chabota26eda92018-07-23 13:08:30 -070033
David Stevens46939562017-03-24 13:04:00 -070034import static com.android.server.wm.WindowContainer.POSITION_TOP;
chaviwebcbc342018-02-07 13:19:00 -080035
Adrian Roos5251b1d2018-03-23 18:57:43 +010036import static org.hamcrest.Matchers.is;
Wale Ogunwale34247952017-02-19 11:57:53 -080037import static org.junit.Assert.assertEquals;
Andrii Kulianf0379de2018-03-14 16:24:07 -070038import static org.junit.Assert.assertFalse;
Adrian Roos5251b1d2018-03-23 18:57:43 +010039import static org.junit.Assert.assertThat;
Wale Ogunwale34247952017-02-19 11:57:53 -080040import static org.junit.Assert.assertTrue;
Riddle Hsu654a6f92018-07-13 22:59:36 +080041import static org.mockito.Mockito.doNothing;
42import static org.mockito.Mockito.spy;
Andrii Kulianf0379de2018-03-14 16:24:07 -070043import static org.mockito.Mockito.times;
44import static org.mockito.Mockito.verify;
Wale Ogunwale34247952017-02-19 11:57:53 -080045
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;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070051import android.util.DisplayMetrics;
Andrii Kulian0214ed92017-05-16 13:44:05 -070052import android.util.SparseIntArray;
Adrian Roos1cf585052018-01-03 18:43:27 +010053import android.view.DisplayCutout;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070054import android.view.MotionEvent;
Adrian Roos1cf585052018-01-03 18:43:27 +010055import android.view.Surface;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070056
Brett Chabota26eda92018-07-23 13:08:30 -070057import androidx.test.filters.FlakyTest;
58import androidx.test.filters.SmallTest;
59import androidx.test.runner.AndroidJUnit4;
60
Adrian Roos6a4fa0e2018-03-05 19:50:16 +010061import com.android.server.wm.utils.WmDisplayCutout;
62
Brett Chabota26eda92018-07-23 13:08:30 -070063import org.junit.Test;
64import org.junit.runner.RunWith;
65
Adrian Roos0f9368c2018-04-08 10:59:08 -070066import java.util.ArrayList;
Wale Ogunwale34247952017-02-19 11:57:53 -080067import java.util.Arrays;
Adrian Roos0f9368c2018-04-08 10:59:08 -070068import java.util.Collections;
Wale Ogunwale34247952017-02-19 11:57:53 -080069import java.util.LinkedList;
70import java.util.List;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070071
72/**
73 * Tests for the {@link DisplayContent} class.
74 *
75 * Build/Install/Run:
Adrian Roos1cf585052018-01-03 18:43:27 +010076 * atest com.android.server.wm.DisplayContentTests
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070077 */
78@SmallTest
79@Presubmit
80@RunWith(AndroidJUnit4.class)
Wale Ogunwale44fbdf52016-11-16 10:18:45 -080081public class DisplayContentTests extends WindowTestsBase {
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070082
83 @Test
Adrian Roos0f9368c2018-04-08 10:59:08 -070084 @FlakyTest(bugId = 77772044)
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070085 public void testForAllWindows() throws Exception {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -080086 final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070087 mDisplayContent, "exiting app");
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070088 final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
89 exitingAppToken.mIsExiting = true;
Bryce Lee6d410262017-02-28 15:30:17 -080090 exitingAppToken.getTask().mStack.mExitingAppTokens.add(exitingAppToken);
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070091
Wale Ogunwale34247952017-02-19 11:57:53 -080092 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -070093 mWallpaperWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -080094 exitingAppWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070095 mChildAppWindowBelow,
96 mAppWindow,
97 mChildAppWindowAbove,
98 mDockedDividerWindow,
99 mStatusBarWindow,
100 mNavBarWindow,
101 mImeWindow,
102 mImeDialogWindow));
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800103 }
104
105 @Test
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800106 public void testForAllWindows_WithAppImeTarget() throws Exception {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800107 final WindowState imeAppTarget =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700108 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800109
110 sWm.mInputMethodTarget = imeAppTarget;
111
Wale Ogunwale34247952017-02-19 11:57:53 -0800112 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700113 mWallpaperWindow,
114 mChildAppWindowBelow,
115 mAppWindow,
116 mChildAppWindowAbove,
Wale Ogunwale34247952017-02-19 11:57:53 -0800117 imeAppTarget,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700118 mImeWindow,
119 mImeDialogWindow,
120 mDockedDividerWindow,
121 mStatusBarWindow,
122 mNavBarWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800123 }
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800124
Wale Ogunwale34247952017-02-19 11:57:53 -0800125 @Test
126 public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700127 sWm.mInputMethodTarget = mChildAppWindowAbove;
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800128
Wale Ogunwale34247952017-02-19 11:57:53 -0800129 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700130 mWallpaperWindow,
131 mChildAppWindowBelow,
132 mAppWindow,
133 mChildAppWindowAbove,
134 mImeWindow,
135 mImeDialogWindow,
136 mDockedDividerWindow,
137 mStatusBarWindow,
138 mNavBarWindow));
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700139 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800140
141 @Test
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800142 public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700143 sWm.mInputMethodTarget = mStatusBarWindow;
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800144
Wale Ogunwale34247952017-02-19 11:57:53 -0800145 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700146 mWallpaperWindow,
147 mChildAppWindowBelow,
148 mAppWindow,
149 mChildAppWindowAbove,
150 mDockedDividerWindow,
151 mStatusBarWindow,
152 mImeWindow,
153 mImeDialogWindow,
154 mNavBarWindow));
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800155 }
156
157 @Test
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800158 public void testForAllWindows_WithInBetweenWindowToken() throws Exception {
159 // This window is set-up to be z-ordered between some windows that go in the same token like
160 // the nav bar and status bar.
161 final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700162 mDisplayContent, "voiceInteractionWindow");
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800163
Wale Ogunwale34247952017-02-19 11:57:53 -0800164 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700165 mWallpaperWindow,
166 mChildAppWindowBelow,
167 mAppWindow,
168 mChildAppWindowAbove,
169 mDockedDividerWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -0800170 voiceInteractionWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700171 mStatusBarWindow,
172 mNavBarWindow,
173 mImeWindow,
174 mImeDialogWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800175 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800176
Wale Ogunwale34247952017-02-19 11:57:53 -0800177 @Test
178 public void testComputeImeTarget() throws Exception {
179 // Verify that an app window can be an ime target.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700180 final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
Wale Ogunwale34247952017-02-19 11:57:53 -0800181 appWin.setHasSurface(true);
182 assertTrue(appWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700183 WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800184 assertEquals(appWin, imeTarget);
chaviwebcbc342018-02-07 13:19:00 -0800185 appWin.mHidden = false;
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800186
Wale Ogunwale34247952017-02-19 11:57:53 -0800187 // Verify that an child window can be an ime target.
188 final WindowState childWin = createWindow(appWin,
189 TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
190 childWin.setHasSurface(true);
191 assertTrue(childWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700192 imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800193 assertEquals(childWin, imeTarget);
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800194 }
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800195
Andrii Kuliand68501e2017-01-10 22:57:27 -0800196 /**
197 * This tests stack movement between displays and proper stack's, task's and app token's display
198 * container references updates.
199 */
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800200 @Test
201 public void testMoveStackBetweenDisplays() throws Exception {
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800202 // Create a second display.
203 final DisplayContent dc = createNewDisplay();
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800204
205 // Add stack with activity.
206 final TaskStack stack = createTaskStackOnDisplay(dc);
207 assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
208 assertEquals(dc, stack.getParent().getParent());
209 assertEquals(dc, stack.getDisplayContent());
210
211 final Task task = createTaskInStack(stack, 0 /* userId */);
chaviw97d28202018-02-27 16:23:53 -0800212 final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
213 dc);
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800214 task.addChild(token, 0);
215 assertEquals(dc, task.getDisplayContent());
216 assertEquals(dc, token.getDisplayContent());
217
218 // Move stack to first display.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700219 mDisplayContent.moveStackToDisplay(stack, true /* onTop */);
220 assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
221 assertEquals(mDisplayContent, stack.getParent().getParent());
222 assertEquals(mDisplayContent, stack.getDisplayContent());
223 assertEquals(mDisplayContent, task.getDisplayContent());
224 assertEquals(mDisplayContent, token.getDisplayContent());
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800225 }
Andrii Kuliand68501e2017-01-10 22:57:27 -0800226
227 /**
228 * This tests override configuration updates for display content.
229 */
230 @Test
231 public void testDisplayOverrideConfigUpdate() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700232 final int displayId = mDisplayContent.getDisplayId();
233 final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800234
235 // Create new, slightly changed override configuration and apply it to the display.
236 final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
237 newOverrideConfig.densityDpi += 120;
238 newOverrideConfig.fontScale += 0.3;
239
240 sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
241
242 // Check that override config is applied.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700243 assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration());
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800244 }
245
246 /**
247 * This tests global configuration updates when default display config is updated.
248 */
249 @Test
250 public void testDefaultDisplayOverrideConfigUpdate() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700251 final Configuration currentConfig = mDisplayContent.getConfiguration();
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800252
253 // Create new, slightly changed override configuration and apply it to the display.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700254 final Configuration newOverrideConfig = new Configuration(currentConfig);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800255 newOverrideConfig.densityDpi += 120;
256 newOverrideConfig.fontScale += 0.3;
257
258 sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800259
260 // Check that global configuration is updated, as we've updated default display's config.
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800261 Configuration globalConfig = sWm.mRoot.getConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800262 assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
263 assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800264
265 // Return back to original values.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700266 sWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800267 globalConfig = sWm.mRoot.getConfiguration();
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700268 assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
269 assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800270 }
Wale Ogunwale34247952017-02-19 11:57:53 -0800271
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700272 /**
273 * Tests tapping on a stack in different display results in window gaining focus.
274 */
275 @Test
276 public void testInputEventBringsCorrectDisplayInFocus() throws Exception {
277 DisplayContent dc0 = sWm.getDefaultDisplayContentLocked();
278 // Create a second display
279 final DisplayContent dc1 = createNewDisplay();
280
281 // Add stack with activity.
282 final TaskStack stack0 = createTaskStackOnDisplay(dc0);
283 final Task task0 = createTaskInStack(stack0, 0 /* userId */);
284 final WindowTestUtils.TestAppWindowToken token =
chaviw97d28202018-02-27 16:23:53 -0800285 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700286 task0.addChild(token, 0);
287 dc0.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
288 sWm.registerPointerEventListener(dc0.mTapDetector);
289 final TaskStack stack1 = createTaskStackOnDisplay(dc1);
290 final Task task1 = createTaskInStack(stack1, 0 /* userId */);
291 final WindowTestUtils.TestAppWindowToken token1 =
chaviw97d28202018-02-27 16:23:53 -0800292 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700293 task1.addChild(token1, 0);
294 dc1.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
295 sWm.registerPointerEventListener(dc1.mTapDetector);
296
297 // tap on primary display (by sending ACTION_DOWN followed by ACTION_UP)
298 DisplayMetrics dm0 = dc0.getDisplayMetrics();
299 dc0.mTapDetector.onPointerEvent(
300 createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, true));
301 dc0.mTapDetector.onPointerEvent(
302 createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, false));
303
304 // Check focus is on primary display.
305 assertEquals(sWm.mCurrentFocus, dc0.findFocusedWindow());
306
307 // Tap on secondary display
308 DisplayMetrics dm1 = dc1.getDisplayMetrics();
309 dc1.mTapDetector.onPointerEvent(
310 createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, true));
311 dc1.mTapDetector.onPointerEvent(
312 createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, false));
313
314 // Check focus is on secondary.
315 assertEquals(sWm.mCurrentFocus, dc1.findFocusedWindow());
316 }
317
David Stevens46939562017-03-24 13:04:00 -0700318 @Test
319 public void testFocusedWindowMultipleDisplays() throws Exception {
Andrii Kulian0214ed92017-05-16 13:44:05 -0700320 // Create a focusable window and check that focus is calculated correctly
David Stevens46939562017-03-24 13:04:00 -0700321 final WindowState window1 =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700322 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
David Stevens46939562017-03-24 13:04:00 -0700323 assertEquals(window1, sWm.mRoot.computeFocusedWindow());
324
325 // Check that a new display doesn't affect focus
326 final DisplayContent dc = createNewDisplay();
327 assertEquals(window1, sWm.mRoot.computeFocusedWindow());
328
329 // Add a window to the second display, and it should be focused
330 final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
331 assertEquals(window2, sWm.mRoot.computeFocusedWindow());
332
333 // Move the first window to the to including parents, and make sure focus is updated
334 window1.getParent().positionChildAt(POSITION_TOP, window1, true);
335 assertEquals(window1, sWm.mRoot.computeFocusedWindow());
336 }
337
Adrian Roos4163d622018-05-22 16:56:35 +0200338 @Test
339 public void testKeyguard_preventsSecondaryDisplayFocus() throws Exception {
340 final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR,
341 sWm.getDefaultDisplayContentLocked(), "keyguard");
342 assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
343
344 // Add a window to a second display, and it should be focused
345 final DisplayContent dc = createNewDisplay();
346 final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
347 assertEquals(win, sWm.mRoot.computeFocusedWindow());
348
349 mWmRule.getWindowManagerPolicy().keyguardShowingAndNotOccluded = true;
350 assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
351 }
352
Bryce Lee27cec322017-03-21 09:41:37 -0700353 /**
354 * This tests setting the maximum ui width on a display.
355 */
356 @Test
357 public void testMaxUiWidth() throws Exception {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800358 // Prevent base display metrics for test from being updated to the value of real display.
359 final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
Bryce Lee27cec322017-03-21 09:41:37 -0700360 final int baseWidth = 1440;
361 final int baseHeight = 2560;
362 final int baseDensity = 300;
363
Riddle Hsu654a6f92018-07-13 22:59:36 +0800364 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700365
366 final int maxWidth = 300;
367 final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
368 final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
369
Riddle Hsu654a6f92018-07-13 22:59:36 +0800370 displayContent.setMaxUiWidth(maxWidth);
371 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700372
373 // Assert setting values again does not change;
Riddle Hsu654a6f92018-07-13 22:59:36 +0800374 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
375 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700376
377 final int smallerWidth = 200;
378 final int smallerHeight = 400;
379 final int smallerDensity = 100;
380
381 // Specify smaller dimension, verify that it is honored
Riddle Hsu654a6f92018-07-13 22:59:36 +0800382 displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
383 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700384
385 // Verify that setting the max width to a greater value than the base width has no effect
Riddle Hsu654a6f92018-07-13 22:59:36 +0800386 displayContent.setMaxUiWidth(maxWidth);
387 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700388 }
389
Bryce Lee48f4b572017-04-10 10:54:15 -0700390 /**
Kazuki Takise148d00a2018-05-31 15:32:19 +0900391 * This test enforces that alwaysOnTop stack is placed at proper position.
Bryce Lee48f4b572017-04-10 10:54:15 -0700392 */
393 @Test
Kazuki Takise148d00a2018-05-31 15:32:19 +0900394 public void testAlwaysOnTopStackLocation() {
Kazuki Takise048e2662018-06-27 17:05:11 +0900395 final TaskStack alwaysOnTopStack = createStackControllerOnStackOnDisplay(
396 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900397 final Task task = createTaskInStack(alwaysOnTopStack, 0 /* userId */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900398 alwaysOnTopStack.setAlwaysOnTop(true);
Riddle Hsu57831b52018-07-27 00:31:48 +0800399 mDisplayContent.positionStackAt(POSITION_TOP, alwaysOnTopStack,
400 false /* includingParents */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900401 assertTrue(alwaysOnTopStack.isAlwaysOnTop());
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900402 // Ensure always on top state is synced to the children of the stack.
403 assertTrue(alwaysOnTopStack.getTopChild().isAlwaysOnTop());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900404 assertEquals(alwaysOnTopStack, mDisplayContent.getTopStack());
405
Wale Ogunwale61911492017-10-11 08:50:50 -0700406 final TaskStack pinnedStack = createStackControllerOnStackOnDisplay(
407 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Wale Ogunwale61911492017-10-11 08:50:50 -0700408 assertEquals(pinnedStack, mDisplayContent.getPinnedStack());
409 assertEquals(pinnedStack, mDisplayContent.getTopStack());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900410
Kazuki Takise048e2662018-06-27 17:05:11 +0900411 final TaskStack anotherAlwaysOnTopStack = createStackControllerOnStackOnDisplay(
412 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900413 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
Riddle Hsu57831b52018-07-27 00:31:48 +0800414 mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack,
415 false /* includingParents */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900416 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
417 int topPosition = mDisplayContent.getStacks().size() - 1;
418 // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
419 // existing alwaysOnTop stack.
420 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
421
Kazuki Takise048e2662018-06-27 17:05:11 +0900422 final TaskStack nonAlwaysOnTopStack = createStackControllerOnStackOnDisplay(
423 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900424 assertEquals(mDisplayContent, nonAlwaysOnTopStack.getDisplayContent());
425 topPosition = mDisplayContent.getStacks().size() - 1;
426 // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
427 // existing other non-alwaysOnTop stacks.
428 assertEquals(nonAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 3));
Kazuki Takisef85197b2018-06-18 18:18:36 +0900429
430 anotherAlwaysOnTopStack.setAlwaysOnTop(false);
Riddle Hsu57831b52018-07-27 00:31:48 +0800431 mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack,
432 false /* includingParents */);
Kazuki Takisef85197b2018-06-18 18:18:36 +0900433 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
Kazuki Takisef85197b2018-06-18 18:18:36 +0900434 // Ensure, when always on top is turned off for a stack, the stack is put just below all
435 // other always on top stacks.
436 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
Kazuki Takise048e2662018-06-27 17:05:11 +0900437 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
438
439 // Ensure always on top state changes properly when windowing mode changes.
440 anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
441 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
442 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
443 anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
444 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
445 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
Bryce Lee48f4b572017-04-10 10:54:15 -0700446 }
447
Andrii Kulian0214ed92017-05-16 13:44:05 -0700448 /**
449 * Test that WM does not report displays to AM that are pending to be removed.
450 */
451 @Test
452 public void testDontReportDeferredRemoval() {
453 // Create a display and add an animating window to it.
454 final DisplayContent dc = createNewDisplay();
455 final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
456 window.mAnimatingExit = true;
457 // Request display removal, it should be deferred.
458 dc.removeIfPossible();
459 // Request ordered display ids from WM.
460 final SparseIntArray orderedDisplayIds = new SparseIntArray();
461 sWm.getDisplaysInFocusOrder(orderedDisplayIds);
462 // Make sure that display that is marked for removal is not reported.
463 assertEquals(-1, orderedDisplayIds.indexOfValue(dc.getDisplayId()));
464 }
465
Andrii Kulian92c9a942017-10-10 00:41:41 -0700466 @Test
Adrian Roos1cf585052018-01-03 18:43:27 +0100467 public void testDisplayCutout_rot0() throws Exception {
468 synchronized (sWm.getWindowManagerLock()) {
469 final DisplayContent dc = createNewDisplay();
470 dc.mInitialDisplayWidth = 200;
471 dc.mInitialDisplayHeight = 400;
Adrian Roos24264212018-02-19 16:26:15 +0100472 Rect r = new Rect(80, 0, 120, 10);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100473 final DisplayCutout cutout = new WmDisplayCutout(
474 fromBoundingRect(r.left, r.top, r.right, r.bottom), null)
475 .computeSafeInsets(200, 400).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100476
477 dc.mInitialDisplayCutout = cutout;
478 dc.setRotation(Surface.ROTATION_0);
479 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
480
481 assertEquals(cutout, dc.getDisplayInfo().displayCutout);
482 }
483 }
484
485 @Test
486 public void testDisplayCutout_rot90() throws Exception {
487 synchronized (sWm.getWindowManagerLock()) {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800488 // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
489 // if the device has no cutout).
490 final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
491 // Rotation may use real display info to compute bound, so here also uses the
492 // same width and height.
493 final int displayWidth = dc.mInitialDisplayWidth;
494 final int displayHeight = dc.mInitialDisplayHeight;
495 final int cutoutWidth = 40;
496 final int cutoutHeight = 10;
497 final int left = (displayWidth - cutoutWidth) / 2;
498 final int top = 0;
499 final int right = (displayWidth + cutoutWidth) / 2;
500 final int bottom = cutoutHeight;
501
502 final Rect r1 = new Rect(left, top, right, bottom);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100503 final DisplayCutout cutout = new WmDisplayCutout(
504 fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800505 .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100506
507 dc.mInitialDisplayCutout = cutout;
508 dc.setRotation(Surface.ROTATION_90);
509 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
510
Riddle Hsu654a6f92018-07-13 22:59:36 +0800511 // ----o---------- -------------
512 // | | | | |
513 // | ------o | o---
514 // | | | |
515 // | | -> | |
516 // | | ---o
517 // | | |
518 // | | -------------
519 final Rect r = new Rect(top, left, bottom, right);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100520 assertEquals(new WmDisplayCutout(
521 fromBoundingRect(r.left, r.top, r.right, r.bottom), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800522 .computeSafeInsets(displayHeight, displayWidth)
523 .getDisplayCutout(), dc.getDisplayInfo().displayCutout);
Adrian Roos1cf585052018-01-03 18:43:27 +0100524 }
525 }
526
527 @Test
Adrian Roos5251b1d2018-03-23 18:57:43 +0100528 public void testLayoutSeq_assignedDuringLayout() throws Exception {
529 synchronized (sWm.getWindowManagerLock()) {
530
531 final DisplayContent dc = createNewDisplay();
532 final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
533
534 dc.setLayoutNeeded();
535 dc.performLayout(true /* initial */, false /* updateImeWindows */);
536
537 assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
538 }
539 }
540
541 @Test
Andrii Kulian92c9a942017-10-10 00:41:41 -0700542 @SuppressLint("InlinedApi")
543 public void testOrientationDefinedByKeyguard() {
544 final DisplayContent dc = createNewDisplay();
545 // Create a window that requests landscape orientation. It will define device orientation
546 // by default.
547 final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
548 window.mAppToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
549
550 final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, dc, "keyguard");
551 keyguard.mHasSurface = true;
552 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
553
554 assertEquals("Screen orientation must be defined by the app window by default",
555 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
556
557 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
558 assertEquals("Visible keyguard must influence device orientation",
559 SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
560
561 sWm.setKeyguardGoingAway(true);
562 assertEquals("Keyguard that is going away must not influence device orientation",
563 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
564 }
565
Andrii Kulianf0379de2018-03-14 16:24:07 -0700566 @Test
567 public void testDisableDisplayInfoOverrideFromWindowManager() {
568 final DisplayContent dc = createNewDisplay();
569
570 assertTrue(dc.mShouldOverrideDisplayConfiguration);
571 sWm.dontOverrideDisplayInfo(dc.getDisplayId());
572
573 assertFalse(dc.mShouldOverrideDisplayConfiguration);
574 verify(sWm.mDisplayManagerInternal, times(1))
575 .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
576 }
577
Bryce Lee27cec322017-03-21 09:41:37 -0700578 private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
579 int expectedBaseHeight, int expectedBaseDensity) {
580 assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
581 assertEquals(displayContent.mBaseDisplayHeight, expectedBaseHeight);
582 assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
583 }
584
Riddle Hsu654a6f92018-07-13 22:59:36 +0800585 /**
586 * Create DisplayContent that does not update display base/initial values from device to keep
587 * the values set by test.
588 */
589 private DisplayContent createDisplayNoUpdateDisplayInfo() {
590 final DisplayContent displayContent = spy(createNewDisplay());
591 doNothing().when(displayContent).updateDisplayInfo();
592 return displayContent;
593 }
594
Adrian Roos0f9368c2018-04-08 10:59:08 -0700595 private void assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop) {
596 final LinkedList<WindowState> actualWindows = new LinkedList<>();
Wale Ogunwale34247952017-02-19 11:57:53 -0800597
598 // Test forward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700599 mDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700600 assertThat("bottomToTop", actualWindows, is(expectedWindowsBottomToTop));
601
602 actualWindows.clear();
Wale Ogunwale34247952017-02-19 11:57:53 -0800603
604 // Test backward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700605 mDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700606 assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop)));
607 }
608
609 private static List<WindowState> reverseList(List<WindowState> list) {
610 final ArrayList<WindowState> result = new ArrayList<>(list);
611 Collections.reverse(result);
612 return result;
Wale Ogunwale34247952017-02-19 11:57:53 -0800613 }
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700614
615 private MotionEvent createTapEvent(float x, float y, boolean isDownEvent) {
616 final long downTime = SystemClock.uptimeMillis();
617 final long eventTime = SystemClock.uptimeMillis() + 100;
618 final int metaState = 0;
619
620 return MotionEvent.obtain(
621 downTime,
622 eventTime,
623 isDownEvent ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP,
624 x,
625 y,
626 metaState);
627 }
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700628}