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