blob: 96c5fde83926d7314a144a8bd06c4e85a2653cc5 [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;
Tiger Huang1e5b10a2018-07-30 20:19:51 +080035import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
chaviwebcbc342018-02-07 13:19:00 -080036
Adrian Roos5251b1d2018-03-23 18:57:43 +010037import static org.hamcrest.Matchers.is;
Wale Ogunwale34247952017-02-19 11:57:53 -080038import static org.junit.Assert.assertEquals;
Andrii Kulianf0379de2018-03-14 16:24:07 -070039import static org.junit.Assert.assertFalse;
Adrian Roos5251b1d2018-03-23 18:57:43 +010040import static org.junit.Assert.assertThat;
Wale Ogunwale34247952017-02-19 11:57:53 -080041import static org.junit.Assert.assertTrue;
Riddle Hsu654a6f92018-07-13 22:59:36 +080042import static org.mockito.Mockito.doNothing;
43import static org.mockito.Mockito.spy;
Andrii Kulianf0379de2018-03-14 16:24:07 -070044import static org.mockito.Mockito.times;
45import static org.mockito.Mockito.verify;
Wale Ogunwale34247952017-02-19 11:57:53 -080046
Andrii Kulian92c9a942017-10-10 00:41:41 -070047import android.annotation.SuppressLint;
Andrii Kuliand68501e2017-01-10 22:57:27 -080048import android.content.res.Configuration;
Adrian Roos1cf585052018-01-03 18:43:27 +010049import android.graphics.Rect;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070050import android.os.SystemClock;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070051import android.platform.test.annotations.Presubmit;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070052import android.util.DisplayMetrics;
John Reck3d294e72018-09-21 20:26:48 +000053import android.util.SparseIntArray;
Adrian Roos1cf585052018-01-03 18:43:27 +010054import android.view.DisplayCutout;
Riddle Hsua4d6fa22018-08-11 00:50:39 +080055import android.view.Gravity;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070056import android.view.MotionEvent;
Adrian Roos1cf585052018-01-03 18:43:27 +010057import android.view.Surface;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070058
Brett Chabota26eda92018-07-23 13:08:30 -070059import androidx.test.filters.FlakyTest;
60import androidx.test.filters.SmallTest;
61import androidx.test.runner.AndroidJUnit4;
62
Adrian Roos6a4fa0e2018-03-05 19:50:16 +010063import com.android.server.wm.utils.WmDisplayCutout;
64
Brett Chabota26eda92018-07-23 13:08:30 -070065import org.junit.Test;
66import org.junit.runner.RunWith;
67
Adrian Roos0f9368c2018-04-08 10:59:08 -070068import java.util.ArrayList;
Wale Ogunwale34247952017-02-19 11:57:53 -080069import java.util.Arrays;
Adrian Roos0f9368c2018-04-08 10:59:08 -070070import java.util.Collections;
Wale Ogunwale34247952017-02-19 11:57:53 -080071import java.util.LinkedList;
72import java.util.List;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070073
74/**
75 * Tests for the {@link DisplayContent} class.
76 *
77 * Build/Install/Run:
John Reck3d294e72018-09-21 20:26:48 +000078 * atest com.android.server.wm.DisplayContentTests
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070079 */
80@SmallTest
81@Presubmit
82@RunWith(AndroidJUnit4.class)
Wale Ogunwale44fbdf52016-11-16 10:18:45 -080083public class DisplayContentTests extends WindowTestsBase {
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070084
85 @Test
Adrian Roos0f9368c2018-04-08 10:59:08 -070086 @FlakyTest(bugId = 77772044)
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070087 public void testForAllWindows() throws Exception {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -080088 final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070089 mDisplayContent, "exiting app");
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070090 final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
91 exitingAppToken.mIsExiting = true;
Bryce Lee6d410262017-02-28 15:30:17 -080092 exitingAppToken.getTask().mStack.mExitingAppTokens.add(exitingAppToken);
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070093
Wale Ogunwale34247952017-02-19 11:57:53 -080094 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -070095 mWallpaperWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -080096 exitingAppWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070097 mChildAppWindowBelow,
98 mAppWindow,
99 mChildAppWindowAbove,
100 mDockedDividerWindow,
101 mStatusBarWindow,
102 mNavBarWindow,
103 mImeWindow,
104 mImeDialogWindow));
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800105 }
106
107 @Test
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800108 public void testForAllWindows_WithAppImeTarget() throws Exception {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800109 final WindowState imeAppTarget =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700110 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800111
112 sWm.mInputMethodTarget = imeAppTarget;
113
Wale Ogunwale34247952017-02-19 11:57:53 -0800114 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700115 mWallpaperWindow,
116 mChildAppWindowBelow,
117 mAppWindow,
118 mChildAppWindowAbove,
Wale Ogunwale34247952017-02-19 11:57:53 -0800119 imeAppTarget,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700120 mImeWindow,
121 mImeDialogWindow,
122 mDockedDividerWindow,
123 mStatusBarWindow,
124 mNavBarWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800125 }
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800126
Wale Ogunwale34247952017-02-19 11:57:53 -0800127 @Test
128 public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700129 sWm.mInputMethodTarget = mChildAppWindowAbove;
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800130
Wale Ogunwale34247952017-02-19 11:57:53 -0800131 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700132 mWallpaperWindow,
133 mChildAppWindowBelow,
134 mAppWindow,
135 mChildAppWindowAbove,
136 mImeWindow,
137 mImeDialogWindow,
138 mDockedDividerWindow,
139 mStatusBarWindow,
140 mNavBarWindow));
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700141 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800142
143 @Test
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800144 public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700145 sWm.mInputMethodTarget = mStatusBarWindow;
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800146
Wale Ogunwale34247952017-02-19 11:57:53 -0800147 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700148 mWallpaperWindow,
149 mChildAppWindowBelow,
150 mAppWindow,
151 mChildAppWindowAbove,
152 mDockedDividerWindow,
153 mStatusBarWindow,
154 mImeWindow,
155 mImeDialogWindow,
156 mNavBarWindow));
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800157 }
158
159 @Test
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800160 public void testForAllWindows_WithInBetweenWindowToken() throws Exception {
161 // This window is set-up to be z-ordered between some windows that go in the same token like
162 // the nav bar and status bar.
163 final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700164 mDisplayContent, "voiceInteractionWindow");
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800165
Wale Ogunwale34247952017-02-19 11:57:53 -0800166 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700167 mWallpaperWindow,
168 mChildAppWindowBelow,
169 mAppWindow,
170 mChildAppWindowAbove,
171 mDockedDividerWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -0800172 voiceInteractionWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700173 mStatusBarWindow,
174 mNavBarWindow,
175 mImeWindow,
176 mImeDialogWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800177 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800178
Wale Ogunwale34247952017-02-19 11:57:53 -0800179 @Test
180 public void testComputeImeTarget() throws Exception {
181 // Verify that an app window can be an ime target.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700182 final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
Wale Ogunwale34247952017-02-19 11:57:53 -0800183 appWin.setHasSurface(true);
184 assertTrue(appWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700185 WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800186 assertEquals(appWin, imeTarget);
chaviwebcbc342018-02-07 13:19:00 -0800187 appWin.mHidden = false;
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800188
Wale Ogunwale34247952017-02-19 11:57:53 -0800189 // Verify that an child window can be an ime target.
190 final WindowState childWin = createWindow(appWin,
191 TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
192 childWin.setHasSurface(true);
193 assertTrue(childWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700194 imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800195 assertEquals(childWin, imeTarget);
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800196 }
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800197
Andrii Kuliand68501e2017-01-10 22:57:27 -0800198 /**
199 * This tests stack movement between displays and proper stack's, task's and app token's display
200 * container references updates.
201 */
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800202 @Test
203 public void testMoveStackBetweenDisplays() throws Exception {
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800204 // Create a second display.
205 final DisplayContent dc = createNewDisplay();
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800206
207 // Add stack with activity.
208 final TaskStack stack = createTaskStackOnDisplay(dc);
209 assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
210 assertEquals(dc, stack.getParent().getParent());
211 assertEquals(dc, stack.getDisplayContent());
212
213 final Task task = createTaskInStack(stack, 0 /* userId */);
chaviw97d28202018-02-27 16:23:53 -0800214 final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
215 dc);
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800216 task.addChild(token, 0);
217 assertEquals(dc, task.getDisplayContent());
218 assertEquals(dc, token.getDisplayContent());
219
220 // Move stack to first display.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700221 mDisplayContent.moveStackToDisplay(stack, true /* onTop */);
222 assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
223 assertEquals(mDisplayContent, stack.getParent().getParent());
224 assertEquals(mDisplayContent, stack.getDisplayContent());
225 assertEquals(mDisplayContent, task.getDisplayContent());
226 assertEquals(mDisplayContent, token.getDisplayContent());
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800227 }
Andrii Kuliand68501e2017-01-10 22:57:27 -0800228
229 /**
230 * This tests override configuration updates for display content.
231 */
232 @Test
233 public void testDisplayOverrideConfigUpdate() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700234 final int displayId = mDisplayContent.getDisplayId();
235 final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800236
237 // Create new, slightly changed override configuration and apply it to the display.
238 final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
239 newOverrideConfig.densityDpi += 120;
240 newOverrideConfig.fontScale += 0.3;
241
242 sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
243
244 // Check that override config is applied.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700245 assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration());
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800246 }
247
248 /**
249 * This tests global configuration updates when default display config is updated.
250 */
251 @Test
252 public void testDefaultDisplayOverrideConfigUpdate() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700253 final Configuration currentConfig = mDisplayContent.getConfiguration();
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800254
255 // Create new, slightly changed override configuration and apply it to the display.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700256 final Configuration newOverrideConfig = new Configuration(currentConfig);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800257 newOverrideConfig.densityDpi += 120;
258 newOverrideConfig.fontScale += 0.3;
259
260 sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800261
262 // Check that global configuration is updated, as we've updated default display's config.
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800263 Configuration globalConfig = sWm.mRoot.getConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800264 assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
265 assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800266
267 // Return back to original values.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700268 sWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800269 globalConfig = sWm.mRoot.getConfiguration();
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700270 assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
271 assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800272 }
Wale Ogunwale34247952017-02-19 11:57:53 -0800273
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700274 /**
275 * Tests tapping on a stack in different display results in window gaining focus.
276 */
277 @Test
278 public void testInputEventBringsCorrectDisplayInFocus() throws Exception {
279 DisplayContent dc0 = sWm.getDefaultDisplayContentLocked();
280 // Create a second display
281 final DisplayContent dc1 = createNewDisplay();
282
283 // Add stack with activity.
284 final TaskStack stack0 = createTaskStackOnDisplay(dc0);
285 final Task task0 = createTaskInStack(stack0, 0 /* userId */);
286 final WindowTestUtils.TestAppWindowToken token =
chaviw97d28202018-02-27 16:23:53 -0800287 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700288 task0.addChild(token, 0);
289 dc0.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
290 sWm.registerPointerEventListener(dc0.mTapDetector);
291 final TaskStack stack1 = createTaskStackOnDisplay(dc1);
292 final Task task1 = createTaskInStack(stack1, 0 /* userId */);
293 final WindowTestUtils.TestAppWindowToken token1 =
chaviw97d28202018-02-27 16:23:53 -0800294 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700295 task1.addChild(token1, 0);
296 dc1.mTapDetector = new TaskTapPointerEventListener(sWm, dc0);
297 sWm.registerPointerEventListener(dc1.mTapDetector);
298
299 // tap on primary display (by sending ACTION_DOWN followed by ACTION_UP)
300 DisplayMetrics dm0 = dc0.getDisplayMetrics();
301 dc0.mTapDetector.onPointerEvent(
302 createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, true));
303 dc0.mTapDetector.onPointerEvent(
304 createTapEvent(dm0.widthPixels / 2, dm0.heightPixels / 2, false));
305
306 // Check focus is on primary display.
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800307 assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
308 dc0.findFocusedWindow());
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700309
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.
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800318 assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
319 dc1.findFocusedWindow());
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700320 }
321
David Stevens46939562017-03-24 13:04:00 -0700322 @Test
323 public void testFocusedWindowMultipleDisplays() throws Exception {
Andrii Kulian0214ed92017-05-16 13:44:05 -0700324 // Create a focusable window and check that focus is calculated correctly
David Stevens46939562017-03-24 13:04:00 -0700325 final WindowState window1 =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700326 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800327 updateFocusedWindow();
328 assertTrue(window1.isFocused());
329 assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
David Stevens46939562017-03-24 13:04:00 -0700330
331 // Check that a new display doesn't affect focus
332 final DisplayContent dc = createNewDisplay();
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800333 updateFocusedWindow();
334 assertTrue(window1.isFocused());
335 assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
David Stevens46939562017-03-24 13:04:00 -0700336
337 // Add a window to the second display, and it should be focused
338 final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800339 updateFocusedWindow();
340 assertTrue(window1.isFocused());
341 assertTrue(window2.isFocused());
342 assertEquals(window2, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
David Stevens46939562017-03-24 13:04:00 -0700343
344 // Move the first window to the to including parents, and make sure focus is updated
345 window1.getParent().positionChildAt(POSITION_TOP, window1, true);
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800346 updateFocusedWindow();
347 assertTrue(window1.isFocused());
348 assertTrue(window2.isFocused());
349 assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
Adrian Roos4163d622018-05-22 16:56:35 +0200350 }
351
Bryce Lee27cec322017-03-21 09:41:37 -0700352 /**
353 * This tests setting the maximum ui width on a display.
354 */
355 @Test
356 public void testMaxUiWidth() throws Exception {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800357 // Prevent base display metrics for test from being updated to the value of real display.
358 final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
Bryce Lee27cec322017-03-21 09:41:37 -0700359 final int baseWidth = 1440;
360 final int baseHeight = 2560;
361 final int baseDensity = 300;
362
Riddle Hsu654a6f92018-07-13 22:59:36 +0800363 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700364
365 final int maxWidth = 300;
366 final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
367 final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
368
Riddle Hsu654a6f92018-07-13 22:59:36 +0800369 displayContent.setMaxUiWidth(maxWidth);
370 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700371
372 // Assert setting values again does not change;
Riddle Hsu654a6f92018-07-13 22:59:36 +0800373 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
374 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700375
376 final int smallerWidth = 200;
377 final int smallerHeight = 400;
378 final int smallerDensity = 100;
379
380 // Specify smaller dimension, verify that it is honored
Riddle Hsu654a6f92018-07-13 22:59:36 +0800381 displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
382 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700383
384 // Verify that setting the max width to a greater value than the base width has no effect
Riddle Hsu654a6f92018-07-13 22:59:36 +0800385 displayContent.setMaxUiWidth(maxWidth);
386 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700387 }
388
Bryce Lee48f4b572017-04-10 10:54:15 -0700389 /**
Kazuki Takise148d00a2018-05-31 15:32:19 +0900390 * This test enforces that alwaysOnTop stack is placed at proper position.
Bryce Lee48f4b572017-04-10 10:54:15 -0700391 */
392 @Test
Kazuki Takise148d00a2018-05-31 15:32:19 +0900393 public void testAlwaysOnTopStackLocation() {
Kazuki Takise048e2662018-06-27 17:05:11 +0900394 final TaskStack alwaysOnTopStack = createStackControllerOnStackOnDisplay(
395 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900396 final Task task = createTaskInStack(alwaysOnTopStack, 0 /* userId */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900397 alwaysOnTopStack.setAlwaysOnTop(true);
Riddle Hsu57831b52018-07-27 00:31:48 +0800398 mDisplayContent.positionStackAt(POSITION_TOP, alwaysOnTopStack,
399 false /* includingParents */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900400 assertTrue(alwaysOnTopStack.isAlwaysOnTop());
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900401 // Ensure always on top state is synced to the children of the stack.
402 assertTrue(alwaysOnTopStack.getTopChild().isAlwaysOnTop());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900403 assertEquals(alwaysOnTopStack, mDisplayContent.getTopStack());
404
Wale Ogunwale61911492017-10-11 08:50:50 -0700405 final TaskStack pinnedStack = createStackControllerOnStackOnDisplay(
406 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Wale Ogunwale61911492017-10-11 08:50:50 -0700407 assertEquals(pinnedStack, mDisplayContent.getPinnedStack());
408 assertEquals(pinnedStack, mDisplayContent.getTopStack());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900409
Kazuki Takise048e2662018-06-27 17:05:11 +0900410 final TaskStack anotherAlwaysOnTopStack = createStackControllerOnStackOnDisplay(
411 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900412 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
Riddle Hsu57831b52018-07-27 00:31:48 +0800413 mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack,
414 false /* includingParents */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900415 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
416 int topPosition = mDisplayContent.getStacks().size() - 1;
417 // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
418 // existing alwaysOnTop stack.
419 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
420
Kazuki Takise048e2662018-06-27 17:05:11 +0900421 final TaskStack nonAlwaysOnTopStack = createStackControllerOnStackOnDisplay(
422 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900423 assertEquals(mDisplayContent, nonAlwaysOnTopStack.getDisplayContent());
424 topPosition = mDisplayContent.getStacks().size() - 1;
425 // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
426 // existing other non-alwaysOnTop stacks.
427 assertEquals(nonAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 3));
Kazuki Takisef85197b2018-06-18 18:18:36 +0900428
429 anotherAlwaysOnTopStack.setAlwaysOnTop(false);
Riddle Hsu57831b52018-07-27 00:31:48 +0800430 mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack,
431 false /* includingParents */);
Kazuki Takisef85197b2018-06-18 18:18:36 +0900432 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
Kazuki Takisef85197b2018-06-18 18:18:36 +0900433 // Ensure, when always on top is turned off for a stack, the stack is put just below all
434 // other always on top stacks.
435 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
Kazuki Takise048e2662018-06-27 17:05:11 +0900436 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
437
438 // Ensure always on top state changes properly when windowing mode changes.
439 anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
440 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
441 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
442 anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
443 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
444 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
Bryce Lee48f4b572017-04-10 10:54:15 -0700445 }
446
Andrii Kulian92c9a942017-10-10 00:41:41 -0700447 @Test
Adrian Roos1cf585052018-01-03 18:43:27 +0100448 public void testDisplayCutout_rot0() throws Exception {
449 synchronized (sWm.getWindowManagerLock()) {
450 final DisplayContent dc = createNewDisplay();
451 dc.mInitialDisplayWidth = 200;
452 dc.mInitialDisplayHeight = 400;
Adrian Roos24264212018-02-19 16:26:15 +0100453 Rect r = new Rect(80, 0, 120, 10);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100454 final DisplayCutout cutout = new WmDisplayCutout(
455 fromBoundingRect(r.left, r.top, r.right, r.bottom), null)
456 .computeSafeInsets(200, 400).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100457
458 dc.mInitialDisplayCutout = cutout;
459 dc.setRotation(Surface.ROTATION_0);
460 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
461
462 assertEquals(cutout, dc.getDisplayInfo().displayCutout);
463 }
464 }
465
466 @Test
467 public void testDisplayCutout_rot90() throws Exception {
468 synchronized (sWm.getWindowManagerLock()) {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800469 // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
470 // if the device has no cutout).
471 final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
472 // Rotation may use real display info to compute bound, so here also uses the
473 // same width and height.
474 final int displayWidth = dc.mInitialDisplayWidth;
475 final int displayHeight = dc.mInitialDisplayHeight;
476 final int cutoutWidth = 40;
477 final int cutoutHeight = 10;
478 final int left = (displayWidth - cutoutWidth) / 2;
479 final int top = 0;
480 final int right = (displayWidth + cutoutWidth) / 2;
481 final int bottom = cutoutHeight;
482
483 final Rect r1 = new Rect(left, top, right, bottom);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100484 final DisplayCutout cutout = new WmDisplayCutout(
485 fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800486 .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100487
488 dc.mInitialDisplayCutout = cutout;
489 dc.setRotation(Surface.ROTATION_90);
490 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
491
Riddle Hsu654a6f92018-07-13 22:59:36 +0800492 // ----o---------- -------------
493 // | | | | |
494 // | ------o | o---
495 // | | | |
496 // | | -> | |
497 // | | ---o
498 // | | |
499 // | | -------------
500 final Rect r = new Rect(top, left, bottom, right);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100501 assertEquals(new WmDisplayCutout(
502 fromBoundingRect(r.left, r.top, r.right, r.bottom), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800503 .computeSafeInsets(displayHeight, displayWidth)
504 .getDisplayCutout(), dc.getDisplayInfo().displayCutout);
Adrian Roos1cf585052018-01-03 18:43:27 +0100505 }
506 }
507
508 @Test
Adrian Roos5251b1d2018-03-23 18:57:43 +0100509 public void testLayoutSeq_assignedDuringLayout() throws Exception {
510 synchronized (sWm.getWindowManagerLock()) {
511
512 final DisplayContent dc = createNewDisplay();
513 final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
514
515 dc.setLayoutNeeded();
516 dc.performLayout(true /* initial */, false /* updateImeWindows */);
517
518 assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
519 }
520 }
521
522 @Test
Andrii Kulian92c9a942017-10-10 00:41:41 -0700523 @SuppressLint("InlinedApi")
524 public void testOrientationDefinedByKeyguard() {
525 final DisplayContent dc = createNewDisplay();
526 // Create a window that requests landscape orientation. It will define device orientation
527 // by default.
528 final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
529 window.mAppToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
530
531 final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, dc, "keyguard");
532 keyguard.mHasSurface = true;
533 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
534
535 assertEquals("Screen orientation must be defined by the app window by default",
536 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
537
538 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
539 assertEquals("Visible keyguard must influence device orientation",
540 SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
541
542 sWm.setKeyguardGoingAway(true);
543 assertEquals("Keyguard that is going away must not influence device orientation",
544 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
545 }
546
Andrii Kulianf0379de2018-03-14 16:24:07 -0700547 @Test
548 public void testDisableDisplayInfoOverrideFromWindowManager() {
549 final DisplayContent dc = createNewDisplay();
550
551 assertTrue(dc.mShouldOverrideDisplayConfiguration);
552 sWm.dontOverrideDisplayInfo(dc.getDisplayId());
553
554 assertFalse(dc.mShouldOverrideDisplayConfiguration);
555 verify(sWm.mDisplayManagerInternal, times(1))
556 .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
557 }
558
Riddle Hsua4d6fa22018-08-11 00:50:39 +0800559 @Test
560 public void testGetPreferredOptionsPanelGravityFromDifferentDisplays() {
561 final DisplayContent portraitDisplay = createNewDisplay();
562 portraitDisplay.mInitialDisplayHeight = 2000;
563 portraitDisplay.mInitialDisplayWidth = 1000;
564
565 portraitDisplay.setRotation(Surface.ROTATION_0);
566 assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
567 portraitDisplay.setRotation(Surface.ROTATION_90);
568 assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
569
570 final DisplayContent landscapeDisplay = createNewDisplay();
571 landscapeDisplay.mInitialDisplayHeight = 1000;
572 landscapeDisplay.mInitialDisplayWidth = 2000;
573
574 landscapeDisplay.setRotation(Surface.ROTATION_0);
575 assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
576 landscapeDisplay.setRotation(Surface.ROTATION_90);
577 assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
578 }
579
580 private boolean isOptionsPanelAtRight(int displayId) {
581 return (sWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
582 }
583
Bryce Lee27cec322017-03-21 09:41:37 -0700584 private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
585 int expectedBaseHeight, int expectedBaseDensity) {
586 assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
587 assertEquals(displayContent.mBaseDisplayHeight, expectedBaseHeight);
588 assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
589 }
590
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800591 private void updateFocusedWindow() {
592 synchronized (sWm.mWindowMap) {
593 sWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false);
594 }
595 }
596
Riddle Hsu654a6f92018-07-13 22:59:36 +0800597 /**
598 * Create DisplayContent that does not update display base/initial values from device to keep
599 * the values set by test.
600 */
601 private DisplayContent createDisplayNoUpdateDisplayInfo() {
602 final DisplayContent displayContent = spy(createNewDisplay());
603 doNothing().when(displayContent).updateDisplayInfo();
604 return displayContent;
605 }
606
Adrian Roos0f9368c2018-04-08 10:59:08 -0700607 private void assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop) {
608 final LinkedList<WindowState> actualWindows = new LinkedList<>();
Wale Ogunwale34247952017-02-19 11:57:53 -0800609
610 // Test forward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700611 mDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700612 assertThat("bottomToTop", actualWindows, is(expectedWindowsBottomToTop));
613
614 actualWindows.clear();
Wale Ogunwale34247952017-02-19 11:57:53 -0800615
616 // Test backward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700617 mDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700618 assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop)));
619 }
620
621 private static List<WindowState> reverseList(List<WindowState> list) {
622 final ArrayList<WindowState> result = new ArrayList<>(list);
623 Collections.reverse(result);
624 return result;
Wale Ogunwale34247952017-02-19 11:57:53 -0800625 }
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700626
627 private MotionEvent createTapEvent(float x, float y, boolean isDownEvent) {
628 final long downTime = SystemClock.uptimeMillis();
629 final long eventTime = SystemClock.uptimeMillis() + 100;
630 final int metaState = 0;
631
632 return MotionEvent.obtain(
633 downTime,
634 eventTime,
635 isDownEvent ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP,
636 x,
637 y,
638 metaState);
639 }
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700640}