1 /*
2  * Copyright (C) 2018 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.util.DisplayMetrics.DENSITY_DEFAULT;
20 import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM;
21 import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
22 import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT;
23 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
24 import static android.view.Surface.ROTATION_0;
25 import static android.view.Surface.ROTATION_180;
26 import static android.view.Surface.ROTATION_270;
27 import static android.view.Surface.ROTATION_90;
28 
29 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
30 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
31 import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
32 
33 import static org.junit.Assert.assertEquals;
34 import static org.mockito.ArgumentMatchers.anyInt;
35 
36 import android.content.Context;
37 import android.content.ContextWrapper;
38 import android.content.pm.PackageManager;
39 import android.content.res.Resources;
40 import android.graphics.Matrix;
41 import android.graphics.RectF;
42 import android.os.Binder;
43 import android.os.IBinder;
44 import android.testing.TestableResources;
45 import android.util.Pair;
46 import android.view.DisplayCutout;
47 import android.view.DisplayInfo;
48 import android.view.Gravity;
49 import android.view.WindowManagerGlobal;
50 
51 import com.android.internal.R;
52 import com.android.server.wm.utils.WmDisplayCutout;
53 
54 import org.junit.Before;
55 
56 public class DisplayPolicyTestsBase extends WindowTestsBase {
57 
58     static final int DISPLAY_WIDTH = 500;
59     static final int DISPLAY_HEIGHT = 1000;
60     static final int DISPLAY_DENSITY = 320;
61 
62     static final int DISPLAY_CUTOUT_HEIGHT = 8;
63     static final int IME_HEIGHT = 415;
64 
65     DisplayPolicy mDisplayPolicy;
66 
67     @Before
setUpDisplayPolicy()68     public void setUpDisplayPolicy() {
69         // Disable surface placement because it has no direct relation to layout policy and it also
70         // avoids some noises such as the display info is modified, screen frozen, config change.
71         mWm.mWindowPlacerLocked.deferLayout();
72 
73         mDisplayPolicy = mDisplayContent.getDisplayPolicy();
74         spyOn(mDisplayPolicy);
75 
76         final TestContextWrapper context = new TestContextWrapper(
77                 mDisplayPolicy.getContext(), mDisplayPolicy.getCurrentUserResources());
78         final TestableResources resources = context.getResourceMocker();
79         resources.addOverride(R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
80         resources.addOverride(R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT);
81         resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
82         resources.addOverride(R.dimen.navigation_bar_frame_height_landscape, NAV_BAR_HEIGHT);
83         resources.addOverride(R.dimen.navigation_bar_frame_height, NAV_BAR_HEIGHT);
84         doReturn(STATUS_BAR_HEIGHT).when(mDisplayPolicy).getStatusBarHeightForRotation(anyInt());
85         doReturn(resources.getResources()).when(mDisplayPolicy).getCurrentUserResources();
86         doReturn(true).when(mDisplayPolicy).hasNavigationBar();
87         doReturn(true).when(mDisplayPolicy).hasStatusBar();
88 
89         final int shortSizeDp =
90                 Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY;
91         final int longSizeDp =
92                 Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY;
93         mDisplayContent.getDisplayRotation().configure(
94                 DISPLAY_WIDTH, DISPLAY_HEIGHT, shortSizeDp, longSizeDp);
95         mDisplayPolicy.onConfigurationChanged();
96 
97         mStatusBarWindow.mAttrs.gravity = Gravity.TOP;
98         addWindow(mStatusBarWindow);
99 
100         mNavBarWindow.mAttrs.gravity = Gravity.BOTTOM;
101         addWindow(mNavBarWindow);
102 
103         // Update source frame and visibility of insets providers.
104         mDisplayContent.getInsetsStateController().onPostLayout();
105     }
106 
addWindow(WindowState win)107     void addWindow(WindowState win) {
108         mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs);
109         assertEquals(WindowManagerGlobal.ADD_OKAY, mDisplayPolicy.validateAddingWindowLw(
110                 win.mAttrs, Binder.getCallingPid(), Binder.getCallingUid()));
111         mDisplayPolicy.addWindowLw(win, win.mAttrs);
112         win.mHasSurface = true;
113     }
114 
displayInfoAndCutoutForRotation(int rotation, boolean withDisplayCutout, boolean isLongEdgeCutout)115     static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation,
116             boolean withDisplayCutout, boolean isLongEdgeCutout) {
117         final DisplayInfo info = new DisplayInfo();
118         WmDisplayCutout cutout = WmDisplayCutout.NO_CUTOUT;
119 
120         final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
121         info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
122         info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
123         info.rotation = rotation;
124         if (withDisplayCutout) {
125             cutout = WmDisplayCutout.computeSafeInsets(
126                     displayCutoutForRotation(rotation, isLongEdgeCutout), info.logicalWidth,
127                     info.logicalHeight);
128             info.displayCutout = cutout.getDisplayCutout();
129         } else {
130             info.displayCutout = null;
131         }
132         return Pair.create(info, cutout);
133     }
134 
displayCutoutForRotation(int rotation, boolean isLongEdgeCutout)135     private static DisplayCutout displayCutoutForRotation(int rotation, boolean isLongEdgeCutout) {
136         RectF rectF = new RectF();
137         if (isLongEdgeCutout) {
138             rectF.set(0, DISPLAY_HEIGHT / 4, DISPLAY_CUTOUT_HEIGHT, DISPLAY_HEIGHT * 3 / 4);
139         } else {
140             rectF.set(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT);
141         }
142 
143         final Matrix m = new Matrix();
144         transformPhysicalToLogicalCoordinates(rotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, m);
145         m.mapRect(rectF);
146 
147         int pos = -1;
148         switch (rotation) {
149             case ROTATION_0:
150                 pos = isLongEdgeCutout ? BOUNDS_POSITION_LEFT : BOUNDS_POSITION_TOP;
151                 break;
152             case ROTATION_90:
153                 pos = isLongEdgeCutout ? BOUNDS_POSITION_BOTTOM : BOUNDS_POSITION_LEFT;
154                 break;
155             case ROTATION_180:
156                 pos = isLongEdgeCutout ? BOUNDS_POSITION_RIGHT : BOUNDS_POSITION_BOTTOM;
157                 break;
158             case ROTATION_270:
159                 pos = isLongEdgeCutout ? BOUNDS_POSITION_TOP : BOUNDS_POSITION_RIGHT;
160                 break;
161         }
162 
163         return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top,
164                 (int) rectF.right, (int) rectF.bottom, pos);
165     }
166 
167     static class TestContextWrapper extends ContextWrapper {
168         private final TestableResources mResourceMocker;
169 
TestContextWrapper(Context targetContext, Resources targetResources)170         TestContextWrapper(Context targetContext, Resources targetResources) {
171             super(targetContext);
172             mResourceMocker = new TestableResources(targetResources);
173         }
174 
175         @Override
checkPermission(String permission, int pid, int uid)176         public int checkPermission(String permission, int pid, int uid) {
177             return PackageManager.PERMISSION_GRANTED;
178         }
179 
180         @Override
checkPermission(String permission, int pid, int uid, IBinder callerToken)181         public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
182             return PackageManager.PERMISSION_GRANTED;
183         }
184 
185         @Override
getResources()186         public Resources getResources() {
187             return mResourceMocker.getResources();
188         }
189 
getResourceMocker()190         TestableResources getResourceMocker() {
191             return mResourceMocker;
192         }
193     }
194 
195 }
196