• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
22 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR;
24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
25 import static android.view.Display.DEFAULT_DISPLAY;
26 import static android.view.DisplayCutout.NO_CUTOUT;
27 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
28 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DISABLED;
29 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
30 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_IF_NO_AUTO_ROTATION;
31 
32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
33 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
34 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
35 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
36 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atMost;
37 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
38 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
39 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
40 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
43 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
44 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
45 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
46 
47 import static org.junit.Assert.assertEquals;
48 import static org.junit.Assert.assertFalse;
49 import static org.junit.Assert.assertTrue;
50 import static org.mockito.Mockito.clearInvocations;
51 
52 import android.app.WindowConfiguration;
53 import android.content.ContentResolver;
54 import android.content.Context;
55 import android.content.Intent;
56 import android.content.pm.ActivityInfo;
57 import android.content.pm.PackageManager;
58 import android.content.res.Resources;
59 import android.database.ContentObserver;
60 import android.hardware.Sensor;
61 import android.hardware.SensorEvent;
62 import android.hardware.SensorEventListener;
63 import android.hardware.SensorManager;
64 import android.hardware.devicestate.DeviceStateManager;
65 import android.os.Handler;
66 import android.os.IBinder;
67 import android.os.PowerManagerInternal;
68 import android.os.SystemClock;
69 import android.platform.test.annotations.Presubmit;
70 import android.provider.Settings;
71 import android.view.Display;
72 import android.view.DisplayAddress;
73 import android.view.IRotationWatcher;
74 import android.view.Surface;
75 import android.view.WindowManager;
76 
77 import androidx.annotation.Nullable;
78 import androidx.test.filters.SmallTest;
79 
80 import com.android.internal.R;
81 import com.android.internal.util.test.FakeSettingsProvider;
82 import com.android.server.UiThread;
83 import com.android.server.policy.WindowManagerPolicy;
84 import com.android.server.statusbar.StatusBarManagerInternal;
85 import com.android.server.testutils.OffsettableClock;
86 import com.android.server.testutils.TestHandler;
87 import com.android.server.wm.DisplayContent.FixedRotationTransitionListener;
88 
89 import org.junit.AfterClass;
90 import org.junit.Before;
91 import org.junit.BeforeClass;
92 import org.junit.Test;
93 import org.mockito.ArgumentCaptor;
94 
95 import java.lang.reflect.Constructor;
96 import java.lang.reflect.Field;
97 import java.lang.reflect.Method;
98 import java.util.Collections;
99 import java.util.concurrent.CountDownLatch;
100 import java.util.concurrent.TimeUnit;
101 import java.util.function.IntConsumer;
102 
103 /**
104  * Test class for {@link DisplayRotation}.
105  *
106  * Build/Install/Run:
107  *  atest WmTests:DisplayRotationTests
108  */
109 @SmallTest
110 @Presubmit
111 public class DisplayRotationTests {
112     private static final long UI_HANDLER_WAIT_TIMEOUT_MS = 50;
113 
114     private StatusBarManagerInternal mPreviousStatusBarManagerInternal;
115     private static final OffsettableClock sClock = new OffsettableClock.Stopped();
116     private static TestHandler sHandler;
117     private static long sCurrentUptimeMillis = 10_000;
118 
119     private static WindowManagerService sMockWm;
120     private DisplayContent mMockDisplayContent;
121     private DisplayRotationReversionController mMockDisplayRotationReversionController;
122     private DisplayPolicy mMockDisplayPolicy;
123     private DisplayAddress mMockDisplayAddress;
124     private Context mMockContext;
125     private Resources mMockRes;
126     private SensorManager mMockSensorManager;
127     private Sensor mFakeOrientationSensor;
128     private Sensor mFakeHingeAngleSensor;
129     private DisplayWindowSettings mMockDisplayWindowSettings;
130     private ContentResolver mMockResolver;
131     private FakeSettingsProvider mFakeSettingsProvider;
132     private StatusBarManagerInternal mMockStatusBarManagerInternal;
133     private DeviceStateManager mMockDeviceStateManager;
134 
135     // Fields below are callbacks captured from test target.
136     private ContentObserver mShowRotationSuggestionsObserver;
137     private ContentObserver mAccelerometerRotationObserver;
138     private ContentObserver mUserRotationObserver;
139     private SensorEventListener mOrientationSensorListener;
140 
141     ArgumentCaptor<SensorEventListener> mHingeAngleSensorListenerCaptor = ArgumentCaptor.forClass(
142             SensorEventListener.class);
143 
144     private DisplayRotationBuilder mBuilder;
145 
146     private DeviceStateController mDeviceStateController;
147     private TestDisplayRotation mTarget;
148     @Nullable
149     private DisplayRotationImmersiveAppCompatPolicy mDisplayRotationImmersiveAppCompatPolicyMock;
150 
151     @BeforeClass
setUpOnce()152     public static void setUpOnce() {
153         sMockWm = mock(WindowManagerService.class);
154         sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
155         sMockWm.mPolicy = mock(WindowManagerPolicy.class);
156         sHandler = new TestHandler(null, sClock);
157     }
158 
159     @AfterClass
tearDownOnce()160     public static void tearDownOnce() {
161         sMockWm = null;
162         // Make sure the fake settings are cleared after the last test method.
163         FakeSettingsProvider.clearSettingsProvider();
164     }
165 
166     @Before
setUp()167     public void setUp() {
168         FakeSettingsProvider.clearSettingsProvider();
169 
170         mDisplayRotationImmersiveAppCompatPolicyMock = null;
171         mBuilder = new DisplayRotationBuilder();
172     }
173 
174     // ================================
175     // Display Settings Related Tests
176     // ================================
177     @Test
testLocksUserRotation_LockRotation_DefaultDisplay()178     public void testLocksUserRotation_LockRotation_DefaultDisplay() throws Exception {
179         mBuilder.build();
180 
181         freezeRotation(Surface.ROTATION_180);
182 
183         assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, mTarget.getUserRotationMode());
184         assertEquals(Surface.ROTATION_180, mTarget.getUserRotation());
185 
186         assertEquals(0, Settings.System.getInt(mMockResolver,
187                 Settings.System.ACCELEROMETER_ROTATION));
188         assertEquals(Surface.ROTATION_180, Settings.System.getInt(mMockResolver,
189                 Settings.System.USER_ROTATION));
190     }
191 
192     @Test
testPersistsUserRotation_LockRotation_NonDefaultDisplay()193     public void testPersistsUserRotation_LockRotation_NonDefaultDisplay() throws Exception {
194         mBuilder.setIsDefaultDisplay(false).build();
195 
196         freezeRotation(Surface.ROTATION_180);
197 
198         assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, mTarget.getUserRotationMode());
199         assertEquals(Surface.ROTATION_180, mTarget.getUserRotation());
200 
201         verify(mMockDisplayWindowSettings).setUserRotation(mMockDisplayContent,
202                 WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_180);
203     }
204 
205     @Test
testUserRotationSystemProperty_NonDefault_InternalDisplay()206     public void testUserRotationSystemProperty_NonDefault_InternalDisplay() throws Exception {
207         mBuilder.setIsDefaultDisplay(false).build();
208         when(mMockDisplayContent.getDisplay().getType()).thenReturn(Display.TYPE_INTERNAL);
209         spyOn(mTarget);
210         when(mTarget.getDemoUserRotationOverride()).thenReturn(Surface.ROTATION_90);
211 
212         mTarget.restoreSettings(WindowManagerPolicy.USER_ROTATION_FREE, Surface.ROTATION_270,
213                 /*fixedToUserRotation=*/ 0);
214 
215         assertEquals(Surface.ROTATION_270, mTarget.getUserRotation());
216         assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, mTarget.getUserRotationMode());
217         assertEquals(0, mTarget.getFixedToUserRotationMode());
218     }
219 
220     @Test
testUserRotationSystemProperty_NonDefault_ExternalDisplay()221     public void testUserRotationSystemProperty_NonDefault_ExternalDisplay() throws Exception {
222         mBuilder.setIsDefaultDisplay(false).build();
223         when(mMockDisplayContent.getDisplay().getType()).thenReturn(Display.TYPE_EXTERNAL);
224         spyOn(mTarget);
225         when(mTarget.getDemoUserRotationOverride()).thenReturn(Surface.ROTATION_90);
226 
227         mTarget.restoreSettings(WindowManagerPolicy.USER_ROTATION_FREE, Surface.ROTATION_270,
228                 /*fixedToUserRotation=*/ 0);
229 
230         assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, mTarget.getUserRotationMode());
231         assertEquals(Surface.ROTATION_90, mTarget.getUserRotation());
232         assertEquals(0, mTarget.getFixedToUserRotationMode());
233     }
234 
235     @Test
testUserRotationSystemProperty_NonDefault_OverlayDisplay()236     public void testUserRotationSystemProperty_NonDefault_OverlayDisplay() throws Exception {
237         mBuilder.setIsDefaultDisplay(false).build();
238         when(mMockDisplayContent.getDisplay().getType()).thenReturn(Display.TYPE_OVERLAY);
239         spyOn(mTarget);
240         when(mTarget.getDemoUserRotationOverride()).thenReturn(Surface.ROTATION_90);
241 
242         mTarget.restoreSettings(WindowManagerPolicy.USER_ROTATION_FREE, Surface.ROTATION_270,
243                 /*fixedToUserRotation=*/ 0);
244 
245         assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, mTarget.getUserRotationMode());
246         assertEquals(Surface.ROTATION_90, mTarget.getUserRotation());
247         assertEquals(0, mTarget.getFixedToUserRotationMode());
248     }
249 
250     @Test
testUserRotationSystemProperty_NonDefault_VirtualDisplay()251     public void testUserRotationSystemProperty_NonDefault_VirtualDisplay() throws Exception {
252         mBuilder.setIsDefaultDisplay(false).build();
253         when(mMockDisplayContent.getDisplay().getType()).thenReturn(Display.TYPE_VIRTUAL);
254         final var packageName = "abc";
255         when(mMockDisplayContent.getDisplay().getOwnerPackageName()).thenReturn(packageName);
256         spyOn(mTarget);
257         when(mTarget.getDemoUserRotationOverride()).thenReturn(Surface.ROTATION_90);
258 
259         // Without package name
260         when(mTarget.getDemoUserRotationPackage()).thenReturn("");
261         mTarget.restoreSettings(WindowManagerPolicy.USER_ROTATION_FREE, Surface.ROTATION_270,
262                 /*fixedToUserRotation=*/ 0);
263 
264         assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, mTarget.getUserRotationMode());
265         assertEquals(Surface.ROTATION_270, mTarget.getUserRotation());
266         assertEquals(0, mTarget.getFixedToUserRotationMode());
267 
268         // Use package name
269         when(mTarget.getDemoUserRotationPackage()).thenReturn(packageName);
270         mTarget.restoreSettings(WindowManagerPolicy.USER_ROTATION_FREE, Surface.ROTATION_270,
271                 /*fixedToUserRotation=*/ 0);
272 
273         assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, mTarget.getUserRotation());
274         assertEquals(Surface.ROTATION_90, mTarget.getUserRotationMode());
275         assertEquals(0, mTarget.getFixedToUserRotationMode());
276     }
277 
278     @Test
testPersistUserRotation_UnlockRotation_DefaultDisplay()279     public void testPersistUserRotation_UnlockRotation_DefaultDisplay() throws Exception {
280         mBuilder.build();
281 
282         thawRotation();
283 
284         assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, mTarget.getUserRotationMode());
285 
286         assertEquals(1, Settings.System.getInt(mMockResolver,
287                 Settings.System.ACCELEROMETER_ROTATION));
288     }
289 
290     @Test
testPersistsUserRotation_UnlockRotation_NonDefaultDisplay()291     public void testPersistsUserRotation_UnlockRotation_NonDefaultDisplay() throws Exception {
292         mBuilder.setIsDefaultDisplay(false).build();
293 
294         thawRotation();
295 
296         assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, mTarget.getUserRotationMode());
297 
298         verify(mMockDisplayWindowSettings).setUserRotation(same(mMockDisplayContent),
299                 eq(WindowManagerPolicy.USER_ROTATION_FREE), anyInt());
300     }
301 
302     @Test
testPersistsFixedToUserRotation()303     public void testPersistsFixedToUserRotation() throws Exception {
304         mBuilder.build();
305 
306         mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
307 
308         verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent,
309                 FIXED_TO_USER_ROTATION_ENABLED);
310 
311         reset(mMockDisplayWindowSettings);
312         mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_DISABLED);
313 
314         verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent,
315                 FIXED_TO_USER_ROTATION_DISABLED);
316 
317         reset(mMockDisplayWindowSettings);
318         mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_DEFAULT);
319 
320         verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent,
321                 FIXED_TO_USER_ROTATION_DEFAULT);
322     }
323 
324     // ========================================
325     // Tests for User Rotation based Rotation
326     // ========================================
327     @Test
testReturnsUserRotation_UserRotationLocked_NoAppRequest()328     public void testReturnsUserRotation_UserRotationLocked_NoAppRequest()
329             throws Exception {
330         mBuilder.build();
331         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
332 
333         freezeRotation(Surface.ROTATION_180);
334 
335         assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation(
336                 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_90));
337     }
338 
339     @Test
testReturnsLandscape_UserRotationLockedSeascape_AppRequestsLandscape()340     public void testReturnsLandscape_UserRotationLockedSeascape_AppRequestsLandscape()
341             throws Exception {
342         mBuilder.build();
343         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */,
344                 false /* isTv */);
345 
346         freezeRotation(Surface.ROTATION_180);
347 
348         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
349                 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, Surface.ROTATION_90));
350     }
351 
352     @Test
testReturnsSeascape_UserRotationLockedSeascape_AppRequestsSeascape()353     public void testReturnsSeascape_UserRotationLockedSeascape_AppRequestsSeascape()
354             throws Exception {
355         mBuilder.build();
356         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */,
357                 false /* isTv */);
358 
359         freezeRotation(Surface.ROTATION_180);
360 
361         assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation(
362                 ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE, Surface.ROTATION_90));
363     }
364 
365     @Test
testReturnsPortrait_UserRotationLockedPortrait_AppRequestsPortrait()366     public void testReturnsPortrait_UserRotationLockedPortrait_AppRequestsPortrait()
367             throws Exception {
368         mBuilder.build();
369         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */,
370                 false /* isTv */);
371 
372         freezeRotation(Surface.ROTATION_270);
373 
374         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
375                 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, Surface.ROTATION_0));
376     }
377 
378     @Test
testReturnsUpsideDown_UserRotationLockedUpsideDown_AppRequestsUpsideDown()379     public void testReturnsUpsideDown_UserRotationLockedUpsideDown_AppRequestsUpsideDown()
380             throws Exception {
381         mBuilder.build();
382         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */,
383                 false /* isTv */);
384 
385         freezeRotation(Surface.ROTATION_90);
386 
387         assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
388                 ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, Surface.ROTATION_0));
389     }
390 
391     @Test
testReturnsSideways_UserRotationLocked_IncompatibleAppRequest()392     public void testReturnsSideways_UserRotationLocked_IncompatibleAppRequest()
393             throws Exception {
394         mBuilder.build();
395         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
396 
397         freezeRotation(Surface.ROTATION_180);
398 
399         final int rotation = mTarget.rotationForOrientation(
400                 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, Surface.ROTATION_90);
401         assertTrue("Rotation should be sideways, but it's "
402                         + Surface.rotationToString(rotation),
403                 rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
404     }
405 
406     // =================================
407     // Tests for Sensor based Rotation
408     // =================================
verifyOrientationListenerRegistration(int numOfInvocation)409     private void verifyOrientationListenerRegistration(int numOfInvocation) {
410         final ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass(
411                 SensorEventListener.class);
412         waitForUiHandler();
413         verify(mMockSensorManager, times(numOfInvocation)).registerListener(
414                 listenerCaptor.capture(),
415                 same(mFakeOrientationSensor),
416                 anyInt(),
417                 any());
418         if (numOfInvocation > 0) {
419             mOrientationSensorListener = listenerCaptor.getValue();
420         }
421     }
422 
423     @Test
testNotEnablesSensor_AutoRotationNotSupported()424     public void testNotEnablesSensor_AutoRotationNotSupported() throws Exception {
425         mBuilder.setSupportAutoRotation(false).build();
426         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
427 
428         thawRotation();
429 
430         when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
431         when(mMockDisplayPolicy.isAwake()).thenReturn(true);
432         when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
433         when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
434         mTarget.updateOrientationListener();
435         verifyOrientationListenerRegistration(0);
436     }
437 
438     @Test
testNotEnablesSensor_ScreenNotOn()439     public void testNotEnablesSensor_ScreenNotOn() throws Exception {
440         mBuilder.build();
441         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
442 
443         thawRotation();
444 
445         when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(false);
446         when(mMockDisplayPolicy.isAwake()).thenReturn(true);
447         when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
448         when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
449         mTarget.updateOrientationListener();
450         verifyOrientationListenerRegistration(0);
451     }
452 
453     @Test
testNotEnablesSensor_NotAwake()454     public void testNotEnablesSensor_NotAwake() throws Exception {
455         mBuilder.build();
456         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
457 
458         thawRotation();
459 
460         when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
461         when(mMockDisplayPolicy.isAwake()).thenReturn(false);
462         when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
463         when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
464         mTarget.updateOrientationListener();
465         verifyOrientationListenerRegistration(0);
466     }
467 
468     @Test
testNotEnablesSensor_KeyguardNotDrawnCompletely()469     public void testNotEnablesSensor_KeyguardNotDrawnCompletely() throws Exception {
470         mBuilder.build();
471         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
472 
473         thawRotation();
474 
475         when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
476         when(mMockDisplayPolicy.isAwake()).thenReturn(true);
477         when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(false);
478         when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
479         mTarget.updateOrientationListener();
480         verifyOrientationListenerRegistration(0);
481     }
482 
483     @Test
testNotEnablesSensor_WindowManagerNotDrawnCompletely()484     public void testNotEnablesSensor_WindowManagerNotDrawnCompletely() throws Exception {
485         mBuilder.build();
486         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
487 
488         thawRotation();
489 
490         when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
491         when(mMockDisplayPolicy.isAwake()).thenReturn(true);
492         when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
493         when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(false);
494         mTarget.updateOrientationListener();
495         verifyOrientationListenerRegistration(0);
496     }
497 
498     @Test
testNotEnablesSensor_FixedUserRotation()499     public void testNotEnablesSensor_FixedUserRotation() throws Exception {
500         mBuilder.build();
501         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
502 
503         when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
504         when(mMockDisplayPolicy.isAwake()).thenReturn(true);
505         when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
506         when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
507         mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
508         mTarget.updateOrientationListener();
509         verifyOrientationListenerRegistration(0);
510     }
511 
512     @Test
testNotEnablesSensor_ForceDefaultRotation_Car()513     public void testNotEnablesSensor_ForceDefaultRotation_Car() throws Exception {
514         mBuilder.build();
515         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, true, false);
516 
517         when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
518         when(mMockDisplayPolicy.isAwake()).thenReturn(true);
519         when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
520         when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
521         mTarget.updateOrientationListener();
522         verifyOrientationListenerRegistration(0);
523     }
524 
525     @Test
testNotEnablesSensor_ForceDefaultRotation_Tv()526     public void testNotEnablesSensor_ForceDefaultRotation_Tv() throws Exception {
527         mBuilder.build();
528         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, true);
529 
530         when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
531         when(mMockDisplayPolicy.isAwake()).thenReturn(true);
532         when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
533         when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
534         mTarget.updateOrientationListener();
535         verifyOrientationListenerRegistration(0);
536     }
537 
enableOrientationSensor()538     private void enableOrientationSensor() {
539         when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true);
540         when(mMockDisplayPolicy.isAwake()).thenReturn(true);
541         when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true);
542         when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true);
543         mTarget.updateOrientationListener();
544         verifyOrientationListenerRegistration(1);
545     }
546 
createSensorEvent(int rotation)547     private SensorEvent createSensorEvent(int rotation) throws Exception {
548         return createSensorEvent(mFakeOrientationSensor, rotation);
549     }
550 
createSensorEvent(Sensor sensor, int value)551     private SensorEvent createSensorEvent(Sensor sensor, int value) throws Exception {
552         final Constructor<SensorEvent> constructor =
553                 SensorEvent.class.getDeclaredConstructor(int.class);
554         constructor.setAccessible(true);
555         final SensorEvent event = constructor.newInstance(1);
556         event.sensor = sensor;
557         event.values[0] = value;
558         event.timestamp = SystemClock.elapsedRealtimeNanos();
559         return event;
560     }
561 
562     @Test
testReturnsSensorRotation_RotationThawed()563     public void testReturnsSensorRotation_RotationThawed() throws Exception {
564         mBuilder.build();
565         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
566 
567         thawRotation();
568 
569         enableOrientationSensor();
570 
571         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
572 
573         assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
574                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
575     }
576 
577     @Test
testReverseRotation()578     public void testReverseRotation() throws Exception {
579         mBuilder.build();
580         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
581 
582         when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis(mMockDisplayContent))
583                 .thenReturn(true);
584 
585         thawRotation();
586 
587         enableOrientationSensor();
588 
589         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
590         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
591                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
592 
593         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_270));
594         assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
595                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
596 
597         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
598         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
599                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
600 
601         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
602         assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation(
603                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_180));
604     }
605 
606     @Test
testFreezeRotation_reverseRotationDirectionAroundZAxis_yes()607     public void testFreezeRotation_reverseRotationDirectionAroundZAxis_yes() throws Exception {
608         mBuilder.build();
609         when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis(mMockDisplayContent))
610                 .thenReturn(true);
611 
612         freezeRotation(Surface.ROTATION_90);
613         assertEquals(Surface.ROTATION_270, mTarget.getUserRotation());
614     }
615 
616     @Test
testFreezeRotation_reverseRotationDirectionAroundZAxis_no()617     public void testFreezeRotation_reverseRotationDirectionAroundZAxis_no() throws Exception {
618         mBuilder.build();
619         when(mDeviceStateController.shouldReverseRotationDirectionAroundZAxis(mMockDisplayContent))
620                 .thenReturn(false);
621 
622         freezeRotation(Surface.ROTATION_90);
623         assertEquals(Surface.ROTATION_90, mTarget.getUserRotation());
624     }
625 
waitForUiHandler()626     private boolean waitForUiHandler() {
627         final CountDownLatch latch = new CountDownLatch(1);
628         UiThread.getHandler().post(latch::countDown);
629         try {
630             return latch.await(UI_HANDLER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
631         } catch (InterruptedException ignored) {
632         }
633         throw new AssertionError("Failed to wait for ui handler");
634     }
635 
636     @Test
testUpdatesRotationWhenSensorUpdates_RotationThawed()637     public void testUpdatesRotationWhenSensorUpdates_RotationThawed() throws Exception {
638         mBuilder.build();
639         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
640 
641         thawRotation();
642 
643         enableOrientationSensor();
644 
645         clearInvocations(sMockWm);
646         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
647         assertTrue(waitForUiHandler());
648 
649         verify(sMockWm).updateRotation(false, false);
650     }
651 
652     @Test
testNotifiesChoiceWhenSensorUpdates_RotationLocked()653     public void testNotifiesChoiceWhenSensorUpdates_RotationLocked() throws Exception {
654         mBuilder.build();
655         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
656 
657         freezeRotation(Surface.ROTATION_270);
658 
659         enableOrientationSensor();
660 
661         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
662         assertTrue(waitForUiHandler());
663 
664         verify(mMockStatusBarManagerInternal).onProposedRotationChanged(DEFAULT_DISPLAY,
665                 Surface.ROTATION_90, true);
666     }
667 
668     @Test
testNotifiesChoiceWhenSensorUpdates_immersiveApp()669     public void testNotifiesChoiceWhenSensorUpdates_immersiveApp() throws Exception {
670         mDisplayRotationImmersiveAppCompatPolicyMock = mock(
671                 DisplayRotationImmersiveAppCompatPolicy.class);
672         when(mDisplayRotationImmersiveAppCompatPolicyMock.isRotationLockEnforced(
673                 Surface.ROTATION_90)).thenReturn(true);
674 
675         mBuilder.build();
676         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
677 
678         thawRotation();
679 
680         enableOrientationSensor();
681 
682         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
683         assertTrue(waitForUiHandler());
684 
685         verify(mMockStatusBarManagerInternal).onProposedRotationChanged(DEFAULT_DISPLAY,
686                 Surface.ROTATION_90, true);
687 
688         // An imaginary ActivityRecord.setRequestedOrientation call disables immersive mode:
689         when(mDisplayRotationImmersiveAppCompatPolicyMock.isRotationLockEnforced(
690                 Surface.ROTATION_90)).thenReturn(false);
691 
692         clearInvocations(sMockWm);
693         // And then ActivityRecord.setRequestedOrientation calls onSetRequestedOrientation.
694         mTarget.onSetRequestedOrientation();
695 
696         // onSetRequestedOrientation should lead to a second call to
697         // mOrientationListener.onProposedRotationChanged
698         // but now, instead of notifying mMockStatusBarManagerInternal, it calls updateRotation:
699         verify(sMockWm).updateRotation(false, false);
700     }
701 
702     @Test
testAllowAllRotations_allowsUpsideDownSuggestion()703     public void testAllowAllRotations_allowsUpsideDownSuggestion()
704             throws Exception {
705         mBuilder.build();
706         mTarget.updateOrientation(SCREEN_ORIENTATION_UNSPECIFIED, true);
707         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
708         when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
709                 .thenReturn(true);
710         freezeRotation(Surface.ROTATION_0);
711         enableOrientationSensor();
712 
713         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
714         assertTrue(waitForUiHandler());
715 
716         verify(mMockStatusBarManagerInternal)
717                 .onProposedRotationChanged(DEFAULT_DISPLAY, Surface.ROTATION_180, true);
718     }
719 
720     @Test
testDoNotAllowAllRotations_doesNotAllowUpsideDownSuggestion()721     public void testDoNotAllowAllRotations_doesNotAllowUpsideDownSuggestion()
722             throws Exception {
723         mBuilder.build();
724         mTarget.updateOrientation(SCREEN_ORIENTATION_UNSPECIFIED, true);
725         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
726         when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
727                 .thenReturn(false);
728         freezeRotation(Surface.ROTATION_0);
729         enableOrientationSensor();
730 
731         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
732         assertTrue(waitForUiHandler());
733 
734         verify(mMockStatusBarManagerInternal)
735                 .onProposedRotationChanged(DEFAULT_DISPLAY, Surface.ROTATION_180, false);
736     }
737 
738     @Test
testAllowAllRotations_allowAllRotationsBecomesDisabled_forbidsUpsideDownSuggestion()739     public void testAllowAllRotations_allowAllRotationsBecomesDisabled_forbidsUpsideDownSuggestion()
740             throws Exception {
741         mBuilder.build();
742         mTarget.updateOrientation(SCREEN_ORIENTATION_UNSPECIFIED, true);
743         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
744         when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
745                 .thenReturn(true);
746         freezeRotation(Surface.ROTATION_0);
747         enableOrientationSensor();
748         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
749         assertTrue(waitForUiHandler());
750 
751         // Change resource to disallow all rotations.
752         // Reset "allowAllRotations".
753         mTarget.applyCurrentRotation(Surface.ROTATION_0);
754         clearInvocations(mMockStatusBarManagerInternal);
755         when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
756                 .thenReturn(false);
757         mTarget.resetAllowAllRotations();
758         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
759         assertTrue(waitForUiHandler());
760 
761         verify(mMockStatusBarManagerInternal)
762                 .onProposedRotationChanged(DEFAULT_DISPLAY, Surface.ROTATION_180, false);
763     }
764 
765     @Test
testReturnsCompatibleRotation_SensorEnabled_RotationThawed()766     public void testReturnsCompatibleRotation_SensorEnabled_RotationThawed() throws Exception {
767         mBuilder.build();
768         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
769 
770         thawRotation();
771 
772         enableOrientationSensor();
773 
774         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
775 
776         final int rotation = mTarget.rotationForOrientation(SCREEN_ORIENTATION_LANDSCAPE,
777                 Surface.ROTATION_0);
778         assertTrue("Rotation should be sideways but it's "
779                 + Surface.rotationToString(rotation),
780                 rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
781     }
782 
783     @Test
testReturnsUserRotation_SensorEnabled_RotationLocked()784     public void testReturnsUserRotation_SensorEnabled_RotationLocked() throws Exception {
785         mBuilder.build();
786         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
787 
788         freezeRotation(Surface.ROTATION_270);
789 
790         enableOrientationSensor();
791 
792         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
793 
794         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
795                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
796     }
797 
798     @Test
testReturnsSensorRotation_180degrees_allRotationsAllowed()799     public void testReturnsSensorRotation_180degrees_allRotationsAllowed()
800             throws Exception {
801         mBuilder.build();
802         when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
803                 .thenReturn(true);
804         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
805         enableOrientationSensor();
806         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
807 
808         assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation(
809                 SCREEN_ORIENTATION_SENSOR, Surface.ROTATION_0));
810     }
811 
812     @Test
testReturnLastRotation_sensor180_allRotationsNotAllowed()813     public void testReturnLastRotation_sensor180_allRotationsNotAllowed()
814             throws Exception {
815         mBuilder.build();
816         when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
817                 .thenReturn(false);
818         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
819         enableOrientationSensor();
820         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
821 
822         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
823                 SCREEN_ORIENTATION_SENSOR, Surface.ROTATION_0));
824     }
825 
826     @Test
testAllowRotationsIsCached()827     public void testAllowRotationsIsCached()
828             throws Exception {
829         mBuilder.build();
830         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
831         enableOrientationSensor();
832 
833         // Rotate once to read the resource
834         when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
835                 .thenReturn(true);
836         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
837         mTarget.rotationForOrientation(SCREEN_ORIENTATION_SENSOR, Surface.ROTATION_0);
838 
839         // Change resource to disallow all rotations.
840         // Rotate again and 180 degrees rotation should still be returned even if "disallowed".
841         when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
842                 .thenReturn(false);
843         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
844         assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation(
845                 SCREEN_ORIENTATION_SENSOR, Surface.ROTATION_0));
846     }
847 
848     @Test
testResetAllowRotations()849     public void testResetAllowRotations()
850             throws Exception {
851         mBuilder.build();
852         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
853         enableOrientationSensor();
854 
855         // Rotate once to read the resource
856         when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
857                 .thenReturn(true);
858         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
859         mTarget.rotationForOrientation(SCREEN_ORIENTATION_SENSOR, Surface.ROTATION_0);
860 
861         // Change resource to disallow all rotations.
862         // Reset "allowAllRotations".
863         // Rotate again and 180 degrees rotation should not be allowed anymore.
864         when(mMockRes.getBoolean(com.android.internal.R.bool.config_allowAllRotations))
865                 .thenReturn(false);
866         mTarget.resetAllowAllRotations();
867         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180));
868         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
869                 SCREEN_ORIENTATION_SENSOR, Surface.ROTATION_0));
870     }
871 
872     @Test
testProposedRotationListener()873     public void testProposedRotationListener() throws Exception {
874         mBuilder.build();
875         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
876         enableOrientationSensor();
877 
878         final int[] receivedRotation = new int[1];
879         final IBinder listenerBinder = mock(IBinder.class);
880         final IRotationWatcher listener = new IRotationWatcher() {
881             @Override
882             public IBinder asBinder() {
883                 return listenerBinder;
884             }
885 
886             @Override
887             public void onRotationChanged(int rotation) {
888                 receivedRotation[0] = rotation;
889             }
890         };
891         final RotationWatcherController controller = new RotationWatcherController(sMockWm) {
892             final WindowContainer<?> mContainer = mock(WindowContainer.class);
893 
894             @Override
895             WindowContainer<?> getAssociatedWindowContainer(IBinder token) {
896                 return mContainer;
897             }
898         };
899         mTarget.mProposedRotationCallback =
900                 rotation -> controller.dispatchProposedRotation(null /* display */, rotation);
901         controller.registerProposedRotationListener(listener, mock(IBinder.class));
902         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
903         assertEquals(Surface.ROTATION_90, receivedRotation[0]);
904 
905         controller.removeRotationWatcher(listener);
906         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
907         assertEquals(Surface.ROTATION_90, receivedRotation[0]);
908     }
909 
910     // ====================================================
911     // Tests for half-fold auto-rotate override of rotation
912     // ====================================================
913     @Test
testUpdatesRotationWhenSensorUpdates_RotationLocked_HalfFolded()914     public void testUpdatesRotationWhenSensorUpdates_RotationLocked_HalfFolded() throws Exception {
915         mBuilder.setSupportHalfFoldAutoRotateOverride(true);
916         mBuilder.build();
917         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
918 
919         enableOrientationSensor();
920 
921         mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
922         freezeRotation(Surface.ROTATION_270);
923 
924         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
925         assertTrue(waitForUiHandler());
926         // No rotation...
927         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
928                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
929 
930         clearInvocations(sMockWm);
931         // ... until half-fold
932         mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
933         assertTrue(waitForUiHandler());
934         verify(sMockWm).updateRotation(false, false);
935         assertTrue(waitForUiHandler());
936         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
937                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
938 
939         // ... then transition back to flat
940         mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
941         assertTrue(waitForUiHandler());
942         verify(sMockWm, atLeast(1)).updateRotation(false, false);
943         assertTrue(waitForUiHandler());
944         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
945                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
946     }
947 
948     @Test
sensorRotation_locked_halfFolded_configOff_rotationUnchanged()949     public void sensorRotation_locked_halfFolded_configOff_rotationUnchanged() throws Exception {
950         mBuilder.setIsFoldable(true);
951         mBuilder.setSupportHalfFoldAutoRotateOverride(false);
952         mBuilder.build();
953         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
954 
955         enableOrientationSensor();
956 
957         mTarget.foldStateChanged(DeviceStateController.DeviceState.OPEN);
958         freezeRotation(Surface.ROTATION_270);
959 
960         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_0));
961         assertTrue(waitForUiHandler());
962         // No rotation...
963         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
964                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
965 
966         clearInvocations(sMockWm);
967         // ... half-fold -> still no rotation
968         mTarget.foldStateChanged(DeviceStateController.DeviceState.HALF_FOLDED);
969         assertTrue(waitForUiHandler());
970         verify(sMockWm).updateRotation(false, false);
971         assertTrue(waitForUiHandler());
972         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
973                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
974     }
975 
976     // =================================
977     // Tests for Policy based Rotation
978     // =================================
979     @Test
testReturnsUserRotation_ForceDefaultRotation_Car()980     public void testReturnsUserRotation_ForceDefaultRotation_Car() throws Exception {
981         mBuilder.build();
982         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, true, false);
983 
984         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT,
985                 Surface.ROTATION_180));
986     }
987 
988     @Test
testReturnsUserRotation_ForceDefaultRotation_Tv()989     public void testReturnsUserRotation_ForceDefaultRotation_Tv() throws Exception {
990         mBuilder.build();
991         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, true);
992 
993         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT,
994                 Surface.ROTATION_180));
995     }
996 
997     @Test
testReturnsLidOpenRotation_LidOpen()998     public void testReturnsLidOpenRotation_LidOpen() throws Exception {
999         mBuilder.setLidOpenRotation(Surface.ROTATION_90).build();
1000         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
1001 
1002         when(mMockDisplayPolicy.getLidState()).thenReturn(
1003                 WindowManagerPolicy.WindowManagerFuncs.LID_OPEN);
1004 
1005         freezeRotation(Surface.ROTATION_270);
1006 
1007         assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
1008                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
1009     }
1010 
1011     @Test
testReturnsCarDockRotation_CarDockedMode()1012     public void testReturnsCarDockRotation_CarDockedMode() throws Exception {
1013         mBuilder.setCarDockRotation(Surface.ROTATION_270).build();
1014         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
1015 
1016         when(mMockDisplayPolicy.getDockMode()).thenReturn(Intent.EXTRA_DOCK_STATE_CAR);
1017 
1018         freezeRotation(Surface.ROTATION_90);
1019 
1020         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
1021                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_90));
1022     }
1023 
1024     @Test
testReturnsDeskDockRotation_DeskDockedMode()1025     public void testReturnsDeskDockRotation_DeskDockedMode() throws Exception {
1026         mBuilder.setDeskDockRotation(Surface.ROTATION_270).build();
1027         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
1028 
1029         when(mMockDisplayPolicy.getDockMode()).thenReturn(Intent.EXTRA_DOCK_STATE_DESK);
1030 
1031         freezeRotation(Surface.ROTATION_90);
1032 
1033         assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
1034                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_90));
1035     }
1036 
1037     @Test
testIgnoresDeskDockRotation_whenNoSensorAndLockedRespected()1038     public void testIgnoresDeskDockRotation_whenNoSensorAndLockedRespected() throws Exception {
1039         mBuilder.setDeskDockRotation(Surface.ROTATION_270).build();
1040         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
1041 
1042         when(mMockDisplayPolicy.getDockMode()).thenReturn(Intent.EXTRA_DOCK_STATE_DESK);
1043 
1044         freezeRotation(Surface.ROTATION_90);
1045 
1046         assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
1047                 SCREEN_ORIENTATION_LOCKED, Surface.ROTATION_90));
1048         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
1049                 SCREEN_ORIENTATION_NOSENSOR, Surface.ROTATION_90));
1050     }
1051 
1052     @Test
testReturnsUserRotation_FixedToUserRotation_IgnoreIncompatibleAppRequest()1053     public void testReturnsUserRotation_FixedToUserRotation_IgnoreIncompatibleAppRequest()
1054             throws Exception {
1055         mBuilder.build();
1056         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
1057 
1058         mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
1059 
1060         freezeRotation(Surface.ROTATION_180);
1061 
1062         final int rotation = mTarget.rotationForOrientation(
1063                 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, Surface.ROTATION_90);
1064         assertEquals(Surface.ROTATION_180, rotation);
1065     }
1066 
1067     @Test
testReturnsUserRotation_NonDefaultDisplay()1068     public void testReturnsUserRotation_NonDefaultDisplay() throws Exception {
1069         mBuilder.setIsDefaultDisplay(false).build();
1070         configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
1071 
1072         freezeRotation(Surface.ROTATION_90);
1073 
1074         assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
1075                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
1076     }
1077 
1078     @Test
testShouldRotateSeamlessly()1079     public void testShouldRotateSeamlessly() throws Exception {
1080         mBuilder.build();
1081 
1082         final WindowState win = mock(WindowState.class);
1083         win.mToken = win.mActivityRecord = mock(ActivityRecord.class);
1084         final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams();
1085         attrs.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
1086 
1087         WindowTestsBase.setFieldValue(win, "mAttrs", attrs);
1088         doReturn(true).when(mMockDisplayPolicy).navigationBarCanMove();
1089         doReturn(win).when(mMockDisplayPolicy).getTopFullscreenOpaqueWindow();
1090         mMockDisplayContent.mCurrentFocus = win;
1091         // This should not affect the condition of shouldRotateSeamlessly.
1092         mTarget.mUpsideDownRotation = Surface.ROTATION_90;
1093 
1094         doReturn(true).when(win.mActivityRecord).matchParentBounds();
1095         // The focused fullscreen opaque window without override bounds should be able to be
1096         // rotated seamlessly.
1097         assertTrue(mTarget.shouldRotateSeamlessly(
1098                 Surface.ROTATION_0, Surface.ROTATION_90, false /* forceUpdate */));
1099         // Reject any 180 degree because non-movable navbar will be placed in a different position.
1100         doReturn(false).when(mMockDisplayPolicy).navigationBarCanMove();
1101         assertFalse(mTarget.shouldRotateSeamlessly(
1102                 Surface.ROTATION_90, Surface.ROTATION_180, false /* forceUpdate */));
1103 
1104         doReturn(true).when(mMockDisplayPolicy).navigationBarCanMove();
1105         doReturn(false).when(win.mActivityRecord).matchParentBounds();
1106         // No seamless rotation if the window may be positioned with offset after rotation.
1107         assertFalse(mTarget.shouldRotateSeamlessly(
1108                 Surface.ROTATION_0, Surface.ROTATION_90, false /* forceUpdate */));
1109     }
1110 
1111     @Test
testSensorRotationAfterDisplayChangeBeforeTimeout_ignoresSensor()1112     public void testSensorRotationAfterDisplayChangeBeforeTimeout_ignoresSensor() throws Exception {
1113         mBuilder.setIsFoldable(true)
1114                 .setPauseRotationWhenUnfolding(true)
1115                 .setDisplaySwitchRotationBlockTimeMs(1000)
1116                 .build();
1117         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
1118         thawRotation();
1119         enableOrientationSensor();
1120 
1121         mTarget.physicalDisplayChanged();
1122 
1123         moveTimeForward(900);
1124         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
1125         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
1126                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
1127     }
1128 
1129     @Test
testSensorRotationAfterDisplayChangeAfterTimeout_usesSensor()1130     public void testSensorRotationAfterDisplayChangeAfterTimeout_usesSensor() throws Exception {
1131         mBuilder.setIsFoldable(true)
1132                 .setPauseRotationWhenUnfolding(true)
1133                 .setDisplaySwitchRotationBlockTimeMs(1000)
1134                 .build();
1135         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
1136         thawRotation();
1137         enableOrientationSensor();
1138 
1139         mTarget.physicalDisplayChanged();
1140 
1141         moveTimeForward(1100);
1142         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
1143         assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
1144                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
1145     }
1146 
1147     @Test
testSensorRotationAfterHingeEventBeforeTimeout_ignoresSensor()1148     public void testSensorRotationAfterHingeEventBeforeTimeout_ignoresSensor() throws Exception {
1149         mBuilder.setIsFoldable(true)
1150                 .setPauseRotationWhenUnfolding(true)
1151                 .setMaxHingeAngle(165)
1152                 .setHingeAngleRotationBlockTimeMs(400)
1153                 .build();
1154         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
1155         thawRotation();
1156         enableOrientationSensor();
1157 
1158         sendHingeAngleEvent(130);
1159 
1160         moveTimeForward( 300);
1161         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
1162         assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
1163                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
1164     }
1165 
1166     @Test
testSensorRotationAfterHingeEventBeforeTimeoutFlagDisabled_usesSensorData()1167     public void testSensorRotationAfterHingeEventBeforeTimeoutFlagDisabled_usesSensorData()
1168             throws Exception {
1169         mBuilder.setIsFoldable(true)
1170                 .setPauseRotationWhenUnfolding(false)
1171                 .setMaxHingeAngle(165)
1172                 .setHingeAngleRotationBlockTimeMs(400)
1173                 .build();
1174         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
1175         thawRotation();
1176         enableOrientationSensor();
1177 
1178         sendHingeAngleEvent(130);
1179 
1180         moveTimeForward( 300);
1181         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
1182         assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
1183                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
1184     }
1185 
1186     @Test
testSensorRotationAfterHingeEventAfterTimeout_usesSensorData()1187     public void testSensorRotationAfterHingeEventAfterTimeout_usesSensorData() throws Exception {
1188         mBuilder.setIsFoldable(true)
1189                 .setPauseRotationWhenUnfolding(true)
1190                 .setMaxHingeAngle(165)
1191                 .setHingeAngleRotationBlockTimeMs(400)
1192                 .build();
1193         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
1194         thawRotation();
1195         enableOrientationSensor();
1196 
1197         sendHingeAngleEvent(180);
1198 
1199         moveTimeForward(1010);
1200         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
1201         assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
1202                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
1203     }
1204 
1205 
1206     @Test
testSensorRotationAfterLargeHingeEventBeforeTimeout_usesSensor()1207     public void testSensorRotationAfterLargeHingeEventBeforeTimeout_usesSensor() throws Exception {
1208         mBuilder.setIsFoldable(true)
1209                 .setPauseRotationWhenUnfolding(true)
1210                 .setMaxHingeAngle(165)
1211                 .setHingeAngleRotationBlockTimeMs(400)
1212                 .build();
1213         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
1214         thawRotation();
1215         enableOrientationSensor();
1216 
1217         sendHingeAngleEvent(180);
1218 
1219         moveTimeForward(300);
1220         mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
1221         assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
1222                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
1223     }
1224 
1225     @Test
testReturnsUserRotation_FixedToUserRotationIfNoAutoRotation_AutoRotationNotSupport()1226     public void testReturnsUserRotation_FixedToUserRotationIfNoAutoRotation_AutoRotationNotSupport()
1227             throws Exception {
1228         mBuilder.setSupportAutoRotation(false).build();
1229         configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false);
1230         mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_IF_NO_AUTO_ROTATION);
1231 
1232         freezeRotation(Surface.ROTATION_180);
1233 
1234         assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, mTarget.getUserRotationMode());
1235         assertEquals(Surface.ROTATION_180, mTarget.getUserRotation());
1236 
1237         assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation(
1238                 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0));
1239     }
1240 
1241     // ========================
1242     // Non-rotation API Tests
1243     // ========================
1244     @Test
testIsNotFixedToUserRotationByDefault()1245     public void testIsNotFixedToUserRotationByDefault() throws Exception {
1246         mBuilder.build();
1247 
1248         assertFalse("Display rotation should respect app requested orientation by"
1249                 + " default.", mTarget.isFixedToUserRotation());
1250     }
1251 
1252     @Test
testIsFixedToUserRotation()1253     public void testIsFixedToUserRotation() throws Exception {
1254         mBuilder.build();
1255         mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
1256 
1257         assertTrue("Display rotation shouldn't respect app requested orientation if"
1258                 + " fixed to user rotation.", mTarget.isFixedToUserRotation());
1259     }
1260 
1261     @Test
testIsFixedToUserRotation_displayShouldNotRotateWithContent()1262     public void testIsFixedToUserRotation_displayShouldNotRotateWithContent() throws Exception {
1263         mBuilder.build();
1264         when(mMockDisplayContent.shouldRotateWithContent()).thenReturn(false);
1265 
1266         assertFalse("Display rotation should respect app requested orientation if"
1267                 + " the display does not rotate with content.", mTarget.isFixedToUserRotation());
1268     }
1269 
1270     @Test
testIsFixedToUserRotation_FixedToUserRotationIfNoAutoRotation()1271     public void testIsFixedToUserRotation_FixedToUserRotationIfNoAutoRotation() throws Exception {
1272         mBuilder.build();
1273         mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_IF_NO_AUTO_ROTATION);
1274 
1275         assertFalse("Display rotation should respect app requested orientation if"
1276                 + " fixed to user rotation if no auto rotation.", mTarget.isFixedToUserRotation());
1277     }
1278 
moveTimeForward(long timeMillis)1279     private void moveTimeForward(long timeMillis) {
1280         sCurrentUptimeMillis += timeMillis;
1281         sClock.fastForward(timeMillis);
1282         sHandler.timeAdvance();
1283     }
1284 
1285     /**
1286      * Call {@link DisplayRotation#configure(int, int)} to configure {@link #mTarget}
1287      * according to given parameters.
1288      */
configureDisplayRotation(int displayOrientation, boolean isCar, boolean isTv)1289     private void configureDisplayRotation(int displayOrientation, boolean isCar, boolean isTv) {
1290         final int width;
1291         final int height;
1292         switch (displayOrientation) {
1293             case SCREEN_ORIENTATION_LANDSCAPE:
1294                 width = 1920;
1295                 height = 1080;
1296                 break;
1297             case SCREEN_ORIENTATION_PORTRAIT:
1298                 width = 1080;
1299                 height = 1920;
1300                 break;
1301             default:
1302                 throw new IllegalArgumentException("displayOrientation needs to be either landscape"
1303                         + " or portrait, but we got "
1304                         + ActivityInfo.screenOrientationToString(displayOrientation));
1305         }
1306 
1307         final PackageManager mockPackageManager = mock(PackageManager.class);
1308         when(mMockContext.getPackageManager()).thenReturn(mockPackageManager);
1309         when(mockPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
1310                 .thenReturn(isCar);
1311         when(mockPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
1312                 .thenReturn(isTv);
1313 
1314         mTarget.configure(width, height);
1315     }
1316 
sendHingeAngleEvent(int hingeAngle)1317     private void sendHingeAngleEvent(int hingeAngle) {
1318         mHingeAngleSensorListenerCaptor.getAllValues().forEach(sensorEventListener -> {
1319             try {
1320                 sensorEventListener.onSensorChanged(createSensorEvent(mFakeHingeAngleSensor,
1321                             hingeAngle));
1322             } catch (Exception e) {
1323                 throw new RuntimeException(e);
1324             }
1325         });
1326     }
1327 
freezeRotation(int rotation)1328     private void freezeRotation(int rotation) {
1329         mTarget.freezeRotation(rotation, /* caller= */ "DisplayRotationTests");
1330 
1331         if (mTarget.isDefaultDisplay) {
1332             mAccelerometerRotationObserver.onChange(false);
1333             mUserRotationObserver.onChange(false);
1334         }
1335     }
1336 
thawRotation()1337     private void thawRotation() {
1338         mTarget.thawRotation(/* caller= */ "DisplayRotationTests");
1339 
1340         if (mTarget.isDefaultDisplay) {
1341             mAccelerometerRotationObserver.onChange(false);
1342             mUserRotationObserver.onChange(false);
1343         }
1344     }
1345 
1346     private class DisplayRotationBuilder {
1347         private boolean mIsDefaultDisplay = true;
1348         private boolean mSupportAutoRotation = true;
1349         private boolean mPauseRotationWhenUnfolding = false;
1350         private boolean mSupportHalfFoldAutoRotateOverride = false;
1351         private int mDisplaySwitchRotationBlockTimeMs;
1352         private int mHingeAngleRotationBlockTimeMs;
1353         private int mMaxHingeAngle;
1354 
1355         private int mLidOpenRotation = WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
1356         private int mCarDockRotation;
1357         private int mDeskDockRotation;
1358         private int mUndockedHdmiRotation;
1359         private boolean mIsFoldable;
1360 
setIsDefaultDisplay(boolean isDefaultDisplay)1361         private DisplayRotationBuilder setIsDefaultDisplay(boolean isDefaultDisplay) {
1362             mIsDefaultDisplay = isDefaultDisplay;
1363             return this;
1364         }
1365 
setPauseRotationWhenUnfolding( boolean pauseRotationWhenUnfolding)1366         public DisplayRotationBuilder setPauseRotationWhenUnfolding(
1367                 boolean pauseRotationWhenUnfolding) {
1368             mPauseRotationWhenUnfolding = pauseRotationWhenUnfolding;
1369             return this;
1370         }
1371 
setDisplaySwitchRotationBlockTimeMs( int displaySwitchRotationBlockTimeMs)1372         public DisplayRotationBuilder setDisplaySwitchRotationBlockTimeMs(
1373                 int displaySwitchRotationBlockTimeMs) {
1374             mDisplaySwitchRotationBlockTimeMs = displaySwitchRotationBlockTimeMs;
1375             return this;
1376         }
1377 
setHingeAngleRotationBlockTimeMs( int hingeAngleRotationBlockTimeMs)1378         public DisplayRotationBuilder setHingeAngleRotationBlockTimeMs(
1379                 int hingeAngleRotationBlockTimeMs) {
1380             mHingeAngleRotationBlockTimeMs = hingeAngleRotationBlockTimeMs;
1381             return this;
1382         }
1383 
setMaxHingeAngle(int maxHingeAngle)1384         public DisplayRotationBuilder setMaxHingeAngle(int maxHingeAngle) {
1385             mMaxHingeAngle = maxHingeAngle;
1386             return this;
1387         }
1388 
setSupportAutoRotation(boolean supportAutoRotation)1389         private DisplayRotationBuilder setSupportAutoRotation(boolean supportAutoRotation) {
1390             mSupportAutoRotation = supportAutoRotation;
1391             return this;
1392         }
1393 
setLidOpenRotation(int rotation)1394         private DisplayRotationBuilder setLidOpenRotation(int rotation) {
1395             mLidOpenRotation = rotation;
1396             return this;
1397         }
1398 
setCarDockRotation(int rotation)1399         private DisplayRotationBuilder setCarDockRotation(int rotation) {
1400             mCarDockRotation = rotation;
1401             return this;
1402         }
1403 
setDeskDockRotation(int rotation)1404         private DisplayRotationBuilder setDeskDockRotation(int rotation) {
1405             mDeskDockRotation = rotation;
1406             return this;
1407         }
1408 
setUndockedHdmiRotation(int rotation)1409         private DisplayRotationBuilder setUndockedHdmiRotation(int rotation) {
1410             mUndockedHdmiRotation = rotation;
1411             return this;
1412         }
1413 
setIsFoldable(boolean value)1414         private DisplayRotationBuilder setIsFoldable(boolean value) {
1415             mIsFoldable = value;
1416             return this;
1417         }
1418 
setSupportHalfFoldAutoRotateOverride( boolean supportHalfFoldAutoRotateOverride)1419         private DisplayRotationBuilder setSupportHalfFoldAutoRotateOverride(
1420                 boolean supportHalfFoldAutoRotateOverride) {
1421             mSupportHalfFoldAutoRotateOverride = supportHalfFoldAutoRotateOverride;
1422             if (supportHalfFoldAutoRotateOverride) {
1423                 mIsFoldable = true;
1424             }
1425             return this;
1426         }
1427 
captureObservers()1428         private void captureObservers() {
1429             ArgumentCaptor<ContentObserver> captor = ArgumentCaptor.forClass(
1430                     ContentObserver.class);
1431             verify(mMockResolver, atMost(1)).registerContentObserver(
1432                     eq(Settings.Secure.getUriFor(Settings.Secure.SHOW_ROTATION_SUGGESTIONS)),
1433                     anyBoolean(),
1434                     captor.capture(),
1435                     anyInt());
1436             if (!captor.getAllValues().isEmpty()) {
1437                 mShowRotationSuggestionsObserver = captor.getValue();
1438             }
1439 
1440             captor = ArgumentCaptor.forClass(ContentObserver.class);
1441             verify(mMockResolver, atMost(1)).registerContentObserver(
1442                     eq(Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION)),
1443                     anyBoolean(),
1444                     captor.capture(),
1445                     anyInt());
1446             if (!captor.getAllValues().isEmpty()) {
1447                 mAccelerometerRotationObserver = captor.getValue();
1448             }
1449 
1450             captor = ArgumentCaptor.forClass(ContentObserver.class);
1451             verify(mMockResolver, atMost(1)).registerContentObserver(
1452                     eq(Settings.System.getUriFor(Settings.System.USER_ROTATION)),
1453                     anyBoolean(),
1454                     captor.capture(),
1455                     anyInt());
1456             if (!captor.getAllValues().isEmpty()) {
1457                 mUserRotationObserver = captor.getValue();
1458             }
1459         }
1460 
createSensor(int type)1461         private Sensor createSensor(int type) throws Exception {
1462             Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
1463             constr.setAccessible(true);
1464             Sensor sensor = constr.newInstance();
1465 
1466             setSensorType(sensor, type);
1467             setSensorField(sensor, "mName", "Mock " + sensor.getStringType() + "/" + type);
1468             setSensorField(sensor, "mVendor", "Mock Vendor");
1469             setSensorField(sensor, "mVersion", 1);
1470             setSensorField(sensor, "mHandle", -1);
1471             setSensorField(sensor, "mMaxRange", 10);
1472             setSensorField(sensor, "mResolution", 1);
1473             setSensorField(sensor, "mPower", 1);
1474             setSensorField(sensor, "mMinDelay", 1000);
1475             setSensorField(sensor, "mMaxDelay", 1000000000);
1476             setSensorField(sensor, "mFlags", 0);
1477             setSensorField(sensor, "mId", -1);
1478 
1479             return sensor;
1480         }
1481 
setSensorType(Sensor sensor, int type)1482         private void setSensorType(Sensor sensor, int type) throws Exception {
1483             Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
1484             setter.setAccessible(true);
1485             setter.invoke(sensor, type);
1486         }
1487 
setSensorField(Sensor sensor, String fieldName, Object value)1488         private void setSensorField(Sensor sensor, String fieldName, Object value)
1489                 throws Exception {
1490             Field field = Sensor.class.getDeclaredField(fieldName);
1491             field.setAccessible(true);
1492             field.set(sensor, value);
1493         }
1494 
convertRotationToDegrees(@urface.Rotation int rotation)1495         private int convertRotationToDegrees(@Surface.Rotation int rotation) {
1496             switch (rotation) {
1497                 case Surface.ROTATION_0:
1498                     return 0;
1499                 case Surface.ROTATION_90:
1500                     return 90;
1501                 case Surface.ROTATION_180:
1502                     return 180;
1503                 case Surface.ROTATION_270:
1504                     return 270;
1505                 default:
1506                     return -1;
1507             }
1508         }
1509 
build()1510         private void build() throws Exception {
1511             mMockContext = mock(Context.class);
1512 
1513             mMockDisplayContent = mock(DisplayContent.class);
1514             when(mMockDisplayContent.getDisplay()).thenReturn(mock(Display.class));
1515             when(mMockDisplayContent.getDisplayId()).thenReturn(DEFAULT_DISPLAY);
1516             mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay;
1517             when(mMockDisplayContent.calculateDisplayCutoutForRotation(anyInt()))
1518                     .thenReturn(NO_CUTOUT);
1519             when(mMockDisplayContent.getDefaultTaskDisplayArea())
1520                     .thenReturn(mock(TaskDisplayArea.class));
1521             when(mMockDisplayContent.getWindowConfiguration())
1522                     .thenReturn(new WindowConfiguration());
1523             when(mMockDisplayContent.shouldRotateWithContent()).thenReturn(true);
1524 
1525             Field field = DisplayContent.class
1526                     .getDeclaredField("mFixedRotationTransitionListener");
1527             field.setAccessible(true);
1528             field.set(mMockDisplayContent, mock(FixedRotationTransitionListener.class));
1529 
1530             mMockDisplayPolicy = mock(DisplayPolicy.class);
1531             mMockStatusBarManagerInternal = mock(StatusBarManagerInternal.class);
1532             when(mMockDisplayPolicy.getStatusBarManagerInternal()).thenReturn(
1533                     mMockStatusBarManagerInternal);
1534 
1535             mMockRes = mock(Resources.class);
1536             when(mMockContext.getResources()).thenReturn((mMockRes));
1537             when(mMockRes.getBoolean(com.android.internal.R.bool
1538                     .config_windowManagerPauseRotationWhenUnfolding))
1539                     .thenReturn(mPauseRotationWhenUnfolding);
1540             when(mMockRes.getInteger(com.android.internal.R.integer
1541                     .config_pauseRotationWhenUnfolding_displaySwitchTimeout))
1542                     .thenReturn(mDisplaySwitchRotationBlockTimeMs);
1543             when(mMockRes.getInteger(com.android.internal.R.integer
1544                     .config_pauseRotationWhenUnfolding_hingeEventTimeout))
1545                     .thenReturn(mHingeAngleRotationBlockTimeMs);
1546             when(mMockRes.getInteger(com.android.internal.R.integer
1547                     .config_pauseRotationWhenUnfolding_maxHingeAngle))
1548                     .thenReturn(mMaxHingeAngle);
1549             when(mMockRes.getBoolean(com.android.internal.R.bool.config_supportAutoRotation))
1550                     .thenReturn(mSupportAutoRotation);
1551             when(mMockRes.getInteger(com.android.internal.R.integer.config_lidOpenRotation))
1552                     .thenReturn(convertRotationToDegrees(mLidOpenRotation));
1553             when(mMockRes.getInteger(com.android.internal.R.integer.config_carDockRotation))
1554                     .thenReturn(convertRotationToDegrees(mCarDockRotation));
1555             when(mMockRes.getInteger(com.android.internal.R.integer.config_deskDockRotation))
1556                     .thenReturn(convertRotationToDegrees(mDeskDockRotation));
1557             when(mMockRes.getInteger(com.android.internal.R.integer.config_undockedHdmiRotation))
1558                     .thenReturn(convertRotationToDegrees(mUndockedHdmiRotation));
1559 
1560             mMockSensorManager = mock(SensorManager.class);
1561             when(mMockContext.getSystemService(SensorManager.class))
1562                     .thenReturn(mMockSensorManager);
1563             when(mMockContext.getSystemService(Context.SENSOR_SERVICE))
1564                     .thenReturn(mMockSensorManager);
1565             mFakeOrientationSensor = createSensor(Sensor.TYPE_DEVICE_ORIENTATION);
1566             when(mMockSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION)).thenReturn(
1567                     Collections.singletonList(mFakeOrientationSensor));
1568             mFakeHingeAngleSensor = mock(Sensor.class);
1569             when(mMockSensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)).thenReturn(
1570                     mFakeHingeAngleSensor);
1571 
1572             when(mMockContext.getResources().getBoolean(
1573                     com.android.internal.R.bool.config_windowManagerHalfFoldAutoRotateOverride))
1574                     .thenReturn(mSupportHalfFoldAutoRotateOverride);
1575 
1576             when(mMockContext.getResources().getIntArray(
1577                     R.array.config_foldedDeviceStates))
1578                     .thenReturn(mIsFoldable ? new int[]{0} : new int[]{});
1579 
1580             mMockDisplayRotationReversionController =
1581                     mock(DisplayRotationReversionController.class);
1582             when(mMockDisplayContent.getRotationReversionController())
1583                         .thenReturn(mMockDisplayRotationReversionController);
1584 
1585             mMockResolver = mock(ContentResolver.class);
1586             when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
1587             mFakeSettingsProvider = new FakeSettingsProvider();
1588             when(mMockResolver.acquireProvider(Settings.AUTHORITY))
1589                     .thenReturn(mFakeSettingsProvider.getIContentProvider());
1590 
1591             mMockDisplayAddress = mock(DisplayAddress.class);
1592 
1593             mMockDisplayWindowSettings = mock(DisplayWindowSettings.class);
1594 
1595             mMockDeviceStateManager = mock(DeviceStateManager.class);
1596             when(mMockContext.getSystemService(eq(DeviceStateManager.class)))
1597                     .thenReturn(mMockDeviceStateManager);
1598 
1599             mDeviceStateController = mock(DeviceStateController.class);
1600             mMockDisplayContent.mAppCompatCameraPolicy = mock(AppCompatCameraPolicy.class);
1601             mTarget = new TestDisplayRotation(mMockDisplayContent, mMockDisplayAddress,
1602                     mMockDisplayPolicy, mMockDisplayWindowSettings, mMockContext,
1603                     mDeviceStateController);
1604 
1605             reset(sMockWm);
1606 
1607             verify(mMockSensorManager, atLeast(0)).registerListener(
1608                     mHingeAngleSensorListenerCaptor.capture(), eq(mFakeHingeAngleSensor), anyInt(),
1609                     any());
1610 
1611             captureObservers();
1612         }
1613     }
1614 
1615     private class TestDisplayRotation extends DisplayRotation {
1616         IntConsumer mProposedRotationCallback;
1617 
TestDisplayRotation(DisplayContent dc, DisplayAddress address, DisplayPolicy policy, DisplayWindowSettings displayWindowSettings, Context context, DeviceStateController deviceStateController)1618         TestDisplayRotation(DisplayContent dc, DisplayAddress address, DisplayPolicy policy,
1619                 DisplayWindowSettings displayWindowSettings, Context context,
1620                 DeviceStateController deviceStateController) {
1621             super(sMockWm, dc, address, policy, displayWindowSettings, context, new Object(),
1622                     deviceStateController, mock(DisplayRotationCoordinator.class));
1623         }
1624 
1625         @Override
initImmersiveAppCompatPolicy( WindowManagerService service, DisplayContent displayContent)1626         DisplayRotationImmersiveAppCompatPolicy initImmersiveAppCompatPolicy(
1627                 WindowManagerService service, DisplayContent displayContent) {
1628             return mDisplayRotationImmersiveAppCompatPolicyMock;
1629         }
1630 
1631         @Override
dispatchProposedRotation(int rotation)1632         void dispatchProposedRotation(int rotation) {
1633             if (mProposedRotationCallback != null) {
1634                 mProposedRotationCallback.accept(rotation);
1635             }
1636         }
1637 
1638         @Override
getHandler()1639         Handler getHandler() {
1640             return sHandler;
1641         }
1642 
1643         @Override
uptimeMillis()1644         long uptimeMillis() {
1645             return sCurrentUptimeMillis;
1646         }
1647     }
1648 }
1649