xref: /aosp_15_r20/frameworks/base/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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