blob: 8fe411653ce201b33f24f7dd12bd8127029e26ab [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
14 * limitations under the License
15 */
16
17package com.android.server.wm;
18
19import org.junit.Before;
20import org.junit.Test;
21import org.junit.runner.RunWith;
22
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010023import android.app.ActivityManager.TaskDescription;
Robert Carr16a4e3c2016-10-28 11:45:22 -070024import android.content.Context;
25import android.graphics.Rect;
Robert Carr16a4e3c2016-10-28 11:45:22 -070026import android.platform.test.annotations.Presubmit;
27import android.support.test.InstrumentationRegistry;
28import android.support.test.filters.SmallTest;
29import android.support.test.runner.AndroidJUnit4;
Robert Carrfbbde852016-10-18 11:02:28 -070030import android.view.DisplayInfo;
Robert Carr16a4e3c2016-10-28 11:45:22 -070031import android.view.Gravity;
32import android.view.IWindow;
33import android.view.WindowManager;
34
35import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
Robert Carr16a4e3c2016-10-28 11:45:22 -070036import static android.view.WindowManager.LayoutParams.FILL_PARENT;
37import static org.junit.Assert.assertEquals;
Robert Carre4ee8f8a2016-10-31 12:40:15 -070038import static org.junit.Assert.assertTrue;
Robert Carr16a4e3c2016-10-28 11:45:22 -070039
40/**
41 * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery.
42 *
43 * Build/Install/Run: bit FrameworksServicesTests:com.android.server.wm.WindowFrameTests
44 */
45@SmallTest
46@Presubmit
47@RunWith(AndroidJUnit4.class)
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -070048public class WindowFrameTests extends WindowTestsBase {
Robert Carr16a4e3c2016-10-28 11:45:22 -070049
Robert Carr16a4e3c2016-10-28 11:45:22 -070050 private WindowToken mWindowToken;
51 private final IWindow mIWindow = new TestIWindow();
52
53 class WindowStateWithTask extends WindowState {
54 final Task mTask;
Robert Carrfbbde852016-10-18 11:02:28 -070055 boolean mDockedResizingForTest = false;
Robert Carr16a4e3c2016-10-28 11:45:22 -070056 WindowStateWithTask(WindowManager.LayoutParams attrs, Task t) {
Wale Ogunwale5cd907d2017-01-26 14:14:08 -080057 super(sWm, null, mIWindow, mWindowToken, null, 0, 0, attrs, 0, 0,
58 false /* ownerCanAddInternalSystemWindow */);
Robert Carr16a4e3c2016-10-28 11:45:22 -070059 mTask = t;
60 }
61
62 @Override
63 Task getTask() {
64 return mTask;
65 }
Robert Carrfbbde852016-10-18 11:02:28 -070066
67 @Override
68 boolean isDockedResizing() {
69 return mDockedResizingForTest;
70 }
Robert Carr16a4e3c2016-10-28 11:45:22 -070071 };
72
73 class TaskWithBounds extends Task {
74 final Rect mBounds;
Robert Carr15dd7ef2016-11-03 14:26:58 -070075 final Rect mInsetBounds = new Rect();
76 boolean mFullscreenForTest = true;
Robert Carr16a4e3c2016-10-28 11:45:22 -070077 TaskWithBounds(Rect bounds) {
Wale Ogunwale069bbd32017-02-03 07:58:14 -080078 super(0, mStubStack, 0, sWm, null, null, 0, false, false, new TaskDescription(), null);
Robert Carr16a4e3c2016-10-28 11:45:22 -070079 mBounds = bounds;
80 }
81 @Override
82 void getBounds(Rect outBounds) {
83 outBounds.set(mBounds);
84 }
85 @Override
86 void getTempInsetBounds(Rect outBounds) {
Robert Carr15dd7ef2016-11-03 14:26:58 -070087 outBounds.set(mInsetBounds);
Robert Carr16a4e3c2016-10-28 11:45:22 -070088 }
89 @Override
90 boolean isFullscreen() {
Robert Carr15dd7ef2016-11-03 14:26:58 -070091 return mFullscreenForTest;
Robert Carr16a4e3c2016-10-28 11:45:22 -070092 }
93 }
94
95 TaskStack mStubStack;
96
97 @Before
98 public void setUp() throws Exception {
Wale Ogunwale11cc5162017-04-25 20:29:13 -070099 super.setUp();
Robert Carrfbbde852016-10-18 11:02:28 -0700100
101 // Just any non zero value.
102 sWm.mSystemDecorLayer = 10000;
103
Bryce Leeaf691c02017-03-20 14:20:22 -0700104 mWindowToken = new WindowTestUtils.TestAppWindowToken(sWm.getDefaultDisplayContentLocked());
Robert Carr16a4e3c2016-10-28 11:45:22 -0700105 mStubStack = new TaskStack(sWm, 0);
106 }
107
108 public void assertRect(Rect rect, int left, int top, int right, int bottom) {
109 assertEquals(left, rect.left);
110 assertEquals(top, rect.top);
111 assertEquals(right, rect.right);
112 assertEquals(bottom, rect.bottom);
113 }
114
115 @Test
Robert Carre4ee8f8a2016-10-31 12:40:15 -0700116 public void testLayoutInFullscreenTaskInsets() throws Exception {
117 Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame
118 WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
119 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
120
121 final int bottomContentInset = 100;
122 final int topContentInset = 50;
123 final int bottomVisibleInset = 30;
124 final int topVisibleInset = 70;
125 final int leftStableInset = 20;
126 final int rightStableInset = 90;
127
128 // With no insets or system decor all the frames incoming from PhoneWindowManager
129 // are identical.
130 final Rect pf = new Rect(0, 0, 1000, 1000);
131 final Rect df = pf;
132 final Rect of = df;
133 final Rect cf = new Rect(pf);
134 // Produce some insets
135 cf.top += 50;
136 cf.bottom -= 100;
137 final Rect vf = new Rect(pf);
138 vf.top += topVisibleInset;
139 vf.bottom -= bottomVisibleInset;
140 final Rect sf = new Rect(pf);
141 sf.left += leftStableInset;
142 sf.right -= rightStableInset;
143
144 final Rect dcf = pf;
145 // When mFrame extends past cf, the content insets are
146 // the difference between mFrame and ContentFrame. Visible
147 // and stable frames work the same way.
148 w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
149 assertRect(w.mFrame,0, 0, 1000, 1000);
150 assertRect(w.mContentInsets, 0, topContentInset, 0, bottomContentInset);
151 assertRect(w.mVisibleInsets, 0, topVisibleInset, 0, bottomVisibleInset);
152 assertRect(w.mStableInsets, leftStableInset, 0, rightStableInset, 0);
153 // The frames remain as passed in shrunk to the window frame
154 assertTrue(cf.equals(w.getContentFrameLw()));
155 assertTrue(vf.equals(w.getVisibleFrameLw()));
156 assertTrue(sf.equals(w.getStableFrameLw()));
157 // On the other hand mFrame doesn't extend past cf we won't get any insets
158 w.mAttrs.x = 100;
159 w.mAttrs.y = 100;
160 w.mAttrs.width = 100; w.mAttrs.height = 100; //have to clear MATCH_PARENT
161 w.mRequestedWidth = 100;
162 w.mRequestedHeight = 100;
163 w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
164 assertRect(w.mFrame, 100, 100, 200, 200);
165 assertRect(w.mContentInsets, 0, 0, 0, 0);
166 // In this case the frames are shrunk to the window frame.
167 assertTrue(w.mFrame.equals(w.getContentFrameLw()));
168 assertTrue(w.mFrame.equals(w.getVisibleFrameLw()));
169 assertTrue(w.mFrame.equals(w.getStableFrameLw()));
170 }
171
172 @Test
Robert Carr16a4e3c2016-10-28 11:45:22 -0700173 public void testLayoutInFullscreenTaskNoInsets() throws Exception {
174 Task task = new TaskWithBounds(null); // fullscreen task doesn't use bounds for computeFrame
175 WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
176 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
177
178 // With no insets or system decor all the frames incoming from PhoneWindowManager
179 // are identical.
180 final Rect pf = new Rect(0, 0, 1000, 1000);
181
182 // Here the window has FILL_PARENT, FILL_PARENT
183 // so we expect it to fill the entire available frame.
184 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
185 assertRect(w.mFrame, 0, 0, 1000, 1000);
186
187 // It can select various widths and heights within the bounds.
188 // Strangely the window attribute width is ignored for normal windows
189 // and we use mRequestedWidth/mRequestedHeight
190 w.mAttrs.width = 300;
191 w.mAttrs.height = 300;
192 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
193 // Explicit width and height without requested width/height
194 // gets us nothing.
195 assertRect(w.mFrame, 0, 0, 0, 0);
196
197 w.mRequestedWidth = 300;
198 w.mRequestedHeight = 300;
199 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
200 // With requestedWidth/Height we can freely choose our size within the
201 // parent bounds.
202 assertRect(w.mFrame, 0, 0, 300, 300);
203
204 // With FLAG_SCALED though, requestedWidth/height is used to control
205 // the unscaled surface size, and mAttrs.width/height becomes the
206 // layout controller.
207 w.mAttrs.flags = WindowManager.LayoutParams.FLAG_SCALED;
208 w.mRequestedHeight = -1;
209 w.mRequestedWidth = -1;
210 w.mAttrs.width = 100;
211 w.mAttrs.height = 100;
212 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
213 assertRect(w.mFrame, 0, 0, 100, 100);
214 w.mAttrs.flags = 0;
215
216 // But sizes too large will be clipped to the containing frame
217 w.mRequestedWidth = 1200;
218 w.mRequestedHeight = 1200;
219 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
220 assertRect(w.mFrame, 0, 0, 1000, 1000);
221
222 // Before they are clipped though windows will be shifted
223 w.mAttrs.x = 300;
224 w.mAttrs.y = 300;
225 w.mRequestedWidth = 1000;
226 w.mRequestedHeight = 1000;
227 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
228 assertRect(w.mFrame, 0, 0, 1000, 1000);
229
230 // If there is room to move around in the parent frame the window will be shifted according
231 // to gravity.
232 w.mAttrs.x = 0;
233 w.mAttrs.y = 0;
234 w.mRequestedWidth = 300;
235 w.mRequestedHeight = 300;
236 w.mAttrs.gravity = Gravity.RIGHT | Gravity.TOP;
237 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
238 assertRect(w.mFrame, 700, 0, 1000, 300);
239 w.mAttrs.gravity = Gravity.RIGHT | Gravity.BOTTOM;
240 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
241 assertRect(w.mFrame, 700, 700, 1000, 1000);
242 // Window specified x and y are interpreted as offsets in the opposite
243 // direction of gravity
244 w.mAttrs.x = 100;
245 w.mAttrs.y = 100;
246 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
247 assertRect(w.mFrame, 600, 600, 900, 900);
248 }
249
Robert Carr15dd7ef2016-11-03 14:26:58 -0700250 @Test
251 public void testLayoutNonfullscreenTask() {
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700252 final DisplayInfo displayInfo = sWm.getDefaultDisplayContentLocked().getDisplayInfo();
253 final int logicalWidth = displayInfo.logicalWidth;
254 final int logicalHeight = displayInfo.logicalHeight;
255
256 final int taskLeft = logicalWidth / 4;
257 final int taskTop = logicalHeight / 4;
258 final int taskRight = logicalWidth / 4 * 3;
259 final int taskBottom = logicalHeight / 4 * 3;
260 final Rect taskBounds = new Rect(taskLeft, taskTop, taskRight, taskBottom);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700261 TaskWithBounds task = new TaskWithBounds(taskBounds);
262 task.mFullscreenForTest = false;
263 WindowState w = createWindow(task, FILL_PARENT, FILL_PARENT);
264 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
265
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700266 final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700267 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, null);
268 // For non fullscreen tasks the containing frame is based off the
269 // task bounds not the parent frame.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700270 assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
271 assertRect(w.getContentFrameLw(), taskLeft, taskTop, taskRight, taskBottom);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700272 assertRect(w.mContentInsets, 0, 0, 0, 0);
273
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700274 pf.set(0, 0, logicalWidth, logicalHeight);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700275 // We still produce insets against the containing frame the same way.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700276 final int cfRight = logicalWidth / 2;
277 final int cfBottom = logicalHeight / 2;
278 final Rect cf = new Rect(0, 0, cfRight, cfBottom);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700279 w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null);
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700280 assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
281 int contentInsetRight = taskRight - cfRight;
282 int contentInsetBottom = taskBottom - cfBottom;
283 assertRect(w.mContentInsets, 0, 0, contentInsetRight, contentInsetBottom);
284 assertRect(w.getContentFrameLw(), taskLeft, taskTop, taskRight - contentInsetRight,
285 taskBottom - contentInsetBottom);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700286
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700287 pf.set(0, 0, logicalWidth, logicalHeight);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700288 // However if we set temp inset bounds, the insets will be computed
289 // as if our window was laid out there, but it will be laid out according to
290 // the task bounds.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700291 final int insetLeft = logicalWidth / 5;
292 final int insetTop = logicalHeight / 5;
293 final int insetRight = insetLeft + (taskRight - taskLeft);
294 final int insetBottom = insetTop + (taskBottom - taskTop);
295 task.mInsetBounds.set(insetLeft, insetTop, insetRight, insetBottom);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700296 w.computeFrameLw(pf, pf, pf, cf, cf, pf, cf, null);
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700297 assertRect(w.mFrame, taskLeft, taskTop, taskRight, taskBottom);
298 contentInsetRight = insetRight - cfRight;
299 contentInsetBottom = insetBottom - cfBottom;
300 assertRect(w.mContentInsets, 0, 0, contentInsetRight, contentInsetBottom);
301 assertRect(w.getContentFrameLw(), taskLeft, taskTop, taskRight - contentInsetRight,
302 taskBottom - contentInsetBottom);
Robert Carr15dd7ef2016-11-03 14:26:58 -0700303 }
304
Robert Carrfbbde852016-10-18 11:02:28 -0700305 @Test
306 public void testCalculatePolicyCrop() {
307 final WindowStateWithTask w = createWindow(
308 new TaskWithBounds(null), FILL_PARENT, FILL_PARENT);
309 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
310
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700311 final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
312 final int logicalWidth = displayInfo.logicalWidth;
313 final int logicalHeight = displayInfo.logicalHeight;
314 final Rect pf = new Rect(0, 0, logicalWidth, logicalHeight);
Robert Carrfbbde852016-10-18 11:02:28 -0700315 final Rect df = pf;
316 final Rect of = df;
317 final Rect cf = new Rect(pf);
318 // Produce some insets
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700319 cf.top += displayInfo.logicalWidth / 10;
320 cf.bottom -= displayInfo.logicalWidth / 5;
Robert Carrfbbde852016-10-18 11:02:28 -0700321 final Rect vf = cf;
322 final Rect sf = vf;
323 // We use a decor content frame with insets to produce cropping.
324 Rect dcf = cf;
325
326 final Rect policyCrop = new Rect();
327
328 w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
329 w.calculatePolicyCrop(policyCrop);
330 // If we were above system decor we wouldnt' get any cropping though
331 w.mLayer = sWm.mSystemDecorLayer + 1;
332 w.calculatePolicyCrop(policyCrop);
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700333 assertRect(policyCrop, 0, 0, logicalWidth, logicalHeight);
Robert Carrfbbde852016-10-18 11:02:28 -0700334 w.mLayer = 1;
335 dcf.setEmpty();
336 // Likewise with no decor frame we would get no crop
337 w.computeFrameLw(pf, df, of, cf, vf, dcf, sf, null);
338 w.calculatePolicyCrop(policyCrop);
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700339 assertRect(policyCrop, 0, 0, logicalWidth, logicalHeight);
Robert Carrfbbde852016-10-18 11:02:28 -0700340
341 // Now we set up a window which doesn't fill the entire decor frame.
342 // Normally it would be cropped to it's frame but in the case of docked resizing
343 // we need to account for the fact the windows surface will be made
344 // fullscreen and thus also make the crop fullscreen.
345 w.mAttrs.gravity = Gravity.LEFT | Gravity.TOP;
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700346 w.mAttrs.width = logicalWidth / 2;
347 w.mAttrs.height = logicalHeight / 2;
348 w.mRequestedWidth = logicalWidth / 2;
349 w.mRequestedHeight = logicalHeight / 2;
Robert Carrfbbde852016-10-18 11:02:28 -0700350 w.computeFrameLw(pf, pf, pf, pf, pf, pf, pf, pf);
351
352 w.calculatePolicyCrop(policyCrop);
353 // Normally the crop is shrunk from the decor frame
354 // to the computed window frame.
Andrii Kuliana95bfff2017-03-30 19:00:41 -0700355 assertRect(policyCrop, 0, 0, logicalWidth / 2, logicalHeight / 2);
Robert Carrfbbde852016-10-18 11:02:28 -0700356
357 w.mDockedResizingForTest = true;
358 w.calculatePolicyCrop(policyCrop);
Robert Carr186d9de2017-02-09 12:41:03 -0800359 // But if we are docked resizing it won't be, however we will still be
360 // shrunk to the decor frame and the display.
Robert Carr186d9de2017-02-09 12:41:03 -0800361 assertRect(policyCrop, 0, 0,
362 Math.min(pf.width(), displayInfo.logicalWidth),
363 Math.min(pf.height(), displayInfo.logicalHeight));
Robert Carrfbbde852016-10-18 11:02:28 -0700364 }
365
366 private WindowStateWithTask createWindow(Task task, int width, int height) {
Robert Carr16a4e3c2016-10-28 11:45:22 -0700367 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
368 attrs.width = width;
369 attrs.height = height;
370
371 return new WindowStateWithTask(attrs, task);
372 }
373}