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