blob: ecc3b4f072f9ca0988f8f47c7180232a6d0edf50 [file] [log] [blame]
Adrian Roos7419a172018-05-24 18:20:51 +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 android.view;
18
Tiger Huang5fb9ab72020-03-02 16:16:01 +080019import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
Tiger Huang4a7835f2019-11-06 00:07:56 +080020import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
21import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
Tiger Huang5fb9ab72020-03-02 16:16:01 +080022import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
23import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
24import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
25import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
Tiger Huang4a7835f2019-11-06 00:07:56 +080026import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
27import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
28import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
29import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
30
Adrian Roos7419a172018-05-24 18:20:51 +020031import static org.hamcrest.Matchers.equalTo;
Tiger Huang4a7835f2019-11-06 00:07:56 +080032import static org.junit.Assert.assertEquals;
Adrian Roos7419a172018-05-24 18:20:51 +020033import static org.junit.Assert.assertThat;
Tiger Huang4a7835f2019-11-06 00:07:56 +080034import static org.junit.Assume.assumeTrue;
Adrian Roos7419a172018-05-24 18:20:51 +020035
36import android.content.Context;
Adrian Roos60f59292018-08-24 16:29:06 +020037import android.graphics.Insets;
Adrian Roos7419a172018-05-24 18:20:51 +020038import android.graphics.Rect;
39import android.platform.test.annotations.Presubmit;
Tiger Huang4a7835f2019-11-06 00:07:56 +080040import android.view.WindowInsets.Side;
41import android.view.WindowInsets.Type;
Tadashi G. Takaokab4470f22019-01-15 18:29:15 +090042
Diego Velaa586fa32020-04-03 14:26:51 -070043import androidx.test.ext.junit.runners.AndroidJUnit4;
Tadashi G. Takaokab4470f22019-01-15 18:29:15 +090044import androidx.test.filters.SmallTest;
Diego Velaa586fa32020-04-03 14:26:51 -070045import androidx.test.platform.app.InstrumentationRegistry;
Adrian Roos7419a172018-05-24 18:20:51 +020046
47import org.junit.Before;
48import org.junit.Test;
49import org.junit.runner.RunWith;
50
51import java.lang.reflect.Field;
52import java.lang.reflect.Method;
53
Diego Velaa586fa32020-04-03 14:26:51 -070054/**
55 * Tests for {@link ViewRootImpl}
56 *
57 * Build/Install/Run:
58 * atest FrameworksCoreTests:ViewRootImplTest
59 */
Adrian Roos7419a172018-05-24 18:20:51 +020060@Presubmit
61@SmallTest
62@RunWith(AndroidJUnit4.class)
63public class ViewRootImplTest {
64
65 private Context mContext;
66 private ViewRootImplAccessor mViewRootImpl;
67
68 @Before
69 public void setUp() throws Exception {
Diego Velaa586fa32020-04-03 14:26:51 -070070 mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
Adrian Roos7419a172018-05-24 18:20:51 +020071
72 InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
73 mViewRootImpl = new ViewRootImplAccessor(
Andrii Kulian5877c7d2020-01-29 16:57:32 -080074 new ViewRootImpl(mContext, mContext.getDisplayNoVerify()));
Adrian Roos7419a172018-05-24 18:20:51 +020075 });
76 }
77
78 @Test
79 public void negativeInsets_areSetToZero() throws Exception {
Tiger Huang4a7835f2019-11-06 00:07:56 +080080 assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
81
Adrian Roos7419a172018-05-24 18:20:51 +020082 mViewRootImpl.getAttachInfo().getContentInsets().set(-10, -20, -30 , -40);
83 mViewRootImpl.getAttachInfo().getStableInsets().set(-10, -20, -30 , -40);
84 final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
85
Adrian Roos60f59292018-08-24 16:29:06 +020086 assertThat(insets.getSystemWindowInsets(), equalTo(Insets.NONE));
87 assertThat(insets.getStableInsets(), equalTo(Insets.NONE));
Adrian Roos7419a172018-05-24 18:20:51 +020088 }
89
90 @Test
91 public void negativeInsets_areSetToZero_positiveAreLeftAsIs() throws Exception {
Tiger Huang4a7835f2019-11-06 00:07:56 +080092 assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
93
Adrian Roos7419a172018-05-24 18:20:51 +020094 mViewRootImpl.getAttachInfo().getContentInsets().set(-10, 20, -30 , 40);
95 mViewRootImpl.getAttachInfo().getStableInsets().set(10, -20, 30 , -40);
96 final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
97
Adrian Roos60f59292018-08-24 16:29:06 +020098 assertThat(insets.getSystemWindowInsets(), equalTo(Insets.of(0, 20, 0, 40)));
99 assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 0, 30, 0)));
Adrian Roos7419a172018-05-24 18:20:51 +0200100 }
101
102 @Test
103 public void positiveInsets_areLeftAsIs() throws Exception {
Tiger Huang4a7835f2019-11-06 00:07:56 +0800104 assumeTrue(ViewRootImpl.sNewInsetsMode != ViewRootImpl.NEW_INSETS_MODE_FULL);
105
Adrian Roos7419a172018-05-24 18:20:51 +0200106 mViewRootImpl.getAttachInfo().getContentInsets().set(10, 20, 30 , 40);
107 mViewRootImpl.getAttachInfo().getStableInsets().set(10, 20, 30 , 40);
108 final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
109
Adrian Roos60f59292018-08-24 16:29:06 +0200110 assertThat(insets.getSystemWindowInsets(), equalTo(Insets.of(10, 20, 30, 40)));
111 assertThat(insets.getStableInsets(), equalTo(Insets.of(10, 20, 30, 40)));
Adrian Roos7419a172018-05-24 18:20:51 +0200112 }
113
Tiger Huang4a7835f2019-11-06 00:07:56 +0800114 @Test
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800115 public void adjustLayoutParamsForCompatibility_layoutFullscreen() {
Tiger Huang4a7835f2019-11-06 00:07:56 +0800116 assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
117
118 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
119 attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
120 ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
121
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800122 // Type.statusBars() must be removed.
Tiger Huang52724442020-01-20 21:38:42 +0800123 assertEquals(0, attrs.getFitInsetsTypes() & Type.statusBars());
Tiger Huang4a7835f2019-11-06 00:07:56 +0800124 }
125
126 @Test
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800127 public void adjustLayoutParamsForCompatibility_layoutInScreen() {
Tiger Huang4a7835f2019-11-06 00:07:56 +0800128 assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
129
130 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
131 attrs.flags = FLAG_LAYOUT_IN_SCREEN;
132 ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
133
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800134 // Type.statusBars() must be removed.
Tiger Huang52724442020-01-20 21:38:42 +0800135 assertEquals(0, attrs.getFitInsetsTypes() & Type.statusBars());
Tiger Huang4a7835f2019-11-06 00:07:56 +0800136 }
137
138 @Test
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800139 public void adjustLayoutParamsForCompatibility_layoutHideNavigation() {
Tiger Huang4a7835f2019-11-06 00:07:56 +0800140 assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
141
142 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
143 attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
144 ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
145
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800146 // Type.systemBars() must be removed.
Tiger Huang52724442020-01-20 21:38:42 +0800147 assertEquals(0, attrs.getFitInsetsTypes() & Type.systemBars());
Tiger Huang4a7835f2019-11-06 00:07:56 +0800148 }
149
150 @Test
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800151 public void adjustLayoutParamsForCompatibility_toast() {
Tiger Huang4a7835f2019-11-06 00:07:56 +0800152 assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
153
154 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_TOAST);
155 ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
156
Tiger Huang52724442020-01-20 21:38:42 +0800157 assertEquals(true, attrs.isFitInsetsIgnoringVisibility());
Tiger Huang4a7835f2019-11-06 00:07:56 +0800158 }
159
160 @Test
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800161 public void adjustLayoutParamsForCompatibility_systemAlert() {
Tiger Huang4a7835f2019-11-06 00:07:56 +0800162 assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
163
164 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_SYSTEM_ALERT);
165 ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
166
Tiger Huang52724442020-01-20 21:38:42 +0800167 assertEquals(true, attrs.isFitInsetsIgnoringVisibility());
Tiger Huang4a7835f2019-11-06 00:07:56 +0800168 }
169
170 @Test
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800171 public void adjustLayoutParamsForCompatibility_fitSystemBars() {
172 assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
173
174 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
175 ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
176
177 // A window which fits system bars must fit IME, unless its type is toast or system alert.
178 assertEquals(Type.systemBars() | Type.ime(), attrs.getFitInsetsTypes());
179 }
180
181 @Test
182 public void adjustLayoutParamsForCompatibility_noAdjustLayout() {
Tiger Huang4a7835f2019-11-06 00:07:56 +0800183 assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
184
185 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION);
186 final int types = Type.all();
187 final int sides = Side.TOP | Side.LEFT;
188 final boolean fitMaxInsets = true;
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800189 attrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
Tiger Huang52724442020-01-20 21:38:42 +0800190 attrs.setFitInsetsTypes(types);
191 attrs.setFitInsetsSides(sides);
192 attrs.setFitInsetsIgnoringVisibility(fitMaxInsets);
Tiger Huang4a7835f2019-11-06 00:07:56 +0800193 ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
194
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800195 // Fit-insets related fields must not be adjusted due to legacy system UI visibility
196 // after calling fit-insets related methods.
Tiger Huang52724442020-01-20 21:38:42 +0800197 assertEquals(types, attrs.getFitInsetsTypes());
198 assertEquals(sides, attrs.getFitInsetsSides());
199 assertEquals(fitMaxInsets, attrs.isFitInsetsIgnoringVisibility());
Tiger Huang4a7835f2019-11-06 00:07:56 +0800200 }
201
Tiger Huang5fb9ab72020-03-02 16:16:01 +0800202 @Test
203 public void adjustLayoutParamsForCompatibility_noAdjustAppearance() {
204 assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
205
206 final ViewRootImpl viewRoot = mViewRootImpl.get();
207 final WindowInsetsController controller = viewRoot.getInsetsController();
208 final WindowManager.LayoutParams attrs = viewRoot.mWindowAttributes;
209 final int appearance = 0;
210 controller.setSystemBarsAppearance(appearance, 0xffffffff);
211 attrs.systemUiVisibility = SYSTEM_UI_FLAG_LOW_PROFILE
212 | SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
213 | SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
214 ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
215
216 // Appearance must not be adjusted due to legacy system UI visibility after calling
217 // setSystemBarsAppearance.
218 assertEquals(appearance, controller.getSystemBarsAppearance());
219 }
220
221 @Test
222 public void adjustLayoutParamsForCompatibility_noAdjustBehavior() {
223 assumeTrue(ViewRootImpl.sNewInsetsMode == ViewRootImpl.NEW_INSETS_MODE_FULL);
224
225 final ViewRootImpl viewRoot = mViewRootImpl.get();
226 final WindowInsetsController controller = viewRoot.getInsetsController();
227 final WindowManager.LayoutParams attrs = viewRoot.mWindowAttributes;
228 final int behavior = BEHAVIOR_SHOW_BARS_BY_TOUCH;
229 controller.setSystemBarsBehavior(behavior);
230 attrs.systemUiVisibility = SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
231 ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
232
233 // Behavior must not be adjusted due to legacy system UI visibility after calling
234 // setSystemBarsBehavior.
235 assertEquals(behavior, controller.getSystemBarsBehavior());
236 }
237
Adrian Roos7419a172018-05-24 18:20:51 +0200238 private static class ViewRootImplAccessor {
239
240 private final ViewRootImpl mViewRootImpl;
241
242 ViewRootImplAccessor(ViewRootImpl viewRootImpl) {
243 mViewRootImpl = viewRootImpl;
244 }
245
246 public ViewRootImpl get() {
247 return mViewRootImpl;
248 }
249
250 AttachInfoAccessor getAttachInfo() throws Exception {
251 return new AttachInfoAccessor(
252 getField(mViewRootImpl, ViewRootImpl.class.getDeclaredField("mAttachInfo")));
253 }
254
255 WindowInsets getWindowInsets(boolean forceConstruct) throws Exception {
256 return (WindowInsets) invokeMethod(mViewRootImpl,
257 ViewRootImpl.class.getDeclaredMethod("getWindowInsets", boolean.class),
258 forceConstruct);
259 }
260
261 class AttachInfoAccessor {
262
263 private final Class<?> mClass;
264 private final Object mAttachInfo;
265
266 AttachInfoAccessor(Object attachInfo) throws Exception {
267 mAttachInfo = attachInfo;
268 mClass = ViewRootImpl.class.getClassLoader().loadClass(
269 "android.view.View$AttachInfo");
270 }
271
272 Rect getContentInsets() throws Exception {
273 return (Rect) getField(mAttachInfo, mClass.getDeclaredField("mContentInsets"));
274 }
275
276 Rect getStableInsets() throws Exception {
277 return (Rect) getField(mAttachInfo, mClass.getDeclaredField("mStableInsets"));
278 }
279 }
280
281 private static Object getField(Object o, Field field) throws Exception {
282 field.setAccessible(true);
283 return field.get(o);
284 }
285
286 private static Object invokeMethod(Object o, Method method, Object... args)
287 throws Exception {
288 method.setAccessible(true);
289 return method.invoke(o, args);
290 }
291 }
292}