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