blob: 55947ae9626f3bd188ecb389e36a3395a87f9633 [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;
Jorim Jaggi956ca412019-01-07 14:49:14 +010022import static android.view.InsetsState.TYPE_TOP_BAR;
Jorim Jaggi28620472019-01-02 23:21:49 +010023import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
24import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
25import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
26import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
27import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
28import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
29import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
30
31import static org.junit.Assert.assertEquals;
32import static org.junit.Assert.assertNotNull;
33import static org.junit.Assert.assertNull;
34
35import android.platform.test.annotations.Presubmit;
Jorim Jaggi956ca412019-01-07 14:49:14 +010036import android.util.IntArray;
Jorim Jaggi28620472019-01-02 23:21:49 +010037import android.view.InsetsSourceControl;
Jorim Jaggi956ca412019-01-07 14:49:14 +010038import android.view.InsetsState;
Jorim Jaggi28620472019-01-02 23:21:49 +010039import android.view.test.InsetsModeSession;
40
41import androidx.test.filters.FlakyTest;
42import androidx.test.filters.SmallTest;
43
44import org.junit.AfterClass;
45import org.junit.BeforeClass;
46import org.junit.Test;
47import org.junit.runner.RunWith;
48
49@SmallTest
50@FlakyTest(detail = "Promote to pre-submit once confirmed stable.")
51@Presubmit
52@RunWith(WindowTestRunner.class)
53public class InsetsPolicyTest extends WindowTestsBase {
54 private static InsetsModeSession sInsetsModeSession;
55
56 @BeforeClass
57 public static void setUpOnce() {
58 // To let the insets provider control the insets visibility, the insets mode has to be
59 // NEW_INSETS_MODE_FULL.
60 sInsetsModeSession = new InsetsModeSession(NEW_INSETS_MODE_FULL);
61 }
62
63 @AfterClass
64 public static void tearDownOnce() {
65 sInsetsModeSession.close();
66 }
67
68 @Test
69 public void testControlsForDispatch_regular() {
70 addWindow(TYPE_STATUS_BAR, "topBar");
71 addWindow(TYPE_NAVIGATION_BAR, "navBar");
72
73 final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
74
75 // The app can control both system bars.
76 assertNotNull(controls);
77 assertEquals(2, controls.length);
78 }
79
80 @Test
81 public void testControlsForDispatch_dockedStackVisible() {
82 addWindow(TYPE_STATUS_BAR, "topBar");
83 addWindow(TYPE_NAVIGATION_BAR, "navBar");
84
85 final WindowState win = createWindowOnStack(null, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
86 ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
87 final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
88
89 // The app must not control any system bars.
90 assertNull(controls);
91 }
92
93 @Test
94 public void testControlsForDispatch_freeformStackVisible() {
95 addWindow(TYPE_STATUS_BAR, "topBar");
96 addWindow(TYPE_NAVIGATION_BAR, "navBar");
97
98 final WindowState win = createWindowOnStack(null, WINDOWING_MODE_FREEFORM,
99 ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app");
100 final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win);
101
102 // The app must not control any bars.
103 assertNull(controls);
104 }
105
106 @Test
107 public void testControlsForDispatch_dockedDividerControllerResizing() {
108 addWindow(TYPE_STATUS_BAR, "topBar");
109 addWindow(TYPE_NAVIGATION_BAR, "navBar");
110 mDisplayContent.getDockedDividerController().setResizing(true);
111
112 final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
113
114 // The app must not control any system bars.
115 assertNull(controls);
116 }
117
118 @Test
119 public void testControlsForDispatch_keyguard() {
120 addWindow(TYPE_STATUS_BAR, "topBar").mAttrs.privateFlags |= PRIVATE_FLAG_KEYGUARD;
121 addWindow(TYPE_NAVIGATION_BAR, "navBar");
122
123 final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
124
125 // The app must not control the top bar.
126 assertNotNull(controls);
127 assertEquals(1, controls.length);
128 }
129
130 // TODO: adjust this test if we pretend to the app that it's still able to control it.
131 @Test
132 public void testControlsForDispatch_forceStatusBarVisibleTransparent() {
133 addWindow(TYPE_STATUS_BAR, "topBar").mAttrs.privateFlags |=
134 PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
135 addWindow(TYPE_NAVIGATION_BAR, "navBar");
136
137 final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
138
139 // The app must not control the top bar.
140 assertNotNull(controls);
141 assertEquals(1, controls.length);
142 }
143
144 @Test
145 public void testControlsForDispatch_statusBarForceShowNavigation() {
146 addWindow(TYPE_STATUS_BAR, "topBar").mAttrs.privateFlags |=
147 PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
148 addWindow(TYPE_NAVIGATION_BAR, "navBar");
149
150 final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch();
151
152 // The app must not control the navigation bar.
153 assertNotNull(controls);
154 assertEquals(1, controls.length);
155 }
156
Jorim Jaggi956ca412019-01-07 14:49:14 +0100157 @Test
158 public void testShowTransientBars_bothCanBeTransient_appGetsBothFakeControls() {
159 addWindow(TYPE_STATUS_BAR, "topBar")
160 .getControllableInsetProvider().getSource().setVisible(false);
161 addWindow(TYPE_NAVIGATION_BAR, "navBar")
162 .getControllableInsetProvider().getSource().setVisible(false);
163 final WindowState app = addWindow(TYPE_APPLICATION, "app");
164
165 final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
166 policy.updateBarControlTarget(app);
167 policy.showTransient(
168 IntArray.wrap(new int[]{TYPE_TOP_BAR, InsetsState.TYPE_NAVIGATION_BAR}));
169 final InsetsSourceControl[] controls =
170 mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
171
172 // The app must get both fake controls.
173 assertEquals(2, controls.length);
174 for (int i = controls.length - 1; i >= 0; i--) {
175 assertNull(controls[i].getLeash());
176 }
177 }
178
179 @Test
180 public void testShowTransientBars_topCanBeTransient_appGetsTopFakeControl() {
Tiger Huang0dbd5372019-10-26 00:24:22 +0800181 // Adding app window before setting source visibility is to prevent the visibility from
182 // being cleared by InsetsSourceProvider.updateVisibility.
183 final WindowState app = addWindow(TYPE_APPLICATION, "app");
184
Jorim Jaggi956ca412019-01-07 14:49:14 +0100185 addWindow(TYPE_STATUS_BAR, "topBar")
186 .getControllableInsetProvider().getSource().setVisible(false);
187 addWindow(TYPE_NAVIGATION_BAR, "navBar")
188 .getControllableInsetProvider().getSource().setVisible(true);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100189
190 final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
191 policy.updateBarControlTarget(app);
192 policy.showTransient(
193 IntArray.wrap(new int[]{TYPE_TOP_BAR, InsetsState.TYPE_NAVIGATION_BAR}));
194 final InsetsSourceControl[] controls =
195 mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
196
197 // The app must get the fake control of the top bar, and must get the real control of the
198 // navigation bar.
199 assertEquals(2, controls.length);
200 for (int i = controls.length - 1; i >= 0; i--) {
201 final InsetsSourceControl control = controls[i];
202 if (control.getType() == TYPE_TOP_BAR) {
203 assertNull(controls[i].getLeash());
204 } else {
205 assertNotNull(controls[i].getLeash());
206 }
207 }
208 }
209
210 @Test
211 public void testAbortTransientBars_bothCanBeAborted_appGetsBothRealControls() {
212 addWindow(TYPE_STATUS_BAR, "topBar")
213 .getControllableInsetProvider().getSource().setVisible(false);
214 addWindow(TYPE_NAVIGATION_BAR, "navBar")
215 .getControllableInsetProvider().getSource().setVisible(false);
216 final WindowState app = addWindow(TYPE_APPLICATION, "app");
217
218 final InsetsPolicy policy = mDisplayContent.getInsetsPolicy();
219 policy.updateBarControlTarget(app);
220 policy.showTransient(
221 IntArray.wrap(new int[]{TYPE_TOP_BAR, InsetsState.TYPE_NAVIGATION_BAR}));
222 InsetsSourceControl[] controls =
223 mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
224
225 // The app must get both fake controls.
226 assertEquals(2, controls.length);
227 for (int i = controls.length - 1; i >= 0; i--) {
228 assertNull(controls[i].getLeash());
229 }
230
231 final InsetsState state = policy.getInsetsForDispatch(app);
232 state.setSourceVisible(TYPE_TOP_BAR, true);
233 state.setSourceVisible(InsetsState.TYPE_NAVIGATION_BAR, true);
234 policy.onInsetsModified(app, state);
235
236 controls = mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
237
238 // The app must get both real controls.
239 assertEquals(2, controls.length);
240 for (int i = controls.length - 1; i >= 0; i--) {
241 assertNotNull(controls[i].getLeash());
242 }
243 }
244
Jorim Jaggi28620472019-01-02 23:21:49 +0100245 private WindowState addWindow(int type, String name) {
246 final WindowState win = createWindow(null, type, name);
247 mDisplayContent.getDisplayPolicy().addWindowLw(win, win.mAttrs);
248 return win;
249 }
250
251 private InsetsSourceControl[] addAppWindowAndGetControlsForDispatch() {
252 return addWindowAndGetControlsForDispatch(addWindow(TYPE_APPLICATION, "app"));
253 }
254
255 private InsetsSourceControl[] addWindowAndGetControlsForDispatch(WindowState win) {
256 mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
257 return mDisplayContent.getInsetsStateController().getControlsForDispatch(win);
258 }
259}