1 /* 2 * Copyright (C) 2019 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.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 20 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; 21 import static android.view.Surface.ROTATION_0; 22 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM; 23 24 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; 25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; 26 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; 27 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 28 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 29 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 30 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 32 33 import android.annotation.NonNull; 34 import android.annotation.Nullable; 35 import android.content.res.Configuration; 36 import android.graphics.Insets; 37 import android.graphics.Rect; 38 import android.hardware.display.DisplayManagerGlobal; 39 import android.view.Display; 40 import android.view.DisplayCutout; 41 import android.view.DisplayInfo; 42 43 import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry; 44 45 class TestDisplayContent extends DisplayContent { 46 47 public static final int DEFAULT_LOGICAL_DISPLAY_DENSITY = 300; 48 49 /** Please use the {@link Builder} to create, visible for use in test builder overrides only. */ TestDisplayContent(RootWindowContainer rootWindowContainer, Display display, @NonNull DeviceStateController deviceStateController)50 TestDisplayContent(RootWindowContainer rootWindowContainer, Display display, 51 @NonNull DeviceStateController deviceStateController) { 52 super(display, rootWindowContainer, deviceStateController); 53 // Normally this comes from display-properties as exposed by WM. Without that, just 54 // hard-code to FULLSCREEN for tests. 55 setWindowingMode(WINDOWING_MODE_FULLSCREEN); 56 spyOn(this); 57 forAllTaskDisplayAreas(taskDisplayArea -> { 58 spyOn(taskDisplayArea); 59 }); 60 final DisplayRotation displayRotation = getDisplayRotation(); 61 spyOn(displayRotation); 62 doAnswer(invocation -> { 63 // Bypass all the rotation animation and display freezing stuff for testing and just 64 // set the rotation we want for the display 65 final int oldRotation = displayRotation.getRotation(); 66 final int rotation = displayRotation.rotationForOrientation( 67 displayRotation.getLastOrientation(), oldRotation); 68 if (oldRotation == rotation) { 69 return false; 70 } 71 setLayoutNeeded(); 72 displayRotation.setRotation(rotation); 73 return true; 74 }).when(displayRotation).updateRotationUnchecked(anyBoolean()); 75 76 final InputMonitor inputMonitor = getInputMonitor(); 77 spyOn(inputMonitor); 78 doNothing().when(inputMonitor).resumeDispatchingLw(any()); 79 80 final InsetsPolicy insetsPolicy = getInsetsPolicy(); 81 WindowTestsBase.suppressInsetsAnimation(insetsPolicy.getPermanentControlTarget()); 82 WindowTestsBase.suppressInsetsAnimation(insetsPolicy.getTransientControlTarget()); 83 84 // For devices that set the sysprop ro.bootanim.set_orientation_<display_id> 85 // See DisplayRotation#readDefaultDisplayRotation for context. 86 // Without that, meaning of height and width in context of the tests can be swapped if 87 // the default rotation is 90 or 270. 88 displayRotation.setRotation(ROTATION_0); 89 } 90 91 public static class Builder { 92 private final DisplayInfo mInfo; 93 private boolean mCanRotate = true; 94 private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; 95 private int mPosition = POSITION_BOTTOM; 96 protected final ActivityTaskManagerService mService; 97 private boolean mSystemDecorations = false; 98 private int mStatusBarHeight = 0; 99 private SettingsEntry mOverrideSettings; 100 @NonNull 101 private DeviceStateController mDeviceStateController = mock(DeviceStateController.class); 102 Builder(ActivityTaskManagerService service, int width, int height)103 Builder(ActivityTaskManagerService service, int width, int height) { 104 mService = service; 105 mInfo = new DisplayInfo(); 106 mService.mContext.getDisplay().getDisplayInfo(mInfo); 107 mInfo.logicalWidth = width; 108 mInfo.logicalHeight = height; 109 mInfo.logicalDensityDpi = DEFAULT_LOGICAL_DISPLAY_DENSITY; 110 mInfo.displayCutout = null; 111 // Set unique ID so physical display overrides are not inheritted from 112 // DisplayWindowSettings. 113 mInfo.uniqueId = generateUniqueId(); 114 } Builder(ActivityTaskManagerService service, DisplayInfo info)115 Builder(ActivityTaskManagerService service, DisplayInfo info) { 116 mService = service; 117 mInfo = info; 118 // Set unique ID so physical display overrides are not inheritted from 119 // DisplayWindowSettings. 120 mInfo.uniqueId = generateUniqueId(); 121 } generateUniqueId()122 private String generateUniqueId() { 123 return "TEST_DISPLAY_CONTENT_" + System.currentTimeMillis(); 124 } setOverrideSettings(@ullable SettingsEntry overrideSettings)125 Builder setOverrideSettings(@Nullable SettingsEntry overrideSettings) { 126 mOverrideSettings = overrideSettings; 127 return this; 128 } setSystemDecorations(boolean yes)129 Builder setSystemDecorations(boolean yes) { 130 mSystemDecorations = yes; 131 return this; 132 } setPosition(int position)133 Builder setPosition(int position) { 134 mPosition = position; 135 return this; 136 } setUniqueId(String uniqueId)137 Builder setUniqueId(String uniqueId) { 138 mInfo.uniqueId = uniqueId; 139 return this; 140 } setType(int type)141 Builder setType(int type) { 142 mInfo.type = type; 143 return this; 144 } setOwnerUid(int ownerUid)145 Builder setOwnerUid(int ownerUid) { 146 mInfo.ownerUid = ownerUid; 147 return this; 148 } setCutout(int left, int top, int right, int bottom)149 Builder setCutout(int left, int top, int right, int bottom) { 150 final int cutoutFillerSize = 80; 151 Rect boundLeft = left != 0 ? new Rect(0, 0, left, cutoutFillerSize) : null; 152 Rect boundTop = top != 0 ? new Rect(0, 0, cutoutFillerSize, top) : null; 153 Rect boundRight = right != 0 ? new Rect(mInfo.logicalWidth - right, 0, 154 mInfo.logicalWidth, cutoutFillerSize) : null; 155 Rect boundBottom = bottom != 0 156 ? new Rect(0, mInfo.logicalHeight - bottom, cutoutFillerSize, 157 mInfo.logicalHeight) : null; 158 159 mInfo.displayCutout = new DisplayCutout( 160 Insets.of(left, top, right, bottom), 161 boundLeft, boundTop, boundRight, boundBottom); 162 return this; 163 } setNotch(int height)164 Builder setNotch(int height) { 165 return setCutout(0, height, 0, 0); 166 } setStatusBarHeight(int height)167 Builder setStatusBarHeight(int height) { 168 mStatusBarHeight = height; 169 return this; 170 } setCanRotate(boolean canRotate)171 Builder setCanRotate(boolean canRotate) { 172 mCanRotate = canRotate; 173 return this; 174 } setWindowingMode(int windowingMode)175 Builder setWindowingMode(int windowingMode) { 176 mWindowingMode = windowingMode; 177 return this; 178 } setDensityDpi(int dpi)179 Builder setDensityDpi(int dpi) { 180 mInfo.logicalDensityDpi = dpi; 181 return this; 182 } 183 setDeviceStateController(@onNull DeviceStateController deviceStateController)184 Builder setDeviceStateController(@NonNull DeviceStateController deviceStateController) { 185 mDeviceStateController = deviceStateController; 186 return this; 187 } createInternal(Display display)188 TestDisplayContent createInternal(Display display) { 189 return new TestDisplayContent(mService.mRootWindowContainer, display, 190 mDeviceStateController); 191 } build()192 TestDisplayContent build() { 193 SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock); 194 195 if (mOverrideSettings != null) { 196 mService.mWindowManager.mDisplayWindowSettingsProvider 197 .updateOverrideSettings(mInfo, mOverrideSettings); 198 } 199 200 final int displayId = SystemServicesTestRule.sNextDisplayId++; 201 mInfo.displayId = displayId; 202 final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, 203 mInfo, DEFAULT_DISPLAY_ADJUSTMENTS); 204 final TestDisplayContent newDisplay = createInternal(display); 205 // disable the normal system decorations 206 final DisplayPolicy displayPolicy = newDisplay.getDisplayPolicy(); 207 spyOn(displayPolicy); 208 if (mSystemDecorations) { 209 doReturn(true).when(newDisplay).supportsSystemDecorations(); 210 doReturn(true).when(displayPolicy).hasNavigationBar(); 211 doReturn(NAV_BAR_BOTTOM).when(displayPolicy).navigationBarPosition(anyInt()); 212 } else { 213 doReturn(false).when(displayPolicy).hasNavigationBar(); 214 doReturn(false).when(displayPolicy).hasStatusBar(); 215 doReturn(false).when(newDisplay).supportsSystemDecorations(); 216 } 217 // Update the display policy to make the screen fully turned on so animation is allowed 218 displayPolicy.screenTurningOn(null /* screenOnListener */); 219 displayPolicy.finishKeyguardDrawn(); 220 displayPolicy.finishWindowsDrawn(); 221 displayPolicy.finishScreenTurningOn(); 222 if (mStatusBarHeight > 0) { 223 doReturn(true).when(displayPolicy).hasStatusBar(); 224 } 225 Configuration c = new Configuration(); 226 newDisplay.computeScreenConfiguration(c); 227 c.windowConfiguration.setWindowingMode(mWindowingMode); 228 newDisplay.onRequestedOverrideConfigurationChanged(c); 229 if (!mCanRotate) { 230 final DisplayRotation displayRotation = newDisplay.getDisplayRotation(); 231 doReturn(true).when(displayRotation).isFixedToUserRotation(); 232 } 233 // Please add stubbing before this line. Services will start using this display in other 234 // threads immediately after adding it to hierarchy. Calling doAnswer() type of stubbing 235 // reduces chance of races, but still doesn't eliminate race conditions. 236 mService.mRootWindowContainer.addChild(newDisplay, mPosition); 237 238 // Set the default focused TDA. 239 newDisplay.onLastFocusedTaskDisplayAreaChanged(newDisplay.getDefaultTaskDisplayArea()); 240 241 return newDisplay; 242 } 243 } 244 } 245