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