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.util.DisplayMetrics.DENSITY_DEFAULT; 20 import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM; 21 import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT; 22 import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT; 23 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP; 24 import static android.view.Surface.ROTATION_0; 25 import static android.view.Surface.ROTATION_180; 26 import static android.view.Surface.ROTATION_270; 27 import static android.view.Surface.ROTATION_90; 28 29 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 30 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 31 import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates; 32 33 import static org.junit.Assert.assertEquals; 34 import static org.mockito.ArgumentMatchers.anyInt; 35 36 import android.content.Context; 37 import android.content.ContextWrapper; 38 import android.content.pm.PackageManager; 39 import android.content.res.Resources; 40 import android.graphics.Matrix; 41 import android.graphics.RectF; 42 import android.os.Binder; 43 import android.os.IBinder; 44 import android.testing.TestableResources; 45 import android.util.Pair; 46 import android.view.DisplayCutout; 47 import android.view.DisplayInfo; 48 import android.view.Gravity; 49 import android.view.WindowManagerGlobal; 50 51 import com.android.internal.R; 52 import com.android.server.wm.utils.WmDisplayCutout; 53 54 import org.junit.Before; 55 56 public class DisplayPolicyTestsBase extends WindowTestsBase { 57 58 static final int DISPLAY_WIDTH = 500; 59 static final int DISPLAY_HEIGHT = 1000; 60 static final int DISPLAY_DENSITY = 320; 61 62 static final int DISPLAY_CUTOUT_HEIGHT = 8; 63 static final int IME_HEIGHT = 415; 64 65 DisplayPolicy mDisplayPolicy; 66 67 @Before setUpDisplayPolicy()68 public void setUpDisplayPolicy() { 69 // Disable surface placement because it has no direct relation to layout policy and it also 70 // avoids some noises such as the display info is modified, screen frozen, config change. 71 mWm.mWindowPlacerLocked.deferLayout(); 72 73 mDisplayPolicy = mDisplayContent.getDisplayPolicy(); 74 spyOn(mDisplayPolicy); 75 76 final TestContextWrapper context = new TestContextWrapper( 77 mDisplayPolicy.getContext(), mDisplayPolicy.getCurrentUserResources()); 78 final TestableResources resources = context.getResourceMocker(); 79 resources.addOverride(R.dimen.navigation_bar_height, NAV_BAR_HEIGHT); 80 resources.addOverride(R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT); 81 resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT); 82 resources.addOverride(R.dimen.navigation_bar_frame_height_landscape, NAV_BAR_HEIGHT); 83 resources.addOverride(R.dimen.navigation_bar_frame_height, NAV_BAR_HEIGHT); 84 doReturn(STATUS_BAR_HEIGHT).when(mDisplayPolicy).getStatusBarHeightForRotation(anyInt()); 85 doReturn(resources.getResources()).when(mDisplayPolicy).getCurrentUserResources(); 86 doReturn(true).when(mDisplayPolicy).hasNavigationBar(); 87 doReturn(true).when(mDisplayPolicy).hasStatusBar(); 88 89 final int shortSizeDp = 90 Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY; 91 final int longSizeDp = 92 Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY; 93 mDisplayContent.getDisplayRotation().configure( 94 DISPLAY_WIDTH, DISPLAY_HEIGHT, shortSizeDp, longSizeDp); 95 mDisplayPolicy.onConfigurationChanged(); 96 97 mStatusBarWindow.mAttrs.gravity = Gravity.TOP; 98 addWindow(mStatusBarWindow); 99 100 mNavBarWindow.mAttrs.gravity = Gravity.BOTTOM; 101 addWindow(mNavBarWindow); 102 103 // Update source frame and visibility of insets providers. 104 mDisplayContent.getInsetsStateController().onPostLayout(); 105 } 106 addWindow(WindowState win)107 void addWindow(WindowState win) { 108 mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs); 109 assertEquals(WindowManagerGlobal.ADD_OKAY, mDisplayPolicy.validateAddingWindowLw( 110 win.mAttrs, Binder.getCallingPid(), Binder.getCallingUid())); 111 mDisplayPolicy.addWindowLw(win, win.mAttrs); 112 win.mHasSurface = true; 113 } 114 displayInfoAndCutoutForRotation(int rotation, boolean withDisplayCutout, boolean isLongEdgeCutout)115 static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation, 116 boolean withDisplayCutout, boolean isLongEdgeCutout) { 117 final DisplayInfo info = new DisplayInfo(); 118 WmDisplayCutout cutout = WmDisplayCutout.NO_CUTOUT; 119 120 final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270; 121 info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH; 122 info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT; 123 info.rotation = rotation; 124 if (withDisplayCutout) { 125 cutout = WmDisplayCutout.computeSafeInsets( 126 displayCutoutForRotation(rotation, isLongEdgeCutout), info.logicalWidth, 127 info.logicalHeight); 128 info.displayCutout = cutout.getDisplayCutout(); 129 } else { 130 info.displayCutout = null; 131 } 132 return Pair.create(info, cutout); 133 } 134 displayCutoutForRotation(int rotation, boolean isLongEdgeCutout)135 private static DisplayCutout displayCutoutForRotation(int rotation, boolean isLongEdgeCutout) { 136 RectF rectF = new RectF(); 137 if (isLongEdgeCutout) { 138 rectF.set(0, DISPLAY_HEIGHT / 4, DISPLAY_CUTOUT_HEIGHT, DISPLAY_HEIGHT * 3 / 4); 139 } else { 140 rectF.set(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT); 141 } 142 143 final Matrix m = new Matrix(); 144 transformPhysicalToLogicalCoordinates(rotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, m); 145 m.mapRect(rectF); 146 147 int pos = -1; 148 switch (rotation) { 149 case ROTATION_0: 150 pos = isLongEdgeCutout ? BOUNDS_POSITION_LEFT : BOUNDS_POSITION_TOP; 151 break; 152 case ROTATION_90: 153 pos = isLongEdgeCutout ? BOUNDS_POSITION_BOTTOM : BOUNDS_POSITION_LEFT; 154 break; 155 case ROTATION_180: 156 pos = isLongEdgeCutout ? BOUNDS_POSITION_RIGHT : BOUNDS_POSITION_BOTTOM; 157 break; 158 case ROTATION_270: 159 pos = isLongEdgeCutout ? BOUNDS_POSITION_TOP : BOUNDS_POSITION_RIGHT; 160 break; 161 } 162 163 return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top, 164 (int) rectF.right, (int) rectF.bottom, pos); 165 } 166 167 static class TestContextWrapper extends ContextWrapper { 168 private final TestableResources mResourceMocker; 169 TestContextWrapper(Context targetContext, Resources targetResources)170 TestContextWrapper(Context targetContext, Resources targetResources) { 171 super(targetContext); 172 mResourceMocker = new TestableResources(targetResources); 173 } 174 175 @Override checkPermission(String permission, int pid, int uid)176 public int checkPermission(String permission, int pid, int uid) { 177 return PackageManager.PERMISSION_GRANTED; 178 } 179 180 @Override checkPermission(String permission, int pid, int uid, IBinder callerToken)181 public int checkPermission(String permission, int pid, int uid, IBinder callerToken) { 182 return PackageManager.PERMISSION_GRANTED; 183 } 184 185 @Override getResources()186 public Resources getResources() { 187 return mResourceMocker.getResources(); 188 } 189 getResourceMocker()190 TestableResources getResourceMocker() { 191 return mResourceMocker; 192 } 193 } 194 195 } 196