blob: 61b74b0c1d0fe0f7b4e374bfd9e77db5fa3bcf78 [file] [log] [blame]
Jorim Jaggif96c90a2018-09-26 16:55:15 +02001/*
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
17package com.android.server.wm;
18
Tiger Huang0f5347e2020-03-06 17:09:41 +080019import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
Winson Chung8a168902020-03-12 22:39:22 -070020import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
Tiger Huang0f5347e2020-03-06 17:09:41 +080021import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Tiger Huang57e2e1c2020-03-13 22:54:36 +080022import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Tiger Huang332793b2019-10-29 23:21:27 +080023import static android.view.InsetsState.ITYPE_IME;
24import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
25import static android.view.InsetsState.ITYPE_STATUS_BAR;
Yunfan Chenb04dc002019-02-14 17:08:39 +090026import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
Tiger Huang57e2e1c2020-03-13 22:54:36 +080027import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
Tiger Huanga16634032020-02-05 17:10:03 +080028import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020029import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
Tiger Huanga16634032020-02-05 17:10:03 +080030
Jorim Jaggif96c90a2018-09-26 16:55:15 +020031import static org.junit.Assert.assertEquals;
Jorim Jaggi28620472019-01-02 23:21:49 +010032import static org.junit.Assert.assertNotEquals;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020033import static org.junit.Assert.assertNotNull;
Jorim Jaggib6030952018-10-23 18:31:52 +020034import static org.junit.Assert.assertNull;
Tiger Huang53c8eb82020-03-31 18:22:05 +080035import static org.mockito.Mockito.atLeast;
36import static org.mockito.Mockito.clearInvocations;
37import static org.mockito.Mockito.spy;
38import static org.mockito.Mockito.verify;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020039
Jorim Jaggi9b4f4202020-01-28 17:05:06 +010040import android.graphics.Rect;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020041import android.platform.test.annotations.Presubmit;
Jorim Jaggi28620472019-01-02 23:21:49 +010042import android.view.InsetsSource;
Jorim Jaggib6030952018-10-23 18:31:52 +020043import android.view.InsetsSourceControl;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020044import android.view.InsetsState;
Jorim Jaggi28620472019-01-02 23:21:49 +010045import android.view.test.InsetsModeSession;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020046
Tiger Huanga16634032020-02-05 17:10:03 +080047import androidx.test.filters.FlakyTest;
48import androidx.test.filters.SmallTest;
49
Yunfan Chenb04dc002019-02-14 17:08:39 +090050import org.junit.AfterClass;
51import org.junit.BeforeClass;
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +090052import org.junit.Test;
Jorim Jaggi28620472019-01-02 23:21:49 +010053import org.junit.runner.RunWith;
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +090054
Jorim Jaggif96c90a2018-09-26 16:55:15 +020055@SmallTest
Jorim Jaggif96c90a2018-09-26 16:55:15 +020056@Presubmit
Jorim Jaggi28620472019-01-02 23:21:49 +010057@RunWith(WindowTestRunner.class)
Jorim Jaggif96c90a2018-09-26 16:55:15 +020058public class InsetsStateControllerTest extends WindowTestsBase {
Jorim Jaggi28620472019-01-02 23:21:49 +010059 private static InsetsModeSession sInsetsModeSession;
Yunfan Chenb04dc002019-02-14 17:08:39 +090060
61 @BeforeClass
62 public static void setUpOnce() {
Yunfan Chenb04dc002019-02-14 17:08:39 +090063 // To let the insets provider control the insets visibility, the insets mode has to be
64 // NEW_INSETS_MODE_FULL.
Jorim Jaggi28620472019-01-02 23:21:49 +010065 sInsetsModeSession = new InsetsModeSession(NEW_INSETS_MODE_FULL);
Yunfan Chenb04dc002019-02-14 17:08:39 +090066 }
67
68 @AfterClass
69 public static void tearDownOnce() {
Jorim Jaggi28620472019-01-02 23:21:49 +010070 sInsetsModeSession.close();
Yunfan Chenb04dc002019-02-14 17:08:39 +090071 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +020072
73 @Test
74 public void testStripForDispatch_notOwn() {
Tiger Huang332793b2019-10-29 23:21:27 +080075 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +010076 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +010077 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
Tiger Huang332793b2019-10-29 23:21:27 +080078 statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR));
Tiger Huang0f5347e2020-03-06 17:09:41 +080079 assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
Jorim Jaggif96c90a2018-09-26 16:55:15 +020080 }
81
82 @Test
83 public void testStripForDispatch_own() {
Tiger Huang332793b2019-10-29 23:21:27 +080084 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
85 mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR)
Jorim Jaggi9b4f4202020-01-28 17:05:06 +010086 .setWindow(statusBar, null, null);
Tiger Huang332793b2019-10-29 23:21:27 +080087 statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR));
88 final InsetsState state = getController().getInsetsForDispatch(statusBar);
Jorim Jaggi28620472019-01-02 23:21:49 +010089 for (int i = state.getSourcesCount() - 1; i >= 0; i--) {
90 final InsetsSource source = state.sourceAt(i);
Tiger Huang332793b2019-10-29 23:21:27 +080091 assertNotEquals(ITYPE_STATUS_BAR, source.getType());
Jorim Jaggi28620472019-01-02 23:21:49 +010092 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +020093 }
94
95 @Test
96 public void testStripForDispatch_navBar() {
Jorim Jaggi28620472019-01-02 23:21:49 +010097 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
Tiger Huang332793b2019-10-29 23:21:27 +080098 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +010099 final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
Tiger Huanga16634032020-02-05 17:10:03 +0800100
101 // IME cannot be the IME target.
102 ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
103
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100104 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
105 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
106 getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
Jorim Jaggi963c5c22020-04-01 22:53:42 +0200107 assertNull(getController().getInsetsForDispatch(navBar).peekSource(ITYPE_IME));
108 assertNull(getController().getInsetsForDispatch(navBar).peekSource(ITYPE_STATUS_BAR));
Jorim Jaggib6030952018-10-23 18:31:52 +0200109 }
110
111 @Test
Tiger Huang0f5347e2020-03-06 17:09:41 +0800112 public void testStripForDispatch_pip() {
113 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
114 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
115 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
116
117 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
118 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
119 app.setWindowingMode(WINDOWING_MODE_PINNED);
120
121 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
122 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
123 }
124
125 @Test
126 public void testStripForDispatch_freeform() {
127 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
128 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
129 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
130
131 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
132 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
133 app.setWindowingMode(WINDOWING_MODE_FREEFORM);
134
135 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
136 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
137 }
138
139 @Test
Winson Chung8a168902020-03-12 22:39:22 -0700140 public void testStripForDispatch_multiwindow_alwaysOnTop() {
141 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
142 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
143 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
144
145 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
146 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
147 app.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
148 app.setAlwaysOnTop(true);
149
150 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
151 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
152 }
153
154 @Test
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800155 public void testStripForDispatch_belowIme() {
156 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
157 final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
158
159 getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
160
161 assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
162 }
163
164 @Test
165 public void testStripForDispatch_aboveIme() {
166 final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
167 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
168
169 getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
170
171 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
172 }
173
174 @Test
Tiger Huang53c8eb82020-03-31 18:22:05 +0800175 public void testStripForDispatch_imeOrderChanged() {
176 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
177
178 // This window can be the IME target while app cannot be the IME target.
179 createWindow(null, TYPE_APPLICATION, "base");
180
181 // Send our spy window (app) into the system so that we can detect the invocation.
182 final WindowState win = createWindow(null, TYPE_APPLICATION, "app");
183 final WindowToken parent = win.mToken;
184 parent.removeChild(win);
185 final WindowState app = spy(win);
186 parent.addWindow(app);
187
188 // Adding FLAG_NOT_FOCUSABLE makes app above IME.
189 app.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
190 mDisplayContent.computeImeTarget(true);
191 mDisplayContent.setLayoutNeeded();
192 mDisplayContent.applySurfaceChangesTransaction();
193
194 // app won't get IME insets while above IME.
195 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
196
197 // Reset invocation counter.
198 clearInvocations(app);
199
200 // Removing FLAG_NOT_FOCUSABLE makes app below IME.
201 app.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
202 mDisplayContent.computeImeTarget(true);
203 mDisplayContent.setLayoutNeeded();
204 mDisplayContent.applySurfaceChangesTransaction();
205
206 // Make sure app got notified.
207 verify(app, atLeast(1)).notifyInsetsChanged();
208
209 // app will get IME insets while below IME.
210 assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
211 }
212
213 @Test
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800214 public void testStripForDispatch_childWindow_altFocusable() {
215 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
216
217 final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
218 child.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
219
220 final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
221
222 // IME cannot be the IME target.
223 ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
224
225 getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
226
227 assertNull(getController().getInsetsForDispatch(child).peekSource(ITYPE_IME));
228 }
229
230 @Test
231 public void testStripForDispatch_childWindow_splitScreen() {
232 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
233
234 final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
235 child.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
236 child.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
237
238 final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
239
240 // IME cannot be the IME target.
241 ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
242
243 getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
244
245 assertNull(getController().getInsetsForDispatch(child).peekSource(ITYPE_IME));
246 }
247
248 @Test
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100249 public void testImeForDispatch() {
250 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
251 final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
Tiger Huanga16634032020-02-05 17:10:03 +0800252
253 // IME cannot be the IME target.
254 ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
255
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100256 InsetsSourceProvider statusBarProvider =
257 getController().getSourceProvider(ITYPE_STATUS_BAR);
258 statusBarProvider.setWindow(statusBar, null, ((displayFrames, windowState, rect) ->
259 rect.set(0, 1, 2, 3)));
260 getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
261 statusBar.setControllableInsetProvider(statusBarProvider);
262
263 statusBarProvider.onPostLayout();
264
265 final InsetsState state = getController().getInsetsForDispatch(ime);
266 assertEquals(new Rect(0, 1, 2, 3), state.getSource(ITYPE_STATUS_BAR).getFrame());
267 }
268
269 @Test
Jorim Jaggib6030952018-10-23 18:31:52 +0200270 public void testBarControllingWinChanged() {
Jorim Jaggi28620472019-01-02 23:21:49 +0100271 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
Tiger Huang332793b2019-10-29 23:21:27 +0800272 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100273 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100274 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
275 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100276 getController().onBarControlTargetChanged(app, null, app, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200277 InsetsSourceControl[] controls = getController().getControlsForDispatch(app);
278 assertEquals(2, controls.length);
279 }
280
281 @Test
282 public void testControlRevoked() {
Tiger Huang332793b2019-10-29 23:21:27 +0800283 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100284 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100285 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100286 getController().onBarControlTargetChanged(app, null, null, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200287 assertNotNull(getController().getControlsForDispatch(app));
Jorim Jaggi956ca412019-01-07 14:49:14 +0100288 getController().onBarControlTargetChanged(null, null, null, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200289 assertNull(getController().getControlsForDispatch(app));
290 }
291
292 @Test
293 public void testControlRevoked_animation() {
Tiger Huang332793b2019-10-29 23:21:27 +0800294 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100295 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100296 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100297 getController().onBarControlTargetChanged(app, null, null, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200298 assertNotNull(getController().getControlsForDispatch(app));
Tiger Huang332793b2019-10-29 23:21:27 +0800299 statusBar.cancelAnimation();
Jorim Jaggib6030952018-10-23 18:31:52 +0200300 assertNull(getController().getControlsForDispatch(app));
301 }
302
303 private InsetsStateController getController() {
304 return mDisplayContent.getInsetsStateController();
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200305 }
306}