• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package android.server.wm;
18 
19 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
20 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
21 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
22 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
23 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
24 
25 import static androidx.test.InstrumentationRegistry.getInstrumentation;
26 
27 import static org.junit.Assert.assertEquals;
28 
29 import android.graphics.Insets;
30 import android.graphics.Rect;
31 import android.os.Bundle;
32 import android.platform.test.annotations.Presubmit;
33 import android.view.View;
34 import android.view.WindowInsets;
35 import android.view.WindowInsets.Side;
36 import android.view.WindowInsets.Type;
37 import android.view.WindowManager;
38 
39 import androidx.annotation.Nullable;
40 
41 import com.android.compatibility.common.util.PollingCheck;
42 
43 import org.junit.Test;
44 
45 /**
46  * Test whether WindowManager performs the correct layout while the app applies the fit-window-
47  * insets APIs.
48  *
49  * Build/Install/Run:
50  *     atest CtsWindowManagerDeviceTestCases:WindowInsetsLayoutTests
51  */
52 @Presubmit
53 @android.server.wm.annotation.Group2
54 public class WindowInsetsLayoutTests extends WindowManagerTestBase {
55 
56     private final static long TIMEOUT = 1000; // milliseconds
57 
58     @Test
testSetFitInsetsTypes()59     public void testSetFitInsetsTypes() {
60         // Start the Activity in fullscreen windowing mode for its bounds to match display bounds.
61         final TestActivity activity =
62                 startActivityInWindowingMode(TestActivity.class, WINDOWING_MODE_FULLSCREEN);
63 
64         // Make sure the main window has been laid out.
65         final View mainWindowRoot = activity.getWindow().getDecorView();
66         PollingCheck.waitFor(TIMEOUT, () -> mainWindowRoot.getWidth() > 0);
67 
68         getInstrumentation().runOnMainSync(() -> {
69             activity.assertMatchesWindowBounds();
70         });
71 
72         testSetFitInsetsTypesInner(Type.statusBars(), activity);
73         testSetFitInsetsTypesInner(Type.navigationBars(), activity);
74         testSetFitInsetsTypesInner(Type.systemBars(), activity);
75     }
76 
testSetFitInsetsTypesInner(int types, TestActivity activity)77     private void testSetFitInsetsTypesInner(int types, TestActivity activity) {
78         getInstrumentation().runOnMainSync(() -> {
79             activity.addChildWindow(types, Side.all(), false);
80         });
81 
82         // Make sure the child window has been laid out.
83         final View childWindowRoot = activity.getChildWindowRoot();
84         PollingCheck.waitFor(TIMEOUT, () -> childWindowRoot.getWidth() > 0);
85 
86         getInstrumentation().runOnMainSync(() -> {
87             final WindowInsets windowInsets = childWindowRoot.getRootWindowInsets();
88             final Insets insets = windowInsets.getInsets(types);
89             assertEquals(Insets.NONE, insets);
90             activity.removeChildWindow();
91         });
92     }
93 
94     @Test
testSetFitInsetsSides()95     public void testSetFitInsetsSides() {
96         // Start the Activity in fullscreen windowing mode for its bounds to match display bounds.
97         final TestActivity activity =
98                 startActivityInWindowingMode(TestActivity.class, WINDOWING_MODE_FULLSCREEN);
99 
100         // Make sure the main window has been laid out.
101         final View mainWindowRoot = activity.getWindow().getDecorView();
102         PollingCheck.waitFor(TIMEOUT, () -> mainWindowRoot.getWidth() > 0);
103 
104         getInstrumentation().runOnMainSync(() -> {
105             activity.assertMatchesWindowBounds();
106         });
107 
108         testSetFitInsetsSidesInner(Side.LEFT, activity);
109         testSetFitInsetsSidesInner(Side.TOP, activity);
110         testSetFitInsetsSidesInner(Side.RIGHT, activity);
111         testSetFitInsetsSidesInner(Side.BOTTOM, activity);
112     }
113 
testSetFitInsetsSidesInner(int sides, TestActivity activity)114     private void testSetFitInsetsSidesInner(int sides, TestActivity activity) {
115         final int types = Type.systemBars();
116         getInstrumentation().runOnMainSync(() -> {
117             activity.addChildWindow(types, sides, false);
118         });
119 
120         // Make sure the child window has been laid out.
121         final View childWindowRoot = activity.getChildWindowRoot();
122         PollingCheck.waitFor(TIMEOUT, () -> childWindowRoot.getWidth() > 0);
123 
124         getInstrumentation().runOnMainSync(() -> {
125             final WindowInsets windowInsets = childWindowRoot.getRootWindowInsets();
126             final Insets insets = windowInsets.getInsets(types);
127             if ((sides & Side.LEFT) != 0) {
128                 assertEquals(0, insets.left);
129             }
130             if ((sides & Side.TOP) != 0) {
131                 assertEquals(0, insets.top);
132             }
133             if ((sides & Side.RIGHT) != 0) {
134                 assertEquals(0, insets.right);
135             }
136             if ((sides & Side.BOTTOM) != 0) {
137                 assertEquals(0, insets.bottom);
138             }
139             activity.removeChildWindow();
140         });
141     }
142 
143     @Test
testSetFitInsetsIgnoringVisibility()144     public void testSetFitInsetsIgnoringVisibility() {
145         // Start the Activity in fullscreen windowing mode for its bounds to match display bounds.
146         final TestActivity activity =
147                 startActivityInWindowingMode(TestActivity.class, WINDOWING_MODE_FULLSCREEN);
148 
149         // Make sure the main window has been laid out.
150         final View mainWindowRoot = activity.getWindow().getDecorView();
151         PollingCheck.waitFor(TIMEOUT, () -> mainWindowRoot.getWidth() > 0);
152 
153         final int types = Type.systemBars();
154         final int sides = Side.all();
155         final int[] locationAndSize1 = new int[4];
156         final int[] locationAndSize2 = new int[4];
157 
158         getInstrumentation().runOnMainSync(() -> {
159             activity.assertMatchesWindowBounds();
160             activity.addChildWindow(types, sides, false);
161         });
162 
163         // Make sure the 1st child window has been laid out.
164         final View childWindowRoot1 = activity.getChildWindowRoot();
165         PollingCheck.waitFor(TIMEOUT, () -> childWindowRoot1.getWidth() > 0);
166 
167         getInstrumentation().runOnMainSync(() -> {
168             childWindowRoot1.getLocationOnScreen(locationAndSize1);
169             locationAndSize1[2] = childWindowRoot1.getWidth();
170             locationAndSize1[3] = childWindowRoot1.getHeight();
171             activity.removeChildWindow();
172 
173             mainWindowRoot.getWindowInsetsController().hide(types);
174 
175             activity.addChildWindow(types, sides, true);
176         });
177 
178         // Make sure the 2nd child window has been laid out.
179         final View childWindowRoot2 = activity.getChildWindowRoot();
180         PollingCheck.waitFor(TIMEOUT, () -> childWindowRoot2.getWidth() > 0);
181 
182         getInstrumentation().runOnMainSync(() -> {
183             childWindowRoot2.getLocationOnScreen(locationAndSize2);
184             locationAndSize2[2] = childWindowRoot2.getWidth();
185             locationAndSize2[3] = childWindowRoot2.getHeight();
186             activity.removeChildWindow();
187         });
188 
189         for (int i = 0; i < 4; i++) {
190             assertEquals(locationAndSize1[i], locationAndSize2[i]);
191         }
192     }
193 
194     public static class TestActivity extends FocusableActivity {
195 
196         private View mChildWindowRoot;
197 
198         @Override
onCreate(@ullable Bundle savedInstanceState)199         protected void onCreate(@Nullable Bundle savedInstanceState) {
200             super.onCreate(savedInstanceState);
201             final View view = new View(this);
202             setContentView(view);
203             WindowManager.LayoutParams lp = getWindow().getAttributes();
204             lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
205             getWindow().setAttributes(lp);
206         }
207 
addChildWindow(int types, int sides, boolean ignoreVis)208         void addChildWindow(int types, int sides, boolean ignoreVis) {
209             final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams();
210             attrs.type = TYPE_APPLICATION_PANEL;
211             attrs.width = MATCH_PARENT;
212             attrs.height = MATCH_PARENT;
213             attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
214             attrs.flags = FLAG_NOT_FOCUSABLE;
215             attrs.setFitInsetsTypes(types);
216             attrs.setFitInsetsSides(sides);
217             attrs.setFitInsetsIgnoringVisibility(ignoreVis);
218             mChildWindowRoot = new View(this);
219             getWindowManager().addView(mChildWindowRoot, attrs);
220         }
221 
removeChildWindow()222         void removeChildWindow() {
223             getWindowManager().removeViewImmediate(mChildWindowRoot);
224         }
225 
getChildWindowRoot()226         View getChildWindowRoot() {
227             return mChildWindowRoot;
228         }
229 
assertMatchesWindowBounds()230         void assertMatchesWindowBounds() {
231             final View rootView = getWindow().getDecorView();
232             final Rect windowMetricsBounds =
233                     getWindowManager().getCurrentWindowMetrics().getBounds();
234             assertEquals(windowMetricsBounds.width(), rootView.getWidth());
235             assertEquals(windowMetricsBounds.height(), rootView.getHeight());
236             final int[] locationOnScreen = new int[2];
237             rootView.getLocationOnScreen(locationOnScreen);
238             assertEquals(locationOnScreen[0] /* expected x */, windowMetricsBounds.left);
239             assertEquals(locationOnScreen[1] /* expected y */, windowMetricsBounds.top);
240         }
241     }
242 }
243