1 /* 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 17 package com.android.server.wm; 18 19 import static android.view.Surface.ROTATION_0; 20 import static android.view.Surface.ROTATION_90; 21 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; 22 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; 23 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; 24 25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 26 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 27 28 import static org.junit.Assert.assertEquals; 29 import static org.junit.Assert.assertTrue; 30 import static org.mockito.ArgumentMatchers.eq; 31 import static org.mockito.Mockito.doNothing; 32 import static org.mockito.Mockito.spy; 33 34 import android.graphics.Rect; 35 import android.os.Binder; 36 import android.platform.test.annotations.Presubmit; 37 import android.util.SparseArray; 38 import android.view.DisplayInfo; 39 import android.view.InsetsFrameProvider; 40 import android.view.InsetsSource; 41 import android.view.InsetsState; 42 import android.view.PrivacyIndicatorBounds; 43 import android.view.RoundedCorners; 44 import android.view.WindowInsets; 45 46 import androidx.test.filters.SmallTest; 47 48 import org.junit.Before; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 52 import java.io.PrintWriter; 53 import java.io.StringWriter; 54 55 /** 56 * Tests for the {@link DisplayPolicy} class. 57 * 58 * Build/Install/Run: 59 * atest WmTests:DisplayPolicyLayoutTests 60 */ 61 @SmallTest 62 @Presubmit 63 @WindowTestsBase.SetupWindows( 64 addWindows = { WindowTestsBase.W_STATUS_BAR, WindowTestsBase.W_NAVIGATION_BAR }) 65 @RunWith(WindowTestRunner.class) 66 public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { 67 68 private DisplayFrames mFrames; 69 private WindowState mWindow; 70 private int mRotation = ROTATION_0; 71 private boolean mHasDisplayCutout; 72 private boolean mIsLongEdgeDisplayCutout; 73 private boolean mHasRoundedCorners; 74 75 private final Rect mDisplayBounds = new Rect(); 76 77 @Before setUp()78 public void setUp() throws Exception { 79 mWindow = spy(createWindow(null, TYPE_APPLICATION, "window")); 80 81 spyOn(mStatusBarWindow); 82 spyOn(mNavBarWindow); 83 84 // Disabling this call for most tests since it can override the systemUiFlags when called. 85 doNothing().when(mDisplayPolicy).updateSystemBarAttributes(); 86 87 updateDisplayFrames(); 88 } 89 setRotation(int rotation, boolean includingWindows)90 public void setRotation(int rotation, boolean includingWindows) { 91 mRotation = rotation; 92 updateDisplayFrames(); 93 if (includingWindows) { 94 mNavBarWindow.getWindowConfiguration().setRotation(rotation); 95 mStatusBarWindow.getWindowConfiguration().setRotation(rotation); 96 mWindow.getWindowConfiguration().setRotation(rotation); 97 } 98 } 99 addDisplayCutout()100 public void addDisplayCutout() { 101 mHasDisplayCutout = true; 102 updateDisplayFrames(); 103 } 104 addLongEdgeDisplayCutout()105 public void addLongEdgeDisplayCutout() { 106 mHasDisplayCutout = true; 107 mIsLongEdgeDisplayCutout = true; 108 updateDisplayFrames(); 109 } 110 addRoundedCorners()111 public void addRoundedCorners() { 112 mHasRoundedCorners = true; 113 updateDisplayFrames(); 114 } 115 updateDisplayFrames()116 private void updateDisplayFrames() { 117 mFrames = createDisplayFrames( 118 mDisplayContent.getInsetsStateController().getRawInsetsState()); 119 mDisplayBounds.set(0, 0, mFrames.mWidth, mFrames.mHeight); 120 mDisplayContent.mDisplayFrames = mFrames; 121 mDisplayContent.setBounds(mDisplayBounds); 122 mDisplayPolicy.layoutWindowLw(mNavBarWindow, null, mFrames); 123 mDisplayPolicy.layoutWindowLw(mStatusBarWindow, null, mFrames); 124 } 125 createDisplayFrames(InsetsState insetsState)126 private DisplayFrames createDisplayFrames(InsetsState insetsState) { 127 final DisplayInfo info = displayInfoAndCutoutForRotation(mRotation, 128 mHasDisplayCutout, mIsLongEdgeDisplayCutout); 129 final RoundedCorners roundedCorners = mHasRoundedCorners 130 ? mDisplayContent.calculateRoundedCornersForRotation(mRotation) 131 : RoundedCorners.NO_ROUNDED_CORNERS; 132 return new DisplayFrames(insetsState, info, info.displayCutout, roundedCorners, 133 new PrivacyIndicatorBounds(), info.displayShape); 134 } 135 136 @Test addingWindow_doesNotTamperWithSysuiFlags()137 public void addingWindow_doesNotTamperWithSysuiFlags() { 138 mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; 139 addWindow(mWindow); 140 141 assertEquals(0, mWindow.mAttrs.systemUiVisibility); 142 assertEquals(0, mWindow.mAttrs.subtreeSystemUiVisibility); 143 } 144 145 @Test addingWindow_withInsetsTypes()146 public void addingWindow_withInsetsTypes() { 147 mDisplayPolicy.removeWindowLw(mStatusBarWindow); // Removes the existing one. 148 149 final WindowState win = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "statusBar"); 150 final Binder owner = new Binder(); 151 win.mAttrs.providedInsets = new InsetsFrameProvider[] { 152 new InsetsFrameProvider(owner, 0, WindowInsets.Type.statusBars()), 153 new InsetsFrameProvider(owner, 0, WindowInsets.Type.systemGestures()) 154 }; 155 addWindow(win); 156 win.getFrame().set(0, 0, 500, 100); 157 win.updateSourceFrame(win.getFrame()); 158 mDisplayContent.getInsetsStateController().onPostLayout(); 159 160 assertTrue(win.hasInsetsSourceProvider()); 161 final SparseArray<InsetsSourceProvider> providers = win.getInsetsSourceProviders(); 162 for (int i = providers.size() - 1; i >= 0; i--) { 163 final InsetsSourceProvider provider = providers.valueAt(i); 164 assertEquals(new Rect(0, 0, 500, 100), provider.getSource().getFrame()); 165 } 166 } 167 168 /** 169 * Verify that {@link DisplayPolicy#simulateLayoutDisplay} outputs the same display frames as 170 * the real one. 171 */ 172 @Test testSimulateLayoutDisplay()173 public void testSimulateLayoutDisplay() { 174 assertSimulateLayoutSameDisplayFrames(); 175 setRotation(ROTATION_90, false /* includingWindows */); 176 assertSimulateLayoutSameDisplayFrames(); 177 addDisplayCutout(); 178 assertSimulateLayoutSameDisplayFrames(); 179 addRoundedCorners(); 180 assertSimulateLayoutSameDisplayFrames(); 181 } 182 assertSimulateLayoutSameDisplayFrames()183 private void assertSimulateLayoutSameDisplayFrames() { 184 final String prefix = ""; 185 final InsetsState simulatedInsetsState = new InsetsState(); 186 final DisplayFrames simulatedDisplayFrames = createDisplayFrames(simulatedInsetsState); 187 // Force the display bounds because it is not synced with display frames in policy test. 188 mDisplayContent.getWindowConfiguration().setBounds(mFrames.mUnrestricted); 189 mDisplayContent.getInsetsStateController().onPostLayout(); 190 mDisplayPolicy.simulateLayoutDisplay(simulatedDisplayFrames); 191 192 final StringWriter realFramesDump = new StringWriter(); 193 mFrames.dump(prefix, new PrintWriter(realFramesDump)); 194 final StringWriter simulatedFramesDump = new StringWriter(); 195 simulatedDisplayFrames.dump(prefix, new PrintWriter(simulatedFramesDump)); 196 197 assertEquals(new ToStringComparatorWrapper<>(realFramesDump), 198 new ToStringComparatorWrapper<>(simulatedFramesDump)); 199 200 final InsetsState realInsetsState = new InsetsState( 201 mDisplayContent.getInsetsStateController().getRawInsetsState()); 202 // Exclude comparing IME insets because currently the simulated layout only focuses on the 203 // insets from status bar and navigation bar. 204 realInsetsState.removeSource(InsetsSource.ID_IME); 205 206 assertEquals(new ToStringComparatorWrapper<>(realInsetsState), 207 new ToStringComparatorWrapper<>(simulatedInsetsState)); 208 } 209 210 @Test testFixedRotationInsetsSourceFrame()211 public void testFixedRotationInsetsSourceFrame() { 212 mDisplayContent.mBaseDisplayHeight = DISPLAY_HEIGHT; 213 mDisplayContent.mBaseDisplayWidth = DISPLAY_WIDTH; 214 doReturn((mDisplayContent.getRotation() + 1) % 4).when(mDisplayContent) 215 .rotationForActivityInDifferentOrientation(eq(mWindow.mActivityRecord)); 216 mWindow.mAboveInsetsState.set( 217 mDisplayContent.getInsetsStateController().getRawInsetsState()); 218 final int statusBarId = mStatusBarWindow.getControllableInsetProvider().getSource().getId(); 219 final Rect frame = mWindow.getInsetsState().peekSource(statusBarId).getFrame(); 220 mDisplayContent.rotateInDifferentOrientationIfNeeded(mWindow.mActivityRecord); 221 final Rect rotatedFrame = mWindow.getInsetsState().peekSource(statusBarId).getFrame(); 222 223 assertEquals(DISPLAY_WIDTH, frame.width()); 224 assertEquals(DISPLAY_HEIGHT, rotatedFrame.width()); 225 } 226 } 227