1 /*
2  * Copyright (C) 2022 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_FREEFORM;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
23 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
24 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
25 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
26 
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.spy;
30 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
31 
32 import static org.junit.Assert.assertFalse;
33 import static org.junit.Assert.assertTrue;
34 
35 import android.platform.test.annotations.Presubmit;
36 import android.view.Surface;
37 import android.view.WindowInsets.Type;
38 
39 import androidx.test.filters.SmallTest;
40 
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 
45 /**
46  * Test class for {@link DisplayRotationImmersiveAppCompatPolicy}.
47  *
48  * Build/Install/Run:
49  *  atest WmTests:DisplayRotationImmersiveAppCompatPolicyTests
50  */
51 @SmallTest
52 @Presubmit
53 @RunWith(WindowTestRunner.class)
54 public class DisplayRotationImmersiveAppCompatPolicyTests extends WindowTestsBase {
55 
56     private DisplayRotationImmersiveAppCompatPolicy mPolicy;
57 
58     private LetterboxConfiguration mMockLetterboxConfiguration;
59     private ActivityRecord mMockActivityRecord;
60     private Task mMockTask;
61     private WindowState mMockWindowState;
62 
63     @Before
setUp()64     public void setUp() throws Exception {
65         mMockActivityRecord = mock(ActivityRecord.class);
66         mMockTask = mock(Task.class);
67         when(mMockTask.getWindowingMode()).thenReturn(WINDOWING_MODE_FULLSCREEN);
68         when(mMockActivityRecord.getTask()).thenReturn(mMockTask);
69         when(mMockActivityRecord.areBoundsLetterboxed()).thenReturn(false);
70         when(mMockActivityRecord.getRequestedConfigurationOrientation()).thenReturn(
71                 ORIENTATION_LANDSCAPE);
72         mMockWindowState = mock(WindowState.class);
73         when(mMockWindowState.getRequestedVisibleTypes()).thenReturn(0);
74         when(mMockActivityRecord.findMainWindow()).thenReturn(mMockWindowState);
75 
76         spy(mDisplayContent);
77         doReturn(mMockActivityRecord).when(mDisplayContent).topRunningActivity();
78         when(mDisplayContent.getIgnoreOrientationRequest()).thenReturn(true);
79 
80         mMockLetterboxConfiguration = mock(LetterboxConfiguration.class);
81         when(mMockLetterboxConfiguration.isDisplayRotationImmersiveAppCompatPolicyEnabled())
82                 .thenReturn(true);
83         when(mMockLetterboxConfiguration
84                 .isDisplayRotationImmersiveAppCompatPolicyEnabledAtBuildTime())
85                     .thenReturn(true);
86 
87         mPolicy = DisplayRotationImmersiveAppCompatPolicy.createIfNeeded(
88                 mMockLetterboxConfiguration, createDisplayRotationMock(),
89                 mDisplayContent);
90     }
91 
createDisplayRotationMock()92     private DisplayRotation createDisplayRotationMock() {
93         DisplayRotation mockDisplayRotation = mock(DisplayRotation.class);
94 
95         when(mockDisplayRotation.isAnyPortrait(Surface.ROTATION_0)).thenReturn(true);
96         when(mockDisplayRotation.isAnyPortrait(Surface.ROTATION_90)).thenReturn(false);
97         when(mockDisplayRotation.isAnyPortrait(Surface.ROTATION_180)).thenReturn(true);
98         when(mockDisplayRotation.isAnyPortrait(Surface.ROTATION_270)).thenReturn(false);
99         when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_0)).thenReturn(false);
100         when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_90)).thenReturn(true);
101         when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_180)).thenReturn(false);
102         when(mockDisplayRotation.isLandscapeOrSeascape(Surface.ROTATION_270)).thenReturn(true);
103 
104         return mockDisplayRotation;
105     }
106 
107     @Test
testIsRotationLockEnforced_landscapeActivity_lockedWhenRotatingToPortrait()108     public void testIsRotationLockEnforced_landscapeActivity_lockedWhenRotatingToPortrait() {
109         // Base case: App is optimal in Landscape.
110 
111         // ROTATION_* is the target display orientation counted from the natural display
112         // orientation. Outside of test environment, ROTATION_0 means that proposed display
113         // rotation is the natural device orientation.
114         // DisplayRotationImmersiveAppCompatPolicy assesses whether the proposed target
115         // orientation ROTATION_* is optimal for the top fullscreen activity or not.
116         // For instance, ROTATION_0 means portrait screen orientation (see
117         // createDisplayRotationMock) which isn't optimal for a landscape-only activity so
118         // we should show a rotation suggestion button instead of rotating directly.
119 
120         // Rotation to portrait
121         assertTrue(mPolicy.isRotationLockEnforced(Surface.ROTATION_0));
122         // Rotation to landscape
123         assertFalse(mPolicy.isRotationLockEnforced(Surface.ROTATION_90));
124         // Rotation to portrait
125         assertTrue(mPolicy.isRotationLockEnforced(Surface.ROTATION_180));
126         // Rotation to landscape
127         assertFalse(mPolicy.isRotationLockEnforced(Surface.ROTATION_270));
128     }
129 
130     @Test
testIsRotationLockEnforced_portraitActivity_lockedWhenRotatingToLandscape()131     public void testIsRotationLockEnforced_portraitActivity_lockedWhenRotatingToLandscape() {
132         when(mMockActivityRecord.getRequestedConfigurationOrientation()).thenReturn(
133                 ORIENTATION_PORTRAIT);
134 
135         // Rotation to portrait
136         assertFalse(mPolicy.isRotationLockEnforced(Surface.ROTATION_0));
137         // Rotation to landscape
138         assertTrue(mPolicy.isRotationLockEnforced(Surface.ROTATION_90));
139         // Rotation to portrait
140         assertFalse(mPolicy.isRotationLockEnforced(Surface.ROTATION_180));
141         // Rotation to landscape
142         assertTrue(mPolicy.isRotationLockEnforced(Surface.ROTATION_270));
143     }
144 
145     @Test
testIsRotationLockEnforced_responsiveActivity_lockNotEnforced()146     public void testIsRotationLockEnforced_responsiveActivity_lockNotEnforced() {
147         // Do not fix screen orientation
148         when(mMockActivityRecord.getRequestedConfigurationOrientation()).thenReturn(
149                 ORIENTATION_UNDEFINED);
150 
151         assertIsRotationLockEnforcedReturnsFalseForAllRotations();
152     }
153 
154     @Test
testIsRotationLockEnforced_statusBarVisible_lockNotEnforced()155     public void testIsRotationLockEnforced_statusBarVisible_lockNotEnforced() {
156         // Some system bars are visible
157         when(mMockWindowState.getRequestedVisibleTypes()).thenReturn(Type.statusBars());
158 
159         assertIsRotationLockEnforcedReturnsFalseForAllRotations();
160     }
161 
162     @Test
testIsRotationLockEnforced_navBarVisible_lockNotEnforced()163     public void testIsRotationLockEnforced_navBarVisible_lockNotEnforced() {
164         // Some system bars are visible
165         when(mMockWindowState.getRequestedVisibleTypes()).thenReturn(Type.navigationBars());
166 
167         assertIsRotationLockEnforcedReturnsFalseForAllRotations();
168     }
169 
170     @Test
testIsRotationLockEnforced_activityIsLetterboxed_lockNotEnforced()171     public void testIsRotationLockEnforced_activityIsLetterboxed_lockNotEnforced() {
172         // Activity is letterboxed
173         when(mMockActivityRecord.areBoundsLetterboxed()).thenReturn(true);
174 
175         assertIsRotationLockEnforcedReturnsFalseForAllRotations();
176     }
177 
178     @Test
testIsRotationLockEnforced_notFullscreen_lockNotEnforced()179     public void testIsRotationLockEnforced_notFullscreen_lockNotEnforced() {
180         when(mMockTask.getWindowingMode()).thenReturn(WINDOWING_MODE_MULTI_WINDOW);
181 
182         assertIsRotationLockEnforcedReturnsFalseForAllRotations();
183 
184         when(mMockTask.getWindowingMode()).thenReturn(WINDOWING_MODE_PINNED);
185 
186         assertIsRotationLockEnforcedReturnsFalseForAllRotations();
187 
188         when(mMockTask.getWindowingMode()).thenReturn(WINDOWING_MODE_FREEFORM);
189 
190         assertIsRotationLockEnforcedReturnsFalseForAllRotations();
191     }
192 
193     @Test
testIsRotationLockEnforced_ignoreOrientationRequestDisabled_lockNotEnforced()194     public void testIsRotationLockEnforced_ignoreOrientationRequestDisabled_lockNotEnforced() {
195         when(mDisplayContent.getIgnoreOrientationRequest()).thenReturn(false);
196 
197         assertIsRotationLockEnforcedReturnsFalseForAllRotations();
198     }
199 
200     @Test
testRotationChoiceEnforcedOnly_nullTopRunningActivity_lockNotEnforced()201     public void testRotationChoiceEnforcedOnly_nullTopRunningActivity_lockNotEnforced() {
202         when(mDisplayContent.topRunningActivity()).thenReturn(null);
203 
204         assertIsRotationLockEnforcedReturnsFalseForAllRotations();
205     }
206 
207     @Test
testRotationChoiceEnforcedOnly_featureFlagDisabled_lockNotEnforced()208     public void testRotationChoiceEnforcedOnly_featureFlagDisabled_lockNotEnforced() {
209         when(mMockLetterboxConfiguration.isDisplayRotationImmersiveAppCompatPolicyEnabled())
210                 .thenReturn(false);
211 
212         assertIsRotationLockEnforcedReturnsFalseForAllRotations();
213     }
214 
assertIsRotationLockEnforcedReturnsFalseForAllRotations()215     private void assertIsRotationLockEnforcedReturnsFalseForAllRotations() {
216         assertFalse(mPolicy.isRotationLockEnforced(Surface.ROTATION_0));
217         assertFalse(mPolicy.isRotationLockEnforced(Surface.ROTATION_90));
218         assertFalse(mPolicy.isRotationLockEnforced(Surface.ROTATION_180));
219         assertFalse(mPolicy.isRotationLockEnforced(Surface.ROTATION_270));
220     }
221 }
222