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.view.ViewGroup.LayoutParams.MATCH_PARENT; 20 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 21 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 22 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; 23 24 import static androidx.test.InstrumentationRegistry.getInstrumentation; 25 26 import static org.junit.Assert.assertEquals; 27 28 import android.graphics.Insets; 29 import android.graphics.Point; 30 import android.platform.test.annotations.Presubmit; 31 import android.view.Display; 32 import android.view.View; 33 import android.view.WindowInsets; 34 import android.view.WindowInsets.Side; 35 import android.view.WindowInsets.Type; 36 import android.view.WindowManager; 37 38 import androidx.test.filters.FlakyTest; 39 40 import com.android.compatibility.common.util.PollingCheck; 41 42 import org.junit.Ignore; 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 @FlakyTest(detail = "Promote once confirmed non-flaky") 53 @Presubmit 54 public class WindowInsetsLayoutTests extends WindowManagerTestBase { 55 56 private final static long TIMEOUT = 1000; // milliseconds 57 58 @Test testSetFitInsetsTypes()59 public void testSetFitInsetsTypes() { 60 final TestActivity activity = startActivity(TestActivity.class); 61 62 // Make sure the main window has been laid out. 63 final View mainWindowRoot = activity.getWindow().getDecorView(); 64 PollingCheck.waitFor(TIMEOUT, () -> mainWindowRoot.getWidth() > 0); 65 66 getInstrumentation().runOnMainSync(() -> { 67 activity.assertMatchDisplay(); 68 }); 69 70 testSetFitInsetsTypesInner(Type.statusBars(), activity, mainWindowRoot); 71 testSetFitInsetsTypesInner(Type.navigationBars(), activity, mainWindowRoot); 72 testSetFitInsetsTypesInner(Type.systemBars(), activity, mainWindowRoot); 73 } 74 testSetFitInsetsTypesInner( int types, TestActivity activity, View mainWindowRoot)75 private void testSetFitInsetsTypesInner( 76 int types, TestActivity activity, View mainWindowRoot) { 77 getInstrumentation().runOnMainSync(() -> { 78 activity.addChildWindow(types, Side.all(), false); 79 }); 80 81 // Make sure the child window has been laid out. 82 final View childWindowRoot = activity.getChildWindowRoot(); 83 PollingCheck.waitFor(TIMEOUT, () -> childWindowRoot.getWidth() > 0); 84 85 getInstrumentation().runOnMainSync(() -> { 86 final WindowInsets windowInsets = mainWindowRoot.getRootWindowInsets(); 87 final Insets insets = windowInsets.getInsets(types); 88 final int[] locationOnScreen = new int[2]; 89 childWindowRoot.getLocationOnScreen(locationOnScreen); 90 assertEquals(insets.left, locationOnScreen[0]); 91 assertEquals(insets.top, locationOnScreen[1]); 92 assertEquals(insets.right, 93 mainWindowRoot.getWidth() - locationOnScreen[0] - childWindowRoot.getWidth()); 94 assertEquals(insets.bottom, 95 mainWindowRoot.getHeight()- locationOnScreen[1] - childWindowRoot.getHeight()); 96 activity.removeChildWindow(); 97 }); 98 } 99 100 @Test testSetFitInsetsSides()101 public void testSetFitInsetsSides() { 102 final TestActivity activity = startActivity(TestActivity.class); 103 104 // Make sure the main window has been laid out. 105 final View mainWindowRoot = activity.getWindow().getDecorView(); 106 PollingCheck.waitFor(TIMEOUT, () -> mainWindowRoot.getWidth() > 0); 107 108 getInstrumentation().runOnMainSync(() -> { 109 activity.assertMatchDisplay(); 110 }); 111 112 testSetFitInsetsSidesInner(Side.LEFT, activity, mainWindowRoot); 113 testSetFitInsetsSidesInner(Side.TOP, activity, mainWindowRoot); 114 testSetFitInsetsSidesInner(Side.RIGHT, activity, mainWindowRoot); 115 testSetFitInsetsSidesInner(Side.BOTTOM, activity, mainWindowRoot); 116 } 117 testSetFitInsetsSidesInner( int sides, TestActivity activity, View mainWindowRoot)118 private void testSetFitInsetsSidesInner( 119 int sides, TestActivity activity, View mainWindowRoot) { 120 final int types = Type.systemBars(); 121 getInstrumentation().runOnMainSync(() -> { 122 activity.addChildWindow(types, sides, false); 123 }); 124 125 // Make sure the child window has been laid out. 126 final View childWindowRoot = activity.getChildWindowRoot(); 127 PollingCheck.waitFor(TIMEOUT, () -> childWindowRoot.getWidth() > 0); 128 129 getInstrumentation().runOnMainSync(() -> { 130 final WindowInsets windowInsets = mainWindowRoot.getRootWindowInsets(); 131 final Insets insets = windowInsets.getInsets(types); 132 final int[] locationOnScreen = new int[2]; 133 childWindowRoot.getLocationOnScreen(locationOnScreen); 134 assertEquals((sides & Side.LEFT) != 0 ? insets.left : 0, locationOnScreen[0]); 135 assertEquals((sides & Side.TOP) != 0 ? insets.top : 0, locationOnScreen[1]); 136 assertEquals((sides & Side.RIGHT) != 0 ? insets.right : 0, 137 mainWindowRoot.getWidth() - locationOnScreen[0] - childWindowRoot.getWidth()); 138 assertEquals((sides & Side.BOTTOM) != 0 ? insets.bottom : 0, 139 mainWindowRoot.getHeight()- locationOnScreen[1] - childWindowRoot.getHeight()); 140 activity.removeChildWindow(); 141 }); 142 } 143 144 @Test testSetFitInsetsIgnoringVisibility()145 public void testSetFitInsetsIgnoringVisibility() { 146 final TestActivity activity = startActivity(TestActivity.class); 147 148 // Make sure the main window has been laid out. 149 final View mainWindowRoot = activity.getWindow().getDecorView(); 150 PollingCheck.waitFor(TIMEOUT, () -> mainWindowRoot.getWidth() > 0); 151 152 final int types = Type.systemBars(); 153 final int sides = Side.all(); 154 final int[] locationAndSize1 = new int[4]; 155 final int[] locationAndSize2 = new int[4]; 156 157 getInstrumentation().runOnMainSync(() -> { 158 activity.assertMatchDisplay(); 159 activity.addChildWindow(types, sides, false); 160 }); 161 162 // Make sure the 1st child window has been laid out. 163 final View childWindowRoot1 = activity.getChildWindowRoot(); 164 PollingCheck.waitFor(TIMEOUT, () -> childWindowRoot1.getWidth() > 0); 165 166 getInstrumentation().runOnMainSync(() -> { 167 childWindowRoot1.getLocationOnScreen(locationAndSize1); 168 locationAndSize1[2] = childWindowRoot1.getWidth(); 169 locationAndSize1[3] = childWindowRoot1.getHeight(); 170 activity.removeChildWindow(); 171 172 mainWindowRoot.getWindowInsetsController().hide(types); 173 174 activity.addChildWindow(types, sides, true); 175 }); 176 177 // Make sure the 2nd child window has been laid out. 178 final View childWindowRoot2 = activity.getChildWindowRoot(); 179 PollingCheck.waitFor(TIMEOUT, () -> childWindowRoot2.getWidth() > 0); 180 181 getInstrumentation().runOnMainSync(() -> { 182 childWindowRoot2.getLocationOnScreen(locationAndSize2); 183 locationAndSize2[2] = childWindowRoot2.getWidth(); 184 locationAndSize2[3] = childWindowRoot2.getHeight(); 185 activity.removeChildWindow(); 186 }); 187 188 for (int i = 0; i < 4; i++) { 189 assertEquals(locationAndSize1[i], locationAndSize2[i]); 190 } 191 } 192 193 public static class TestActivity extends FocusableActivity { 194 195 private View mChildWindowRoot; 196 addChildWindow(int types, int sides, boolean ignoreVis)197 void addChildWindow(int types, int sides, boolean ignoreVis) { 198 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(); 199 attrs.type = TYPE_APPLICATION_PANEL; 200 attrs.width = MATCH_PARENT; 201 attrs.height = MATCH_PARENT; 202 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 203 attrs.flags = FLAG_NOT_FOCUSABLE; 204 attrs.setFitInsetsTypes(types); 205 attrs.setFitInsetsSides(sides); 206 attrs.setFitInsetsIgnoringVisibility(ignoreVis); 207 mChildWindowRoot = new View(this); 208 getWindowManager().addView(mChildWindowRoot, attrs); 209 } 210 removeChildWindow()211 void removeChildWindow() { 212 getWindowManager().removeViewImmediate(mChildWindowRoot); 213 } 214 getChildWindowRoot()215 View getChildWindowRoot() { 216 return mChildWindowRoot; 217 } 218 assertMatchDisplay()219 void assertMatchDisplay() { 220 final View rootView = getWindow().getDecorView(); 221 final Display display = rootView.getDisplay(); 222 final Point size = new Point(); 223 display.getRealSize(size); 224 assertEquals(size.x, rootView.getWidth()); 225 assertEquals(size.y, rootView.getHeight()); 226 final int[] locationOnScreen = new int[2]; 227 rootView.getLocationOnScreen(locationOnScreen); 228 assertEquals(0 /* expected x */, locationOnScreen[0]); 229 assertEquals(0 /* expected y */, locationOnScreen[1]); 230 } 231 } 232 } 233