• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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