blob: 88b876a3b75b6818c5108cc30816bf9e7ffbfe75 [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;
Issei Suzuki43190bd2018-08-20 17:28:41 +020027import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
28import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
Adrian Roos24264212018-02-19 16:26:15 +010029import static android.view.DisplayCutout.fromBoundingRect;
Wale Ogunwale34247952017-02-19 11:57:53 -080030import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
31import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
32import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
Andrii Kulian92c9a942017-10-10 00:41:41 -070033import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
Wale Ogunwale34247952017-02-19 11:57:53 -080034import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
Brett Chabota26eda92018-07-23 13:08:30 -070035
David Stevens46939562017-03-24 13:04:00 -070036import static com.android.server.wm.WindowContainer.POSITION_TOP;
chaviwebcbc342018-02-07 13:19:00 -080037
Adrian Roos5251b1d2018-03-23 18:57:43 +010038import static org.hamcrest.Matchers.is;
Wale Ogunwale34247952017-02-19 11:57:53 -080039import static org.junit.Assert.assertEquals;
Andrii Kulianf0379de2018-03-14 16:24:07 -070040import static org.junit.Assert.assertFalse;
Adrian Roos5251b1d2018-03-23 18:57:43 +010041import static org.junit.Assert.assertThat;
Wale Ogunwale34247952017-02-19 11:57:53 -080042import static org.junit.Assert.assertTrue;
Riddle Hsu654a6f92018-07-13 22:59:36 +080043import static org.mockito.Mockito.doNothing;
44import static org.mockito.Mockito.spy;
Andrii Kulianf0379de2018-03-14 16:24:07 -070045import static org.mockito.Mockito.times;
46import static org.mockito.Mockito.verify;
Wale Ogunwale34247952017-02-19 11:57:53 -080047
Andrii Kulian92c9a942017-10-10 00:41:41 -070048import android.annotation.SuppressLint;
Andrii Kuliand68501e2017-01-10 22:57:27 -080049import android.content.res.Configuration;
Adrian Roos1cf585052018-01-03 18:43:27 +010050import android.graphics.Rect;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070051import android.os.SystemClock;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070052import android.platform.test.annotations.Presubmit;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070053import android.util.DisplayMetrics;
John Reck3d294e72018-09-21 20:26:48 +000054import android.util.SparseIntArray;
Adrian Roos1cf585052018-01-03 18:43:27 +010055import android.view.DisplayCutout;
Riddle Hsua4d6fa22018-08-11 00:50:39 +080056import android.view.Gravity;
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
Brett Chabota26eda92018-07-23 13:08:30 -070060import androidx.test.filters.FlakyTest;
61import androidx.test.filters.SmallTest;
62import androidx.test.runner.AndroidJUnit4;
63
Adrian Roos6a4fa0e2018-03-05 19:50:16 +010064import com.android.server.wm.utils.WmDisplayCutout;
65
Brett Chabota26eda92018-07-23 13:08:30 -070066import org.junit.Test;
67import org.junit.runner.RunWith;
68
Adrian Roos0f9368c2018-04-08 10:59:08 -070069import java.util.ArrayList;
Wale Ogunwale34247952017-02-19 11:57:53 -080070import java.util.Arrays;
Adrian Roos0f9368c2018-04-08 10:59:08 -070071import java.util.Collections;
Wale Ogunwale34247952017-02-19 11:57:53 -080072import java.util.LinkedList;
73import java.util.List;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070074
75/**
76 * Tests for the {@link DisplayContent} class.
77 *
78 * Build/Install/Run:
John Reck3d294e72018-09-21 20:26:48 +000079 * atest com.android.server.wm.DisplayContentTests
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070080 */
81@SmallTest
82@Presubmit
83@RunWith(AndroidJUnit4.class)
Wale Ogunwale44fbdf52016-11-16 10:18:45 -080084public class DisplayContentTests extends WindowTestsBase {
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070085
86 @Test
Adrian Roos0f9368c2018-04-08 10:59:08 -070087 @FlakyTest(bugId = 77772044)
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070088 public void testForAllWindows() throws Exception {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -080089 final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070090 mDisplayContent, "exiting app");
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070091 final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
92 exitingAppToken.mIsExiting = true;
Bryce Lee6d410262017-02-28 15:30:17 -080093 exitingAppToken.getTask().mStack.mExitingAppTokens.add(exitingAppToken);
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070094
Wale Ogunwale34247952017-02-19 11:57:53 -080095 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -070096 mWallpaperWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -080097 exitingAppWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070098 mChildAppWindowBelow,
99 mAppWindow,
100 mChildAppWindowAbove,
101 mDockedDividerWindow,
102 mStatusBarWindow,
103 mNavBarWindow,
104 mImeWindow,
105 mImeDialogWindow));
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800106 }
107
108 @Test
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800109 public void testForAllWindows_WithAppImeTarget() throws Exception {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800110 final WindowState imeAppTarget =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700111 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800112
113 sWm.mInputMethodTarget = imeAppTarget;
114
Wale Ogunwale34247952017-02-19 11:57:53 -0800115 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700116 mWallpaperWindow,
117 mChildAppWindowBelow,
118 mAppWindow,
119 mChildAppWindowAbove,
Wale Ogunwale34247952017-02-19 11:57:53 -0800120 imeAppTarget,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700121 mImeWindow,
122 mImeDialogWindow,
123 mDockedDividerWindow,
124 mStatusBarWindow,
125 mNavBarWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800126 }
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800127
Wale Ogunwale34247952017-02-19 11:57:53 -0800128 @Test
129 public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700130 sWm.mInputMethodTarget = mChildAppWindowAbove;
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800131
Wale Ogunwale34247952017-02-19 11:57:53 -0800132 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700133 mWallpaperWindow,
134 mChildAppWindowBelow,
135 mAppWindow,
136 mChildAppWindowAbove,
137 mImeWindow,
138 mImeDialogWindow,
139 mDockedDividerWindow,
140 mStatusBarWindow,
141 mNavBarWindow));
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700142 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800143
144 @Test
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800145 public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700146 sWm.mInputMethodTarget = mStatusBarWindow;
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800147
Wale Ogunwale34247952017-02-19 11:57:53 -0800148 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700149 mWallpaperWindow,
150 mChildAppWindowBelow,
151 mAppWindow,
152 mChildAppWindowAbove,
153 mDockedDividerWindow,
154 mStatusBarWindow,
155 mImeWindow,
156 mImeDialogWindow,
157 mNavBarWindow));
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800158 }
159
160 @Test
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800161 public void testForAllWindows_WithInBetweenWindowToken() throws Exception {
162 // This window is set-up to be z-ordered between some windows that go in the same token like
163 // the nav bar and status bar.
164 final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700165 mDisplayContent, "voiceInteractionWindow");
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800166
Wale Ogunwale34247952017-02-19 11:57:53 -0800167 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700168 mWallpaperWindow,
169 mChildAppWindowBelow,
170 mAppWindow,
171 mChildAppWindowAbove,
172 mDockedDividerWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -0800173 voiceInteractionWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700174 mStatusBarWindow,
175 mNavBarWindow,
176 mImeWindow,
177 mImeDialogWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800178 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800179
Wale Ogunwale34247952017-02-19 11:57:53 -0800180 @Test
181 public void testComputeImeTarget() throws Exception {
182 // Verify that an app window can be an ime target.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700183 final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
Wale Ogunwale34247952017-02-19 11:57:53 -0800184 appWin.setHasSurface(true);
185 assertTrue(appWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700186 WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800187 assertEquals(appWin, imeTarget);
chaviwebcbc342018-02-07 13:19:00 -0800188 appWin.mHidden = false;
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800189
Wale Ogunwale34247952017-02-19 11:57:53 -0800190 // Verify that an child window can be an ime target.
191 final WindowState childWin = createWindow(appWin,
192 TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
193 childWin.setHasSurface(true);
194 assertTrue(childWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700195 imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800196 assertEquals(childWin, imeTarget);
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800197 }
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800198
Andrii Kuliand68501e2017-01-10 22:57:27 -0800199 /**
200 * This tests stack movement between displays and proper stack's, task's and app token's display
201 * container references updates.
202 */
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800203 @Test
204 public void testMoveStackBetweenDisplays() throws Exception {
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800205 // Create a second display.
206 final DisplayContent dc = createNewDisplay();
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800207
208 // Add stack with activity.
209 final TaskStack stack = createTaskStackOnDisplay(dc);
210 assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
211 assertEquals(dc, stack.getParent().getParent());
212 assertEquals(dc, stack.getDisplayContent());
213
214 final Task task = createTaskInStack(stack, 0 /* userId */);
chaviw97d28202018-02-27 16:23:53 -0800215 final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
216 dc);
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800217 task.addChild(token, 0);
218 assertEquals(dc, task.getDisplayContent());
219 assertEquals(dc, token.getDisplayContent());
220
221 // Move stack to first display.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700222 mDisplayContent.moveStackToDisplay(stack, true /* onTop */);
223 assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
224 assertEquals(mDisplayContent, stack.getParent().getParent());
225 assertEquals(mDisplayContent, stack.getDisplayContent());
226 assertEquals(mDisplayContent, task.getDisplayContent());
227 assertEquals(mDisplayContent, token.getDisplayContent());
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800228 }
Andrii Kuliand68501e2017-01-10 22:57:27 -0800229
230 /**
231 * This tests override configuration updates for display content.
232 */
233 @Test
234 public void testDisplayOverrideConfigUpdate() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700235 final int displayId = mDisplayContent.getDisplayId();
236 final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800237
238 // Create new, slightly changed override configuration and apply it to the display.
239 final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
240 newOverrideConfig.densityDpi += 120;
241 newOverrideConfig.fontScale += 0.3;
242
243 sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
244
245 // Check that override config is applied.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700246 assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration());
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800247 }
248
249 /**
250 * This tests global configuration updates when default display config is updated.
251 */
252 @Test
253 public void testDefaultDisplayOverrideConfigUpdate() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700254 final Configuration currentConfig = mDisplayContent.getConfiguration();
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800255
256 // Create new, slightly changed override configuration and apply it to the display.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700257 final Configuration newOverrideConfig = new Configuration(currentConfig);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800258 newOverrideConfig.densityDpi += 120;
259 newOverrideConfig.fontScale += 0.3;
260
261 sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800262
263 // Check that global configuration is updated, as we've updated default display's config.
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800264 Configuration globalConfig = sWm.mRoot.getConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800265 assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
266 assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800267
268 // Return back to original values.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700269 sWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800270 globalConfig = sWm.mRoot.getConfiguration();
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700271 assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
272 assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800273 }
Wale Ogunwale34247952017-02-19 11:57:53 -0800274
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700275 /**
276 * Tests tapping on a stack in different display results in window gaining focus.
277 */
278 @Test
279 public void testInputEventBringsCorrectDisplayInFocus() throws Exception {
280 DisplayContent dc0 = sWm.getDefaultDisplayContentLocked();
281 // Create a second display
282 final DisplayContent dc1 = createNewDisplay();
283
284 // Add stack with activity.
285 final TaskStack stack0 = createTaskStackOnDisplay(dc0);
286 final Task task0 = createTaskInStack(stack0, 0 /* userId */);
287 final WindowTestUtils.TestAppWindowToken token =
chaviw97d28202018-02-27 16:23:53 -0800288 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700289 task0.addChild(token, 0);
290 dc0.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
291 sWm.registerPointerEventListener(dc0.mTapDetector);
292 final TaskStack stack1 = createTaskStackOnDisplay(dc1);
293 final Task task1 = createTaskInStack(stack1, 0 /* userId */);
294 final WindowTestUtils.TestAppWindowToken token1 =
chaviw97d28202018-02-27 16:23:53 -0800295 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700296 task1.addChild(token1, 0);
297 dc1.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
298 sWm.registerPointerEventListener(dc1.mTapDetector);
299
300 // tap on primary display (by sending ACTION_DOWN followed by ACTION_UP)
301 DisplayMetrics dm0 = dc0.getDisplayMetrics();
302 dc0.mTapDetector.onPointerEvent(
303 createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, true));
304 dc0.mTapDetector.onPointerEvent(
305 createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, false));
306
307 // Check focus is on primary display.
308 assertEquals(sWm.mCurrentFocus, dc0.findFocusedWindow());
309
310 // Tap on secondary display
311 DisplayMetrics dm1 = dc1.getDisplayMetrics();
312 dc1.mTapDetector.onPointerEvent(
313 createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, true));
314 dc1.mTapDetector.onPointerEvent(
315 createTapEvent(dm1.widthPixels / 2, dm1.heightPixels / 2, false));
316
317 // Check focus is on secondary.
318 assertEquals(sWm.mCurrentFocus, dc1.findFocusedWindow());
319 }
320
David Stevens46939562017-03-24 13:04:00 -0700321 @Test
322 public void testFocusedWindowMultipleDisplays() throws Exception {
Andrii Kulian0214ed92017-05-16 13:44:05 -0700323 // Create a focusable window and check that focus is calculated correctly
David Stevens46939562017-03-24 13:04:00 -0700324 final WindowState window1 =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700325 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
David Stevens46939562017-03-24 13:04:00 -0700326 assertEquals(window1, sWm.mRoot.computeFocusedWindow());
327
328 // Check that a new display doesn't affect focus
329 final DisplayContent dc = createNewDisplay();
330 assertEquals(window1, sWm.mRoot.computeFocusedWindow());
331
332 // Add a window to the second display, and it should be focused
333 final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
334 assertEquals(window2, sWm.mRoot.computeFocusedWindow());
335
336 // Move the first window to the to including parents, and make sure focus is updated
337 window1.getParent().positionChildAt(POSITION_TOP, window1, true);
338 assertEquals(window1, sWm.mRoot.computeFocusedWindow());
339 }
340
Adrian Roos4163d622018-05-22 16:56:35 +0200341 @Test
342 public void testKeyguard_preventsSecondaryDisplayFocus() throws Exception {
343 final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR,
344 sWm.getDefaultDisplayContentLocked(), "keyguard");
345 assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
346
347 // Add a window to a second display, and it should be focused
348 final DisplayContent dc = createNewDisplay();
349 final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
350 assertEquals(win, sWm.mRoot.computeFocusedWindow());
351
352 mWmRule.getWindowManagerPolicy().keyguardShowingAndNotOccluded = true;
353 assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
354 }
355
Bryce Lee27cec322017-03-21 09:41:37 -0700356 /**
357 * This tests setting the maximum ui width on a display.
358 */
359 @Test
360 public void testMaxUiWidth() throws Exception {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800361 // Prevent base display metrics for test from being updated to the value of real display.
362 final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
Bryce Lee27cec322017-03-21 09:41:37 -0700363 final int baseWidth = 1440;
364 final int baseHeight = 2560;
365 final int baseDensity = 300;
366
Riddle Hsu654a6f92018-07-13 22:59:36 +0800367 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700368
369 final int maxWidth = 300;
370 final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
371 final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
372
Riddle Hsu654a6f92018-07-13 22:59:36 +0800373 displayContent.setMaxUiWidth(maxWidth);
374 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700375
376 // Assert setting values again does not change;
Riddle Hsu654a6f92018-07-13 22:59:36 +0800377 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
378 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700379
380 final int smallerWidth = 200;
381 final int smallerHeight = 400;
382 final int smallerDensity = 100;
383
384 // Specify smaller dimension, verify that it is honored
Riddle Hsu654a6f92018-07-13 22:59:36 +0800385 displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
386 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700387
388 // Verify that setting the max width to a greater value than the base width has no effect
Riddle Hsu654a6f92018-07-13 22:59:36 +0800389 displayContent.setMaxUiWidth(maxWidth);
390 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700391 }
392
Bryce Lee48f4b572017-04-10 10:54:15 -0700393 /**
Kazuki Takise148d00a2018-05-31 15:32:19 +0900394 * This test enforces that alwaysOnTop stack is placed at proper position.
Bryce Lee48f4b572017-04-10 10:54:15 -0700395 */
396 @Test
Kazuki Takise148d00a2018-05-31 15:32:19 +0900397 public void testAlwaysOnTopStackLocation() {
Kazuki Takise048e2662018-06-27 17:05:11 +0900398 final TaskStack alwaysOnTopStack = createStackControllerOnStackOnDisplay(
399 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900400 final Task task = createTaskInStack(alwaysOnTopStack, 0 /* userId */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900401 alwaysOnTopStack.setAlwaysOnTop(true);
Riddle Hsu57831b52018-07-27 00:31:48 +0800402 mDisplayContent.positionStackAt(POSITION_TOP, alwaysOnTopStack,
403 false /* includingParents */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900404 assertTrue(alwaysOnTopStack.isAlwaysOnTop());
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900405 // Ensure always on top state is synced to the children of the stack.
406 assertTrue(alwaysOnTopStack.getTopChild().isAlwaysOnTop());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900407 assertEquals(alwaysOnTopStack, mDisplayContent.getTopStack());
408
Wale Ogunwale61911492017-10-11 08:50:50 -0700409 final TaskStack pinnedStack = createStackControllerOnStackOnDisplay(
410 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Wale Ogunwale61911492017-10-11 08:50:50 -0700411 assertEquals(pinnedStack, mDisplayContent.getPinnedStack());
412 assertEquals(pinnedStack, mDisplayContent.getTopStack());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900413
Kazuki Takise048e2662018-06-27 17:05:11 +0900414 final TaskStack anotherAlwaysOnTopStack = createStackControllerOnStackOnDisplay(
415 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900416 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
Riddle Hsu57831b52018-07-27 00:31:48 +0800417 mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack,
418 false /* includingParents */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900419 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
420 int topPosition = mDisplayContent.getStacks().size() - 1;
421 // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
422 // existing alwaysOnTop stack.
423 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
424
Kazuki Takise048e2662018-06-27 17:05:11 +0900425 final TaskStack nonAlwaysOnTopStack = createStackControllerOnStackOnDisplay(
426 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900427 assertEquals(mDisplayContent, nonAlwaysOnTopStack.getDisplayContent());
428 topPosition = mDisplayContent.getStacks().size() - 1;
429 // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
430 // existing other non-alwaysOnTop stacks.
431 assertEquals(nonAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 3));
Kazuki Takisef85197b2018-06-18 18:18:36 +0900432
433 anotherAlwaysOnTopStack.setAlwaysOnTop(false);
Riddle Hsu57831b52018-07-27 00:31:48 +0800434 mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack,
435 false /* includingParents */);
Kazuki Takisef85197b2018-06-18 18:18:36 +0900436 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
Kazuki Takisef85197b2018-06-18 18:18:36 +0900437 // Ensure, when always on top is turned off for a stack, the stack is put just below all
438 // other always on top stacks.
439 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
Kazuki Takise048e2662018-06-27 17:05:11 +0900440 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
441
442 // Ensure always on top state changes properly when windowing mode changes.
443 anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
444 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
445 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
446 anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
447 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
448 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
Bryce Lee48f4b572017-04-10 10:54:15 -0700449 }
450
Andrii Kulian92c9a942017-10-10 00:41:41 -0700451 @Test
Adrian Roos1cf585052018-01-03 18:43:27 +0100452 public void testDisplayCutout_rot0() throws Exception {
453 synchronized (sWm.getWindowManagerLock()) {
454 final DisplayContent dc = createNewDisplay();
455 dc.mInitialDisplayWidth = 200;
456 dc.mInitialDisplayHeight = 400;
Adrian Roos24264212018-02-19 16:26:15 +0100457 Rect r = new Rect(80, 0, 120, 10);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100458 final DisplayCutout cutout = new WmDisplayCutout(
Issei Suzuki43190bd2018-08-20 17:28:41 +0200459 fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_TOP), null)
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100460 .computeSafeInsets(200, 400).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100461
462 dc.mInitialDisplayCutout = cutout;
463 dc.setRotation(Surface.ROTATION_0);
464 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
465
466 assertEquals(cutout, dc.getDisplayInfo().displayCutout);
467 }
468 }
469
470 @Test
471 public void testDisplayCutout_rot90() throws Exception {
472 synchronized (sWm.getWindowManagerLock()) {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800473 // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
474 // if the device has no cutout).
475 final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
476 // Rotation may use real display info to compute bound, so here also uses the
477 // same width and height.
478 final int displayWidth = dc.mInitialDisplayWidth;
479 final int displayHeight = dc.mInitialDisplayHeight;
480 final int cutoutWidth = 40;
481 final int cutoutHeight = 10;
482 final int left = (displayWidth - cutoutWidth) / 2;
483 final int top = 0;
484 final int right = (displayWidth + cutoutWidth) / 2;
485 final int bottom = cutoutHeight;
486
487 final Rect r1 = new Rect(left, top, right, bottom);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100488 final DisplayCutout cutout = new WmDisplayCutout(
Issei Suzuki43190bd2018-08-20 17:28:41 +0200489 fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800490 .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100491
492 dc.mInitialDisplayCutout = cutout;
493 dc.setRotation(Surface.ROTATION_90);
494 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
495
Riddle Hsu654a6f92018-07-13 22:59:36 +0800496 // ----o---------- -------------
497 // | | | | |
498 // | ------o | o---
499 // | | | |
500 // | | -> | |
501 // | | ---o
502 // | | |
503 // | | -------------
504 final Rect r = new Rect(top, left, bottom, right);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100505 assertEquals(new WmDisplayCutout(
Issei Suzuki43190bd2018-08-20 17:28:41 +0200506 fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_LEFT), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800507 .computeSafeInsets(displayHeight, displayWidth)
508 .getDisplayCutout(), dc.getDisplayInfo().displayCutout);
Adrian Roos1cf585052018-01-03 18:43:27 +0100509 }
510 }
511
512 @Test
Adrian Roos5251b1d2018-03-23 18:57:43 +0100513 public void testLayoutSeq_assignedDuringLayout() throws Exception {
514 synchronized (sWm.getWindowManagerLock()) {
515
516 final DisplayContent dc = createNewDisplay();
517 final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
518
519 dc.setLayoutNeeded();
520 dc.performLayout(true /* initial */, false /* updateImeWindows */);
521
522 assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
523 }
524 }
525
526 @Test
Andrii Kulian92c9a942017-10-10 00:41:41 -0700527 @SuppressLint("InlinedApi")
528 public void testOrientationDefinedByKeyguard() {
529 final DisplayContent dc = createNewDisplay();
530 // Create a window that requests landscape orientation. It will define device orientation
531 // by default.
532 final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
533 window.mAppToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
534
535 final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, dc, "keyguard");
536 keyguard.mHasSurface = true;
537 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
538
539 assertEquals("Screen orientation must be defined by the app window by default",
540 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
541
542 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
543 assertEquals("Visible keyguard must influence device orientation",
544 SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
545
546 sWm.setKeyguardGoingAway(true);
547 assertEquals("Keyguard that is going away must not influence device orientation",
548 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
549 }
550
Andrii Kulianf0379de2018-03-14 16:24:07 -0700551 @Test
552 public void testDisableDisplayInfoOverrideFromWindowManager() {
553 final DisplayContent dc = createNewDisplay();
554
555 assertTrue(dc.mShouldOverrideDisplayConfiguration);
556 sWm.dontOverrideDisplayInfo(dc.getDisplayId());
557
558 assertFalse(dc.mShouldOverrideDisplayConfiguration);
559 verify(sWm.mDisplayManagerInternal, times(1))
560 .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
561 }
562
Riddle Hsua4d6fa22018-08-11 00:50:39 +0800563 @Test
564 public void testGetPreferredOptionsPanelGravityFromDifferentDisplays() {
565 final DisplayContent portraitDisplay = createNewDisplay();
566 portraitDisplay.mInitialDisplayHeight = 2000;
567 portraitDisplay.mInitialDisplayWidth = 1000;
568
569 portraitDisplay.setRotation(Surface.ROTATION_0);
570 assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
571 portraitDisplay.setRotation(Surface.ROTATION_90);
572 assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
573
574 final DisplayContent landscapeDisplay = createNewDisplay();
575 landscapeDisplay.mInitialDisplayHeight = 1000;
576 landscapeDisplay.mInitialDisplayWidth = 2000;
577
578 landscapeDisplay.setRotation(Surface.ROTATION_0);
579 assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
580 landscapeDisplay.setRotation(Surface.ROTATION_90);
581 assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
582 }
583
584 private boolean isOptionsPanelAtRight(int displayId) {
585 return (sWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
586 }
587
Bryce Lee27cec322017-03-21 09:41:37 -0700588 private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
589 int expectedBaseHeight, int expectedBaseDensity) {
590 assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
591 assertEquals(displayContent.mBaseDisplayHeight, expectedBaseHeight);
592 assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
593 }
594
Riddle Hsu654a6f92018-07-13 22:59:36 +0800595 /**
596 * Create DisplayContent that does not update display base/initial values from device to keep
597 * the values set by test.
598 */
599 private DisplayContent createDisplayNoUpdateDisplayInfo() {
600 final DisplayContent displayContent = spy(createNewDisplay());
601 doNothing().when(displayContent).updateDisplayInfo();
602 return displayContent;
603 }
604
Adrian Roos0f9368c2018-04-08 10:59:08 -0700605 private void assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop) {
606 final LinkedList<WindowState> actualWindows = new LinkedList<>();
Wale Ogunwale34247952017-02-19 11:57:53 -0800607
608 // Test forward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700609 mDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700610 assertThat("bottomToTop", actualWindows, is(expectedWindowsBottomToTop));
611
612 actualWindows.clear();
Wale Ogunwale34247952017-02-19 11:57:53 -0800613
614 // Test backward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700615 mDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700616 assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop)));
617 }
618
619 private static List<WindowState> reverseList(List<WindowState> list) {
620 final ArrayList<WindowState> result = new ArrayList<>(list);
621 Collections.reverse(result);
622 return result;
Wale Ogunwale34247952017-02-19 11:57:53 -0800623 }
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700624
625 private MotionEvent createTapEvent(float x, float y, boolean isDownEvent) {
626 final long downTime = SystemClock.uptimeMillis();
627 final long eventTime = SystemClock.uptimeMillis() + 100;
628 final int metaState = 0;
629
630 return MotionEvent.obtain(
631 downTime,
632 eventTime,
633 isDownEvent ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP,
634 x,
635 y,
636 metaState);
637 }
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700638}