blob: 1d378020fa4f77d54e97d5a2679b1cdd6b1aa7ff [file] [log] [blame]
Adrian Roose1856fe2017-11-24 19:39:12 +01001/*
2 * Copyright (C) 2017 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
17package com.android.server.policy;
18
19import static android.view.Surface.ROTATION_0;
Adrian Roosdcc92ed2017-11-22 14:35:58 +010020import static android.view.Surface.ROTATION_180;
21import static android.view.Surface.ROTATION_270;
22import static android.view.Surface.ROTATION_90;
Adrian Roose1856fe2017-11-24 19:39:12 +010023import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
24import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
25import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
26
Adrian Roos30f53212018-01-05 16:14:34 +010027import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
28
Adrian Roose1856fe2017-11-24 19:39:12 +010029import static org.junit.Assert.assertEquals;
30import static org.mockito.Mockito.mock;
31
32import android.content.Context;
33import android.content.ContextWrapper;
34import android.content.pm.PackageManager;
35import android.content.res.Resources;
Adrian Roos30f53212018-01-05 16:14:34 +010036import android.graphics.Matrix;
37import android.graphics.Path;
Adrian Roose1856fe2017-11-24 19:39:12 +010038import android.graphics.PixelFormat;
39import android.graphics.Rect;
Jorim Jaggi60640512018-06-29 01:14:31 +020040import android.graphics.RectF;
Adrian Roose1856fe2017-11-24 19:39:12 +010041import android.os.IBinder;
42import android.os.UserHandle;
43import android.support.test.InstrumentationRegistry;
44import android.testing.TestableResources;
Adrian Roos6a4fa0e2018-03-05 19:50:16 +010045import android.util.Pair;
Adrian Roose1856fe2017-11-24 19:39:12 +010046import android.view.Display;
Adrian Roos30f53212018-01-05 16:14:34 +010047import android.view.DisplayCutout;
Adrian Roose1856fe2017-11-24 19:39:12 +010048import android.view.DisplayInfo;
49import android.view.Gravity;
50import android.view.View;
51import android.view.WindowManager;
52import android.view.WindowManagerGlobal;
53import android.view.accessibility.AccessibilityManager;
54import android.view.accessibility.IAccessibilityManager;
55
56import com.android.server.policy.keyguard.KeyguardServiceDelegate;
57import com.android.server.wm.DisplayFrames;
Adrian Roos6a4fa0e2018-03-05 19:50:16 +010058import com.android.server.wm.utils.WmDisplayCutout;
Adrian Roose1856fe2017-11-24 19:39:12 +010059
60import org.junit.Before;
61
62public class PhoneWindowManagerTestBase {
63 static final int DISPLAY_WIDTH = 500;
64 static final int DISPLAY_HEIGHT = 1000;
65
66 static final int STATUS_BAR_HEIGHT = 10;
67 static final int NAV_BAR_HEIGHT = 15;
Adrian Roosdcc92ed2017-11-22 14:35:58 +010068 static final int DISPLAY_CUTOUT_HEIGHT = 8;
Adrian Roose1856fe2017-11-24 19:39:12 +010069
70 TestablePhoneWindowManager mPolicy;
71 TestContextWrapper mContext;
72 DisplayFrames mFrames;
73
74 FakeWindowState mStatusBar;
75 FakeWindowState mNavigationBar;
Adrian Roos30f53212018-01-05 16:14:34 +010076 private boolean mHasDisplayCutout;
77 private int mRotation = ROTATION_0;
Adrian Roose1856fe2017-11-24 19:39:12 +010078
79 @Before
80 public void setUpBase() throws Exception {
81 mContext = new TestContextWrapper(InstrumentationRegistry.getTargetContext());
82 mContext.getResourceMocker().addOverride(
Adrian Roos22af6502018-02-22 16:57:08 +010083 com.android.internal.R.dimen.status_bar_height_portrait, STATUS_BAR_HEIGHT);
84 mContext.getResourceMocker().addOverride(
85 com.android.internal.R.dimen.status_bar_height_landscape, STATUS_BAR_HEIGHT);
Adrian Roose1856fe2017-11-24 19:39:12 +010086 mContext.getResourceMocker().addOverride(
87 com.android.internal.R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
88 mContext.getResourceMocker().addOverride(
89 com.android.internal.R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT);
90 mContext.getResourceMocker().addOverride(
91 com.android.internal.R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
92
93 mPolicy = TestablePhoneWindowManager.create(mContext);
94
Adrian Roos30f53212018-01-05 16:14:34 +010095 updateDisplayFrames();
Adrian Roosdcc92ed2017-11-22 14:35:58 +010096 }
97
98 public void setRotation(int rotation) {
Adrian Roos30f53212018-01-05 16:14:34 +010099 mRotation = rotation;
100 updateDisplayFrames();
101 }
102
103 private void updateDisplayFrames() {
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100104 Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation,
105 mHasDisplayCutout);
106 mFrames = new DisplayFrames(Display.DEFAULT_DISPLAY, info.first, info.second);
Adrian Roose1856fe2017-11-24 19:39:12 +0100107 }
108
109 public void addStatusBar() {
110 mStatusBar = new FakeWindowState();
111 mStatusBar.attrs = new WindowManager.LayoutParams(MATCH_PARENT, STATUS_BAR_HEIGHT,
112 TYPE_STATUS_BAR, 0 /* flags */, PixelFormat.TRANSLUCENT);
113 mStatusBar.attrs.gravity = Gravity.TOP;
114
115 mPolicy.addWindow(mStatusBar);
116 mPolicy.mLastSystemUiFlags |= View.STATUS_BAR_TRANSPARENT;
117 }
118
119 public void addNavigationBar() {
120 mNavigationBar = new FakeWindowState();
Adrian Roosdcc92ed2017-11-22 14:35:58 +0100121 mNavigationBar.attrs = new WindowManager.LayoutParams(MATCH_PARENT, NAV_BAR_HEIGHT,
Adrian Roose1856fe2017-11-24 19:39:12 +0100122 TYPE_NAVIGATION_BAR, 0 /* flags */, PixelFormat.TRANSLUCENT);
123 mNavigationBar.attrs.gravity = Gravity.BOTTOM;
124
125 mPolicy.addWindow(mNavigationBar);
126 mPolicy.mHasNavigationBar = true;
127 mPolicy.mLastSystemUiFlags |= View.NAVIGATION_BAR_TRANSPARENT;
128 }
129
Adrian Roosdcc92ed2017-11-22 14:35:58 +0100130 public void addDisplayCutout() {
Adrian Roos30f53212018-01-05 16:14:34 +0100131 mHasDisplayCutout = true;
132 updateDisplayFrames();
Adrian Roosdcc92ed2017-11-22 14:35:58 +0100133 }
134
Adrian Roose1856fe2017-11-24 19:39:12 +0100135 /** Asserts that {@code actual} is inset by the given amounts from the full display rect. */
136 public void assertInsetBy(Rect actual, int expectedInsetLeft, int expectedInsetTop,
137 int expectedInsetRight, int expectedInsetBottom) {
138 assertEquals(new Rect(expectedInsetLeft, expectedInsetTop,
Adrian Roosdcc92ed2017-11-22 14:35:58 +0100139 mFrames.mDisplayWidth - expectedInsetRight,
140 mFrames.mDisplayHeight - expectedInsetBottom), actual);
Adrian Roose1856fe2017-11-24 19:39:12 +0100141 }
142
143 /**
144 * Asserts that {@code actual} is inset by the given amounts from the full display rect.
145 *
146 * Convenience wrapper for when only the top and bottom inset are non-zero.
147 */
148 public void assertInsetByTopBottom(Rect actual, int expectedInsetTop, int expectedInsetBottom) {
149 assertInsetBy(actual, 0, expectedInsetTop, 0, expectedInsetBottom);
150 }
151
Adrian Roos11c25582018-02-19 18:06:36 +0100152 public static DisplayInfo displayInfoForRotation(int rotation, boolean withDisplayCutout) {
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100153 return displayInfoAndCutoutForRotation(rotation, withDisplayCutout).first;
154 }
155 public static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation,
156 boolean withDisplayCutout) {
Adrian Roos11c25582018-02-19 18:06:36 +0100157 DisplayInfo info = new DisplayInfo();
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100158 WmDisplayCutout cutout = null;
Adrian Roos11c25582018-02-19 18:06:36 +0100159
160 final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
161 info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
162 info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
163 info.rotation = rotation;
164 if (withDisplayCutout) {
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100165 cutout = WmDisplayCutout.computeSafeInsets(
166 displayCutoutForRotation(rotation), info.logicalWidth,
167 info.logicalHeight);
168 info.displayCutout = cutout.getDisplayCutout();
Adrian Roos11c25582018-02-19 18:06:36 +0100169 } else {
170 info.displayCutout = null;
171 }
Adrian Roos6a4fa0e2018-03-05 19:50:16 +0100172 return Pair.create(info, cutout);
Adrian Roos11c25582018-02-19 18:06:36 +0100173 }
174
175 private static DisplayCutout displayCutoutForRotation(int rotation) {
Jorim Jaggi60640512018-06-29 01:14:31 +0200176 RectF rectF = new RectF(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT);
Adrian Roos11c25582018-02-19 18:06:36 +0100177
178 Matrix m = new Matrix();
179 transformPhysicalToLogicalCoordinates(rotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, m);
Jorim Jaggi60640512018-06-29 01:14:31 +0200180 m.mapRect(rectF);
Adrian Roos11c25582018-02-19 18:06:36 +0100181
Jorim Jaggi60640512018-06-29 01:14:31 +0200182 return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top,
183 (int) rectF.right, (int) rectF.bottom);
Adrian Roos11c25582018-02-19 18:06:36 +0100184 }
185
Adrian Roose1856fe2017-11-24 19:39:12 +0100186 static class TestContextWrapper extends ContextWrapper {
187 private final TestableResources mResourceMocker;
188
189 public TestContextWrapper(Context targetContext) {
190 super(targetContext);
191 mResourceMocker = new TestableResources(targetContext.getResources());
192 }
193
194 @Override
195 public int checkPermission(String permission, int pid, int uid) {
196 return PackageManager.PERMISSION_GRANTED;
197 }
198
199 @Override
200 public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
201 return PackageManager.PERMISSION_GRANTED;
202 }
203
204 @Override
205 public Resources getResources() {
206 return mResourceMocker.getResources();
207 }
208
209 public TestableResources getResourceMocker() {
210 return mResourceMocker;
211 }
212 }
213
214 static class TestablePhoneWindowManager extends PhoneWindowManager {
215
216 public TestablePhoneWindowManager() {
217 }
218
219 @Override
220 void initializeHdmiState() {
221 // Do nothing.
222 }
223
224 @Override
225 Context getSystemUiContext() {
226 return mContext;
227 }
228
229 void addWindow(WindowState state) {
230 if (state instanceof FakeWindowState) {
231 ((FakeWindowState) state).surfaceLayer =
Adrian Roosc8045bf2018-03-29 19:41:30 +0200232 getWindowLayerFromTypeLw(state.getAttrs().type,
233 true /* canAddInternalSystemWindow */);
Adrian Roose1856fe2017-11-24 19:39:12 +0100234 }
235 adjustWindowParamsLw(state, state.getAttrs(), true /* hasStatusBarPermission */);
236 assertEquals(WindowManagerGlobal.ADD_OKAY, prepareAddWindowLw(state, state.getAttrs()));
237 }
238
239 public static TestablePhoneWindowManager create(Context context) {
240 TestablePhoneWindowManager[] policy = new TestablePhoneWindowManager[1];
241 InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
242 policy[0] = new TestablePhoneWindowManager();
243 policy[0].mContext = context;
244 policy[0].mKeyguardDelegate = mock(KeyguardServiceDelegate.class);
245 policy[0].mAccessibilityManager = new AccessibilityManager(context,
246 mock(IAccessibilityManager.class), UserHandle.USER_CURRENT);
247 policy[0].mSystemGestures = mock(SystemGesturesPointerEventListener.class);
Adrian Roosdcc92ed2017-11-22 14:35:58 +0100248 policy[0].mNavigationBarCanMove = true;
249 policy[0].mPortraitRotation = ROTATION_0;
250 policy[0].mLandscapeRotation = ROTATION_90;
251 policy[0].mUpsideDownRotation = ROTATION_180;
252 policy[0].mSeascapeRotation = ROTATION_270;
Adrian Roose1856fe2017-11-24 19:39:12 +0100253 policy[0].onConfigurationChanged();
254 });
255 return policy[0];
256 }
257 }
258}