blob: 8430616731d24e5bacfc615dea538351aa7113bd [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
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070014 * limitations under the License.
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070015 */
16
17package com.android.server.wm;
18
Andrii Kulian92c9a942017-10-10 00:41:41 -070019import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
20import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
21import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Tiger Huang51c5a1d2018-12-11 20:24:51 +080022import static android.os.Build.VERSION_CODES.P;
23import static android.os.Build.VERSION_CODES.Q;
Wale Ogunwale34247952017-02-19 11:57:53 -080024import static android.view.Display.DEFAULT_DISPLAY;
Issei Suzuki43190bd2018-08-20 17:28:41 +020025import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
26import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
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
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +090034import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
35import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
36import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
37import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
David Stevens46939562017-03-24 13:04:00 -070038import static com.android.server.wm.WindowContainer.POSITION_TOP;
Tiger Huang1e5b10a2018-07-30 20:19:51 +080039import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
chaviwebcbc342018-02-07 13:19:00 -080040
Adrian Roos5251b1d2018-03-23 18:57:43 +010041import static org.hamcrest.Matchers.is;
Wale Ogunwale34247952017-02-19 11:57:53 -080042import static org.junit.Assert.assertEquals;
Andrii Kulianf0379de2018-03-14 16:24:07 -070043import static org.junit.Assert.assertFalse;
Arthur Hungbe5ce212018-09-13 18:41:56 +080044import static org.junit.Assert.assertNotNull;
lumarkff0ab692018-11-05 20:32:30 +080045import static org.junit.Assert.assertNull;
Adrian Roos5251b1d2018-03-23 18:57:43 +010046import static org.junit.Assert.assertThat;
Wale Ogunwale34247952017-02-19 11:57:53 -080047import static org.junit.Assert.assertTrue;
48
Andrii Kulian92c9a942017-10-10 00:41:41 -070049import android.annotation.SuppressLint;
Andrii Kuliand68501e2017-01-10 22:57:27 -080050import android.content.res.Configuration;
Adrian Roos1cf585052018-01-03 18:43:27 +010051import android.graphics.Rect;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070052import android.os.SystemClock;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070053import android.platform.test.annotations.Presubmit;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -070054import android.util.DisplayMetrics;
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;
Brett Chabota26eda92018-07-23 13:08:30 -070062
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;
Brett Chabota26eda92018-07-23 13:08:30 -070066
Adrian Roos0f9368c2018-04-08 10:59:08 -070067import java.util.ArrayList;
Wale Ogunwale34247952017-02-19 11:57:53 -080068import java.util.Arrays;
Adrian Roos0f9368c2018-04-08 10:59:08 -070069import java.util.Collections;
Wale Ogunwale34247952017-02-19 11:57:53 -080070import java.util.LinkedList;
71import java.util.List;
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070072
73/**
74 * Tests for the {@link DisplayContent} class.
75 *
76 * Build/Install/Run:
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070077 * atest FrameworksServicesTests:DisplayContentTests
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070078 */
79@SmallTest
80@Presubmit
Wale Ogunwale44fbdf52016-11-16 10:18:45 -080081public class DisplayContentTests extends WindowTestsBase {
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070082
83 @Test
Adrian Roos0f9368c2018-04-08 10:59:08 -070084 @FlakyTest(bugId = 77772044)
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070085 public void testForAllWindows() {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -080086 final WindowState exitingAppWindow = createWindow(null, TYPE_BASE_APPLICATION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070087 mDisplayContent, "exiting app");
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070088 final AppWindowToken exitingAppToken = exitingAppWindow.mAppToken;
89 exitingAppToken.mIsExiting = true;
Bryce Lee6d410262017-02-28 15:30:17 -080090 exitingAppToken.getTask().mStack.mExitingAppTokens.add(exitingAppToken);
Wale Ogunwaleb783fd82016-11-04 09:51:54 -070091
Wale Ogunwale34247952017-02-19 11:57:53 -080092 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -070093 mWallpaperWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -080094 exitingAppWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -070095 mChildAppWindowBelow,
96 mAppWindow,
97 mChildAppWindowAbove,
98 mDockedDividerWindow,
99 mStatusBarWindow,
100 mNavBarWindow,
101 mImeWindow,
102 mImeDialogWindow));
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800103 }
104
105 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700106 public void testForAllWindows_WithAppImeTarget() {
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800107 final WindowState imeAppTarget =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700108 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "imeAppTarget");
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800109
lumarkff0ab692018-11-05 20:32:30 +0800110 mDisplayContent.mInputMethodTarget = imeAppTarget;
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800111
Wale Ogunwale34247952017-02-19 11:57:53 -0800112 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700113 mWallpaperWindow,
114 mChildAppWindowBelow,
115 mAppWindow,
116 mChildAppWindowAbove,
Wale Ogunwale34247952017-02-19 11:57:53 -0800117 imeAppTarget,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700118 mImeWindow,
119 mImeDialogWindow,
120 mDockedDividerWindow,
121 mStatusBarWindow,
122 mNavBarWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800123 }
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800124
Wale Ogunwale34247952017-02-19 11:57:53 -0800125 @Test
lumarkff0ab692018-11-05 20:32:30 +0800126 public void testForAllWindows_WithChildWindowImeTarget() throws Exception {
127 mDisplayContent.mInputMethodTarget = mChildAppWindowAbove;
Wale Ogunwale3c1170d2016-12-02 14:44:52 -0800128
Wale Ogunwale34247952017-02-19 11:57:53 -0800129 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700130 mWallpaperWindow,
131 mChildAppWindowBelow,
132 mAppWindow,
133 mChildAppWindowAbove,
134 mImeWindow,
135 mImeDialogWindow,
136 mDockedDividerWindow,
137 mStatusBarWindow,
138 mNavBarWindow));
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700139 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800140
141 @Test
lumarkff0ab692018-11-05 20:32:30 +0800142 public void testForAllWindows_WithStatusBarImeTarget() throws Exception {
143 mDisplayContent.mInputMethodTarget = mStatusBarWindow;
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800144
Wale Ogunwale34247952017-02-19 11:57:53 -0800145 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700146 mWallpaperWindow,
147 mChildAppWindowBelow,
148 mAppWindow,
149 mChildAppWindowAbove,
150 mDockedDividerWindow,
151 mStatusBarWindow,
152 mImeWindow,
153 mImeDialogWindow,
154 mNavBarWindow));
Wale Ogunwale6ce0fb82016-12-13 14:24:00 -0800155 }
156
157 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700158 public void testForAllWindows_WithInBetweenWindowToken() {
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800159 // This window is set-up to be z-ordered between some windows that go in the same token like
160 // the nav bar and status bar.
161 final WindowState voiceInteractionWindow = createWindow(null, TYPE_VOICE_INTERACTION,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700162 mDisplayContent, "voiceInteractionWindow");
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800163
Wale Ogunwale34247952017-02-19 11:57:53 -0800164 assertForAllWindowsOrder(Arrays.asList(
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700165 mWallpaperWindow,
166 mChildAppWindowBelow,
167 mAppWindow,
168 mChildAppWindowAbove,
169 mDockedDividerWindow,
Wale Ogunwale34247952017-02-19 11:57:53 -0800170 voiceInteractionWindow,
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700171 mStatusBarWindow,
172 mNavBarWindow,
173 mImeWindow,
174 mImeDialogWindow));
Wale Ogunwale34247952017-02-19 11:57:53 -0800175 }
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800176
Wale Ogunwale34247952017-02-19 11:57:53 -0800177 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700178 public void testComputeImeTarget() {
Wale Ogunwale34247952017-02-19 11:57:53 -0800179 // Verify that an app window can be an ime target.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700180 final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
Wale Ogunwale34247952017-02-19 11:57:53 -0800181 appWin.setHasSurface(true);
182 assertTrue(appWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700183 WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800184 assertEquals(appWin, imeTarget);
chaviwebcbc342018-02-07 13:19:00 -0800185 appWin.mHidden = false;
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800186
Wale Ogunwale34247952017-02-19 11:57:53 -0800187 // Verify that an child window can be an ime target.
188 final WindowState childWin = createWindow(appWin,
189 TYPE_APPLICATION_ATTACHED_DIALOG, "childWin");
190 childWin.setHasSurface(true);
191 assertTrue(childWin.canBeImeTarget());
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700192 imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
Wale Ogunwale34247952017-02-19 11:57:53 -0800193 assertEquals(childWin, imeTarget);
Wale Ogunwale5d7e7f12016-12-12 14:47:05 -0800194 }
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800195
Andrii Kuliand68501e2017-01-10 22:57:27 -0800196 /**
197 * This tests stack movement between displays and proper stack's, task's and app token's display
198 * container references updates.
199 */
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800200 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700201 public void testMoveStackBetweenDisplays() {
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800202 // Create a second display.
203 final DisplayContent dc = createNewDisplay();
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800204
205 // Add stack with activity.
206 final TaskStack stack = createTaskStackOnDisplay(dc);
207 assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
208 assertEquals(dc, stack.getParent().getParent());
209 assertEquals(dc, stack.getDisplayContent());
210
211 final Task task = createTaskInStack(stack, 0 /* userId */);
chaviw97d28202018-02-27 16:23:53 -0800212 final WindowTestUtils.TestAppWindowToken token = WindowTestUtils.createTestAppWindowToken(
213 dc);
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800214 task.addChild(token, 0);
215 assertEquals(dc, task.getDisplayContent());
216 assertEquals(dc, token.getDisplayContent());
217
218 // Move stack to first display.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700219 mDisplayContent.moveStackToDisplay(stack, true /* onTop */);
220 assertEquals(mDisplayContent.getDisplayId(), stack.getDisplayContent().getDisplayId());
221 assertEquals(mDisplayContent, stack.getParent().getParent());
222 assertEquals(mDisplayContent, stack.getDisplayContent());
223 assertEquals(mDisplayContent, task.getDisplayContent());
224 assertEquals(mDisplayContent, token.getDisplayContent());
Andrii Kulian6cc1a1d2016-12-27 23:52:59 -0800225 }
Andrii Kuliand68501e2017-01-10 22:57:27 -0800226
227 /**
228 * This tests override configuration updates for display content.
229 */
230 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700231 public void testDisplayOverrideConfigUpdate() {
Evan Roskydfe3da72018-10-26 17:21:06 -0700232 final Configuration currentOverrideConfig =
233 mDisplayContent.getRequestedOverrideConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800234
235 // Create new, slightly changed override configuration and apply it to the display.
236 final Configuration newOverrideConfig = new Configuration(currentOverrideConfig);
237 newOverrideConfig.densityDpi += 120;
238 newOverrideConfig.fontScale += 0.3;
239
Evan Roskye747c3e2018-10-30 20:06:41 -0700240 mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, mDisplayContent);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800241
242 // Check that override config is applied.
Evan Roskydfe3da72018-10-26 17:21:06 -0700243 assertEquals(newOverrideConfig, mDisplayContent.getRequestedOverrideConfiguration());
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800244 }
245
246 /**
247 * This tests global configuration updates when default display config is updated.
248 */
249 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700250 public void testDefaultDisplayOverrideConfigUpdate() {
Evan Roskye747c3e2018-10-30 20:06:41 -0700251 DisplayContent defaultDisplay = mWm.mRoot.getDisplayContent(DEFAULT_DISPLAY);
252 final Configuration currentConfig = defaultDisplay.getConfiguration();
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800253
254 // Create new, slightly changed override configuration and apply it to the display.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700255 final Configuration newOverrideConfig = new Configuration(currentConfig);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800256 newOverrideConfig.densityDpi += 120;
257 newOverrideConfig.fontScale += 0.3;
258
Evan Roskye747c3e2018-10-30 20:06:41 -0700259 mWm.setNewDisplayOverrideConfiguration(newOverrideConfig, defaultDisplay);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800260
261 // Check that global configuration is updated, as we've updated default display's config.
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700262 Configuration globalConfig = mWm.mRoot.getConfiguration();
Andrii Kuliand68501e2017-01-10 22:57:27 -0800263 assertEquals(newOverrideConfig.densityDpi, globalConfig.densityDpi);
264 assertEquals(newOverrideConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kulian367ff7f2017-01-25 19:45:34 -0800265
266 // Return back to original values.
Evan Roskye747c3e2018-10-30 20:06:41 -0700267 mWm.setNewDisplayOverrideConfiguration(currentConfig, defaultDisplay);
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700268 globalConfig = mWm.mRoot.getConfiguration();
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700269 assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
270 assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
Andrii Kuliand68501e2017-01-10 22:57:27 -0800271 }
Wale Ogunwale34247952017-02-19 11:57:53 -0800272
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700273 /**
274 * Tests tapping on a stack in different display results in window gaining focus.
275 */
276 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700277 public void testInputEventBringsCorrectDisplayInFocus() {
278 DisplayContent dc0 = mWm.getDefaultDisplayContentLocked();
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700279 // Create a second display
280 final DisplayContent dc1 = createNewDisplay();
281
282 // Add stack with activity.
283 final TaskStack stack0 = createTaskStackOnDisplay(dc0);
284 final Task task0 = createTaskInStack(stack0, 0 /* userId */);
285 final WindowTestUtils.TestAppWindowToken token =
chaviw97d28202018-02-27 16:23:53 -0800286 WindowTestUtils.createTestAppWindowToken(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700287 task0.addChild(token, 0);
Arthur Hungbe5ce212018-09-13 18:41:56 +0800288 dc0.configureDisplayPolicy();
289 assertNotNull(dc0.mTapDetector);
290
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700291 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);
Arthur Hungbe5ce212018-09-13 18:41:56 +0800296 dc1.configureDisplayPolicy();
297 assertNotNull(dc1.mTapDetector);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700298
Arthur Hungbe5ce212018-09-13 18:41:56 +0800299 // tap on primary display.
300 tapOnDisplay(dc0);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700301 // Check focus is on primary display.
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700302 assertEquals(mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800303 dc0.findFocusedWindow());
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700304
Arthur Hungbe5ce212018-09-13 18:41:56 +0800305 // Tap on secondary display.
306 tapOnDisplay(dc1);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700307 // Check focus is on secondary.
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700308 assertEquals(mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus,
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800309 dc1.findFocusedWindow());
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700310 }
311
David Stevens46939562017-03-24 13:04:00 -0700312 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700313 public void testFocusedWindowMultipleDisplays() {
Tiger Huang51c5a1d2018-12-11 20:24:51 +0800314 doTestFocusedWindowMultipleDisplays(false /* perDisplayFocusEnabled */, Q);
315 }
316
317 @Test
318 public void testFocusedWindowMultipleDisplaysPerDisplayFocusEnabled() {
319 doTestFocusedWindowMultipleDisplays(true /* perDisplayFocusEnabled */, Q);
320 }
321
322 @Test
323 public void testFocusedWindowMultipleDisplaysPerDisplayFocusEnabledLegacyApp() {
324 doTestFocusedWindowMultipleDisplays(true /* perDisplayFocusEnabled */, P);
325 }
326
327 private void doTestFocusedWindowMultipleDisplays(boolean perDisplayFocusEnabled,
328 int targetSdk) {
329 mWm.mPerDisplayFocusEnabled = perDisplayFocusEnabled;
330
Andrii Kulian0214ed92017-05-16 13:44:05 -0700331 // Create a focusable window and check that focus is calculated correctly
David Stevens46939562017-03-24 13:04:00 -0700332 final WindowState window1 =
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700333 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "window1");
Tiger Huang51c5a1d2018-12-11 20:24:51 +0800334 window1.mAppToken.mTargetSdk = targetSdk;
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800335 updateFocusedWindow();
336 assertTrue(window1.isFocused());
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700337 assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
David Stevens46939562017-03-24 13:04:00 -0700338
339 // Check that a new display doesn't affect focus
340 final DisplayContent dc = createNewDisplay();
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800341 updateFocusedWindow();
342 assertTrue(window1.isFocused());
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700343 assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
David Stevens46939562017-03-24 13:04:00 -0700344
345 // Add a window to the second display, and it should be focused
346 final WindowState window2 = createWindow(null, TYPE_BASE_APPLICATION, dc, "window2");
Tiger Huang51c5a1d2018-12-11 20:24:51 +0800347 window2.mAppToken.mTargetSdk = targetSdk;
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800348 updateFocusedWindow();
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800349 assertTrue(window2.isFocused());
Tiger Huang51c5a1d2018-12-11 20:24:51 +0800350 assertEquals(perDisplayFocusEnabled && targetSdk >= Q, window1.isFocused());
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700351 assertEquals(window2, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
David Stevens46939562017-03-24 13:04:00 -0700352
Tiger Huang51c5a1d2018-12-11 20:24:51 +0800353 // Move the first window to top including parents, and make sure focus is updated
David Stevens46939562017-03-24 13:04:00 -0700354 window1.getParent().positionChildAt(POSITION_TOP, window1, true);
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800355 updateFocusedWindow();
356 assertTrue(window1.isFocused());
Tiger Huang51c5a1d2018-12-11 20:24:51 +0800357 assertEquals(perDisplayFocusEnabled && targetSdk >= Q, window2.isFocused());
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700358 assertEquals(window1, mWm.mRoot.getTopFocusedDisplayContent().mCurrentFocus);
Adrian Roos4163d622018-05-22 16:56:35 +0200359 }
360
Bryce Lee27cec322017-03-21 09:41:37 -0700361 /**
362 * This tests setting the maximum ui width on a display.
363 */
364 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700365 public void testMaxUiWidth() {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800366 // Prevent base display metrics for test from being updated to the value of real display.
367 final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
Bryce Lee27cec322017-03-21 09:41:37 -0700368 final int baseWidth = 1440;
369 final int baseHeight = 2560;
370 final int baseDensity = 300;
371
Riddle Hsu654a6f92018-07-13 22:59:36 +0800372 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700373
374 final int maxWidth = 300;
375 final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
376 final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
377
Riddle Hsu654a6f92018-07-13 22:59:36 +0800378 displayContent.setMaxUiWidth(maxWidth);
379 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700380
381 // Assert setting values again does not change;
Riddle Hsu654a6f92018-07-13 22:59:36 +0800382 displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
383 verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700384
385 final int smallerWidth = 200;
386 final int smallerHeight = 400;
387 final int smallerDensity = 100;
388
389 // Specify smaller dimension, verify that it is honored
Riddle Hsu654a6f92018-07-13 22:59:36 +0800390 displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
391 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700392
393 // Verify that setting the max width to a greater value than the base width has no effect
Riddle Hsu654a6f92018-07-13 22:59:36 +0800394 displayContent.setMaxUiWidth(maxWidth);
395 verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
Bryce Lee27cec322017-03-21 09:41:37 -0700396 }
397
Andrii Kulian92c9a942017-10-10 00:41:41 -0700398 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700399 public void testDisplayCutout_rot0() {
400 synchronized (mWm.getWindowManagerLock()) {
Adrian Roos1cf585052018-01-03 18:43:27 +0100401 final DisplayContent dc = createNewDisplay();
402 dc.mInitialDisplayWidth = 200;
403 dc.mInitialDisplayHeight = 400;
Adrian Roos24264212018-02-19 16:26:15 +0100404 Rect r = new Rect(80, 0, 120, 10);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100405 final DisplayCutout cutout = new WmDisplayCutout(
Issei Suzuki43190bd2018-08-20 17:28:41 +0200406 fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_TOP), null)
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100407 .computeSafeInsets(200, 400).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100408
409 dc.mInitialDisplayCutout = cutout;
410 dc.setRotation(Surface.ROTATION_0);
411 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
412
413 assertEquals(cutout, dc.getDisplayInfo().displayCutout);
414 }
415 }
416
417 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700418 public void testDisplayCutout_rot90() {
419 synchronized (mWm.getWindowManagerLock()) {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800420 // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
421 // if the device has no cutout).
422 final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
423 // Rotation may use real display info to compute bound, so here also uses the
424 // same width and height.
425 final int displayWidth = dc.mInitialDisplayWidth;
426 final int displayHeight = dc.mInitialDisplayHeight;
427 final int cutoutWidth = 40;
428 final int cutoutHeight = 10;
429 final int left = (displayWidth - cutoutWidth) / 2;
430 final int top = 0;
431 final int right = (displayWidth + cutoutWidth) / 2;
432 final int bottom = cutoutHeight;
433
434 final Rect r1 = new Rect(left, top, right, bottom);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100435 final DisplayCutout cutout = new WmDisplayCutout(
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700436 fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP),
437 null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800438 .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
Adrian Roos1cf585052018-01-03 18:43:27 +0100439
440 dc.mInitialDisplayCutout = cutout;
441 dc.setRotation(Surface.ROTATION_90);
442 dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
443
Riddle Hsu654a6f92018-07-13 22:59:36 +0800444 // ----o---------- -------------
445 // | | | | |
446 // | ------o | o---
447 // | | | |
448 // | | -> | |
449 // | | ---o
450 // | | |
451 // | | -------------
452 final Rect r = new Rect(top, left, bottom, right);
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100453 assertEquals(new WmDisplayCutout(
Issei Suzuki43190bd2018-08-20 17:28:41 +0200454 fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_LEFT), null)
Riddle Hsu654a6f92018-07-13 22:59:36 +0800455 .computeSafeInsets(displayHeight, displayWidth)
456 .getDisplayCutout(), dc.getDisplayInfo().displayCutout);
Adrian Roos1cf585052018-01-03 18:43:27 +0100457 }
458 }
459
460 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700461 public void testLayoutSeq_assignedDuringLayout() {
462 synchronized (mWm.getWindowManagerLock()) {
Adrian Roos5251b1d2018-03-23 18:57:43 +0100463
464 final DisplayContent dc = createNewDisplay();
465 final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
466
467 dc.setLayoutNeeded();
468 dc.performLayout(true /* initial */, false /* updateImeWindows */);
469
470 assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
471 }
472 }
473
474 @Test
Andrii Kulian92c9a942017-10-10 00:41:41 -0700475 @SuppressLint("InlinedApi")
476 public void testOrientationDefinedByKeyguard() {
477 final DisplayContent dc = createNewDisplay();
478 // Create a window that requests landscape orientation. It will define device orientation
479 // by default.
480 final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
481 window.mAppToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
482
483 final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, dc, "keyguard");
484 keyguard.mHasSurface = true;
485 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
486
487 assertEquals("Screen orientation must be defined by the app window by default",
488 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
489
490 keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
491 assertEquals("Visible keyguard must influence device orientation",
492 SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
493
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700494 mWm.setKeyguardGoingAway(true);
Andrii Kulian92c9a942017-10-10 00:41:41 -0700495 assertEquals("Keyguard that is going away must not influence device orientation",
496 SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
497 }
498
Andrii Kulianf0379de2018-03-14 16:24:07 -0700499 @Test
500 public void testDisableDisplayInfoOverrideFromWindowManager() {
501 final DisplayContent dc = createNewDisplay();
502
503 assertTrue(dc.mShouldOverrideDisplayConfiguration);
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700504 mWm.dontOverrideDisplayInfo(dc.getDisplayId());
Andrii Kulianf0379de2018-03-14 16:24:07 -0700505
506 assertFalse(dc.mShouldOverrideDisplayConfiguration);
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700507 verify(mWm.mDisplayManagerInternal, times(1))
Andrii Kulianf0379de2018-03-14 16:24:07 -0700508 .setDisplayInfoOverrideFromWindowManager(dc.getDisplayId(), null);
509 }
510
Riddle Hsua4d6fa22018-08-11 00:50:39 +0800511 @Test
Riddle Hsu85bd04b2018-11-17 00:34:36 +0800512 public void testClearLastFocusWhenReparentingFocusedWindow() {
513 final DisplayContent defaultDisplay = mWm.getDefaultDisplayContentLocked();
514 final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
515 defaultDisplay, "window");
516 defaultDisplay.mLastFocus = window;
517 mDisplayContent.mCurrentFocus = window;
518 mDisplayContent.reParentWindowToken(window.mToken);
519
520 assertNull(defaultDisplay.mLastFocus);
521 }
522
523 @Test
Riddle Hsua4d6fa22018-08-11 00:50:39 +0800524 public void testGetPreferredOptionsPanelGravityFromDifferentDisplays() {
525 final DisplayContent portraitDisplay = createNewDisplay();
526 portraitDisplay.mInitialDisplayHeight = 2000;
527 portraitDisplay.mInitialDisplayWidth = 1000;
528
529 portraitDisplay.setRotation(Surface.ROTATION_0);
530 assertFalse(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
531 portraitDisplay.setRotation(Surface.ROTATION_90);
532 assertTrue(isOptionsPanelAtRight(portraitDisplay.getDisplayId()));
533
534 final DisplayContent landscapeDisplay = createNewDisplay();
535 landscapeDisplay.mInitialDisplayHeight = 1000;
536 landscapeDisplay.mInitialDisplayWidth = 2000;
537
538 landscapeDisplay.setRotation(Surface.ROTATION_0);
539 assertTrue(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
540 landscapeDisplay.setRotation(Surface.ROTATION_90);
541 assertFalse(isOptionsPanelAtRight(landscapeDisplay.getDisplayId()));
542 }
543
lumarkff0ab692018-11-05 20:32:30 +0800544 @Test
545 public void testInputMethodTargetUpdateWhenSwitchingOnDisplays() {
546 final DisplayContent newDisplay = createNewDisplay();
547
548 final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
549 final WindowState appWin1 = createWindow(null, TYPE_APPLICATION, newDisplay, "appWin1");
550 appWin.setHasSurface(true);
551 appWin1.setHasSurface(true);
552
553 // Set current input method window on default display, make sure the input method target
554 // is appWin & null on the other display.
555 mDisplayContent.setInputMethodWindowLocked(mImeWindow);
556 newDisplay.setInputMethodWindowLocked(null);
557 assertTrue("appWin should be IME target window",
558 appWin.equals(mDisplayContent.mInputMethodTarget));
559 assertNull("newDisplay Ime target: ", newDisplay.mInputMethodTarget);
560
561 // Switch input method window on new display & make sure the input method target also
562 // switched as expected.
563 newDisplay.setInputMethodWindowLocked(mImeWindow);
564 mDisplayContent.setInputMethodWindowLocked(null);
565 assertTrue("appWin1 should be IME target window",
566 appWin1.equals(newDisplay.mInputMethodTarget));
567 assertNull("default display Ime target: ", mDisplayContent.mInputMethodTarget);
568 }
569
Riddle Hsua4d6fa22018-08-11 00:50:39 +0800570 private boolean isOptionsPanelAtRight(int displayId) {
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700571 return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
Riddle Hsua4d6fa22018-08-11 00:50:39 +0800572 }
573
Bryce Lee27cec322017-03-21 09:41:37 -0700574 private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
575 int expectedBaseHeight, int expectedBaseDensity) {
576 assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
577 assertEquals(displayContent.mBaseDisplayHeight, expectedBaseHeight);
578 assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
579 }
580
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800581 private void updateFocusedWindow() {
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700582 synchronized (mWm.mGlobalLock) {
583 mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false);
Tiger Huang1e5b10a2018-07-30 20:19:51 +0800584 }
585 }
586
Riddle Hsu654a6f92018-07-13 22:59:36 +0800587 /**
588 * Create DisplayContent that does not update display base/initial values from device to keep
589 * the values set by test.
590 */
591 private DisplayContent createDisplayNoUpdateDisplayInfo() {
592 final DisplayContent displayContent = spy(createNewDisplay());
593 doNothing().when(displayContent).updateDisplayInfo();
594 return displayContent;
595 }
596
Adrian Roos0f9368c2018-04-08 10:59:08 -0700597 private void assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop) {
598 final LinkedList<WindowState> actualWindows = new LinkedList<>();
Wale Ogunwale34247952017-02-19 11:57:53 -0800599
600 // Test forward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700601 mDisplayContent.forAllWindows(actualWindows::addLast, false /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700602 assertThat("bottomToTop", actualWindows, is(expectedWindowsBottomToTop));
603
604 actualWindows.clear();
Wale Ogunwale34247952017-02-19 11:57:53 -0800605
606 // Test backward traversal.
Wale Ogunwale11cc5162017-04-25 20:29:13 -0700607 mDisplayContent.forAllWindows(actualWindows::addLast, true /* traverseTopToBottom */);
Adrian Roos0f9368c2018-04-08 10:59:08 -0700608 assertThat("topToBottom", actualWindows, is(reverseList(expectedWindowsBottomToTop)));
609 }
610
611 private static List<WindowState> reverseList(List<WindowState> list) {
612 final ArrayList<WindowState> result = new ArrayList<>(list);
613 Collections.reverse(result);
614 return result;
Wale Ogunwale34247952017-02-19 11:57:53 -0800615 }
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700616
Arthur Hungbe5ce212018-09-13 18:41:56 +0800617 private void tapOnDisplay(final DisplayContent dc) {
618 final DisplayMetrics dm = dc.getDisplayMetrics();
619 final float x = dm.widthPixels / 2;
620 final float y = dm.heightPixels / 2;
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700621 final long downTime = SystemClock.uptimeMillis();
622 final long eventTime = SystemClock.uptimeMillis() + 100;
Arthur Hungbe5ce212018-09-13 18:41:56 +0800623 // sending ACTION_DOWN
624 final MotionEvent downEvent = MotionEvent.obtain(
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700625 downTime,
Arthur Hungbe5ce212018-09-13 18:41:56 +0800626 downTime,
627 MotionEvent.ACTION_DOWN,
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700628 x,
629 y,
Arthur Hungbe5ce212018-09-13 18:41:56 +0800630 0 /*metaState*/);
631 downEvent.setDisplayId(dc.getDisplayId());
632 dc.mTapDetector.onPointerEvent(downEvent);
633
634 // sending ACTION_UP
635 final MotionEvent upEvent = MotionEvent.obtain(
636 downTime,
637 eventTime,
638 MotionEvent.ACTION_UP,
639 x,
640 y,
641 0 /*metaState*/);
642 upEvent.setDisplayId(dc.getDisplayId());
643 dc.mTapDetector.onPointerEvent(upEvent);
Tarandeep Singhe1cfcf42017-07-10 18:50:00 -0700644 }
Wale Ogunwaleb783fd82016-11-04 09:51:54 -0700645}