blob: df34c7c00b513b7718990c269fe51bd70e18432e [file] [log] [blame]
Jorim Jaggi28620472019-01-02 23:21:49 +01001/*
2 * Copyright (C) 2019 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 static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
21import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Tiger Huang332793b2019-10-29 23:21:27 +080022import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
23import static android.view.InsetsState.ITYPE_STATUS_BAR;
Jorim Jaggi28620472019-01-02 23:21:49 +010024import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
25import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
26import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
27import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
28import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
29import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
30import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
31
32import static org.junit.Assert.assertEquals;
33import static org.junit.Assert.assertNotNull;
34import static org.junit.Assert.assertNull;
35
36import android.platform.test.annotations.Presubmit;
Jorim Jaggi956ca412019-01-07 14:49:14 +010037import android.util.IntArray;
Jorim Jaggi28620472019-01-02 23:21:49 +010038import android.view.InsetsSourceControl;
Jorim Jaggi956ca412019-01-07 14:49:14 +010039import android.view.InsetsState;
Jorim Jaggi28620472019-01-02 23:21:49 +010040import android.view.test.InsetsModeSession;
41
42import androidx.test.filters.FlakyTest;
43import androidx.test.filters.SmallTest;
44
45import org.junit.AfterClass;
46import org.junit.BeforeClass;
47import org.junit.Test;
48import org.junit.runner.RunWith;
49
50@SmallTest
51@FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
52@Presubmit
53@RunWith(WindowTestRunner.class)
54public class InsetsPolicyTest extends WindowTestsBase {
55 private static InsetsModeSession sInsetsModeSession;
56
57 @BeforeClass
58 public static void setUpOnce() {
59 // To let the insets provider control the insets visibility, the insets mode has to be
60 // NEW_INSETS_MODE_FULL.
61 sInsetsModeSession = new InsetsModeSession(NEW_INSETS_MODE_FULL);
62 }
63
64 @AfterClass
65 public static void tearDownOnce() {
66 sInsetsModeSession.close();
67 }
68
69 @Test
70 public void testControlsForDispatch_regular() {
Tiger Huang332793b2019-10-29 23:21:27 +080071 addWindow(TYPE_STATUS_BAR, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +010072 addWindow(TYPE_NAVIGATION_BAR, "navBar");
73
74 final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
75
76 // The app can control both system bars.
77 assertNotNull(controls);
78 assertEquals(2, controls.length);
79 }
80
81 @Test
82 public void testControlsForDispatch_dockedStackVisible() {
Tiger Huang332793b2019-10-29 23:21:27 +080083 addWindow(TYPE_STATUS_BAR, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +010084 addWindow(TYPE_NAVIGATION_BAR, "navBar");
85
86 final WindowState win = createWindowOnStack(null, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
87 ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
88 final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
89
90 // The app must not control any system bars.
91 assertNull(controls);
92 }
93
94 @Test
95 public void testControlsForDispatch_freeformStackVisible() {
Tiger Huang332793b2019-10-29 23:21:27 +080096 addWindow(TYPE_STATUS_BAR, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +010097 addWindow(TYPE_NAVIGATION_BAR, "navBar");
98
99 final WindowState win = createWindowOnStack(null, WINDOWING_MODE_FREEFORM,
100 ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
101 final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
102
103 // The app must not control any bars.
104 assertNull(controls);
105 }
106
107 @Test
108 public void testControlsForDispatch_dockedDividerControllerResizing() {
Tiger Huang332793b2019-10-29 23:21:27 +0800109 addWindow(TYPE_STATUS_BAR, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100110 addWindow(TYPE_NAVIGATION_BAR, "navBar");
111 mDisplayContent.getDockedDividerController().setResizing(true);
112
113 final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
114
115 // The app must not control any system bars.
116 assertNull(controls);
117 }
118
119 @Test
120 public void testControlsForDispatch_keyguard() {
Tiger Huang332793b2019-10-29 23:21:27 +0800121 addWindow(TYPE_STATUS_BAR, "statusBar").mAttrs.privateFlags |= PRIVATE_FLAG_KEYGUARD;
Jorim Jaggi28620472019-01-02 23:21:49 +0100122 addWindow(TYPE_NAVIGATION_BAR, "navBar");
123
124 final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
125
126 // The app must not control the top bar.
127 assertNotNull(controls);
128 assertEquals(1, controls.length);
129 }
130
131 // TODO: adjust this test if we pretend to the app that it's still able to control it.
132 @Test
133 public void testControlsForDispatch_forceStatusBarVisibleTransparent() {
Tiger Huang332793b2019-10-29 23:21:27 +0800134 addWindow(TYPE_STATUS_BAR, "statusBar").mAttrs.privateFlags |=
Jorim Jaggi28620472019-01-02 23:21:49 +0100135 PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
136 addWindow(TYPE_NAVIGATION_BAR, "navBar");
137
138 final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
139
140 // The app must not control the top bar.
141 assertNotNull(controls);
142 assertEquals(1, controls.length);
143 }
144
145 @Test
146 public void testControlsForDispatch_statusBarForceShowNavigation() {
Tiger Huang332793b2019-10-29 23:21:27 +0800147 addWindow(TYPE_STATUS_BAR, "statusBar").mAttrs.privateFlags |=
Jorim Jaggi28620472019-01-02 23:21:49 +0100148 PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
149 addWindow(TYPE_NAVIGATION_BAR, "navBar");
150
151 final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
152
153 // The app must not control the navigation bar.
154 assertNotNull(controls);
155 assertEquals(1, controls.length);
156 }
157
Jorim Jaggi956ca412019-01-07 14:49:14 +0100158 @Test
159 public void testShowTransientBars_bothCanBeTransient_appGetsBothFakeControls() {
Tiger Huang332793b2019-10-29 23:21:27 +0800160 addWindow(TYPE_STATUS_BAR, "statusBar")
Jorim Jaggi956ca412019-01-07 14:49:14 +0100161 .getControllableInsetProvider().getSource().setVisible(false);
162 addWindow(TYPE_NAVIGATION_BAR, "navBar")
163 .getControllableInsetProvider().getSource().setVisible(false);
164 final WindowState app = addWindow(TYPE_APPLICATION, "app");
165
166 final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
167 policy.updateBarControlTarget(app);
168 policy.showTransient(
Tiger Huang332793b2019-10-29 23:21:27 +0800169 IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
Jorim Jaggi956ca412019-01-07 14:49:14 +0100170 final InsetsSourceControl[] controls =
171 mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
172
173 // The app must get both fake controls.
174 assertEquals(2, controls.length);
175 for (int i = controls.length - 1; i >= 0; i--) {
176 assertNull(controls[i].getLeash());
177 }
178 }
179
180 @Test
181 public void testShowTransientBars_topCanBeTransient_appGetsTopFakeControl() {
Tiger Huang0dbd5372019-10-26 00:24:22 +0800182 // Adding app window before setting source visibility is to prevent the visibility from
183 // being cleared by InsetsSourceProvider.updateVisibility.
184 final WindowState app = addWindow(TYPE_APPLICATION, "app");
185
Tiger Huang332793b2019-10-29 23:21:27 +0800186 addWindow(TYPE_STATUS_BAR, "statusBar")
Jorim Jaggi956ca412019-01-07 14:49:14 +0100187 .getControllableInsetProvider().getSource().setVisible(false);
188 addWindow(TYPE_NAVIGATION_BAR, "navBar")
189 .getControllableInsetProvider().getSource().setVisible(true);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100190
191 final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
192 policy.updateBarControlTarget(app);
193 policy.showTransient(
Tiger Huang332793b2019-10-29 23:21:27 +0800194 IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
Jorim Jaggi956ca412019-01-07 14:49:14 +0100195 final InsetsSourceControl[] controls =
196 mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
197
198 // The app must get the fake control of the top bar, and must get the real control of the
199 // navigation bar.
200 assertEquals(2, controls.length);
201 for (int i = controls.length - 1; i >= 0; i--) {
202 final InsetsSourceControl control = controls[i];
Tiger Huang332793b2019-10-29 23:21:27 +0800203 if (control.getType() == ITYPE_STATUS_BAR) {
Jorim Jaggi956ca412019-01-07 14:49:14 +0100204 assertNull(controls[i].getLeash());
205 } else {
206 assertNotNull(controls[i].getLeash());
207 }
208 }
209 }
210
211 @Test
212 public void testAbortTransientBars_bothCanBeAborted_appGetsBothRealControls() {
Tiger Huang332793b2019-10-29 23:21:27 +0800213 addWindow(TYPE_STATUS_BAR, "statusBar")
Jorim Jaggi956ca412019-01-07 14:49:14 +0100214 .getControllableInsetProvider().getSource().setVisible(false);
215 addWindow(TYPE_NAVIGATION_BAR, "navBar")
216 .getControllableInsetProvider().getSource().setVisible(false);
217 final WindowState app = addWindow(TYPE_APPLICATION, "app");
218
219 final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
220 policy.updateBarControlTarget(app);
221 policy.showTransient(
Tiger Huang332793b2019-10-29 23:21:27 +0800222 IntArray.wrap(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
Jorim Jaggi956ca412019-01-07 14:49:14 +0100223 InsetsSourceControl[] controls =
224 mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
225
226 // The app must get both fake controls.
227 assertEquals(2, controls.length);
228 for (int i = controls.length - 1; i >= 0; i--) {
229 assertNull(controls[i].getLeash());
230 }
231
232 final InsetsState state = policy.getInsetsForDispatch(app);
Tiger Huang332793b2019-10-29 23:21:27 +0800233 state.setSourceVisible(ITYPE_STATUS_BAR, true);
234 state.setSourceVisible(ITYPE_NAVIGATION_BAR, true);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100235 policy.onInsetsModified(app, state);
236
237 controls = mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
238
239 // The app must get both real controls.
240 assertEquals(2, controls.length);
241 for (int i = controls.length - 1; i >= 0; i--) {
242 assertNotNull(controls[i].getLeash());
243 }
244 }
245
Jorim Jaggi28620472019-01-02 23:21:49 +0100246 private WindowState addWindow(int type, String name) {
247 final WindowState win = createWindow(null, type, name);
248 mDisplayContent.getDisplayPolicy().addWindowLw(win, win.mAttrs);
249 return win;
250 }
251
252 private InsetsSourceControl[] addAppWindowAndGetControlsForDispatch() {
253 return addWindowAndGetControlsForDispatch(addWindow(TYPE_APPLICATION, "app"));
254 }
255
256 private InsetsSourceControl[] addWindowAndGetControlsForDispatch(WindowState win) {
257 mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
258 return mDisplayContent.getInsetsStateController().getControlsForDispatch(win);
259 }
260}