blob: cb8ca7e4bfc63b9f8516bcdd19f5b10dd990094e [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;
Tiger Huang1e5b10a2018-07-30 20:19:51 +080037import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
chaviwebcbc342018-02-07 13:19:00 -080038
Adrian Roos5251b1d2018-03-23 18:57:43 +010039import static org.hamcrest.Matchers.is;
Wale Ogunwale34247952017-02-19 11:57:53 -080040import static org.junit.Assert.assertEquals;
Andrii Kulianf0379de2018-03-14 16:24:07 -070041import static org.junit.Assert.assertFalse;
Arthur Hungbe5ce212018-09-13 18:41:56 +080042import static org.junit.Assert.assertNotNull;
Adrian Roos5251b1d2018-03-23 18:57:43 +010043import static org.junit.Assert.assertThat;
Wale Ogunwale34247952017-02-19 11:57:53 -080044import static org.junit.Assert.assertTrue;
Riddle Hsu654a6f92018-07-13 22:59:36 +080045import static org.mockito.Mockito.doNothing;
46import static org.mockito.Mockito.spy;
Andrii Kulianf0379de2018-03-14 16:24:07 -070047import static org.mockito.Mockito.times;
48import static org.mockito.Mockito.verify;
Wale Ogunwale34247952017-02-19 11:57:53 -080049
Andrii Kulian92c9a942017-10-10 00:41:41 -070050import android.annotation.SuppressLint;
Andrii Kuliand68501e2017-01-10 22:57:27 -080051import android.content.res.Configuration;
Adrian Roos1cf585052018-01-03 18:43:27 +010052import android.graphics.Rect;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070053import android.os.SystemClock;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070054import android.platform.test.annotations.Presubmit;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070055import android.util.DisplayMetrics;
John Reck3d294e72018-09-21 20:26:48 +000056import android.util.SparseIntArray;
Adrian Roos1cf585052018-01-03 18:43:27 +010057import android.view.DisplayCutout;
Riddle Hsua4d6fa22018-08-11 00:50:39 +080058import android.view.Gravity;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070059import android.view.MotionEvent;
Adrian Roos1cf585052018-01-03 18:43:27 +010060import android.view.Surface;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070061
Brett Chabota26eda92018-07-23 13:08:30 -070062import androidx.test.filters.FlakyTest;
63import androidx.test.filters.SmallTest;
64import androidx.test.runner.AndroidJUnit4;
65
Adrian Roos6a4fa0e2018-03-05 19:50:16 +010066import com.android.server.wm.utils.WmDisplayCutout;
67
Brett Chabota26eda92018-07-23 13:08:30 -070068import org.junit.Test;
69import org.junit.runner.RunWith;
70
Adrian Roos0f9368c2018-04-08 10:59:08 -070071import java.util.ArrayList;
Wale Ogunwale34247952017-02-19 11:57:53 -080072import java.util.Arrays;
Adrian Roos0f9368c2018-04-08 10:59:08 -070073import java.util.Collections;
Wale Ogunwale34247952017-02-19 11:57:53 -080074import java.util.LinkedList;
75import java.util.List;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070076
77/**
78 * Tests for the {@link DisplayContent} class.
79 *
80 * Build/Install/Run:
John Reck3d294e72018-09-21 20:26:48 +000081 * atest com.android.server.wm.DisplayContentTests
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070082 */
83@SmallTest
84@Presubmit
85@RunWith(AndroidJUnit4.class)
Wale Ogunwale44fbdf52016-11-16 10:18:45 -080086public class DisplayContentTests extends WindowTestsBase {
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070087
88 @Test
Adrian Roos0f9368c2018-04-08 10:59:08 -070089 @FlakyTest(bugId = 77772044)
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070090 public void testForAllWindows() throws Exception {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -080091 final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070092 mDisplayContent, "exiting app");
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070093 final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
94 exitingAppToken.mIsExiting = true;
Bryce Lee6d410262017-02-28 15:30:17 -080095 exitingAppToken.getTask().mStack.mExitingAppTokens.add(exitingAppToken);
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070096
Wale Ogunwale34247952017-02-19 11:57:53 -080097 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -070098 mWallpaperWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -080099 exitingAppWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700100 mChildAppWindowBelow,
101 mAppWindow,
102 mChildAppWindowAbove,
103 mDockedDividerWindow,
104 mStatusBarWindow,
105 mNavBarWindow,
106 mImeWindow,
107 mImeDialogWindow));
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800108 }
109
110 @Test
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800111 public void testForAllWindows_WithAppImeTarget() throws Exception {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800112 final WindowState imeAppTarget =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700113 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800114
115 sWm.mInputMethodTarget = imeAppTarget;
116
Wale Ogunwale34247952017-02-19 11:57:53 -0800117 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700118 mWallpaperWindow,
119 mChildAppWindowBelow,
120 mAppWindow,
121 mChildAppWindowAbove,
Wale Ogunwale34247952017-02-19 11:57:53 -0800122 imeAppTarget,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700123 mImeWindow,
124 mImeDialogWindow,
125 mDockedDividerWindow,
126 mStatusBarWindow,
127 mNavBarWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800128 }
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800129
Wale Ogunwale34247952017-02-19 11:57:53 -0800130 @Test
131 public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700132 sWm.mInputMethodTarget = mChildAppWindowAbove;
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800133
Wale Ogunwale34247952017-02-19 11:57:53 -0800134 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700135 mWallpaperWindow,
136 mChildAppWindowBelow,
137 mAppWindow,
138 mChildAppWindowAbove,
139 mImeWindow,
140 mImeDialogWindow,
141 mDockedDividerWindow,
142 mStatusBarWindow,
143 mNavBarWindow));
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700144 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800145
146 @Test
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800147 public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700148 sWm.mInputMethodTarget = mStatusBarWindow;
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800149
Wale Ogunwale34247952017-02-19 11:57:53 -0800150 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700151 mWallpaperWindow,
152 mChildAppWindowBelow,
153 mAppWindow,
154 mChildAppWindowAbove,
155 mDockedDividerWindow,
156 mStatusBarWindow,
157 mImeWindow,
158 mImeDialogWindow,
159 mNavBarWindow));
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800160 }
161
162 @Test
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800163 public void testForAllWindows_WithInBetweenWindowToken() throws Exception {
164 // This window is set-up to be z-ordered between some windows that go in the same token like
165 // the nav bar and status bar.
166 final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700167 mDisplayContent, "voiceInteractionWindow");
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800168
Wale Ogunwale34247952017-02-19 11:57:53 -0800169 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700170 mWallpaperWindow,
171 mChildAppWindowBelow,
172 mAppWindow,
173 mChildAppWindowAbove,
174 mDockedDividerWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -0800175 voiceInteractionWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700176 mStatusBarWindow,
177 mNavBarWindow,
178 mImeWindow,
179 mImeDialogWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800180 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800181
Wale Ogunwale34247952017-02-19 11:57:53 -0800182 @Test
183 public void testComputeImeTarget() throws Exception {
184 // Verify that an app window can be an ime target.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700185 final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
Wale Ogunwale34247952017-02-19 11:57:53 -0800186 appWin.setHasSurface(true);
187 assertTrue(appWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700188 WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800189 assertEquals(appWin, imeTarget);
chaviwebcbc342018-02-07 13:19:00 -0800190 appWin.mHidden = false;
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800191
Wale Ogunwale34247952017-02-19 11:57:53 -0800192 // Verify that an child window can be an ime target.
193 final WindowState childWin = createWindow(appWin,
194 TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
195 childWin.setHasSurface(true);
196 assertTrue(childWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700197 imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800198 assertEquals(childWin, imeTarget);
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800199 }
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800200
Andrii Kuliand68501e2017-01-10 22:57:27 -0800201 /**
202 * This tests stack movement between displays and proper stack's, task's and app token's display
203 * container references updates.
204 */
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800205 @Test
206 public void testMoveStackBetweenDisplays() throws Exception {
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800207 // Create a second display.
208 final DisplayContent dc = createNewDisplay();
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800209
210 // Add stack with activity.
211 final TaskStack stack = createTaskStackOnDisplay(dc);
212 assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
213 assertEquals(dc, stack.getParent().getParent());
214 assertEquals(dc, stack.getDisplayContent());
215
216 final Task task = createTaskInStack(stack, 0 /* userId */);
chaviw97d28202018-02-27 16:23:53 -0800217 final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
218 dc);
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800219 task.addChild(token, 0);
220 assertEquals(dc, task.getDisplayContent());
221 assertEquals(dc, token.getDisplayContent());
222
223 // Move stack to first display.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700224 mDisplayContent.moveStackToDisplay(stack, true /* onTop */);
225 assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
226 assertEquals(mDisplayContent, stack.getParent().getParent());
227 assertEquals(mDisplayContent, stack.getDisplayContent());
228 assertEquals(mDisplayContent, task.getDisplayContent());
229 assertEquals(mDisplayContent, token.getDisplayContent());
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800230 }
Andrii Kuliand68501e2017-01-10 22:57:27 -0800231
232 /**
233 * This tests override configuration updates for display content.
234 */
235 @Test
236 public void testDisplayOverrideConfigUpdate() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700237 final int displayId = mDisplayContent.getDisplayId();
238 final Configuration currentOverrideConfig = mDisplayContent.getOverrideConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800239
240 // Create new, slightly changed override configuration and apply it to the display.
241 final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
242 newOverrideConfig.densityDpi += 120;
243 newOverrideConfig.fontScale += 0.3;
244
245 sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, displayId);
246
247 // Check that override config is applied.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700248 assertEquals(newOverrideConfig, mDisplayContent.getOverrideConfiguration());
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800249 }
250
251 /**
252 * This tests global configuration updates when default display config is updated.
253 */
254 @Test
255 public void testDefaultDisplayOverrideConfigUpdate() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700256 final Configuration currentConfig = mDisplayContent.getConfiguration();
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800257
258 // Create new, slightly changed override configuration and apply it to the display.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700259 final Configuration newOverrideConfig = new Configuration(currentConfig);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800260 newOverrideConfig.densityDpi += 120;
261 newOverrideConfig.fontScale += 0.3;
262
263 sWm.setNewDisplayOverrideConfiguration(newOverrideConfig, DEFAULT_DISPLAY);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800264
265 // Check that global configuration is updated, as we've updated default display's config.
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800266 Configuration globalConfig = sWm.mRoot.getConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800267 assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
268 assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800269
270 // Return back to original values.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700271 sWm.setNewDisplayOverrideConfiguration(currentConfig, DEFAULT_DISPLAY);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800272 globalConfig = sWm.mRoot.getConfiguration();
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700273 assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
274 assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800275 }
Wale Ogunwale34247952017-02-19 11:57:53 -0800276
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700277 /**
278 * Tests tapping on a stack in different display results in window gaining focus.
279 */
280 @Test
281 public void testInputEventBringsCorrectDisplayInFocus() throws Exception {
282 DisplayContent dc0 = sWm.getDefaultDisplayContentLocked();
283 // Create a second display
284 final DisplayContent dc1 = createNewDisplay();
285
286 // Add stack with activity.
287 final TaskStack stack0 = createTaskStackOnDisplay(dc0);
288 final Task task0 = createTaskInStack(stack0, 0 /* userId */);
289 final WindowTestUtils.TestAppWindowToken token =
chaviw97d28202018-02-27 16:23:53 -0800290 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700291 task0.addChild(token, 0);
Arthur Hungbe5ce212018-09-13 18:41:56 +0800292 dc0.configureDisplayPolicy();
293 assertNotNull(dc0.mTapDetector);
294
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700295 final TaskStack stack1 = createTaskStackOnDisplay(dc1);
296 final Task task1 = createTaskInStack(stack1, 0 /* userId */);
297 final WindowTestUtils.TestAppWindowToken token1 =
chaviw97d28202018-02-27 16:23:53 -0800298 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700299 task1.addChild(token1, 0);
Arthur Hungbe5ce212018-09-13 18:41:56 +0800300 dc1.configureDisplayPolicy();
301 assertNotNull(dc1.mTapDetector);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700302
Arthur Hungbe5ce212018-09-13 18:41:56 +0800303 // tap on primary display.
304 tapOnDisplay(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700305 // Check focus is on primary display.
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800306 assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
307 dc0.findFocusedWindow());
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700308
Arthur Hungbe5ce212018-09-13 18:41:56 +0800309 // Tap on secondary display.
310 tapOnDisplay(dc1);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700311 // Check focus is on secondary.
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800312 assertEquals(sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
313 dc1.findFocusedWindow());
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700314 }
315
David Stevens46939562017-03-24 13:04:00 -0700316 @Test
317 public void testFocusedWindowMultipleDisplays() throws Exception {
Andrii Kulian0214ed92017-05-16 13:44:05 -0700318 // Create a focusable window and check that focus is calculated correctly
David Stevens46939562017-03-24 13:04:00 -0700319 final WindowState window1 =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700320 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800321 updateFocusedWindow();
322 assertTrue(window1.isFocused());
323 assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
David Stevens46939562017-03-24 13:04:00 -0700324
325 // Check that a new display doesn't affect focus
326 final DisplayContent dc = createNewDisplay();
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 // Add a window to the second display, and it should be focused
332 final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800333 updateFocusedWindow();
334 assertTrue(window1.isFocused());
335 assertTrue(window2.isFocused());
336 assertEquals(window2, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
David Stevens46939562017-03-24 13:04:00 -0700337
338 // Move the first window to the to including parents, and make sure focus is updated
339 window1.getParent().positionChildAt(POSITION_TOP, window1, true);
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800340 updateFocusedWindow();
341 assertTrue(window1.isFocused());
342 assertTrue(window2.isFocused());
343 assertEquals(window1, sWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
Adrian Roos4163d622018-05-22 16:56:35 +0200344 }
345
Bryce Lee27cec322017-03-21 09:41:37 -0700346 /**
347 * This tests setting the maximum ui width on a display.
348 */
349 @Test
350 public void testMaxUiWidth() throws Exception {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800351 // Prevent base display metrics for test from being updated to the value of real display.
352 final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
Bryce Lee27cec322017-03-21 09:41:37 -0700353 final int baseWidth = 1440;
354 final int baseHeight = 2560;
355 final int baseDensity = 300;
356
Riddle Hsu654a6f92018-07-13 22:59:36 +0800357 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700358
359 final int maxWidth = 300;
360 final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
361 final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
362
Riddle Hsu654a6f92018-07-13 22:59:36 +0800363 displayContent.setMaxUiWidth(maxWidth);
364 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700365
366 // Assert setting values again does not change;
Riddle Hsu654a6f92018-07-13 22:59:36 +0800367 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
368 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700369
370 final int smallerWidth = 200;
371 final int smallerHeight = 400;
372 final int smallerDensity = 100;
373
374 // Specify smaller dimension, verify that it is honored
Riddle Hsu654a6f92018-07-13 22:59:36 +0800375 displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
376 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700377
378 // Verify that setting the max width to a greater value than the base width has no effect
Riddle Hsu654a6f92018-07-13 22:59:36 +0800379 displayContent.setMaxUiWidth(maxWidth);
380 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700381 }
382
Bryce Lee48f4b572017-04-10 10:54:15 -0700383 /**
Kazuki Takise148d00a2018-05-31 15:32:19 +0900384 * This test enforces that alwaysOnTop stack is placed at proper position.
Bryce Lee48f4b572017-04-10 10:54:15 -0700385 */
386 @Test
Kazuki Takise148d00a2018-05-31 15:32:19 +0900387 public void testAlwaysOnTopStackLocation() {
Kazuki Takise048e2662018-06-27 17:05:11 +0900388 final TaskStack alwaysOnTopStack = createStackControllerOnStackOnDisplay(
389 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900390 final Task task = createTaskInStack(alwaysOnTopStack, 0 /* userId */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900391 alwaysOnTopStack.setAlwaysOnTop(true);
Riddle Hsu57831b52018-07-27 00:31:48 +0800392 mDisplayContent.positionStackAt(POSITION_TOP, alwaysOnTopStack,
393 false /* includingParents */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900394 assertTrue(alwaysOnTopStack.isAlwaysOnTop());
Kazuki Takise4e7e7892018-06-19 13:55:23 +0900395 // Ensure always on top state is synced to the children of the stack.
396 assertTrue(alwaysOnTopStack.getTopChild().isAlwaysOnTop());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900397 assertEquals(alwaysOnTopStack, mDisplayContent.getTopStack());
398
Wale Ogunwale61911492017-10-11 08:50:50 -0700399 final TaskStack pinnedStack = createStackControllerOnStackOnDisplay(
400 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Wale Ogunwale61911492017-10-11 08:50:50 -0700401 assertEquals(pinnedStack, mDisplayContent.getPinnedStack());
402 assertEquals(pinnedStack, mDisplayContent.getTopStack());
Kazuki Takise148d00a2018-05-31 15:32:19 +0900403
Kazuki Takise048e2662018-06-27 17:05:11 +0900404 final TaskStack anotherAlwaysOnTopStack = createStackControllerOnStackOnDisplay(
405 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900406 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
Riddle Hsu57831b52018-07-27 00:31:48 +0800407 mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack,
408 false /* includingParents */);
Kazuki Takise148d00a2018-05-31 15:32:19 +0900409 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
410 int topPosition = mDisplayContent.getStacks().size() - 1;
411 // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
412 // existing alwaysOnTop stack.
413 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
414
Kazuki Takise048e2662018-06-27 17:05:11 +0900415 final TaskStack nonAlwaysOnTopStack = createStackControllerOnStackOnDisplay(
416 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
Kazuki Takise148d00a2018-05-31 15:32:19 +0900417 assertEquals(mDisplayContent, nonAlwaysOnTopStack.getDisplayContent());
418 topPosition = mDisplayContent.getStacks().size() - 1;
419 // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
420 // existing other non-alwaysOnTop stacks.
421 assertEquals(nonAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 3));
Kazuki Takisef85197b2018-06-18 18:18:36 +0900422
423 anotherAlwaysOnTopStack.setAlwaysOnTop(false);
Riddle Hsu57831b52018-07-27 00:31:48 +0800424 mDisplayContent.positionStackAt(POSITION_TOP, anotherAlwaysOnTopStack,
425 false /* includingParents */);
Kazuki Takisef85197b2018-06-18 18:18:36 +0900426 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
Kazuki Takisef85197b2018-06-18 18:18:36 +0900427 // Ensure, when always on top is turned off for a stack, the stack is put just below all
428 // other always on top stacks.
429 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
Kazuki Takise048e2662018-06-27 17:05:11 +0900430 anotherAlwaysOnTopStack.setAlwaysOnTop(true);
431
432 // Ensure always on top state changes properly when windowing mode changes.
433 anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
434 assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
435 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 2));
436 anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
437 assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
438 assertEquals(anotherAlwaysOnTopStack, mDisplayContent.getStacks().get(topPosition - 1));
Bryce Lee48f4b572017-04-10 10:54:15 -0700439 }
440
Andrii Kulian92c9a942017-10-10 00:41:41 -0700441 @Test
Adrian Roos1cf585052018-01-03 18:43:27 +0100442 public void testDisplayCutout_rot0() throws Exception {
443 synchronized (sWm.getWindowManagerLock()) {
444 final DisplayContent dc = createNewDisplay();
445 dc.mInitialDisplayWidth = 200;
446 dc.mInitialDisplayHeight = 400;
Adrian Roos24264212018-02-19 16:26:15 +0100447 Rect r = new Rect(80, 0, 120, 10);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100448 final DisplayCutout cutout = new WmDisplayCutout(
Issei Suzuki43190bd2018-08-20 17:28:41 +0200449 fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_TOP), null)
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100450 .computeSafeInsets(200, 400).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100451
452 dc.mInitialDisplayCutout = cutout;
453 dc.setRotation(Surface.ROTATION_0);
454 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
455
456 assertEquals(cutout, dc.getDisplayInfo().displayCutout);
457 }
458 }
459
460 @Test
461 public void testDisplayCutout_rot90() throws Exception {
462 synchronized (sWm.getWindowManagerLock()) {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800463 // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
464 // if the device has no cutout).
465 final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
466 // Rotation may use real display info to compute bound, so here also uses the
467 // same width and height.
468 final int displayWidth = dc.mInitialDisplayWidth;
469 final int displayHeight = dc.mInitialDisplayHeight;
470 final int cutoutWidth = 40;
471 final int cutoutHeight = 10;
472 final int left = (displayWidth - cutoutWidth) / 2;
473 final int top = 0;
474 final int right = (displayWidth + cutoutWidth) / 2;
475 final int bottom = cutoutHeight;
476
477 final Rect r1 = new Rect(left, top, right, bottom);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100478 final DisplayCutout cutout = new WmDisplayCutout(
Issei Suzuki43190bd2018-08-20 17:28:41 +0200479 fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800480 .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100481
482 dc.mInitialDisplayCutout = cutout;
483 dc.setRotation(Surface.ROTATION_90);
484 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
485
Riddle Hsu654a6f92018-07-13 22:59:36 +0800486 // ----o---------- -------------
487 // | | | | |
488 // | ------o | o---
489 // | | | |
490 // | | -> | |
491 // | | ---o
492 // | | |
493 // | | -------------
494 final Rect r = new Rect(top, left, bottom, right);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100495 assertEquals(new WmDisplayCutout(
Issei Suzuki43190bd2018-08-20 17:28:41 +0200496 fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_LEFT), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800497 .computeSafeInsets(displayHeight, displayWidth)
498 .getDisplayCutout(), dc.getDisplayInfo().displayCutout);
Adrian Roos1cf585052018-01-03 18:43:27 +0100499 }
500 }
501
502 @Test
Adrian Roos5251b1d2018-03-23 18:57:43 +0100503 public void testLayoutSeq_assignedDuringLayout() throws Exception {
504 synchronized (sWm.getWindowManagerLock()) {
505
506 final DisplayContent dc = createNewDisplay();
507 final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
508
509 dc.setLayoutNeeded();
510 dc.performLayout(true /* initial */, false /* updateImeWindows */);
511
512 assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
513 }
514 }
515
516 @Test
Andrii Kulian92c9a942017-10-10 00:41:41 -0700517 @SuppressLint("InlinedApi")
518 public void testOrientationDefinedByKeyguard() {
519 final DisplayContent dc = createNewDisplay();
520 // Create a window that requests landscape orientation. It will define device orientation
521 // by default.
522 final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
523 window.mAppToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
524
525 final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, dc, "keyguard");
526 keyguard.mHasSurface = true;
527 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
528
529 assertEquals("Screen orientation must be defined by the app window by default",
530 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
531
532 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
533 assertEquals("Visible keyguard must influence device orientation",
534 SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
535
536 sWm.setKeyguardGoingAway(true);
537 assertEquals("Keyguard that is going away must not influence device orientation",
538 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
539 }
540
Andrii Kulianf0379de2018-03-14 16:24:07 -0700541 @Test
542 public void testDisableDisplayInfoOverrideFromWindowManager() {
543 final DisplayContent dc = createNewDisplay();
544
545 assertTrue(dc.mShouldOverrideDisplayConfiguration);
546 sWm.dontOverrideDisplayInfo(dc.getDisplayId());
547
548 assertFalse(dc.mShouldOverrideDisplayConfiguration);
549 verify(sWm.mDisplayManagerInternal, times(1))
550 .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
551 }
552
Riddle Hsua4d6fa22018-08-11 00:50:39 +0800553 @Test
554 public void testGetPreferredOptionsPanelGravityFromDifferentDisplays() {
555 final DisplayContent portraitDisplay = createNewDisplay();
556 portraitDisplay.mInitialDisplayHeight = 2000;
557 portraitDisplay.mInitialDisplayWidth = 1000;
558
559 portraitDisplay.setRotation(Surface.ROTATION_0);
560 assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
561 portraitDisplay.setRotation(Surface.ROTATION_90);
562 assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
563
564 final DisplayContent landscapeDisplay = createNewDisplay();
565 landscapeDisplay.mInitialDisplayHeight = 1000;
566 landscapeDisplay.mInitialDisplayWidth = 2000;
567
568 landscapeDisplay.setRotation(Surface.ROTATION_0);
569 assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
570 landscapeDisplay.setRotation(Surface.ROTATION_90);
571 assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
572 }
573
574 private boolean isOptionsPanelAtRight(int displayId) {
575 return (sWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
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
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800585 private void updateFocusedWindow() {
586 synchronized (sWm.mWindowMap) {
587 sWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false);
588 }
589 }
590
Riddle Hsu654a6f92018-07-13 22:59:36 +0800591 /**
592 * Create DisplayContent that does not update display base/initial values from device to keep
593 * the values set by test.
594 */
595 private DisplayContent createDisplayNoUpdateDisplayInfo() {
596 final DisplayContent displayContent = spy(createNewDisplay());
597 doNothing().when(displayContent).updateDisplayInfo();
598 return displayContent;
599 }
600
Adrian Roos0f9368c2018-04-08 10:59:08 -0700601 private void assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop) {
602 final LinkedList<WindowState> actualWindows = new LinkedList<>();
Wale Ogunwale34247952017-02-19 11:57:53 -0800603
604 // Test forward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700605 mDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700606 assertThat("bottomToTop", actualWindows, is(expectedWindowsBottomToTop));
607
608 actualWindows.clear();
Wale Ogunwale34247952017-02-19 11:57:53 -0800609
610 // Test backward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700611 mDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700612 assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop)));
613 }
614
615 private static List<WindowState> reverseList(List<WindowState> list) {
616 final ArrayList<WindowState> result = new ArrayList<>(list);
617 Collections.reverse(result);
618 return result;
Wale Ogunwale34247952017-02-19 11:57:53 -0800619 }
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700620
Arthur Hungbe5ce212018-09-13 18:41:56 +0800621 private void tapOnDisplay(final DisplayContent dc) {
622 final DisplayMetrics dm = dc.getDisplayMetrics();
623 final float x = dm.widthPixels / 2;
624 final float y = dm.heightPixels / 2;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700625 final long downTime = SystemClock.uptimeMillis();
626 final long eventTime = SystemClock.uptimeMillis() + 100;
Arthur Hungbe5ce212018-09-13 18:41:56 +0800627 // sending ACTION_DOWN
628 final MotionEvent downEvent = MotionEvent.obtain(
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700629 downTime,
Arthur Hungbe5ce212018-09-13 18:41:56 +0800630 downTime,
631 MotionEvent.ACTION_DOWN,
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700632 x,
633 y,
Arthur Hungbe5ce212018-09-13 18:41:56 +0800634 0 /*metaState*/);
635 downEvent.setDisplayId(dc.getDisplayId());
636 dc.mTapDetector.onPointerEvent(downEvent);
637
638 // sending ACTION_UP
639 final MotionEvent upEvent = MotionEvent.obtain(
640 downTime,
641 eventTime,
642 MotionEvent.ACTION_UP,
643 x,
644 y,
645 0 /*metaState*/);
646 upEvent.setDisplayId(dc.getDisplayId());
647 dc.mTapDetector.onPointerEvent(upEvent);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700648 }
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700649}