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_PORTRAIT; 21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 22 23 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; 24 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; 25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; 26 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atMost; 27 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; 28 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 29 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; 30 import static com.android.dx.mockito.inline.extended.ExtendedMockito.same; 31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; 32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 33 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; 34 import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DEFAULT; 35 import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_DISABLED; 36 import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED; 37 38 import static org.junit.Assert.assertEquals; 39 import static org.junit.Assert.assertFalse; 40 import static org.junit.Assert.assertTrue; 41 42 import android.content.ContentResolver; 43 import android.content.Context; 44 import android.content.Intent; 45 import android.content.pm.ActivityInfo; 46 import android.content.pm.PackageManager; 47 import android.content.res.Resources; 48 import android.database.ContentObserver; 49 import android.hardware.Sensor; 50 import android.hardware.SensorEvent; 51 import android.hardware.SensorEventListener; 52 import android.hardware.SensorManager; 53 import android.os.PowerManagerInternal; 54 import android.os.SystemClock; 55 import android.platform.test.annotations.Presubmit; 56 import android.provider.Settings; 57 import android.view.Surface; 58 59 import androidx.test.filters.SmallTest; 60 61 import com.android.internal.util.test.FakeSettingsProvider; 62 import com.android.server.LocalServices; 63 import com.android.server.UiThread; 64 import com.android.server.policy.WindowManagerPolicy; 65 import com.android.server.statusbar.StatusBarManagerInternal; 66 import com.android.server.wm.utils.WmDisplayCutout; 67 68 import org.junit.After; 69 import org.junit.Before; 70 import org.junit.BeforeClass; 71 import org.junit.Test; 72 import org.mockito.ArgumentCaptor; 73 74 import java.lang.reflect.Constructor; 75 import java.lang.reflect.Field; 76 import java.lang.reflect.Method; 77 import java.util.Collections; 78 import java.util.concurrent.CountDownLatch; 79 import java.util.concurrent.TimeUnit; 80 81 /** 82 * Test class for {@link DisplayRotation}. 83 * 84 * Build/Install/Run: 85 * atest WmTests:DisplayRotationTests 86 */ 87 @SmallTest 88 @Presubmit 89 public class DisplayRotationTests { 90 private static final long UI_HANDLER_WAIT_TIMEOUT_MS = 50; 91 92 private StatusBarManagerInternal mPreviousStatusBarManagerInternal; 93 94 private static WindowManagerService sMockWm; 95 private DisplayContent mMockDisplayContent; 96 private DisplayPolicy mMockDisplayPolicy; 97 private Context mMockContext; 98 private Resources mMockRes; 99 private SensorManager mMockSensorManager; 100 private Sensor mFakeSensor; 101 private DisplayWindowSettings mMockDisplayWindowSettings; 102 private ContentResolver mMockResolver; 103 private FakeSettingsProvider mFakeSettingsProvider; 104 private StatusBarManagerInternal mMockStatusBarManagerInternal; 105 106 // Fields below are callbacks captured from test target. 107 private ContentObserver mShowRotationSuggestionsObserver; 108 private ContentObserver mAccelerometerRotationObserver; 109 private ContentObserver mUserRotationObserver; 110 private SensorEventListener mOrientationSensorListener; 111 112 private DisplayRotationBuilder mBuilder; 113 114 private DisplayRotation mTarget; 115 116 @BeforeClass setUpOnce()117 public static void setUpOnce() { 118 sMockWm = mock(WindowManagerService.class); 119 sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class); 120 sMockWm.mPolicy = mock(WindowManagerPolicy.class); 121 } 122 123 @Before setUp()124 public void setUp() { 125 FakeSettingsProvider.clearSettingsProvider(); 126 127 mPreviousStatusBarManagerInternal = LocalServices.getService( 128 StatusBarManagerInternal.class); 129 LocalServices.removeServiceForTest(StatusBarManagerInternal.class); 130 mMockStatusBarManagerInternal = mock(StatusBarManagerInternal.class); 131 LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal); 132 133 mBuilder = new DisplayRotationBuilder(); 134 } 135 136 @After tearDown()137 public void tearDown() { 138 LocalServices.removeServiceForTest(StatusBarManagerInternal.class); 139 if (mPreviousStatusBarManagerInternal != null) { 140 LocalServices.addService(StatusBarManagerInternal.class, 141 mPreviousStatusBarManagerInternal); 142 mPreviousStatusBarManagerInternal = null; 143 } 144 } 145 146 // ================================ 147 // Display Settings Related Tests 148 // ================================ 149 @Test testLocksUserRotation_LockRotation_DefaultDisplay()150 public void testLocksUserRotation_LockRotation_DefaultDisplay() throws Exception { 151 mBuilder.build(); 152 153 freezeRotation(Surface.ROTATION_180); 154 155 assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, mTarget.getUserRotationMode()); 156 assertEquals(Surface.ROTATION_180, mTarget.getUserRotation()); 157 158 assertEquals(0, Settings.System.getInt(mMockResolver, 159 Settings.System.ACCELEROMETER_ROTATION)); 160 assertEquals(Surface.ROTATION_180, Settings.System.getInt(mMockResolver, 161 Settings.System.USER_ROTATION)); 162 } 163 164 @Test testPersistsUserRotation_LockRotation_NonDefaultDisplay()165 public void testPersistsUserRotation_LockRotation_NonDefaultDisplay() throws Exception { 166 mBuilder.setIsDefaultDisplay(false).build(); 167 168 freezeRotation(Surface.ROTATION_180); 169 170 assertEquals(WindowManagerPolicy.USER_ROTATION_LOCKED, mTarget.getUserRotationMode()); 171 assertEquals(Surface.ROTATION_180, mTarget.getUserRotation()); 172 173 verify(mMockDisplayWindowSettings).setUserRotation(mMockDisplayContent, 174 WindowManagerPolicy.USER_ROTATION_LOCKED, Surface.ROTATION_180); 175 } 176 177 @Test testPersistUserRotation_UnlockRotation_DefaultDisplay()178 public void testPersistUserRotation_UnlockRotation_DefaultDisplay() throws Exception { 179 mBuilder.build(); 180 181 thawRotation(); 182 183 assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, mTarget.getUserRotationMode()); 184 185 assertEquals(1, Settings.System.getInt(mMockResolver, 186 Settings.System.ACCELEROMETER_ROTATION)); 187 } 188 189 @Test testPersistsUserRotation_UnlockRotation_NonDefaultDisplay()190 public void testPersistsUserRotation_UnlockRotation_NonDefaultDisplay() throws Exception { 191 mBuilder.setIsDefaultDisplay(false).build(); 192 193 thawRotation(); 194 195 assertEquals(WindowManagerPolicy.USER_ROTATION_FREE, mTarget.getUserRotationMode()); 196 197 verify(mMockDisplayWindowSettings).setUserRotation(same(mMockDisplayContent), 198 eq(WindowManagerPolicy.USER_ROTATION_FREE), anyInt()); 199 } 200 201 @Test testPersistsFixedToUserRotation()202 public void testPersistsFixedToUserRotation() throws Exception { 203 mBuilder.build(); 204 205 mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED); 206 207 verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent, 208 FIXED_TO_USER_ROTATION_ENABLED); 209 210 reset(mMockDisplayWindowSettings); 211 mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_DISABLED); 212 213 verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent, 214 FIXED_TO_USER_ROTATION_DISABLED); 215 216 reset(mMockDisplayWindowSettings); 217 mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_DEFAULT); 218 219 verify(mMockDisplayWindowSettings).setFixedToUserRotation(mMockDisplayContent, 220 FIXED_TO_USER_ROTATION_DEFAULT); 221 } 222 223 // ======================================== 224 // Tests for User Rotation based Rotation 225 // ======================================== 226 @Test testReturnsUserRotation_UserRotationLocked_NoAppRequest()227 public void testReturnsUserRotation_UserRotationLocked_NoAppRequest() 228 throws Exception { 229 mBuilder.build(); 230 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); 231 232 freezeRotation(Surface.ROTATION_180); 233 234 assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation( 235 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_90)); 236 } 237 238 @Test testReturnsUserRotation_UserRotationLocked_CompatibleAppRequest()239 public void testReturnsUserRotation_UserRotationLocked_CompatibleAppRequest() 240 throws Exception { 241 mBuilder.build(); 242 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); 243 244 freezeRotation(Surface.ROTATION_180); 245 246 assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation( 247 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, Surface.ROTATION_90)); 248 } 249 250 @Test testReturnsSideways_UserRotationLocked_IncompatibleAppRequest()251 public void testReturnsSideways_UserRotationLocked_IncompatibleAppRequest() 252 throws Exception { 253 mBuilder.build(); 254 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); 255 256 freezeRotation(Surface.ROTATION_180); 257 258 final int rotation = mTarget.rotationForOrientation( 259 ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, Surface.ROTATION_90); 260 assertTrue("Rotation should be sideways, but it's " 261 + Surface.rotationToString(rotation), 262 rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270); 263 } 264 265 // ================================= 266 // Tests for Sensor based Rotation 267 // ================================= verifyOrientationListenerRegistration(int numOfInvocation)268 private void verifyOrientationListenerRegistration(int numOfInvocation) { 269 final ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass( 270 SensorEventListener.class); 271 verify(mMockSensorManager, times(numOfInvocation)).registerListener( 272 listenerCaptor.capture(), 273 same(mFakeSensor), 274 anyInt(), 275 any()); 276 if (numOfInvocation > 0) { 277 mOrientationSensorListener = listenerCaptor.getValue(); 278 } 279 } 280 281 @Test testNotEnablesSensor_AutoRotationNotSupported()282 public void testNotEnablesSensor_AutoRotationNotSupported() throws Exception { 283 mBuilder.setSupportAutoRotation(false).build(); 284 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 285 286 thawRotation(); 287 288 when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); 289 when(mMockDisplayPolicy.isAwake()).thenReturn(true); 290 when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); 291 when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); 292 mTarget.updateOrientationListener(); 293 verifyOrientationListenerRegistration(0); 294 } 295 296 @Test testNotEnablesSensor_ScreenNotOn()297 public void testNotEnablesSensor_ScreenNotOn() throws Exception { 298 mBuilder.build(); 299 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 300 301 thawRotation(); 302 303 when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(false); 304 when(mMockDisplayPolicy.isAwake()).thenReturn(true); 305 when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); 306 when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); 307 mTarget.updateOrientationListener(); 308 verifyOrientationListenerRegistration(0); 309 } 310 311 @Test testNotEnablesSensor_NotAwake()312 public void testNotEnablesSensor_NotAwake() throws Exception { 313 mBuilder.build(); 314 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 315 316 thawRotation(); 317 318 when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); 319 when(mMockDisplayPolicy.isAwake()).thenReturn(false); 320 when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); 321 when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); 322 mTarget.updateOrientationListener(); 323 verifyOrientationListenerRegistration(0); 324 } 325 326 @Test testNotEnablesSensor_KeyguardNotDrawnCompletely()327 public void testNotEnablesSensor_KeyguardNotDrawnCompletely() throws Exception { 328 mBuilder.build(); 329 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 330 331 thawRotation(); 332 333 when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); 334 when(mMockDisplayPolicy.isAwake()).thenReturn(true); 335 when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(false); 336 when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); 337 mTarget.updateOrientationListener(); 338 verifyOrientationListenerRegistration(0); 339 } 340 341 @Test testNotEnablesSensor_WindowManagerNotDrawnCompletely()342 public void testNotEnablesSensor_WindowManagerNotDrawnCompletely() throws Exception { 343 mBuilder.build(); 344 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 345 346 thawRotation(); 347 348 when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); 349 when(mMockDisplayPolicy.isAwake()).thenReturn(true); 350 when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); 351 when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(false); 352 mTarget.updateOrientationListener(); 353 verifyOrientationListenerRegistration(0); 354 } 355 356 @Test testNotEnablesSensor_FixedUserRotation()357 public void testNotEnablesSensor_FixedUserRotation() throws Exception { 358 mBuilder.build(); 359 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 360 361 when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); 362 when(mMockDisplayPolicy.isAwake()).thenReturn(true); 363 when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); 364 when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); 365 mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED); 366 mTarget.updateOrientationListener(); 367 verifyOrientationListenerRegistration(0); 368 } 369 370 @Test testNotEnablesSensor_ForceDefaultRotation_Car()371 public void testNotEnablesSensor_ForceDefaultRotation_Car() throws Exception { 372 mBuilder.build(); 373 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, true, false); 374 375 when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); 376 when(mMockDisplayPolicy.isAwake()).thenReturn(true); 377 when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); 378 when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); 379 mTarget.updateOrientationListener(); 380 verifyOrientationListenerRegistration(0); 381 } 382 383 @Test testNotEnablesSensor_ForceDefaultRotation_Tv()384 public void testNotEnablesSensor_ForceDefaultRotation_Tv() throws Exception { 385 mBuilder.build(); 386 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, true); 387 388 when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); 389 when(mMockDisplayPolicy.isAwake()).thenReturn(true); 390 when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); 391 when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); 392 mTarget.updateOrientationListener(); 393 verifyOrientationListenerRegistration(0); 394 } 395 enableOrientationSensor()396 private void enableOrientationSensor() { 397 when(mMockDisplayPolicy.isScreenOnEarly()).thenReturn(true); 398 when(mMockDisplayPolicy.isAwake()).thenReturn(true); 399 when(mMockDisplayPolicy.isKeyguardDrawComplete()).thenReturn(true); 400 when(mMockDisplayPolicy.isWindowManagerDrawComplete()).thenReturn(true); 401 mTarget.updateOrientationListener(); 402 verifyOrientationListenerRegistration(1); 403 } 404 createSensorEvent(int rotation)405 private SensorEvent createSensorEvent(int rotation) throws Exception { 406 final Constructor<SensorEvent> constructor = 407 SensorEvent.class.getDeclaredConstructor(int.class); 408 constructor.setAccessible(true); 409 final SensorEvent event = constructor.newInstance(1); 410 event.sensor = mFakeSensor; 411 event.values[0] = rotation; 412 event.timestamp = SystemClock.elapsedRealtimeNanos(); 413 return event; 414 } 415 416 @Test testReturnsSensorRotation_RotationThawed()417 public void testReturnsSensorRotation_RotationThawed() throws Exception { 418 mBuilder.build(); 419 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 420 421 thawRotation(); 422 423 enableOrientationSensor(); 424 425 mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); 426 427 assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( 428 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); 429 } 430 waitForUiHandler()431 private boolean waitForUiHandler() throws Exception { 432 final CountDownLatch latch = new CountDownLatch(1); 433 UiThread.getHandler().post(latch::countDown); 434 return latch.await(UI_HANDLER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS); 435 } 436 437 @Test testUpdatesRotationWhenSensorUpdates_RotationThawed()438 public void testUpdatesRotationWhenSensorUpdates_RotationThawed() throws Exception { 439 mBuilder.build(); 440 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 441 442 thawRotation(); 443 444 enableOrientationSensor(); 445 446 mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); 447 assertTrue(waitForUiHandler()); 448 449 verify(sMockWm).updateRotation(false, false); 450 } 451 452 @Test testNotifiesChoiceWhenSensorUpdates_RotationLocked()453 public void testNotifiesChoiceWhenSensorUpdates_RotationLocked() throws Exception { 454 mBuilder.build(); 455 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 456 457 freezeRotation(Surface.ROTATION_270); 458 459 enableOrientationSensor(); 460 461 mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90)); 462 assertTrue(waitForUiHandler()); 463 464 verify(mMockStatusBarManagerInternal).onProposedRotationChanged(Surface.ROTATION_90, true); 465 } 466 467 @Test testReturnsCompatibleRotation_SensorEnabled_RotationThawed()468 public void testReturnsCompatibleRotation_SensorEnabled_RotationThawed() throws Exception { 469 mBuilder.build(); 470 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 471 472 thawRotation(); 473 474 enableOrientationSensor(); 475 476 mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180)); 477 478 final int rotation = mTarget.rotationForOrientation(SCREEN_ORIENTATION_LANDSCAPE, 479 Surface.ROTATION_0); 480 assertTrue("Rotation should be sideways but it's " 481 + Surface.rotationToString(rotation), 482 rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270); 483 } 484 485 @Test testReturnsUserRotation_SensorEnabled_RotationLocked()486 public void testReturnsUserRotation_SensorEnabled_RotationLocked() throws Exception { 487 mBuilder.build(); 488 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 489 490 freezeRotation(Surface.ROTATION_270); 491 492 enableOrientationSensor(); 493 494 mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_180)); 495 496 assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation( 497 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); 498 } 499 500 // ================================= 501 // Tests for Policy based Rotation 502 // ================================= 503 @Test testReturnsUserRotation_ForceDefaultRotation_Car()504 public void testReturnsUserRotation_ForceDefaultRotation_Car() throws Exception { 505 mBuilder.build(); 506 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, true, false); 507 508 assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT, 509 Surface.ROTATION_180)); 510 } 511 512 @Test testReturnsUserRotation_ForceDefaultRotation_Tv()513 public void testReturnsUserRotation_ForceDefaultRotation_Tv() throws Exception { 514 mBuilder.build(); 515 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, true); 516 517 assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(SCREEN_ORIENTATION_PORTRAIT, 518 Surface.ROTATION_180)); 519 } 520 521 @Test testReturnsLidOpenRotation_LidOpen()522 public void testReturnsLidOpenRotation_LidOpen() throws Exception { 523 mBuilder.setLidOpenRotation(Surface.ROTATION_90).build(); 524 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); 525 526 when(mMockDisplayPolicy.getLidState()).thenReturn( 527 WindowManagerPolicy.WindowManagerFuncs.LID_OPEN); 528 529 freezeRotation(Surface.ROTATION_270); 530 531 assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( 532 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); 533 } 534 535 @Test testReturnsCarDockRotation_CarDockedMode()536 public void testReturnsCarDockRotation_CarDockedMode() throws Exception { 537 mBuilder.setCarDockRotation(Surface.ROTATION_270).build(); 538 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); 539 540 when(mMockDisplayPolicy.getDockMode()).thenReturn(Intent.EXTRA_DOCK_STATE_CAR); 541 542 freezeRotation(Surface.ROTATION_90); 543 544 assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation( 545 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_90)); 546 } 547 548 @Test testReturnsDeskDockRotation_DeskDockedMode()549 public void testReturnsDeskDockRotation_DeskDockedMode() throws Exception { 550 mBuilder.setDeskDockRotation(Surface.ROTATION_270).build(); 551 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); 552 553 when(mMockDisplayPolicy.getDockMode()).thenReturn(Intent.EXTRA_DOCK_STATE_DESK); 554 555 freezeRotation(Surface.ROTATION_90); 556 557 assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation( 558 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_90)); 559 } 560 561 @Test testReturnsUserRotation_FixedToUserRotation_IgnoreIncompatibleAppRequest()562 public void testReturnsUserRotation_FixedToUserRotation_IgnoreIncompatibleAppRequest() 563 throws Exception { 564 mBuilder.build(); 565 configureDisplayRotation(SCREEN_ORIENTATION_PORTRAIT, false, false); 566 567 mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED); 568 569 freezeRotation(Surface.ROTATION_180); 570 571 final int rotation = mTarget.rotationForOrientation( 572 ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, Surface.ROTATION_90); 573 assertEquals(Surface.ROTATION_180, rotation); 574 } 575 576 @Test testReturnsUserRotation_NonDefaultDisplay()577 public void testReturnsUserRotation_NonDefaultDisplay() throws Exception { 578 mBuilder.setIsDefaultDisplay(false).build(); 579 configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false); 580 581 freezeRotation(Surface.ROTATION_90); 582 583 assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation( 584 SCREEN_ORIENTATION_UNSPECIFIED, Surface.ROTATION_0)); 585 } 586 587 // ======================== 588 // Non-rotation API Tests 589 // ======================== 590 @Test testRespectsAppRequestedOrientationByDefault()591 public void testRespectsAppRequestedOrientationByDefault() throws Exception { 592 mBuilder.build(); 593 594 assertTrue("Display rotation should respect app requested orientation by" 595 + " default.", mTarget.respectAppRequestedOrientation()); 596 } 597 598 @Test testNotRespectAppRequestedOrientation_FixedToUserRotation()599 public void testNotRespectAppRequestedOrientation_FixedToUserRotation() throws Exception { 600 mBuilder.build(); 601 mTarget.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED); 602 603 assertFalse("Display rotation shouldn't respect app requested orientation if" 604 + " fixed to user rotation.", mTarget.respectAppRequestedOrientation()); 605 } 606 607 /** 608 * Call {@link DisplayRotation#configure(int, int, int, int)} to configure {@link #mTarget} 609 * according to given parameters. 610 */ configureDisplayRotation(int displayOrientation, boolean isCar, boolean isTv)611 private void configureDisplayRotation(int displayOrientation, boolean isCar, boolean isTv) { 612 final int width; 613 final int height; 614 switch (displayOrientation) { 615 case SCREEN_ORIENTATION_LANDSCAPE: 616 width = 1920; 617 height = 1080; 618 break; 619 case SCREEN_ORIENTATION_PORTRAIT: 620 width = 1080; 621 height = 1920; 622 break; 623 default: 624 throw new IllegalArgumentException("displayOrientation needs to be either landscape" 625 + " or portrait, but we got " 626 + ActivityInfo.screenOrientationToString(displayOrientation)); 627 } 628 629 final PackageManager mockPackageManager = mock(PackageManager.class); 630 when(mMockContext.getPackageManager()).thenReturn(mockPackageManager); 631 when(mockPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) 632 .thenReturn(isCar); 633 when(mockPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) 634 .thenReturn(isTv); 635 636 final int shortSizeDp = (isCar || isTv) ? 540 : 720; 637 final int longSizeDp = 960; 638 mTarget.configure(width, height, shortSizeDp, longSizeDp); 639 } 640 freezeRotation(int rotation)641 private void freezeRotation(int rotation) { 642 mTarget.freezeRotation(rotation); 643 644 if (mTarget.isDefaultDisplay) { 645 mAccelerometerRotationObserver.onChange(false); 646 mUserRotationObserver.onChange(false); 647 } 648 } 649 thawRotation()650 private void thawRotation() { 651 mTarget.thawRotation(); 652 653 if (mTarget.isDefaultDisplay) { 654 mAccelerometerRotationObserver.onChange(false); 655 mUserRotationObserver.onChange(false); 656 } 657 } 658 659 private class DisplayRotationBuilder { 660 private boolean mIsDefaultDisplay = true; 661 private boolean mSupportAutoRotation = true; 662 663 private int mLidOpenRotation = WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; 664 private int mCarDockRotation; 665 private int mDeskDockRotation; 666 private int mUndockedHdmiRotation; 667 setIsDefaultDisplay(boolean isDefaultDisplay)668 private DisplayRotationBuilder setIsDefaultDisplay(boolean isDefaultDisplay) { 669 mIsDefaultDisplay = isDefaultDisplay; 670 return this; 671 } 672 setSupportAutoRotation(boolean supportAutoRotation)673 private DisplayRotationBuilder setSupportAutoRotation(boolean supportAutoRotation) { 674 mSupportAutoRotation = supportAutoRotation; 675 return this; 676 } 677 setLidOpenRotation(int rotation)678 private DisplayRotationBuilder setLidOpenRotation(int rotation) { 679 mLidOpenRotation = rotation; 680 return this; 681 } 682 setCarDockRotation(int rotation)683 private DisplayRotationBuilder setCarDockRotation(int rotation) { 684 mCarDockRotation = rotation; 685 return this; 686 } 687 setDeskDockRotation(int rotation)688 private DisplayRotationBuilder setDeskDockRotation(int rotation) { 689 mDeskDockRotation = rotation; 690 return this; 691 } 692 setUndockedHdmiRotation(int rotation)693 private DisplayRotationBuilder setUndockedHdmiRotation(int rotation) { 694 mUndockedHdmiRotation = rotation; 695 return this; 696 } 697 captureObservers()698 private void captureObservers() { 699 ArgumentCaptor<ContentObserver> captor = ArgumentCaptor.forClass( 700 ContentObserver.class); 701 verify(mMockResolver, atMost(1)).registerContentObserver( 702 eq(Settings.Secure.getUriFor(Settings.Secure.SHOW_ROTATION_SUGGESTIONS)), 703 anyBoolean(), 704 captor.capture(), 705 anyInt()); 706 if (!captor.getAllValues().isEmpty()) { 707 mShowRotationSuggestionsObserver = captor.getValue(); 708 } 709 710 captor = ArgumentCaptor.forClass(ContentObserver.class); 711 verify(mMockResolver, atMost(1)).registerContentObserver( 712 eq(Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION)), 713 anyBoolean(), 714 captor.capture(), 715 anyInt()); 716 if (!captor.getAllValues().isEmpty()) { 717 mAccelerometerRotationObserver = captor.getValue(); 718 } 719 720 captor = ArgumentCaptor.forClass(ContentObserver.class); 721 verify(mMockResolver, atMost(1)).registerContentObserver( 722 eq(Settings.System.getUriFor(Settings.System.USER_ROTATION)), 723 anyBoolean(), 724 captor.capture(), 725 anyInt()); 726 if (!captor.getAllValues().isEmpty()) { 727 mUserRotationObserver = captor.getValue(); 728 } 729 } 730 createSensor(int type)731 private Sensor createSensor(int type) throws Exception { 732 Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor(); 733 constr.setAccessible(true); 734 Sensor sensor = constr.newInstance(); 735 736 setSensorType(sensor, type); 737 setSensorField(sensor, "mName", "Mock " + sensor.getStringType() + "/" + type); 738 setSensorField(sensor, "mVendor", "Mock Vendor"); 739 setSensorField(sensor, "mVersion", 1); 740 setSensorField(sensor, "mHandle", -1); 741 setSensorField(sensor, "mMaxRange", 10); 742 setSensorField(sensor, "mResolution", 1); 743 setSensorField(sensor, "mPower", 1); 744 setSensorField(sensor, "mMinDelay", 1000); 745 setSensorField(sensor, "mMaxDelay", 1000000000); 746 setSensorField(sensor, "mFlags", 0); 747 setSensorField(sensor, "mId", -1); 748 749 return sensor; 750 } 751 setSensorType(Sensor sensor, int type)752 private void setSensorType(Sensor sensor, int type) throws Exception { 753 Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE); 754 setter.setAccessible(true); 755 setter.invoke(sensor, type); 756 } 757 setSensorField(Sensor sensor, String fieldName, Object value)758 private void setSensorField(Sensor sensor, String fieldName, Object value) 759 throws Exception { 760 Field field = Sensor.class.getDeclaredField(fieldName); 761 field.setAccessible(true); 762 field.set(sensor, value); 763 } 764 convertRotationToDegrees(@urface.Rotation int rotation)765 private int convertRotationToDegrees(@Surface.Rotation int rotation) { 766 switch (rotation) { 767 case Surface.ROTATION_0: 768 return 0; 769 case Surface.ROTATION_90: 770 return 90; 771 case Surface.ROTATION_180: 772 return 180; 773 case Surface.ROTATION_270: 774 return 270; 775 default: 776 return -1; 777 } 778 } 779 build()780 private void build() throws Exception { 781 mMockContext = mock(Context.class); 782 783 mMockDisplayContent = mock(DisplayContent.class); 784 mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay; 785 when(mMockDisplayContent.calculateDisplayCutoutForRotation(anyInt())) 786 .thenReturn(WmDisplayCutout.NO_CUTOUT); 787 788 mMockDisplayPolicy = mock(DisplayPolicy.class); 789 790 mMockRes = mock(Resources.class); 791 when(mMockContext.getResources()).thenReturn((mMockRes)); 792 when(mMockRes.getBoolean(com.android.internal.R.bool.config_supportAutoRotation)) 793 .thenReturn(mSupportAutoRotation); 794 when(mMockRes.getInteger(com.android.internal.R.integer.config_lidOpenRotation)) 795 .thenReturn(convertRotationToDegrees(mLidOpenRotation)); 796 when(mMockRes.getInteger(com.android.internal.R.integer.config_carDockRotation)) 797 .thenReturn(convertRotationToDegrees(mCarDockRotation)); 798 when(mMockRes.getInteger(com.android.internal.R.integer.config_deskDockRotation)) 799 .thenReturn(convertRotationToDegrees(mDeskDockRotation)); 800 when(mMockRes.getInteger(com.android.internal.R.integer.config_undockedHdmiRotation)) 801 .thenReturn(convertRotationToDegrees(mUndockedHdmiRotation)); 802 803 mMockSensorManager = mock(SensorManager.class); 804 when(mMockContext.getSystemService(Context.SENSOR_SERVICE)) 805 .thenReturn(mMockSensorManager); 806 mFakeSensor = createSensor(Sensor.TYPE_DEVICE_ORIENTATION); 807 when(mMockSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION)).thenReturn( 808 Collections.singletonList(mFakeSensor)); 809 810 mMockResolver = mock(ContentResolver.class); 811 when(mMockContext.getContentResolver()).thenReturn(mMockResolver); 812 mFakeSettingsProvider = new FakeSettingsProvider(); 813 when(mMockResolver.acquireProvider(Settings.AUTHORITY)) 814 .thenReturn(mFakeSettingsProvider.getIContentProvider()); 815 816 mMockDisplayWindowSettings = mock(DisplayWindowSettings.class); 817 mTarget = new DisplayRotation(sMockWm, mMockDisplayContent, mMockDisplayPolicy, 818 mMockDisplayWindowSettings, mMockContext, new Object()); 819 reset(sMockWm); 820 821 captureObservers(); 822 } 823 } 824 } 825