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 22 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; 23 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; 24 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; 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.spyOn; 29 30 import static org.mockito.ArgumentMatchers.any; 31 32 import android.content.res.Configuration; 33 import android.graphics.Insets; 34 import android.graphics.Rect; 35 import android.hardware.display.DisplayManagerGlobal; 36 import android.view.Display; 37 import android.view.DisplayCutout; 38 import android.view.DisplayInfo; 39 40 class TestDisplayContent extends DisplayContent { 41 42 public static final int DEFAULT_LOGICAL_DISPLAY_DENSITY = 300; 43 44 /** Please use the {@link Builder} to create, visible for use in test builder overrides only. */ TestDisplayContent(RootWindowContainer rootWindowContainer, Display display)45 TestDisplayContent(RootWindowContainer rootWindowContainer, Display display) { 46 super(display, rootWindowContainer); 47 // Normally this comes from display-properties as exposed by WM. Without that, just 48 // hard-code to FULLSCREEN for tests. 49 setWindowingMode(WINDOWING_MODE_FULLSCREEN); 50 spyOn(this); 51 forAllTaskDisplayAreas(taskDisplayArea -> { 52 spyOn(taskDisplayArea); 53 }); 54 final DisplayRotation displayRotation = getDisplayRotation(); 55 spyOn(displayRotation); 56 doAnswer(invocation -> { 57 // Bypass all the rotation animation and display freezing stuff for testing and just 58 // set the rotation we want for the display 59 final int oldRotation = displayRotation.getRotation(); 60 final int rotation = displayRotation.rotationForOrientation( 61 displayRotation.getLastOrientation(), oldRotation); 62 if (oldRotation == rotation) { 63 return false; 64 } 65 setLayoutNeeded(); 66 displayRotation.setRotation(rotation); 67 return true; 68 }).when(displayRotation).updateRotationUnchecked(anyBoolean()); 69 70 final InputMonitor inputMonitor = getInputMonitor(); 71 spyOn(inputMonitor); 72 doNothing().when(inputMonitor).resumeDispatchingLw(any()); 73 } 74 75 public static class Builder { 76 private final DisplayInfo mInfo; 77 private boolean mCanRotate = true; 78 private int mWindowingMode = WINDOWING_MODE_FULLSCREEN; 79 private int mPosition = POSITION_BOTTOM; 80 protected final ActivityTaskManagerService mService; 81 private boolean mSystemDecorations = false; 82 private int mStatusBarHeight = 0; 83 Builder(ActivityTaskManagerService service, int width, int height)84 Builder(ActivityTaskManagerService service, int width, int height) { 85 mService = service; 86 mInfo = new DisplayInfo(); 87 mService.mContext.getDisplay().getDisplayInfo(mInfo); 88 mInfo.logicalWidth = width; 89 mInfo.logicalHeight = height; 90 mInfo.logicalDensityDpi = DEFAULT_LOGICAL_DISPLAY_DENSITY; 91 mInfo.displayCutout = null; 92 // Set unique ID so physical display overrides are not inheritted from 93 // DisplayWindowSettings. 94 mInfo.uniqueId = generateUniqueId(); 95 } Builder(ActivityTaskManagerService service, DisplayInfo info)96 Builder(ActivityTaskManagerService service, DisplayInfo info) { 97 mService = service; 98 mInfo = info; 99 // Set unique ID so physical display overrides are not inheritted from 100 // DisplayWindowSettings. 101 mInfo.uniqueId = generateUniqueId(); 102 } generateUniqueId()103 private String generateUniqueId() { 104 return "TEST_DISPLAY_CONTENT_" + System.currentTimeMillis(); 105 } setSystemDecorations(boolean yes)106 Builder setSystemDecorations(boolean yes) { 107 mSystemDecorations = yes; 108 return this; 109 } setPosition(int position)110 Builder setPosition(int position) { 111 mPosition = position; 112 return this; 113 } setUniqueId(String uniqueId)114 Builder setUniqueId(String uniqueId) { 115 mInfo.uniqueId = uniqueId; 116 return this; 117 } setType(int type)118 Builder setType(int type) { 119 mInfo.type = type; 120 return this; 121 } setOwnerUid(int ownerUid)122 Builder setOwnerUid(int ownerUid) { 123 mInfo.ownerUid = ownerUid; 124 return this; 125 } setNotch(int height)126 Builder setNotch(int height) { 127 mInfo.displayCutout = new DisplayCutout( 128 Insets.of(0, height, 0, 0), null, new Rect(20, 0, 80, height), null, null); 129 return this; 130 } setStatusBarHeight(int height)131 Builder setStatusBarHeight(int height) { 132 mStatusBarHeight = height; 133 return this; 134 } setCanRotate(boolean canRotate)135 Builder setCanRotate(boolean canRotate) { 136 mCanRotate = canRotate; 137 return this; 138 } setWindowingMode(int windowingMode)139 Builder setWindowingMode(int windowingMode) { 140 mWindowingMode = windowingMode; 141 return this; 142 } setDensityDpi(int dpi)143 Builder setDensityDpi(int dpi) { 144 mInfo.logicalDensityDpi = dpi; 145 return this; 146 } createInternal(Display display)147 TestDisplayContent createInternal(Display display) { 148 return new TestDisplayContent(mService.mRootWindowContainer, display); 149 } build()150 TestDisplayContent build() { 151 SystemServicesTestRule.checkHoldsLock(mService.mGlobalLock); 152 153 final int displayId = SystemServicesTestRule.sNextDisplayId++; 154 final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, 155 mInfo, DEFAULT_DISPLAY_ADJUSTMENTS); 156 final TestDisplayContent newDisplay = createInternal(display); 157 // disable the normal system decorations 158 final DisplayPolicy displayPolicy = newDisplay.getDisplayPolicy(); 159 spyOn(displayPolicy); 160 if (mSystemDecorations) { 161 doReturn(true).when(newDisplay).supportsSystemDecorations(); 162 doReturn(true).when(displayPolicy).hasNavigationBar(); 163 } else { 164 doReturn(false).when(displayPolicy).hasNavigationBar(); 165 doReturn(false).when(displayPolicy).hasStatusBar(); 166 doReturn(false).when(newDisplay).supportsSystemDecorations(); 167 } 168 // Update the display policy to make the screen fully turned on so animation is allowed 169 displayPolicy.screenTurnedOn(null /* screenOnListener */); 170 displayPolicy.finishKeyguardDrawn(); 171 displayPolicy.finishWindowsDrawn(); 172 displayPolicy.finishScreenTurningOn(); 173 if (mStatusBarHeight > 0) { 174 doReturn(true).when(displayPolicy).hasStatusBar(); 175 doAnswer(invocation -> { 176 Rect inOutInsets = (Rect) invocation.getArgument(0); 177 inOutInsets.top = mStatusBarHeight; 178 return null; 179 }).when(displayPolicy).convertNonDecorInsetsToStableInsets(any(), anyInt()); 180 } 181 Configuration c = new Configuration(); 182 newDisplay.computeScreenConfiguration(c); 183 c.windowConfiguration.setWindowingMode(mWindowingMode); 184 newDisplay.onRequestedOverrideConfigurationChanged(c); 185 if (!mCanRotate) { 186 final DisplayRotation displayRotation = newDisplay.getDisplayRotation(); 187 doReturn(true).when(displayRotation).isFixedToUserRotation(); 188 } 189 // Please add stubbing before this line. Services will start using this display in other 190 // threads immediately after adding it to hierarchy. Calling doAnswer() type of stubbing 191 // reduces chance of races, but still doesn't eliminate race conditions. 192 mService.mRootWindowContainer.addChild(newDisplay, mPosition); 193 194 // Set the default focused TDA. 195 newDisplay.onLastFocusedTaskDisplayAreaChanged(newDisplay.getDefaultTaskDisplayArea()); 196 197 return newDisplay; 198 } 199 } 200 } 201