1 /*
2  * Copyright (C) 2018 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 
17 package com.android.server.wm;
18 
19 import static android.view.Gravity.BOTTOM;
20 import static android.view.Gravity.LEFT;
21 import static android.view.Gravity.RIGHT;
22 import static android.view.Gravity.TOP;
23 import static android.view.Surface.ROTATION_0;
24 import static android.view.Surface.ROTATION_270;
25 import static android.view.Surface.ROTATION_90;
26 import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
27 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
28 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
29 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
30 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
31 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
32 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
33 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
34 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
35 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
36 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
37 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
38 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
39 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
40 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
41 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
42 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
43 
44 import static org.hamcrest.Matchers.is;
45 import static org.junit.Assert.assertEquals;
46 import static org.junit.Assert.assertThat;
47 import static org.mockito.Mockito.doNothing;
48 import static org.mockito.Mockito.spy;
49 
50 import android.graphics.Insets;
51 import android.graphics.PixelFormat;
52 import android.graphics.Rect;
53 import android.platform.test.annotations.Presubmit;
54 import android.util.Pair;
55 import android.view.DisplayCutout;
56 import android.view.DisplayInfo;
57 import android.view.WindowManager;
58 
59 import androidx.test.filters.SmallTest;
60 
61 import com.android.server.policy.WindowManagerPolicy;
62 import com.android.server.wm.utils.WmDisplayCutout;
63 
64 import org.junit.Before;
65 import org.junit.Test;
66 
67 @SmallTest
68 @Presubmit
69 public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
70 
71     private DisplayFrames mFrames;
72     private WindowState mWindow;
73     private int mRotation = ROTATION_0;
74     private boolean mHasDisplayCutout;
75     private static final int DECOR_WINDOW_INSET = 50;
76 
77     @Before
setUp()78     public void setUp() throws Exception {
79         updateDisplayFrames();
80 
81         mWindow = spy(createWindow(null, TYPE_APPLICATION, "window"));
82         // We only test window frames set by DisplayPolicy, so here prevents computeFrameLw from
83         // changing those frames.
84         doNothing().when(mWindow).computeFrameLw();
85 
86         final WindowManager.LayoutParams attrs = mWindow.mAttrs;
87         attrs.width = MATCH_PARENT;
88         attrs.height = MATCH_PARENT;
89         attrs.flags =
90                 FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
91         attrs.format = PixelFormat.TRANSLUCENT;
92     }
93 
setRotation(int rotation)94     public void setRotation(int rotation) {
95         mRotation = rotation;
96         updateDisplayFrames();
97     }
98 
addDisplayCutout()99     public void addDisplayCutout() {
100         mHasDisplayCutout = true;
101         updateDisplayFrames();
102     }
103 
updateDisplayFrames()104     private void updateDisplayFrames() {
105         final Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation,
106                 mHasDisplayCutout);
107         mFrames = new DisplayFrames(mDisplayContent.getDisplayId(), info.first, info.second);
108     }
109 
110     @Test
addingWindow_doesNotTamperWithSysuiFlags()111     public void addingWindow_doesNotTamperWithSysuiFlags() {
112         mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
113         addWindow(mWindow);
114 
115         assertEquals(0, mWindow.mAttrs.systemUiVisibility);
116         assertEquals(0, mWindow.mAttrs.subtreeSystemUiVisibility);
117     }
118 
119     @Test
layoutWindowLw_appDrawsBars()120     public void layoutWindowLw_appDrawsBars() {
121         synchronized (mWm.mGlobalLock) {
122             mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
123             addWindow(mWindow);
124 
125             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
126             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
127 
128             assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
129             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
130             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
131             assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
132             assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
133         }
134     }
135 
136     @Test
layoutWindowLw_appWontDrawBars()137     public void layoutWindowLw_appWontDrawBars() {
138         synchronized (mWm.mGlobalLock) {
139             mWindow.mAttrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
140             addWindow(mWindow);
141 
142             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
143             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
144 
145             assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
146             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
147             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
148             assertInsetByTopBottom(mWindow.getDecorFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
149             assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
150         }
151     }
152 
153     @Test
layoutWindowLw_appWontDrawBars_forceStatusAndNav()154     public void layoutWindowLw_appWontDrawBars_forceStatusAndNav() throws Exception {
155         synchronized (mWm.mGlobalLock) {
156             mWindow.mAttrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
157             mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
158             addWindow(mWindow);
159 
160             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
161             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
162 
163             assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
164             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
165             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
166             assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
167             assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
168         }
169     }
170 
171     @Test
layoutWindowLw_keyguardDialog_hideNav()172     public void layoutWindowLw_keyguardDialog_hideNav() {
173         synchronized (mWm.mGlobalLock) {
174             mWindow.mAttrs.type = TYPE_KEYGUARD_DIALOG;
175             mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
176             mWindow.mAttrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
177             addWindow(mWindow);
178 
179             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* uiMode */);
180             mDisplayPolicy.layoutWindowLw(mWindow, null /* attached */, mFrames);
181 
182             assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
183             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
184             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
185             assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
186             assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
187         }
188     }
189 
190     @Test
layoutWindowLw_withDisplayCutout()191     public void layoutWindowLw_withDisplayCutout() {
192         synchronized (mWm.mGlobalLock) {
193             addDisplayCutout();
194 
195             addWindow(mWindow);
196 
197             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
198             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
199 
200             assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
201             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
202             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
203             assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
204             assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
205         }
206     }
207 
208     @Test
layoutWindowLw_withDisplayCutout_never()209     public void layoutWindowLw_withDisplayCutout_never() {
210         synchronized (mWm.mGlobalLock) {
211             addDisplayCutout();
212 
213             mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
214             addWindow(mWindow);
215 
216             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
217             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
218 
219             assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
220             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
221             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
222             assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
223             assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
224         }
225     }
226 
227     @Test
layoutWindowLw_withDisplayCutout_layoutFullscreen()228     public void layoutWindowLw_withDisplayCutout_layoutFullscreen() {
229         synchronized (mWm.mGlobalLock) {
230             addDisplayCutout();
231 
232             mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
233             addWindow(mWindow);
234 
235             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
236             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
237 
238             assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
239             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
240             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
241             assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
242             assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
243         }
244     }
245 
246     @Test
layoutWindowLw_withDisplayCutout_fullscreen()247     public void layoutWindowLw_withDisplayCutout_fullscreen() {
248         synchronized (mWm.mGlobalLock) {
249             addDisplayCutout();
250 
251             mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
252             addWindow(mWindow);
253 
254             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
255             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
256 
257             assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
258             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
259             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
260             assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
261             assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
262         }
263     }
264 
265     @Test
layoutWindowLw_withDisplayCutout_fullscreenInCutout()266     public void layoutWindowLw_withDisplayCutout_fullscreenInCutout() {
267         synchronized (mWm.mGlobalLock) {
268             addDisplayCutout();
269 
270             mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
271             mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
272             addWindow(mWindow);
273 
274             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
275             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
276 
277             assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
278             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
279             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
280             assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
281             assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
282         }
283     }
284 
285 
286     @Test
layoutWindowLw_withDisplayCutout_landscape()287     public void layoutWindowLw_withDisplayCutout_landscape() {
288         synchronized (mWm.mGlobalLock) {
289             addDisplayCutout();
290             setRotation(ROTATION_90);
291             addWindow(mWindow);
292 
293             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
294             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
295 
296             assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
297             assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
298             assertInsetBy(mWindow.getContentFrameLw(),
299                     DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
300             assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
301             assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
302         }
303     }
304 
305     @Test
layoutWindowLw_withDisplayCutout_seascape()306     public void layoutWindowLw_withDisplayCutout_seascape() {
307         synchronized (mWm.mGlobalLock) {
308             addDisplayCutout();
309             setRotation(ROTATION_270);
310             addWindow(mWindow);
311 
312             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
313             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
314 
315             assertInsetBy(mWindow.getParentFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
316             assertInsetBy(mWindow.getStableFrameLw(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
317             assertInsetBy(mWindow.getContentFrameLw(),
318                     NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
319             assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
320             assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
321         }
322     }
323 
324     @Test
layoutWindowLw_withDisplayCutout_fullscreen_landscape()325     public void layoutWindowLw_withDisplayCutout_fullscreen_landscape() {
326         synchronized (mWm.mGlobalLock) {
327             addDisplayCutout();
328             setRotation(ROTATION_90);
329 
330             mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
331             addWindow(mWindow);
332 
333             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
334             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
335 
336             assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
337             assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
338             assertInsetBy(mWindow.getContentFrameLw(),
339                     DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
340             assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
341         }
342     }
343 
344     @Test
layoutWindowLw_withDisplayCutout_floatingInScreen()345     public void layoutWindowLw_withDisplayCutout_floatingInScreen() {
346         synchronized (mWm.mGlobalLock) {
347             addDisplayCutout();
348 
349             mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN;
350             mWindow.mAttrs.type = TYPE_APPLICATION_OVERLAY;
351             mWindow.mAttrs.width = DISPLAY_WIDTH;
352             mWindow.mAttrs.height = DISPLAY_HEIGHT;
353             addWindow(mWindow);
354 
355             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
356             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
357 
358             assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
359             assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
360         }
361     }
362 
363     @Test
layoutWindowLw_withDisplayCutout_fullscreenInCutout_landscape()364     public void layoutWindowLw_withDisplayCutout_fullscreenInCutout_landscape() {
365         synchronized (mWm.mGlobalLock) {
366             addDisplayCutout();
367             setRotation(ROTATION_90);
368 
369             mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
370             mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
371             addWindow(mWindow);
372 
373             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
374             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
375 
376             assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
377             assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
378             assertInsetBy(mWindow.getContentFrameLw(),
379                     DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
380             assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
381         }
382     }
383 
384     @Test
layoutWindowLw_withForwardInset_SoftInputAdjustResize()385     public void layoutWindowLw_withForwardInset_SoftInputAdjustResize() {
386         synchronized (mWm.mGlobalLock) {
387             mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
388             addWindow(mWindow);
389 
390             final int forwardedInsetBottom = 50;
391             mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
392             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
393             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
394 
395             assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
396             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
397             assertInsetByTopBottom(mWindow.getContentFrameLw(),
398                     STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
399             assertInsetByTopBottom(mWindow.getVisibleFrameLw(),
400                     STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
401             assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
402             assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
403         }
404     }
405 
406     @Test
layoutWindowLw_withForwardInset_SoftInputAdjustNothing()407     public void layoutWindowLw_withForwardInset_SoftInputAdjustNothing() {
408         synchronized (mWm.mGlobalLock) {
409             mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
410             addWindow(mWindow);
411 
412             final int forwardedInsetBottom = 50;
413             mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
414             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
415             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
416 
417             assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
418             assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
419             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
420             assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
421             assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
422             assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
423         }
424     }
425 
426     @Test
layoutHint_appWindow()427     public void layoutHint_appWindow() {
428         synchronized (mWm.mGlobalLock) {
429             // Initialize DisplayFrames
430             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
431 
432             final Rect outFrame = new Rect();
433             final Rect outContentInsets = new Rect();
434             final Rect outStableInsets = new Rect();
435             final Rect outOutsets = new Rect();
436             final DisplayCutout.ParcelableWrapper outDisplayCutout =
437                     new DisplayCutout.ParcelableWrapper();
438 
439             mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, null, mFrames,
440                     false /* floatingStack */, outFrame, outContentInsets, outStableInsets,
441                     outOutsets, outDisplayCutout);
442 
443             assertThat(outFrame, is(mFrames.mUnrestricted));
444             assertThat(outContentInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
445             assertThat(outStableInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
446             assertThat(outOutsets, is(new Rect()));
447             assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
448         }
449     }
450 
451     @Test
layoutHint_appWindowInTask()452     public void layoutHint_appWindowInTask() {
453         synchronized (mWm.mGlobalLock) {
454             // Initialize DisplayFrames
455             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
456 
457             final Rect taskBounds = new Rect(100, 100, 200, 200);
458 
459             final Rect outFrame = new Rect();
460             final Rect outContentInsets = new Rect();
461             final Rect outStableInsets = new Rect();
462             final Rect outOutsets = new Rect();
463             final DisplayCutout.ParcelableWrapper outDisplayCutout =
464                     new DisplayCutout.ParcelableWrapper();
465 
466             mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
467                     false /* floatingStack */, outFrame, outContentInsets, outStableInsets,
468                     outOutsets, outDisplayCutout);
469 
470             assertThat(outFrame, is(taskBounds));
471             assertThat(outContentInsets, is(new Rect()));
472             assertThat(outStableInsets, is(new Rect()));
473             assertThat(outOutsets, is(new Rect()));
474             assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
475         }
476     }
477 
478     @Test
layoutHint_appWindowInTask_outsideContentFrame()479     public void layoutHint_appWindowInTask_outsideContentFrame() {
480         synchronized (mWm.mGlobalLock) {
481             // Initialize DisplayFrames
482             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
483 
484             // Task is in the nav bar area (usually does not happen, but this is similar enough to
485             // the possible overlap with the IME)
486             final Rect taskBounds = new Rect(100, mFrames.mContent.bottom + 1,
487                     200, mFrames.mContent.bottom + 10);
488 
489             final Rect outFrame = new Rect();
490             final Rect outContentInsets = new Rect();
491             final Rect outStableInsets = new Rect();
492             final Rect outOutsets = new Rect();
493             final DisplayCutout.ParcelableWrapper outDisplayCutout =
494                     new DisplayCutout.ParcelableWrapper();
495 
496             mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
497                     true /* floatingStack */, outFrame, outContentInsets, outStableInsets,
498                     outOutsets, outDisplayCutout);
499 
500             assertThat(outFrame, is(taskBounds));
501             assertThat(outContentInsets, is(new Rect()));
502             assertThat(outStableInsets, is(new Rect()));
503             assertThat(outOutsets, is(new Rect()));
504             assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
505         }
506     }
507 
508     @Test
forceShowSystemBars_clearsSystemUIFlags()509     public void forceShowSystemBars_clearsSystemUIFlags() {
510         synchronized (mWm.mGlobalLock) {
511             mDisplayPolicy.mLastSystemUiFlags |= SYSTEM_UI_FLAG_FULLSCREEN;
512             mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
513             mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
514             mWindow.mSystemUiVisibility = SYSTEM_UI_FLAG_FULLSCREEN;
515             mDisplayPolicy.setForceShowSystemBars(true);
516             addWindow(mWindow);
517 
518             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
519             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
520             // triggers updateSystemUiVisibilityLw which will reset the flags as needed
521             int finishPostLayoutPolicyLw = mDisplayPolicy.focusChangedLw(mWindow, mWindow);
522 
523             assertEquals(WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT, finishPostLayoutPolicyLw);
524             assertEquals(0, mDisplayPolicy.mLastSystemUiFlags);
525             assertEquals(0, mWindow.mAttrs.systemUiVisibility);
526             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
527         }
528     }
529 
530     @Test
testScreenDecorWindows()531     public void testScreenDecorWindows() {
532         synchronized (mWm.mGlobalLock) {
533             final WindowState decorWindow = createWindow(null, TYPE_APPLICATION_OVERLAY,
534                     "decorWindow");
535             decorWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
536             decorWindow.mAttrs.privateFlags |= PRIVATE_FLAG_IS_SCREEN_DECOR;
537             addWindow(decorWindow);
538             addWindow(mWindow);
539 
540             // Decor on top
541             updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, TOP);
542             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
543             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
544             assertInsetByTopBottom(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT);
545 
546             // Decor on bottom
547             updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, BOTTOM);
548             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
549             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
550             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT,
551                     DECOR_WINDOW_INSET);
552 
553             // Decor on the left
554             updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, LEFT);
555             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
556             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
557             assertInsetBy(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0,
558                     NAV_BAR_HEIGHT);
559 
560             // Decor on the right
561             updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, RIGHT);
562             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
563             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
564             assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET,
565                     NAV_BAR_HEIGHT);
566 
567             // Decor not allowed as inset
568             updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, DECOR_WINDOW_INSET, TOP);
569             mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
570             mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
571             assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
572         }
573     }
574 
updateDecorWindow(WindowState decorWindow, int width, int height, int gravity)575     private void updateDecorWindow(WindowState decorWindow, int width, int height, int gravity) {
576         decorWindow.mAttrs.width = width;
577         decorWindow.mAttrs.height = height;
578         decorWindow.mAttrs.gravity = gravity;
579         decorWindow.setRequestedSize(width, height);
580     }
581 
582     /**
583      * Asserts that {@code actual} is inset by the given amounts from the full display rect.
584      *
585      * Convenience wrapper for when only the top and bottom inset are non-zero.
586      */
assertInsetByTopBottom(Rect actual, int expectedInsetTop, int expectedInsetBottom)587     private void assertInsetByTopBottom(Rect actual, int expectedInsetTop,
588             int expectedInsetBottom) {
589         assertInsetBy(actual, 0, expectedInsetTop, 0, expectedInsetBottom);
590     }
591 
592     /** Asserts that {@code actual} is inset by the given amounts from the full display rect. */
assertInsetBy(Rect actual, int expectedInsetLeft, int expectedInsetTop, int expectedInsetRight, int expectedInsetBottom)593     private void assertInsetBy(Rect actual, int expectedInsetLeft, int expectedInsetTop,
594             int expectedInsetRight, int expectedInsetBottom) {
595         assertEquals(new Rect(expectedInsetLeft, expectedInsetTop,
596                 mFrames.mDisplayWidth - expectedInsetRight,
597                 mFrames.mDisplayHeight - expectedInsetBottom), actual);
598     }
599 }
600