blob: 976ac23239893345e5311e7b958414879f741e55 [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;
Tiger Huanga70fd872020-04-15 05:25:16 +080032import static org.junit.Assert.assertFalse;
Jorim Jaggi28620472019-01-02 23:21:49 +010033import static org.junit.Assert.assertNotEquals;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020034import static org.junit.Assert.assertNotNull;
Jorim Jaggib6030952018-10-23 18:31:52 +020035import static org.junit.Assert.assertNull;
Tiger Huanga70fd872020-04-15 05:25:16 +080036import static org.junit.Assert.assertTrue;
Tiger Huang53c8eb82020-03-31 18:22:05 +080037import static org.mockito.Mockito.atLeast;
38import static org.mockito.Mockito.clearInvocations;
39import static org.mockito.Mockito.spy;
40import static org.mockito.Mockito.verify;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020041
Jorim Jaggi9b4f4202020-01-28 17:05:06 +010042import android.graphics.Rect;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020043import android.platform.test.annotations.Presubmit;
Jorim Jaggi28620472019-01-02 23:21:49 +010044import android.view.InsetsSource;
Jorim Jaggib6030952018-10-23 18:31:52 +020045import android.view.InsetsSourceControl;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020046import android.view.InsetsState;
Jorim Jaggi28620472019-01-02 23:21:49 +010047import android.view.test.InsetsModeSession;
Jorim Jaggif96c90a2018-09-26 16:55:15 +020048
Tiger Huanga16634032020-02-05 17:10:03 +080049import androidx.test.filters.SmallTest;
50
Yunfan Chenb04dc002019-02-14 17:08:39 +090051import org.junit.AfterClass;
52import org.junit.BeforeClass;
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +090053import org.junit.Test;
Jorim Jaggi28620472019-01-02 23:21:49 +010054import org.junit.runner.RunWith;
Tadashi G. Takaokabf0d57b2018-11-19 16:09:58 +090055
Jorim Jaggif96c90a2018-09-26 16:55:15 +020056@SmallTest
Jorim Jaggif96c90a2018-09-26 16:55:15 +020057@Presubmit
Jorim Jaggi28620472019-01-02 23:21:49 +010058@RunWith(WindowTestRunner.class)
Jorim Jaggif96c90a2018-09-26 16:55:15 +020059public class InsetsStateControllerTest extends WindowTestsBase {
Jorim Jaggi28620472019-01-02 23:21:49 +010060 private static InsetsModeSession sInsetsModeSession;
Yunfan Chenb04dc002019-02-14 17:08:39 +090061
62 @BeforeClass
63 public static void setUpOnce() {
Yunfan Chenb04dc002019-02-14 17:08:39 +090064 // To let the insets provider control the insets visibility, the insets mode has to be
65 // NEW_INSETS_MODE_FULL.
Jorim Jaggi28620472019-01-02 23:21:49 +010066 sInsetsModeSession = new InsetsModeSession(NEW_INSETS_MODE_FULL);
Yunfan Chenb04dc002019-02-14 17:08:39 +090067 }
68
69 @AfterClass
70 public static void tearDownOnce() {
Jorim Jaggi28620472019-01-02 23:21:49 +010071 sInsetsModeSession.close();
Yunfan Chenb04dc002019-02-14 17:08:39 +090072 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +020073
74 @Test
75 public void testStripForDispatch_notOwn() {
Tiger Huang332793b2019-10-29 23:21:27 +080076 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +010077 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +010078 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
Tiger Huang332793b2019-10-29 23:21:27 +080079 statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR));
Tiger Huang0f5347e2020-03-06 17:09:41 +080080 assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
Jorim Jaggif96c90a2018-09-26 16:55:15 +020081 }
82
83 @Test
84 public void testStripForDispatch_own() {
Tiger Huang332793b2019-10-29 23:21:27 +080085 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
86 mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR)
Jorim Jaggi9b4f4202020-01-28 17:05:06 +010087 .setWindow(statusBar, null, null);
Tiger Huang332793b2019-10-29 23:21:27 +080088 statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR));
89 final InsetsState state = getController().getInsetsForDispatch(statusBar);
Jorim Jaggibfa95a72020-06-18 22:51:49 +020090 assertNull(state.peekSource(ITYPE_STATUS_BAR));
Jorim Jaggif96c90a2018-09-26 16:55:15 +020091 }
92
93 @Test
94 public void testStripForDispatch_navBar() {
Jorim Jaggi28620472019-01-02 23:21:49 +010095 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
Tiger Huang332793b2019-10-29 23:21:27 +080096 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +010097 final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
Tiger Huanga16634032020-02-05 17:10:03 +080098
99 // IME cannot be the IME target.
100 ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
101
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100102 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
103 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
104 getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
Jorim Jaggi963c5c22020-04-01 22:53:42 +0200105 assertNull(getController().getInsetsForDispatch(navBar).peekSource(ITYPE_IME));
106 assertNull(getController().getInsetsForDispatch(navBar).peekSource(ITYPE_STATUS_BAR));
Jorim Jaggib6030952018-10-23 18:31:52 +0200107 }
108
109 @Test
Tiger Huang0f5347e2020-03-06 17:09:41 +0800110 public void testStripForDispatch_pip() {
111 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
112 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
113 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
114
115 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
116 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
117 app.setWindowingMode(WINDOWING_MODE_PINNED);
118
119 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
120 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
121 }
122
123 @Test
124 public void testStripForDispatch_freeform() {
125 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
126 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
127 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
128
129 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
130 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
131 app.setWindowingMode(WINDOWING_MODE_FREEFORM);
132
133 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
134 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
135 }
136
137 @Test
Winson Chung8a168902020-03-12 22:39:22 -0700138 public void testStripForDispatch_multiwindow_alwaysOnTop() {
139 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
140 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
141 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
142
143 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
144 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
145 app.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
146 app.setAlwaysOnTop(true);
147
148 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
149 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
150 }
151
152 @Test
Tiger Huangc0d837a2020-04-24 00:49:27 +0800153 public void testStripForDispatch_independentSources() {
154 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
155
156 final WindowState app1 = createWindow(null, TYPE_APPLICATION, "app1");
157 app1.mBehindIme = true;
158
159 final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
160 app2.mBehindIme = false;
161
162 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
163 assertFalse(getController().getInsetsForDispatch(app2).getSource(ITYPE_IME).isVisible());
164 assertTrue(getController().getInsetsForDispatch(app1).getSource(ITYPE_IME).isVisible());
165 }
166
167 @Test
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800168 public void testStripForDispatch_belowIme() {
Tiger Huanga70fd872020-04-15 05:25:16 +0800169 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
170
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800171 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Tiger Huanga70fd872020-04-15 05:25:16 +0800172 app.mBehindIme = true;
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800173
Tiger Huanga70fd872020-04-15 05:25:16 +0800174 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
175 assertTrue(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800176 }
177
178 @Test
179 public void testStripForDispatch_aboveIme() {
Tiger Huanga70fd872020-04-15 05:25:16 +0800180 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
181
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800182 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Tiger Huanga70fd872020-04-15 05:25:16 +0800183 app.mBehindIme = false;
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800184
Tiger Huanga70fd872020-04-15 05:25:16 +0800185 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
186 assertFalse(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800187 }
188
189 @Test
Tiger Huang53c8eb82020-03-31 18:22:05 +0800190 public void testStripForDispatch_imeOrderChanged() {
191 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
192
193 // This window can be the IME target while app cannot be the IME target.
194 createWindow(null, TYPE_APPLICATION, "base");
195
196 // Send our spy window (app) into the system so that we can detect the invocation.
197 final WindowState win = createWindow(null, TYPE_APPLICATION, "app");
198 final WindowToken parent = win.mToken;
199 parent.removeChild(win);
200 final WindowState app = spy(win);
201 parent.addWindow(app);
202
203 // Adding FLAG_NOT_FOCUSABLE makes app above IME.
204 app.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
205 mDisplayContent.computeImeTarget(true);
Tiger Huang53c8eb82020-03-31 18:22:05 +0800206 mDisplayContent.applySurfaceChangesTransaction();
207
Tiger Huanga70fd872020-04-15 05:25:16 +0800208 // app won't get visible IME insets while above IME even when IME is visible.
209 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
210 assertFalse(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
Tiger Huang53c8eb82020-03-31 18:22:05 +0800211
212 // Reset invocation counter.
213 clearInvocations(app);
214
215 // Removing FLAG_NOT_FOCUSABLE makes app below IME.
216 app.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
217 mDisplayContent.computeImeTarget(true);
Tiger Huang53c8eb82020-03-31 18:22:05 +0800218 mDisplayContent.applySurfaceChangesTransaction();
219
220 // Make sure app got notified.
221 verify(app, atLeast(1)).notifyInsetsChanged();
222
Tiger Huanga70fd872020-04-15 05:25:16 +0800223 // app will get visible IME insets while below IME when IME is visible.
224 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
225 assertTrue(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
Tiger Huang53c8eb82020-03-31 18:22:05 +0800226 }
227
228 @Test
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800229 public void testStripForDispatch_childWindow_altFocusable() {
Tiger Huanga70fd872020-04-15 05:25:16 +0800230 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800231
Tiger Huanga70fd872020-04-15 05:25:16 +0800232 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800233 final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
234 child.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
235
Tiger Huanga70fd872020-04-15 05:25:16 +0800236 mDisplayContent.computeImeTarget(true);
237 mDisplayContent.setLayoutNeeded();
238 mDisplayContent.applySurfaceChangesTransaction();
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800239
Tiger Huanga70fd872020-04-15 05:25:16 +0800240 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
241 assertTrue(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
242 assertFalse(getController().getInsetsForDispatch(child).getSource(ITYPE_IME).isVisible());
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800243 }
244
245 @Test
246 public void testStripForDispatch_childWindow_splitScreen() {
Tiger Huanga70fd872020-04-15 05:25:16 +0800247 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800248
Tiger Huanga70fd872020-04-15 05:25:16 +0800249 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800250 final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
251 child.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
252 child.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
253
Tiger Huanga70fd872020-04-15 05:25:16 +0800254 mDisplayContent.computeImeTarget(true);
255 mDisplayContent.setLayoutNeeded();
256 mDisplayContent.applySurfaceChangesTransaction();
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800257
Tiger Huanga70fd872020-04-15 05:25:16 +0800258 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
259 assertTrue(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
260 assertFalse(getController().getInsetsForDispatch(child).getSource(ITYPE_IME).isVisible());
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800261 }
262
263 @Test
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100264 public void testImeForDispatch() {
265 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
266 final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
Tiger Huanga16634032020-02-05 17:10:03 +0800267
268 // IME cannot be the IME target.
269 ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
270
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100271 InsetsSourceProvider statusBarProvider =
272 getController().getSourceProvider(ITYPE_STATUS_BAR);
273 statusBarProvider.setWindow(statusBar, null, ((displayFrames, windowState, rect) ->
274 rect.set(0, 1, 2, 3)));
275 getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
276 statusBar.setControllableInsetProvider(statusBarProvider);
277
278 statusBarProvider.onPostLayout();
279
280 final InsetsState state = getController().getInsetsForDispatch(ime);
281 assertEquals(new Rect(0, 1, 2, 3), state.getSource(ITYPE_STATUS_BAR).getFrame());
282 }
283
284 @Test
Jorim Jaggib6030952018-10-23 18:31:52 +0200285 public void testBarControllingWinChanged() {
Jorim Jaggi28620472019-01-02 23:21:49 +0100286 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
Tiger Huang332793b2019-10-29 23:21:27 +0800287 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100288 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100289 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
290 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100291 getController().onBarControlTargetChanged(app, null, app, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200292 InsetsSourceControl[] controls = getController().getControlsForDispatch(app);
293 assertEquals(2, controls.length);
294 }
295
296 @Test
297 public void testControlRevoked() {
Tiger Huang332793b2019-10-29 23:21:27 +0800298 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100299 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100300 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100301 getController().onBarControlTargetChanged(app, null, null, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200302 assertNotNull(getController().getControlsForDispatch(app));
Jorim Jaggi956ca412019-01-07 14:49:14 +0100303 getController().onBarControlTargetChanged(null, null, null, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200304 assertNull(getController().getControlsForDispatch(app));
305 }
306
307 @Test
308 public void testControlRevoked_animation() {
Tiger Huang332793b2019-10-29 23:21:27 +0800309 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100310 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100311 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100312 getController().onBarControlTargetChanged(app, null, null, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200313 assertNotNull(getController().getControlsForDispatch(app));
Tiger Huang332793b2019-10-29 23:21:27 +0800314 statusBar.cancelAnimation();
Jorim Jaggib6030952018-10-23 18:31:52 +0200315 assertNull(getController().getControlsForDispatch(app));
316 }
317
318 private InsetsStateController getController() {
319 return mDisplayContent.getInsetsStateController();
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200320 }
321}