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