blob: 2ccdb9ea068c339438cbf4bf3ae79bb5a4448329 [file] [log] [blame]
Robert Carr16a4e3c2016-10-28 11:45:22 -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.
Robert Carr16a4e3c2016-10-28 11:45:22 -070015 */
16
17package com.android.server.wm;
18
Yunfan Chen279f5582018-12-12 15:24:50 -080019import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
Evan Rosky0d654cb2019-02-26 10:59:10 -080020import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
Yunfan Chen279f5582018-12-12 15:24:50 -080021import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
Issei Suzuki43190bd2018-08-20 17:28:41 +020022import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
Brett Chabota26eda92018-07-23 13:08:30 -070023import static android.view.DisplayCutout.fromBoundingRect;
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070024import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
Brett Chabota26eda92018-07-23 13:08:30 -070025import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
26
27import static org.junit.Assert.assertEquals;
Yunfan Chen279f5582018-12-12 15:24:50 -080028import static org.mockito.Mockito.mock;
Robert Carr16a4e3c2016-10-28 11:45:22 -070029
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010030import android.app.ActivityManager.TaskDescription;
Bryce Leef3c6a472017-11-14 14:53:06 -080031import android.content.res.Configuration;
Robert Carr16a4e3c2016-10-28 11:45:22 -070032import android.graphics.Rect;
Robert Carr16a4e3c2016-10-28 11:45:22 -070033import android.platform.test.annotations.Presubmit;
Robert Carrfbbde852016-10-18 11:02:28 -070034import android.view.DisplayInfo;
Robert Carr16a4e3c2016-10-28 11:45:22 -070035import android.view.Gravity;
36import android.view.IWindow;
37import android.view.WindowManager;
38
Brett Chabota26eda92018-07-23 13:08:30 -070039import androidx.test.filters.SmallTest;
Robert Carr16a4e3c2016-10-28 11:45:22 -070040
Adrian Roos6a4fa0e2018-03-05 19:50:16 +010041import com.android.server.wm.utils.WmDisplayCutout;
42
Brett Chabota26eda92018-07-23 13:08:30 -070043import org.junit.Before;
44import org.junit.Test;
Evan Rosky0d654cb2019-02-26 10:59:10 -080045import org.mockito.Mockito;
Brett Chabota26eda92018-07-23 13:08:30 -070046
Robert Carr16a4e3c2016-10-28 11:45:22 -070047/**
48 * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery.
49 *
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070050 * Build/Install/Run:
51 * atest FrameworksServicesTests:WindowFrameTests
Robert Carr16a4e3c2016-10-28 11:45:22 -070052 */
53@SmallTest
54@Presubmit
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -070055public class WindowFrameTests extends WindowTestsBase {
Robert Carr16a4e3c2016-10-28 11:45:22 -070056
Robert Carr16a4e3c2016-10-28 11:45:22 -070057 private WindowToken mWindowToken;
58 private final IWindow mIWindow = new TestIWindow();
chaviw553b0212018-07-12 13:37:01 -070059 private final Rect mEmptyRect = new Rect();
Robert Carr16a4e3c2016-10-28 11:45:22 -070060
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070061 static class WindowStateWithTask extends WindowState {
Robert Carr16a4e3c2016-10-28 11:45:22 -070062 final Task mTask;
Robert Carrfbbde852016-10-18 11:02:28 -070063 boolean mDockedResizingForTest = false;
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070064 WindowStateWithTask(WindowManagerService wm, IWindow iWindow, WindowToken windowToken,
65 WindowManager.LayoutParams attrs, Task t) {
Yunfan Chen279f5582018-12-12 15:24:50 -080066 super(wm, mock(Session.class), iWindow, windowToken, null, 0, 0, attrs, 0, 0,
Wale Ogunwale5cd907d2017-01-26 14:14:08 -080067 false /* ownerCanAddInternalSystemWindow */);
Robert Carr16a4e3c2016-10-28 11:45:22 -070068 mTask = t;
69 }
70
71 @Override
72 Task getTask() {
73 return mTask;
74 }
Robert Carrfbbde852016-10-18 11:02:28 -070075
76 @Override
77 boolean isDockedResizing() {
78 return mDockedResizingForTest;
79 }
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070080 }
Robert Carr16a4e3c2016-10-28 11:45:22 -070081
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070082 private static class TaskWithBounds extends Task {
Evan Rosky0d654cb2019-02-26 10:59:10 -080083 Rect mBounds;
Evan Roskyed6767f2018-10-26 17:21:06 -070084 final Rect mOverrideDisplayedBounds = new Rect();
Robert Carr15dd7ef2016-11-03 14:26:58 -070085 boolean mFullscreenForTest = true;
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -070086
87 TaskWithBounds(TaskStack stack, WindowManagerService wm, Rect bounds) {
88 super(0, stack, 0, wm, 0, false, new TaskDescription(), null);
Bryce Leef3c6a472017-11-14 14:53:06 -080089 setBounds(bounds);
Robert Carr16a4e3c2016-10-28 11:45:22 -070090 }
Bryce Leef3c6a472017-11-14 14:53:06 -080091
Robert Carr16a4e3c2016-10-28 11:45:22 -070092 @Override
Evan Rosky0d654cb2019-02-26 10:59:10 -080093 public int setBounds(Rect bounds) {
94 mBounds = bounds;
95 return super.setBounds(bounds);
96 }
97
98 @Override
Bryce Leef3c6a472017-11-14 14:53:06 -080099 public Rect getBounds() {
100 return mBounds;
101 }
102
103 @Override
104 public void getBounds(Rect out) {
105 out.set(mBounds);
106 }
107
108 @Override
Evan Roskydfe3da72018-10-26 17:21:06 -0700109 public void getRequestedOverrideBounds(Rect outBounds) {
Robert Carr16a4e3c2016-10-28 11:45:22 -0700110 outBounds.set(mBounds);
111 }
112 @Override
Evan Roskyed6767f2018-10-26 17:21:06 -0700113 Rect getOverrideDisplayedBounds() {
114 return mOverrideDisplayedBounds;
Robert Carr16a4e3c2016-10-28 11:45:22 -0700115 }
116 @Override
117 boolean isFullscreen() {
Robert Carr15dd7ef2016-11-03 14:26:58 -0700118 return mFullscreenForTest;
Robert Carr16a4e3c2016-10-28 11:45:22 -0700119 }
120 }
121
122 TaskStack mStubStack;
123
124 @Before
125 public void setUp() throws Exception {
Yunfan Chen279f5582018-12-12 15:24:50 -0800126 mWindowToken = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
127 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
Tadashi G. Takaokad7aa79a2019-02-08 17:42:37 +0900128 mStubStack = mock(TaskStack.class);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700129 }
130
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900131 // Do not use this function directly in the tests below. Instead, use more explicit function
132 // such as assertFlame().
133 private void assertRect(Rect rect, int left, int top, int right, int bottom) {
Robert Carr16a4e3c2016-10-28 11:45:22 -0700134 assertEquals(left, rect.left);
135 assertEquals(top, rect.top);
136 assertEquals(right, rect.right);
137 assertEquals(bottom, rect.bottom);
138 }
139
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900140 private void assertContentInset(WindowState w, int left, int top, int right, int bottom) {
chaviw9c81e632018-07-31 11:17:52 -0700141 assertRect(w.getContentInsets(), left, top, right, bottom);
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900142 }
143
144 private void assertVisibleInset(WindowState w, int left, int top, int right, int bottom) {
chaviw9c81e632018-07-31 11:17:52 -0700145 assertRect(w.getVisibleInsets(), left, top, right, bottom);
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900146 }
147
148 private void assertStableInset(WindowState w, int left, int top, int right, int bottom) {
chaviw9c81e632018-07-31 11:17:52 -0700149 assertRect(w.getStableInsets(), left, top, right, bottom);
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900150 }
151
152 private void assertFrame(WindowState w, int left, int top, int right, int bottom) {
153 assertRect(w.getFrameLw(), left, top, right, bottom);
154 }
155
156 private void assertContentFrame(WindowState w, Rect expectedRect) {
157 assertRect(w.getContentFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
158 expectedRect.bottom);
159 }
160
161 private void assertVisibleFrame(WindowState w, Rect expectedRect) {
162 assertRect(w.getVisibleFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
163 expectedRect.bottom);
164 }
165
166 private void assertStableFrame(WindowState w, Rect expectedRect) {
167 assertRect(w.getStableFrameLw(), expectedRect.left, expectedRect.top, expectedRect.right,
168 expectedRect.bottom);
169 }
170
171 private void assertPolicyCrop(WindowStateWithTask w, int left, int top, int right, int bottom) {
172 Rect policyCrop = new Rect();
173 w.calculatePolicyCrop(policyCrop);
174 assertRect(policyCrop, left, top, right, bottom);
175 }
176
Robert Carr16a4e3c2016-10-28 11:45:22 -0700177 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700178 public void testLayoutInFullscreenTaskInsets() {
179 // fullscreen task doesn't use bounds for computeFrame
180 final Task task = new TaskWithBounds(mStubStack, mWm, null);
181 WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
Robert Carre4ee8f8a2016-10-31 12:40:15 -0700182 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
183
184 final int bottomContentInset = 100;
185 final int topContentInset = 50;
186 final int bottomVisibleInset = 30;
187 final int topVisibleInset = 70;
188 final int leftStableInset = 20;
189 final int rightStableInset = 90;
190
191 // With no insets or system decor all the frames incoming from PhoneWindowManager
192 // are identical.
193 final Rect pf = new Rect(0, 0, 1000, 1000);
194 final Rect df = pf;
195 final Rect of = df;
196 final Rect cf = new Rect(pf);
197 // Produce some insets
198 cf.top += 50;
199 cf.bottom -= 100;
200 final Rect vf = new Rect(pf);
201 vf.top += topVisibleInset;
202 vf.bottom -= bottomVisibleInset;
203 final Rect sf = new Rect(pf);
204 sf.left += leftStableInset;
205 sf.right -= rightStableInset;
206
207 final Rect dcf = pf;
208 // When mFrame extends past cf, the content insets are
209 // the difference between mFrame and ContentFrame. Visible
210 // and stable frames work the same way.
chaviw1454b392018-08-06 09:54:04 -0700211 w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
212 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900213 assertFrame(w, 0, 0, 1000, 1000);
214 assertContentInset(w, 0, topContentInset, 0, bottomContentInset);
215 assertVisibleInset(w, 0, topVisibleInset, 0, bottomVisibleInset);
216 assertStableInset(w, leftStableInset, 0, rightStableInset, 0);
217 assertContentFrame(w, cf);
218 assertVisibleFrame(w, vf);
219 assertStableFrame(w, sf);
chaviw492139a2018-07-16 16:07:35 -0700220 // On the other hand getFrame() doesn't extend past cf we won't get any insets
Robert Carre4ee8f8a2016-10-31 12:40:15 -0700221 w.mAttrs.x = 100;
222 w.mAttrs.y = 100;
223 w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT
224 w.mRequestedWidth = 100;
225 w.mRequestedHeight = 100;
chaviw1454b392018-08-06 09:54:04 -0700226 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900227 assertFrame(w, 100, 100, 200, 200);
228 assertContentInset(w, 0, 0, 0, 0);
Robert Carre4ee8f8a2016-10-31 12:40:15 -0700229 // In this case the frames are shrunk to the window frame.
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900230 assertContentFrame(w, w.getFrameLw());
231 assertVisibleFrame(w, w.getFrameLw());
232 assertStableFrame(w, w.getFrameLw());
Robert Carre4ee8f8a2016-10-31 12:40:15 -0700233 }
234
235 @Test
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700236 public void testLayoutInFullscreenTaskNoInsets() {
237 // fullscreen task doesn't use bounds for computeFrame
238 final Task task = new TaskWithBounds(mStubStack, mWm, null);
239 WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700240 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
241
242 // With no insets or system decor all the frames incoming from PhoneWindowManager
243 // are identical.
244 final Rect pf = new Rect(0, 0, 1000, 1000);
245
246 // Here the window has FILL_PARENT, FILL_PARENT
247 // so we expect it to fill the entire available frame.
chaviw1454b392018-08-06 09:54:04 -0700248 w.getWindowFrames().setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
249 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900250 assertFrame(w, 0, 0, 1000, 1000);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700251
252 // It can select various widths and heights within the bounds.
253 // Strangely the window attribute width is ignored for normal windows
254 // and we use mRequestedWidth/mRequestedHeight
255 w.mAttrs.width = 300;
256 w.mAttrs.height = 300;
chaviw1454b392018-08-06 09:54:04 -0700257 w.computeFrameLw();
Robert Carr16a4e3c2016-10-28 11:45:22 -0700258 // Explicit width and height without requested width/height
259 // gets us nothing.
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900260 assertFrame(w, 0, 0, 0, 0);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700261
262 w.mRequestedWidth = 300;
263 w.mRequestedHeight = 300;
chaviw1454b392018-08-06 09:54:04 -0700264 w.computeFrameLw();
Robert Carr16a4e3c2016-10-28 11:45:22 -0700265 // With requestedWidth/Height we can freely choose our size within the
266 // parent bounds.
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900267 assertFrame(w, 0, 0, 300, 300);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700268
269 // With FLAG_SCALED though, requestedWidth/height is used to control
270 // the unscaled surface size, and mAttrs.width/height becomes the
271 // layout controller.
272 w.mAttrs.flags = WindowManager.LayoutParams.FLAG_SCALED;
273 w.mRequestedHeight = -1;
274 w.mRequestedWidth = -1;
275 w.mAttrs.width = 100;
276 w.mAttrs.height = 100;
chaviw1454b392018-08-06 09:54:04 -0700277 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900278 assertFrame(w, 0, 0, 100, 100);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700279 w.mAttrs.flags = 0;
280
281 // But sizes too large will be clipped to the containing frame
282 w.mRequestedWidth = 1200;
283 w.mRequestedHeight = 1200;
chaviw1454b392018-08-06 09:54:04 -0700284 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900285 assertFrame(w, 0, 0, 1000, 1000);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700286
287 // Before they are clipped though windows will be shifted
288 w.mAttrs.x = 300;
289 w.mAttrs.y = 300;
290 w.mRequestedWidth = 1000;
291 w.mRequestedHeight = 1000;
chaviw1454b392018-08-06 09:54:04 -0700292 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900293 assertFrame(w, 0, 0, 1000, 1000);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700294
295 // If there is room to move around in the parent frame the window will be shifted according
296 // to gravity.
297 w.mAttrs.x = 0;
298 w.mAttrs.y = 0;
299 w.mRequestedWidth = 300;
300 w.mRequestedHeight = 300;
301 w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
chaviw1454b392018-08-06 09:54:04 -0700302 w.computeFrameLw();
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +0900303 assertFrame(w, 700, 0, 1000, 300);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700304 w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
chaviw1454b392018-08-06 09:54:04 -0700305 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900306 assertFrame(w, 700, 700, 1000, 1000);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700307 // Window specified x and y are interpreted as offsets in the opposite
308 // direction of gravity
309 w.mAttrs.x = 100;
310 w.mAttrs.y = 100;
chaviw1454b392018-08-06 09:54:04 -0700311 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900312 assertFrame(w, 600, 600, 900, 900);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700313 }
314
Robert Carr15dd7ef2016-11-03 14:26:58 -0700315 @Test
316 public void testLayoutNonfullscreenTask() {
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700317 final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo();
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700318 final int logicalWidth = displayInfo.logicalWidth;
319 final int logicalHeight = displayInfo.logicalHeight;
320
321 final int taskLeft = logicalWidth / 4;
322 final int taskTop = logicalHeight / 4;
323 final int taskRight = logicalWidth / 4 * 3;
324 final int taskBottom = logicalHeight / 4 * 3;
325 final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700326 final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700327 task.mFullscreenForTest = false;
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700328 WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700329 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
330
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700331 final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
chaviw1454b392018-08-06 09:54:04 -0700332 final WindowFrames windowFrames = w.getWindowFrames();
333 windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
334 w.computeFrameLw();
Robert Carr15dd7ef2016-11-03 14:26:58 -0700335 // For non fullscreen tasks the containing frame is based off the
336 // task bounds not the parent frame.
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900337 assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
338 assertContentFrame(w, taskBounds);
339 assertContentInset(w, 0, 0, 0, 0);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700340
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700341 pf.set(0, 0, logicalWidth, logicalHeight);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700342 // We still produce insets against the containing frame the same way.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700343 final int cfRight = logicalWidth / 2;
344 final int cfBottom = logicalHeight / 2;
345 final Rect cf = new Rect(0, 0, cfRight, cfBottom);
chaviw553b0212018-07-12 13:37:01 -0700346 windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
chaviw1454b392018-08-06 09:54:04 -0700347 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900348 assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700349 int contentInsetRight = taskRight - cfRight;
350 int contentInsetBottom = taskBottom - cfBottom;
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900351 assertContentInset(w, 0, 0, contentInsetRight, contentInsetBottom);
352 assertContentFrame(w, new Rect(taskLeft, taskTop, taskRight - contentInsetRight,
353 taskBottom - contentInsetBottom));
Robert Carr15dd7ef2016-11-03 14:26:58 -0700354
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700355 pf.set(0, 0, logicalWidth, logicalHeight);
Evan Roskyed6767f2018-10-26 17:21:06 -0700356 // If we set displayed bounds, the insets will be computed with the main task bounds
357 // but the frame will be positioned according to the displayed bounds.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700358 final int insetLeft = logicalWidth / 5;
359 final int insetTop = logicalHeight / 5;
360 final int insetRight = insetLeft + (taskRight - taskLeft);
361 final int insetBottom = insetTop + (taskBottom - taskTop);
Evan Roskyed6767f2018-10-26 17:21:06 -0700362 task.mOverrideDisplayedBounds.set(taskBounds);
363 task.mBounds.set(insetLeft, insetTop, insetRight, insetBottom);
chaviw553b0212018-07-12 13:37:01 -0700364 windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
chaviw1454b392018-08-06 09:54:04 -0700365 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900366 assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700367 contentInsetRight = insetRight - cfRight;
368 contentInsetBottom = insetBottom - cfBottom;
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900369 assertContentInset(w, 0, 0, contentInsetRight, contentInsetBottom);
370 assertContentFrame(w, new Rect(taskLeft, taskTop, taskRight - contentInsetRight,
371 taskBottom - contentInsetBottom));
Robert Carr15dd7ef2016-11-03 14:26:58 -0700372 }
373
Robert Carrfbbde852016-10-18 11:02:28 -0700374 @Test
375 public void testCalculatePolicyCrop() {
376 final WindowStateWithTask w = createWindow(
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700377 new TaskWithBounds(mStubStack, mWm, null), MATCH_PARENT, MATCH_PARENT);
Robert Carrfbbde852016-10-18 11:02:28 -0700378 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
379
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700380 final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
381 final int logicalWidth = displayInfo.logicalWidth;
382 final int logicalHeight = displayInfo.logicalHeight;
383 final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
Robert Carrfbbde852016-10-18 11:02:28 -0700384 final Rect df = pf;
385 final Rect of = df;
386 final Rect cf = new Rect(pf);
387 // Produce some insets
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700388 cf.top += displayInfo.logicalWidth / 10;
389 cf.bottom -= displayInfo.logicalWidth / 5;
Robert Carrfbbde852016-10-18 11:02:28 -0700390 final Rect vf = cf;
391 final Rect sf = vf;
392 // We use a decor content frame with insets to produce cropping.
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900393 Rect dcf = new Rect(cf);
Robert Carrfbbde852016-10-18 11:02:28 -0700394
chaviw1454b392018-08-06 09:54:04 -0700395 final WindowFrames windowFrames = w.getWindowFrames();
396 windowFrames.setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
397 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900398 assertPolicyCrop(w, 0, cf.top, logicalWidth, cf.bottom);
chaviw0eac1682017-11-02 11:27:51 -0700399
chaviw553b0212018-07-12 13:37:01 -0700400 windowFrames.mDecorFrame.setEmpty();
Robert Carrfbbde852016-10-18 11:02:28 -0700401 // Likewise with no decor frame we would get no crop
chaviw1454b392018-08-06 09:54:04 -0700402 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900403 assertPolicyCrop(w, 0, 0, logicalWidth, logicalHeight);
Robert Carrfbbde852016-10-18 11:02:28 -0700404
405 // Now we set up a window which doesn't fill the entire decor frame.
406 // Normally it would be cropped to it's frame but in the case of docked resizing
407 // we need to account for the fact the windows surface will be made
408 // fullscreen and thus also make the crop fullscreen.
chaviw553b0212018-07-12 13:37:01 -0700409
410 windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
Robert Carrfbbde852016-10-18 11:02:28 -0700411 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700412 w.mAttrs.width = logicalWidth / 2;
413 w.mAttrs.height = logicalHeight / 2;
414 w.mRequestedWidth = logicalWidth / 2;
415 w.mRequestedHeight = logicalHeight / 2;
chaviw1454b392018-08-06 09:54:04 -0700416 w.computeFrameLw();
Robert Carrfbbde852016-10-18 11:02:28 -0700417
Robert Carrfbbde852016-10-18 11:02:28 -0700418 // Normally the crop is shrunk from the decor frame
419 // to the computed window frame.
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900420 assertPolicyCrop(w, 0, 0, logicalWidth / 2, logicalHeight / 2);
Robert Carrfbbde852016-10-18 11:02:28 -0700421
422 w.mDockedResizingForTest = true;
Robert Carr186d9de2017-02-09 12:41:03 -0800423 // But if we are docked resizing it won't be, however we will still be
424 // shrunk to the decor frame and the display.
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900425 assertPolicyCrop(w, 0, 0,
Robert Carr186d9de2017-02-09 12:41:03 -0800426 Math.min(pf.width(), displayInfo.logicalWidth),
427 Math.min(pf.height(), displayInfo.logicalHeight));
Robert Carrfbbde852016-10-18 11:02:28 -0700428 }
429
Andrii Kulianc24f3732017-08-08 19:35:17 -0700430 @Test
431 public void testLayoutLetterboxedWindow() {
432 // First verify task behavior in multi-window mode.
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700433 final DisplayInfo displayInfo = mWm.getDefaultDisplayContentLocked().getDisplayInfo();
Andrii Kulianc24f3732017-08-08 19:35:17 -0700434 final int logicalWidth = displayInfo.logicalWidth;
435 final int logicalHeight = displayInfo.logicalHeight;
436
437 final int taskLeft = logicalWidth / 5;
438 final int taskTop = logicalHeight / 5;
439 final int taskRight = logicalWidth / 4 * 3;
440 final int taskBottom = logicalHeight / 4 * 3;
441 final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700442 final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm, taskBounds);
Andrii Kulianc24f3732017-08-08 19:35:17 -0700443 task.mFullscreenForTest = false;
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700444 WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
Andrii Kulianc24f3732017-08-08 19:35:17 -0700445 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
446
447 final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
chaviw1454b392018-08-06 09:54:04 -0700448 final WindowFrames windowFrames = w.getWindowFrames();
449 windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, mEmptyRect);
450 w.computeFrameLw();
Andrii Kulianc24f3732017-08-08 19:35:17 -0700451 // For non fullscreen tasks the containing frame is based off the
452 // task bounds not the parent frame.
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900453 assertFrame(w, taskLeft, taskTop, taskRight, taskBottom);
454 assertContentFrame(w, taskBounds);
455 assertContentInset(w, 0, 0, 0, 0);
Andrii Kulianc24f3732017-08-08 19:35:17 -0700456
457 // Now simulate switch to fullscreen for letterboxed app.
458 final int xInset = logicalWidth / 10;
Riddle Hsub398da32019-01-21 21:48:16 +0800459 final Rect cf = new Rect(xInset, 0, logicalWidth - xInset, logicalHeight);
Evan Roskydfe3da72018-10-26 17:21:06 -0700460 Configuration config = new Configuration(w.mAppToken.getRequestedOverrideConfiguration());
Bryce Leef3c6a472017-11-14 14:53:06 -0800461 config.windowConfiguration.setBounds(cf);
Evan Roskydfe3da72018-10-26 17:21:06 -0700462 w.mAppToken.onRequestedOverrideConfigurationChanged(config);
Andrii Kulianc24f3732017-08-08 19:35:17 -0700463 pf.set(0, 0, logicalWidth, logicalHeight);
464 task.mFullscreenForTest = true;
chaviw553b0212018-07-12 13:37:01 -0700465 windowFrames.setFrames(pf, pf, pf, cf, cf, pf, cf, mEmptyRect);
chaviw1454b392018-08-06 09:54:04 -0700466 w.computeFrameLw();
Kazuki Takisee8d6d442018-07-23 17:40:20 +0900467 assertFrame(w, cf.left, cf.top, cf.right, cf.bottom);
468 assertContentFrame(w, cf);
469 assertContentInset(w, 0, 0, 0, 0);
Andrii Kulianc24f3732017-08-08 19:35:17 -0700470 }
471
Adrian Roos5c6b6222017-11-07 17:36:10 +0100472 @Test
473 public void testDisplayCutout() {
474 // Regular fullscreen task and window
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700475 final Task task = new TaskWithBounds(mStubStack, mWm, null);
476 WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
Adrian Roos5c6b6222017-11-07 17:36:10 +0100477 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
478
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100479 final Rect pf = new Rect(0, 0, 1000, 2000);
Adrian Roos5c6b6222017-11-07 17:36:10 +0100480 // Create a display cutout of size 50x50, aligned top-center
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100481 final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
Issei Suzuki43190bd2018-08-20 17:28:41 +0200482 fromBoundingRect(500, 0, 550, 50, BOUNDS_POSITION_TOP),
483 pf.width(), pf.height());
Adrian Roos5c6b6222017-11-07 17:36:10 +0100484
chaviw1454b392018-08-06 09:54:04 -0700485 final WindowFrames windowFrames = w.getWindowFrames();
486 windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
chaviwcdba9a42018-07-19 11:36:42 -0700487 windowFrames.setDisplayCutout(cutout);
chaviw1454b392018-08-06 09:54:04 -0700488 w.computeFrameLw();
Adrian Roos5c6b6222017-11-07 17:36:10 +0100489
chaviwcdba9a42018-07-19 11:36:42 -0700490 assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50);
491 assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0);
492 assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetLeft(), 0);
493 assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetRight(), 0);
Adrian Roos5c6b6222017-11-07 17:36:10 +0100494 }
495
Jorim Jaggibae2b152018-04-18 17:27:27 +0200496 @Test
Evan Roskyed6767f2018-10-26 17:21:06 -0700497 public void testDisplayCutout_tempDisplayedBounds() {
Jorim Jaggibae2b152018-04-18 17:27:27 +0200498 // Regular fullscreen task and window
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700499 final TaskWithBounds task = new TaskWithBounds(mStubStack, mWm,
Evan Roskyed6767f2018-10-26 17:21:06 -0700500 new Rect(0, 0, 1000, 2000));
Jorim Jaggibae2b152018-04-18 17:27:27 +0200501 task.mFullscreenForTest = false;
Evan Roskyed6767f2018-10-26 17:21:06 -0700502 task.setOverrideDisplayedBounds(new Rect(0, -500, 1000, 1500));
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700503 WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
Jorim Jaggibae2b152018-04-18 17:27:27 +0200504 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
505
506 final Rect pf = new Rect(0, -500, 1000, 1500);
507 // Create a display cutout of size 50x50, aligned top-center
508 final WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
Issei Suzuki43190bd2018-08-20 17:28:41 +0200509 fromBoundingRect(500, 0, 550, 50, BOUNDS_POSITION_TOP),
510 pf.width(), pf.height());
Jorim Jaggibae2b152018-04-18 17:27:27 +0200511
chaviw1454b392018-08-06 09:54:04 -0700512 final WindowFrames windowFrames = w.getWindowFrames();
513 windowFrames.setFrames(pf, pf, pf, pf, pf, pf, pf, pf);
chaviwcdba9a42018-07-19 11:36:42 -0700514 windowFrames.setDisplayCutout(cutout);
chaviw1454b392018-08-06 09:54:04 -0700515 w.computeFrameLw();
Jorim Jaggibae2b152018-04-18 17:27:27 +0200516
chaviwcdba9a42018-07-19 11:36:42 -0700517 assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetTop(), 50);
518 assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetBottom(), 0);
519 assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetLeft(), 0);
520 assertEquals(w.getWmDisplayCutout().getDisplayCutout().getSafeInsetRight(), 0);
Jorim Jaggibae2b152018-04-18 17:27:27 +0200521 }
522
Evan Rosky0d654cb2019-02-26 10:59:10 -0800523 @Test
524 public void testFreeformContentInsets() {
525 // fullscreen task doesn't use bounds for computeFrame
526 final Task task = new TaskWithBounds(mStubStack, mWm, null);
527 WindowState w = createWindow(task, MATCH_PARENT, MATCH_PARENT);
528 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
529 task.setWindowingMode(WINDOWING_MODE_FREEFORM);
530 ((TaskWithBounds) task).mFullscreenForTest = false;
531 w.setWindowingMode(WINDOWING_MODE_FREEFORM);
532
533 DisplayContent dc = mWm.getDefaultDisplayContentLocked();
534 dc.mInputMethodTarget = w;
535 WindowState mockIme = mock(WindowState.class);
536 Mockito.doReturn(true).when(mockIme).isVisibleNow();
537 dc.mInputMethodWindow = mockIme;
538
539 // With no insets or system decor all the frames incoming from PhoneWindowManager
540 // are identical.
541 final Rect pf = new Rect(0, 0, 1000, 800);
542 final Rect df = pf;
543 final Rect of = df;
544 final Rect cf = new Rect(pf);
545 cf.bottom -= 400;
546 final Rect vf = new Rect(cf);
547 final Rect sf = new Rect(pf);
548 final Rect dcf = pf;
549
550 // First check that it only gets moved up enough to show window.
551 final Rect winRect = new Rect(200, 200, 300, 500);
552
553 task.setBounds(winRect);
554 w.setBounds(winRect);
555 w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
556 w.computeFrameLw();
557
558 final Rect expected = new Rect(winRect.left, cf.bottom - winRect.height(),
559 winRect.right, cf.bottom);
560 assertEquals(expected, w.getFrameLw());
561 assertEquals(expected, w.getContentFrameLw());
562 assertEquals(expected, w.getVisibleFrameLw());
563
564 // Now check that it won't get moved beyond the top and then has appropriate insets
565 winRect.bottom = 600;
566 task.setBounds(winRect);
567 w.setBounds(winRect);
568 w.getWindowFrames().setFrames(pf, df, of, cf, vf, dcf, sf, mEmptyRect);
569 w.computeFrameLw();
570
571 assertFrame(w, winRect.left, 0, winRect.right, winRect.height());
572 expected.top = 0;
573 expected.bottom = cf.bottom;
574 assertContentFrame(w, expected);
575 assertVisibleFrame(w, expected);
576
577 // Check that it's moved back without ime insets
578 w.getWindowFrames().setFrames(pf, df, of, pf, pf, dcf, sf, mEmptyRect);
579 w.computeFrameLw();
580 assertEquals(winRect, w.getFrameLw());
581 }
582
Robert Carrfbbde852016-10-18 11:02:28 -0700583 private WindowStateWithTask createWindow(Task task, int width, int height) {
Robert Carr16a4e3c2016-10-28 11:45:22 -0700584 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
585 attrs.width = width;
586 attrs.height = height;
587
Tadashi G. Takaokab6e148c2018-11-03 02:59:06 -0700588 return new WindowStateWithTask(mWm, mIWindow, mWindowToken, attrs, task);
Robert Carr16a4e3c2016-10-28 11:45:22 -0700589 }
Robert Carr16a4e3c2016-10-28 11:45:22 -0700590}