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