1/*
2 * Copyright (C) 2017 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.policy;
18
19import static android.view.Surface.ROTATION_270;
20import static android.view.Surface.ROTATION_90;
21import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
22import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
23import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
24import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
25import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
26import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
27import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
28import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
29import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
30import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
31import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
32import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
33import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
34
35import static org.hamcrest.Matchers.equalTo;
36import static org.hamcrest.Matchers.is;
37import static org.junit.Assert.assertEquals;
38import static org.junit.Assert.assertThat;
39
40import android.graphics.PixelFormat;
41import android.graphics.Rect;
42import android.platform.test.annotations.Presubmit;
43import android.support.test.filters.SmallTest;
44import android.support.test.runner.AndroidJUnit4;
45import android.view.DisplayCutout;
46import android.view.WindowManager;
47
48import org.junit.Before;
49import org.junit.Test;
50import org.junit.runner.RunWith;
51
52@RunWith(AndroidJUnit4.class)
53@SmallTest
54@Presubmit
55public class PhoneWindowManagerLayoutTest extends PhoneWindowManagerTestBase {
56
57    private FakeWindowState mAppWindow;
58
59    @Before
60    public void setUp() throws Exception {
61        mAppWindow = new FakeWindowState();
62        mAppWindow.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT,
63                TYPE_APPLICATION,
64                FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
65                PixelFormat.TRANSLUCENT);
66
67        addStatusBar();
68        addNavigationBar();
69    }
70
71    @Test
72    public void layoutWindowLw_appDrawsBars() throws Exception {
73        mAppWindow.attrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
74        mPolicy.addWindow(mAppWindow);
75
76        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
77        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
78
79        assertInsetByTopBottom(mAppWindow.parentFrame, 0, 0);
80        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
81        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
82        assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
83        assertInsetBy(mAppWindow.displayFrame, 0, 0, 0, 0);
84    }
85
86    @Test
87    public void layoutWindowLw_appWontDrawBars() throws Exception {
88        mAppWindow.attrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
89        mPolicy.addWindow(mAppWindow);
90
91        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
92        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
93
94        assertInsetByTopBottom(mAppWindow.parentFrame, 0, NAV_BAR_HEIGHT);
95        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
96        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
97        assertInsetByTopBottom(mAppWindow.decorFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
98        assertInsetByTopBottom(mAppWindow.displayFrame, 0, NAV_BAR_HEIGHT);
99    }
100
101    @Test
102    public void layoutWindowLw_appWontDrawBars_forceStatus() throws Exception {
103        mAppWindow.attrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
104        mAppWindow.attrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
105        mPolicy.addWindow(mAppWindow);
106
107        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
108        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
109
110        assertInsetByTopBottom(mAppWindow.parentFrame, 0, NAV_BAR_HEIGHT);
111        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
112        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
113        assertInsetByTopBottom(mAppWindow.decorFrame, 0, NAV_BAR_HEIGHT);
114        assertInsetByTopBottom(mAppWindow.displayFrame, 0, NAV_BAR_HEIGHT);
115    }
116
117    @Test
118    public void addingWindow_doesNotTamperWithSysuiFlags() {
119        mAppWindow.attrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
120        mPolicy.addWindow(mAppWindow);
121
122        assertEquals(0, mAppWindow.attrs.systemUiVisibility);
123        assertEquals(0, mAppWindow.attrs.subtreeSystemUiVisibility);
124    }
125
126    @Test
127    public void layoutWindowLw_withDisplayCutout() {
128        addDisplayCutout();
129
130        mPolicy.addWindow(mAppWindow);
131
132        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
133        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
134
135        assertInsetByTopBottom(mAppWindow.parentFrame, 0, 0);
136        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
137        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
138        assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
139        assertInsetByTopBottom(mAppWindow.displayFrame, 0, 0);
140    }
141
142    @Test
143    public void layoutWindowLw_withhDisplayCutout_never() {
144        addDisplayCutout();
145
146        mAppWindow.attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
147        mPolicy.addWindow(mAppWindow);
148
149        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
150        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
151
152        assertInsetByTopBottom(mAppWindow.parentFrame, STATUS_BAR_HEIGHT, 0);
153        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
154        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
155        assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
156        assertInsetByTopBottom(mAppWindow.displayFrame, STATUS_BAR_HEIGHT, 0);
157    }
158
159    @Test
160    public void layoutWindowLw_withDisplayCutout_layoutFullscreen() {
161        addDisplayCutout();
162
163        mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
164        mPolicy.addWindow(mAppWindow);
165
166        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
167        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
168
169        assertInsetByTopBottom(mAppWindow.parentFrame, 0, 0);
170        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
171        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
172        assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
173        assertInsetBy(mAppWindow.displayFrame, 0, 0, 0, 0);
174    }
175
176    @Test
177    public void layoutWindowLw_withDisplayCutout_fullscreen() {
178        addDisplayCutout();
179
180        mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
181        mPolicy.addWindow(mAppWindow);
182
183        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
184        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
185
186        assertInsetByTopBottom(mAppWindow.parentFrame, STATUS_BAR_HEIGHT, 0);
187        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
188        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
189        assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
190        assertInsetByTopBottom(mAppWindow.displayFrame, STATUS_BAR_HEIGHT, 0);
191    }
192
193    @Test
194    public void layoutWindowLw_withDisplayCutout_fullscreenInCutout() {
195        addDisplayCutout();
196
197        mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
198        mAppWindow.attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
199        mPolicy.addWindow(mAppWindow);
200
201        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
202        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
203
204        assertInsetByTopBottom(mAppWindow.parentFrame, 0, 0);
205        assertInsetByTopBottom(mAppWindow.stableFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
206        assertInsetByTopBottom(mAppWindow.contentFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
207        assertInsetByTopBottom(mAppWindow.decorFrame, 0, 0);
208        assertInsetByTopBottom(mAppWindow.displayFrame, 0, 0);
209    }
210
211
212    @Test
213    public void layoutWindowLw_withDisplayCutout_landscape() {
214        addDisplayCutout();
215        setRotation(ROTATION_90);
216        mPolicy.addWindow(mAppWindow);
217
218        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
219        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
220
221        assertInsetBy(mAppWindow.parentFrame, DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
222        assertInsetBy(mAppWindow.stableFrame, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
223        assertInsetBy(mAppWindow.contentFrame,
224                DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
225        assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
226        assertInsetBy(mAppWindow.displayFrame, DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
227    }
228
229    @Test
230    public void layoutWindowLw_withDisplayCutout_seascape() {
231        addDisplayCutout();
232        setRotation(ROTATION_270);
233        mPolicy.addWindow(mAppWindow);
234
235        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
236        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
237
238        assertInsetBy(mAppWindow.parentFrame, 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
239        assertInsetBy(mAppWindow.stableFrame, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
240        assertInsetBy(mAppWindow.contentFrame,
241                NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
242        assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
243        assertInsetBy(mAppWindow.displayFrame, 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
244    }
245
246    @Test
247    public void layoutWindowLw_withDisplayCutout_fullscreen_landscape() {
248        addDisplayCutout();
249        setRotation(ROTATION_90);
250
251        mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
252        mPolicy.addWindow(mAppWindow);
253
254        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
255        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
256
257        assertInsetBy(mAppWindow.parentFrame, DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
258        assertInsetBy(mAppWindow.stableFrame, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
259        assertInsetBy(mAppWindow.contentFrame,
260                DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
261        assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
262    }
263
264    @Test
265    public void layoutWindowLw_withDisplayCutout_floatingInScreen() {
266        addDisplayCutout();
267
268        mAppWindow.attrs.flags = FLAG_LAYOUT_IN_SCREEN;
269        mAppWindow.attrs.type = TYPE_APPLICATION_OVERLAY;
270        mAppWindow.attrs.width = DISPLAY_WIDTH;
271        mAppWindow.attrs.height = DISPLAY_HEIGHT;
272        mPolicy.addWindow(mAppWindow);
273
274        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
275        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
276
277        assertInsetByTopBottom(mAppWindow.parentFrame, 0, NAV_BAR_HEIGHT);
278        assertInsetByTopBottom(mAppWindow.displayFrame, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
279    }
280
281    @Test
282    public void layoutWindowLw_withDisplayCutout_fullscreenInCutout_landscape() {
283        addDisplayCutout();
284        setRotation(ROTATION_90);
285
286        mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
287        mAppWindow.attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
288        mPolicy.addWindow(mAppWindow);
289
290        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
291        mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
292
293        assertInsetBy(mAppWindow.parentFrame, 0, 0, 0, 0);
294        assertInsetBy(mAppWindow.stableFrame, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
295        assertInsetBy(mAppWindow.contentFrame,
296                DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
297        assertInsetBy(mAppWindow.decorFrame, 0, 0, 0, 0);
298    }
299
300    @Test
301    public void layoutHint_screenDecorWindow() {
302        addDisplayCutout();
303        mAppWindow.attrs.privateFlags |= PRIVATE_FLAG_IS_SCREEN_DECOR;
304
305        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
306
307        final Rect frame = new Rect();
308        final Rect content = new Rect();
309        final Rect stable = new Rect();
310        final Rect outsets = new Rect();
311        final DisplayCutout.ParcelableWrapper cutout = new DisplayCutout.ParcelableWrapper();
312        mPolicy.getLayoutHintLw(mAppWindow.attrs, null /* taskBounds */, mFrames, frame, content,
313                stable, outsets, cutout);
314
315        assertThat(frame, equalTo(mFrames.mUnrestricted));
316        assertThat(content, equalTo(new Rect()));
317        assertThat(stable, equalTo(new Rect()));
318        assertThat(outsets, equalTo(new Rect()));
319        assertThat(cutout.get(), equalTo(DisplayCutout.NO_CUTOUT));
320    }
321
322    @Test
323    public void layoutHint_appWindow() {
324        // Initialize DisplayFrames
325        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
326
327        final Rect outFrame = new Rect();
328        final Rect outContentInsets = new Rect();
329        final Rect outStableInsets = new Rect();
330        final Rect outOutsets = new Rect();
331        final DisplayCutout.ParcelableWrapper outDisplayCutout =
332                new DisplayCutout.ParcelableWrapper();
333
334        mPolicy.getLayoutHintLw(mAppWindow.attrs, null, mFrames, outFrame, outContentInsets,
335                outStableInsets, outOutsets, outDisplayCutout);
336
337        assertThat(outFrame, is(mFrames.mUnrestricted));
338        assertThat(outContentInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
339        assertThat(outStableInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
340        assertThat(outOutsets, is(new Rect()));
341        assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
342    }
343
344    @Test
345    public void layoutHint_appWindowInTask() {
346        // Initialize DisplayFrames
347        mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
348
349        final Rect taskBounds = new Rect(100, 100, 200, 200);
350
351        final Rect outFrame = new Rect();
352        final Rect outContentInsets = new Rect();
353        final Rect outStableInsets = new Rect();
354        final Rect outOutsets = new Rect();
355        final DisplayCutout.ParcelableWrapper outDisplayCutout =
356                new DisplayCutout.ParcelableWrapper();
357
358        mPolicy.getLayoutHintLw(mAppWindow.attrs, taskBounds, mFrames, outFrame, outContentInsets,
359                outStableInsets, outOutsets, outDisplayCutout);
360
361        assertThat(outFrame, is(taskBounds));
362        assertThat(outContentInsets, is(new Rect()));
363        assertThat(outStableInsets, is(new Rect()));
364        assertThat(outOutsets, is(new Rect()));
365        assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
366    }
367}