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