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.view.Surface.ROTATION_0;
20 import static android.view.Surface.ROTATION_180;
21 import static android.view.Surface.ROTATION_270;
22 import static android.view.Surface.ROTATION_90;
23 
24 import static org.hamcrest.Matchers.equalTo;
25 
26 import android.graphics.Rect;
27 import android.platform.test.annotations.Presubmit;
28 import android.view.DisplayInfo;
29 
30 import androidx.test.filters.SmallTest;
31 
32 import org.junit.Rule;
33 import org.junit.Test;
34 import org.junit.rules.ErrorCollector;
35 import org.junit.runner.RunWith;
36 
37 @SmallTest
38 @Presubmit
39 @WindowTestsBase.SetupWindows(
40         addWindows = { WindowTestsBase.W_STATUS_BAR, WindowTestsBase.W_NAVIGATION_BAR })
41 @RunWith(WindowTestRunner.class)
42 public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase {
43 
44     @Rule
45     public final ErrorCollector mErrorCollector = new ErrorCollector();
46 
47     @Test
portrait()48     public void portrait() {
49         final DisplayInfo di = displayInfoForRotation(ROTATION_0, false /* withCutout */);
50 
51         verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
52         verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT);
53         verifyConsistency(di);
54     }
55 
56     @Test
portrait_withCutout()57     public void portrait_withCutout() {
58         final DisplayInfo di = displayInfoForRotation(ROTATION_0, true /* withCutout */);
59 
60         verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
61         verifyNonDecorInsets(di, 0, DISPLAY_CUTOUT_HEIGHT, 0, NAV_BAR_HEIGHT);
62         verifyConsistency(di);
63     }
64 
65     @Test
landscape()66     public void landscape() {
67         final DisplayInfo di = displayInfoForRotation(ROTATION_90, false /* withCutout */);
68 
69         if (mDisplayPolicy.navigationBarCanMove()) {
70             verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
71             verifyNonDecorInsets(di, 0, 0, NAV_BAR_HEIGHT, 0);
72         } else {
73             // if the navigation bar cannot move then it is always on the bottom
74             verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
75             verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT);
76         }
77         verifyConsistency(di);
78     }
79 
80     @Test
landscape_withCutout()81     public void landscape_withCutout() {
82         final DisplayInfo di = displayInfoForRotation(ROTATION_90, true /* withCutout */);
83 
84         if (mDisplayPolicy.navigationBarCanMove()) {
85             verifyStableInsets(di, DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
86             verifyNonDecorInsets(di, DISPLAY_CUTOUT_HEIGHT, 0, NAV_BAR_HEIGHT, 0);
87         } else {
88             // if the navigation bar cannot move then it is always on the bottom
89             verifyStableInsets(di, DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
90             verifyNonDecorInsets(di, DISPLAY_CUTOUT_HEIGHT, 0, 0, NAV_BAR_HEIGHT);
91         }
92         verifyConsistency(di);
93     }
94 
95     @Test
seascape()96     public void seascape() {
97         final DisplayInfo di = displayInfoForRotation(ROTATION_270, false /* withCutout */);
98 
99         if (mDisplayPolicy.navigationBarCanMove()) {
100             verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
101             verifyNonDecorInsets(di, NAV_BAR_HEIGHT, 0, 0, 0);
102         } else {
103             // if the navigation bar cannot move then it is always on the bottom
104             verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
105             verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT);
106         }
107         verifyConsistency(di);
108     }
109 
110     @Test
seascape_withCutout()111     public void seascape_withCutout() {
112         final DisplayInfo di = displayInfoForRotation(ROTATION_270, true /* withCutout */);
113 
114         if (mDisplayPolicy.navigationBarCanMove()) {
115             verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
116             verifyNonDecorInsets(di, NAV_BAR_HEIGHT, 0, DISPLAY_CUTOUT_HEIGHT, 0);
117         } else {
118             // if the navigation bar cannot move then it is always on the bottom
119             verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, NAV_BAR_HEIGHT);
120             verifyNonDecorInsets(di, 0, 0, DISPLAY_CUTOUT_HEIGHT, NAV_BAR_HEIGHT);
121         }
122         verifyConsistency(di);
123     }
124 
125     @Test
upsideDown()126     public void upsideDown() {
127         final DisplayInfo di = displayInfoForRotation(ROTATION_180, false /* withCutout */);
128 
129         verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
130         verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT);
131         verifyConsistency(di);
132     }
133 
134     @Test
upsideDown_withCutout()135     public void upsideDown_withCutout() {
136         final DisplayInfo di = displayInfoForRotation(ROTATION_180, true /* withCutout */);
137 
138         verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT);
139         verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT);
140         verifyConsistency(di);
141     }
142 
verifyStableInsets(DisplayInfo di, int left, int top, int right, int bottom)143     private void verifyStableInsets(DisplayInfo di, int left, int top,
144             int right, int bottom) {
145         mErrorCollector.checkThat("stableInsets", getStableInsets(di),
146                 equalTo(new Rect(left, top, right, bottom)));
147     }
148 
verifyNonDecorInsets(DisplayInfo di, int left, int top, int right, int bottom)149     private void verifyNonDecorInsets(DisplayInfo di, int left, int top,
150             int right, int bottom) {
151         mErrorCollector.checkThat("nonDecorInsets",
152                 getNonDecorInsets(di), equalTo(new Rect(left, top, right, bottom)));
153     }
154 
verifyConsistency(DisplayInfo di)155     private void verifyConsistency(DisplayInfo  di) {
156         final DisplayPolicy.DecorInsets.Info info = mDisplayPolicy.getDecorInsetsInfo(
157                 di.rotation, di.logicalWidth, di.logicalHeight);
158         verifyConsistency("configDisplay", di, info.mConfigInsets,
159                 info.mConfigFrame.width(), info.mConfigFrame.height());
160         verifyConsistency("nonDecorDisplay", di, info.mNonDecorInsets,
161                 info.mNonDecorFrame.width(), info.mNonDecorFrame.height());
162     }
163 
verifyConsistency(String what, DisplayInfo di, Rect insets, int width, int height)164     private void verifyConsistency(String what, DisplayInfo di, Rect insets, int width,
165             int height) {
166         mErrorCollector.checkThat(what + ":width", width,
167                 equalTo(di.logicalWidth - insets.left - insets.right));
168         mErrorCollector.checkThat(what + ":height", height,
169                 equalTo(di.logicalHeight - insets.top - insets.bottom));
170     }
171 
getStableInsets(DisplayInfo di)172     private Rect getStableInsets(DisplayInfo di) {
173         return mDisplayPolicy.getDecorInsetsInfo(
174                 di.rotation, di.logicalWidth, di.logicalHeight).mConfigInsets;
175     }
176 
getNonDecorInsets(DisplayInfo di)177     private Rect getNonDecorInsets(DisplayInfo di) {
178         return mDisplayPolicy.getDecorInsetsInfo(
179                 di.rotation, di.logicalWidth, di.logicalHeight).mNonDecorInsets;
180     }
181 
displayInfoForRotation(int rotation, boolean withDisplayCutout)182     private DisplayInfo displayInfoForRotation(int rotation, boolean withDisplayCutout) {
183         return displayInfoAndCutoutForRotation(
184                 rotation, withDisplayCutout, false /* isLongEdgeCutout */);
185     }
186 }
187