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