blob: 9f28f45a05d0730a35fdfc5c42e8c2d69ebee33e [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 Jaggi28620472019-01-02 23:21:49 +010090 for (int i = state.getSourcesCount() - 1; i >= 0; i--) {
91 final InsetsSource source = state.sourceAt(i);
Tiger Huang332793b2019-10-29 23:21:27 +080092 assertNotEquals(ITYPE_STATUS_BAR, source.getType());
Jorim Jaggi28620472019-01-02 23:21:49 +010093 }
Jorim Jaggif96c90a2018-09-26 16:55:15 +020094 }
95
96 @Test
97 public void testStripForDispatch_navBar() {
Jorim Jaggi28620472019-01-02 23:21:49 +010098 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
Tiger Huang332793b2019-10-29 23:21:27 +080099 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100100 final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
Tiger Huanga16634032020-02-05 17:10:03 +0800101
102 // IME cannot be the IME target.
103 ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
104
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100105 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
106 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
107 getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
Jorim Jaggi963c5c22020-04-01 22:53:42 +0200108 assertNull(getController().getInsetsForDispatch(navBar).peekSource(ITYPE_IME));
109 assertNull(getController().getInsetsForDispatch(navBar).peekSource(ITYPE_STATUS_BAR));
Jorim Jaggib6030952018-10-23 18:31:52 +0200110 }
111
112 @Test
Tiger Huang0f5347e2020-03-06 17:09:41 +0800113 public void testStripForDispatch_pip() {
114 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
115 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
116 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
117
118 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
119 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
120 app.setWindowingMode(WINDOWING_MODE_PINNED);
121
122 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
123 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
124 }
125
126 @Test
127 public void testStripForDispatch_freeform() {
128 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
129 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
130 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
131
132 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
133 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
134 app.setWindowingMode(WINDOWING_MODE_FREEFORM);
135
136 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
137 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
138 }
139
140 @Test
Winson Chung8a168902020-03-12 22:39:22 -0700141 public void testStripForDispatch_multiwindow_alwaysOnTop() {
142 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
143 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
144 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
145
146 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
147 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
148 app.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
149 app.setAlwaysOnTop(true);
150
151 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
152 assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
153 }
154
155 @Test
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800156 public void testStripForDispatch_belowIme() {
Tiger Huanga70fd872020-04-15 05:25:16 +0800157 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
158
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800159 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Tiger Huanga70fd872020-04-15 05:25:16 +0800160 app.mBehindIme = true;
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800161
Tiger Huanga70fd872020-04-15 05:25:16 +0800162 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
163 assertTrue(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800164 }
165
166 @Test
167 public void testStripForDispatch_aboveIme() {
Tiger Huanga70fd872020-04-15 05:25:16 +0800168 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
169
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800170 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Tiger Huanga70fd872020-04-15 05:25:16 +0800171 app.mBehindIme = false;
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800172
Tiger Huanga70fd872020-04-15 05:25:16 +0800173 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
174 assertFalse(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800175 }
176
177 @Test
Tiger Huang53c8eb82020-03-31 18:22:05 +0800178 public void testStripForDispatch_imeOrderChanged() {
179 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
180
181 // This window can be the IME target while app cannot be the IME target.
182 createWindow(null, TYPE_APPLICATION, "base");
183
184 // Send our spy window (app) into the system so that we can detect the invocation.
185 final WindowState win = createWindow(null, TYPE_APPLICATION, "app");
186 final WindowToken parent = win.mToken;
187 parent.removeChild(win);
188 final WindowState app = spy(win);
189 parent.addWindow(app);
190
191 // Adding FLAG_NOT_FOCUSABLE makes app above IME.
192 app.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
193 mDisplayContent.computeImeTarget(true);
Tiger Huang53c8eb82020-03-31 18:22:05 +0800194 mDisplayContent.applySurfaceChangesTransaction();
195
Tiger Huanga70fd872020-04-15 05:25:16 +0800196 // app won't get visible IME insets while above IME even when IME is visible.
197 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
198 assertFalse(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
Tiger Huang53c8eb82020-03-31 18:22:05 +0800199
200 // Reset invocation counter.
201 clearInvocations(app);
202
203 // Removing FLAG_NOT_FOCUSABLE makes app below IME.
204 app.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
205 mDisplayContent.computeImeTarget(true);
Tiger Huang53c8eb82020-03-31 18:22:05 +0800206 mDisplayContent.applySurfaceChangesTransaction();
207
208 // Make sure app got notified.
209 verify(app, atLeast(1)).notifyInsetsChanged();
210
Tiger Huanga70fd872020-04-15 05:25:16 +0800211 // app will get visible IME insets while below IME when IME is visible.
212 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
213 assertTrue(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
Tiger Huang53c8eb82020-03-31 18:22:05 +0800214 }
215
216 @Test
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800217 public void testStripForDispatch_childWindow_altFocusable() {
Tiger Huanga70fd872020-04-15 05:25:16 +0800218 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800219
Tiger Huanga70fd872020-04-15 05:25:16 +0800220 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800221 final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
222 child.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
223
Tiger Huanga70fd872020-04-15 05:25:16 +0800224 mDisplayContent.computeImeTarget(true);
225 mDisplayContent.setLayoutNeeded();
226 mDisplayContent.applySurfaceChangesTransaction();
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800227
Tiger Huanga70fd872020-04-15 05:25:16 +0800228 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
229 assertTrue(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
230 assertFalse(getController().getInsetsForDispatch(child).getSource(ITYPE_IME).isVisible());
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800231 }
232
233 @Test
234 public void testStripForDispatch_childWindow_splitScreen() {
Tiger Huanga70fd872020-04-15 05:25:16 +0800235 getController().getSourceProvider(ITYPE_IME).setWindow(mImeWindow, null, null);
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800236
Tiger Huanga70fd872020-04-15 05:25:16 +0800237 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800238 final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
239 child.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
240 child.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
241
Tiger Huanga70fd872020-04-15 05:25:16 +0800242 mDisplayContent.computeImeTarget(true);
243 mDisplayContent.setLayoutNeeded();
244 mDisplayContent.applySurfaceChangesTransaction();
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800245
Tiger Huanga70fd872020-04-15 05:25:16 +0800246 getController().getRawInsetsState().setSourceVisible(ITYPE_IME, true);
247 assertTrue(getController().getInsetsForDispatch(app).getSource(ITYPE_IME).isVisible());
248 assertFalse(getController().getInsetsForDispatch(child).getSource(ITYPE_IME).isVisible());
Tiger Huang57e2e1c2020-03-13 22:54:36 +0800249 }
250
251 @Test
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100252 public void testImeForDispatch() {
253 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
254 final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
Tiger Huanga16634032020-02-05 17:10:03 +0800255
256 // IME cannot be the IME target.
257 ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
258
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100259 InsetsSourceProvider statusBarProvider =
260 getController().getSourceProvider(ITYPE_STATUS_BAR);
261 statusBarProvider.setWindow(statusBar, null, ((displayFrames, windowState, rect) ->
262 rect.set(0, 1, 2, 3)));
263 getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
264 statusBar.setControllableInsetProvider(statusBarProvider);
265
266 statusBarProvider.onPostLayout();
267
268 final InsetsState state = getController().getInsetsForDispatch(ime);
269 assertEquals(new Rect(0, 1, 2, 3), state.getSource(ITYPE_STATUS_BAR).getFrame());
270 }
271
272 @Test
Jorim Jaggib6030952018-10-23 18:31:52 +0200273 public void testBarControllingWinChanged() {
Jorim Jaggi28620472019-01-02 23:21:49 +0100274 final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
Tiger Huang332793b2019-10-29 23:21:27 +0800275 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100276 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100277 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
278 getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100279 getController().onBarControlTargetChanged(app, null, app, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200280 InsetsSourceControl[] controls = getController().getControlsForDispatch(app);
281 assertEquals(2, controls.length);
282 }
283
284 @Test
285 public void testControlRevoked() {
Tiger Huang332793b2019-10-29 23:21:27 +0800286 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100287 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100288 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100289 getController().onBarControlTargetChanged(app, null, null, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200290 assertNotNull(getController().getControlsForDispatch(app));
Jorim Jaggi956ca412019-01-07 14:49:14 +0100291 getController().onBarControlTargetChanged(null, null, null, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200292 assertNull(getController().getControlsForDispatch(app));
293 }
294
295 @Test
296 public void testControlRevoked_animation() {
Tiger Huang332793b2019-10-29 23:21:27 +0800297 final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
Jorim Jaggi28620472019-01-02 23:21:49 +0100298 final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
Jorim Jaggi9b4f4202020-01-28 17:05:06 +0100299 getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
Jorim Jaggi956ca412019-01-07 14:49:14 +0100300 getController().onBarControlTargetChanged(app, null, null, null);
Jorim Jaggib6030952018-10-23 18:31:52 +0200301 assertNotNull(getController().getControlsForDispatch(app));
Tiger Huang332793b2019-10-29 23:21:27 +0800302 statusBar.cancelAnimation();
Jorim Jaggib6030952018-10-23 18:31:52 +0200303 assertNull(getController().getControlsForDispatch(app));
304 }
305
306 private InsetsStateController getController() {
307 return mDisplayContent.getInsetsStateController();
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200308 }
309}