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_UNSPECIFIED; 20 import static android.util.RotationUtils.deltaRotation; 21 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; 22 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT; 23 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; 24 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; 25 26 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; 27 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN; 28 import static com.android.server.wm.DisplayRotationProto.FIXED_TO_USER_ROTATION_MODE; 29 import static com.android.server.wm.DisplayRotationProto.FROZEN_TO_USER_ROTATION; 30 import static com.android.server.wm.DisplayRotationProto.LAST_ORIENTATION; 31 import static com.android.server.wm.DisplayRotationProto.ROTATION; 32 import static com.android.server.wm.DisplayRotationProto.USER_ROTATION; 33 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 34 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 35 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 36 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE; 37 import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION; 38 39 import android.annotation.AnimRes; 40 import android.annotation.IntDef; 41 import android.annotation.UserIdInt; 42 import android.app.ActivityManager; 43 import android.content.ContentResolver; 44 import android.content.Context; 45 import android.content.Intent; 46 import android.content.pm.ActivityInfo; 47 import android.content.pm.ActivityInfo.ScreenOrientation; 48 import android.content.pm.PackageManager; 49 import android.content.res.Resources; 50 import android.database.ContentObserver; 51 import android.hardware.power.Boost; 52 import android.net.Uri; 53 import android.os.Handler; 54 import android.os.RemoteException; 55 import android.os.SystemProperties; 56 import android.os.UserHandle; 57 import android.provider.Settings; 58 import android.util.Slog; 59 import android.util.SparseArray; 60 import android.util.proto.ProtoOutputStream; 61 import android.view.IDisplayWindowRotationCallback; 62 import android.view.IWindowManager; 63 import android.view.Surface; 64 import android.window.WindowContainerTransaction; 65 66 import com.android.internal.R; 67 import com.android.internal.annotations.VisibleForTesting; 68 import com.android.internal.protolog.common.ProtoLog; 69 import com.android.internal.util.function.pooled.PooledLambda; 70 import com.android.server.LocalServices; 71 import com.android.server.UiThread; 72 import com.android.server.policy.WindowManagerPolicy; 73 import com.android.server.statusbar.StatusBarManagerInternal; 74 75 import java.io.PrintWriter; 76 import java.lang.annotation.Retention; 77 import java.lang.annotation.RetentionPolicy; 78 79 /** 80 * Defines the mapping between orientation and rotation of a display. 81 * Non-public methods are assumed to run inside WM lock. 82 */ 83 public class DisplayRotation { 84 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM; 85 86 private static class RotationAnimationPair { 87 @AnimRes 88 int mEnter; 89 @AnimRes 90 int mExit; 91 } 92 93 private final WindowManagerService mService; 94 private final DisplayContent mDisplayContent; 95 private final DisplayPolicy mDisplayPolicy; 96 private final DisplayWindowSettings mDisplayWindowSettings; 97 private final Context mContext; 98 private final Object mLock; 99 100 public final boolean isDefaultDisplay; 101 private final boolean mSupportAutoRotation; 102 private final int mLidOpenRotation; 103 private final int mCarDockRotation; 104 private final int mDeskDockRotation; 105 private final int mUndockedHdmiRotation; 106 private final RotationAnimationPair mTmpRotationAnim = new RotationAnimationPair(); 107 108 private OrientationListener mOrientationListener; 109 private StatusBarManagerInternal mStatusBarManagerInternal; 110 private SettingsObserver mSettingsObserver; 111 112 @ScreenOrientation 113 private int mCurrentAppOrientation = SCREEN_ORIENTATION_UNSPECIFIED; 114 115 /** 116 * Last applied orientation of the display. 117 * 118 * @see #updateOrientationFromApp 119 */ 120 @ScreenOrientation 121 private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED; 122 123 /** 124 * Current rotation of the display. 125 * 126 * @see #updateRotationUnchecked 127 */ 128 @Surface.Rotation 129 private int mRotation; 130 131 @VisibleForTesting 132 int mLandscapeRotation; // default landscape 133 @VisibleForTesting 134 int mSeascapeRotation; // "other" landscape, 180 degrees from mLandscapeRotation 135 @VisibleForTesting 136 int mPortraitRotation; // default portrait 137 @VisibleForTesting 138 int mUpsideDownRotation; // "other" portrait 139 140 private boolean mAllowSeamlessRotationDespiteNavBarMoving; 141 142 private int mDeferredRotationPauseCount; 143 144 /** 145 * A count of the windows which are 'seamlessly rotated', e.g. a surface at an old orientation 146 * is being transformed. We freeze orientation updates while any windows are seamlessly rotated, 147 * so we need to track when this hits zero so we can apply deferred orientation updates. 148 */ 149 private int mSeamlessRotationCount; 150 151 /** 152 * True in the interval from starting seamless rotation until the last rotated window draws in 153 * the new orientation. 154 */ 155 private boolean mRotatingSeamlessly; 156 157 /** 158 * Behavior of rotation suggestions. 159 * 160 * @see Settings.Secure#SHOW_ROTATION_SUGGESTIONS 161 */ 162 private int mShowRotationSuggestions; 163 164 private static final int ALLOW_ALL_ROTATIONS_UNDEFINED = -1; 165 private static final int ALLOW_ALL_ROTATIONS_DISABLED = 0; 166 private static final int ALLOW_ALL_ROTATIONS_ENABLED = 1; 167 168 @IntDef({ ALLOW_ALL_ROTATIONS_UNDEFINED, ALLOW_ALL_ROTATIONS_DISABLED, 169 ALLOW_ALL_ROTATIONS_ENABLED }) 170 @Retention(RetentionPolicy.SOURCE) 171 private @interface AllowAllRotations {} 172 173 /** 174 * Whether to allow the screen to rotate to all rotations (including 180 degree) according to 175 * the sensor even when the current orientation is not 176 * {@link ActivityInfo#SCREEN_ORIENTATION_FULL_SENSOR} or 177 * {@link ActivityInfo#SCREEN_ORIENTATION_FULL_USER}. 178 */ 179 @AllowAllRotations 180 private int mAllowAllRotations = ALLOW_ALL_ROTATIONS_UNDEFINED; 181 182 @WindowManagerPolicy.UserRotationMode 183 private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; 184 185 @Surface.Rotation 186 private int mUserRotation = Surface.ROTATION_0; 187 188 private static final int CAMERA_ROTATION_DISABLED = 0; 189 private static final int CAMERA_ROTATION_ENABLED = 1; 190 private int mCameraRotationMode = CAMERA_ROTATION_DISABLED; 191 192 /** 193 * Flag that indicates this is a display that may run better when fixed to user rotation. 194 */ 195 private boolean mDefaultFixedToUserRotation; 196 197 /** 198 * A flag to indicate if the display rotation should be fixed to user specified rotation 199 * regardless of all other states (including app requrested orientation). {@code true} the 200 * display rotation should be fixed to user specified rotation, {@code false} otherwise. 201 */ 202 private int mFixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT; 203 204 private int mDemoHdmiRotation; 205 private int mDemoRotation; 206 private boolean mDemoHdmiRotationLock; 207 private boolean mDemoRotationLock; 208 209 private static final int REMOTE_ROTATION_TIMEOUT_MS = 800; 210 211 private boolean mIsWaitingForRemoteRotation = false; 212 213 private final Runnable mDisplayRotationHandlerTimeout = 214 new Runnable() { 215 @Override 216 public void run() { 217 continueRotation(mRotation, null /* transaction */); 218 } 219 }; 220 221 private final IDisplayWindowRotationCallback mRemoteRotationCallback = 222 new IDisplayWindowRotationCallback.Stub() { 223 @Override 224 public void continueRotateDisplay(int targetRotation, 225 WindowContainerTransaction t) { 226 synchronized (mService.getWindowManagerLock()) { 227 mService.mH.sendMessage(PooledLambda.obtainMessage( 228 DisplayRotation::continueRotation, DisplayRotation.this, 229 targetRotation, t)); 230 } 231 } 232 }; 233 DisplayRotation(WindowManagerService service, DisplayContent displayContent)234 DisplayRotation(WindowManagerService service, DisplayContent displayContent) { 235 this(service, displayContent, displayContent.getDisplayPolicy(), 236 service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock()); 237 } 238 239 @VisibleForTesting DisplayRotation(WindowManagerService service, DisplayContent displayContent, DisplayPolicy displayPolicy, DisplayWindowSettings displayWindowSettings, Context context, Object lock)240 DisplayRotation(WindowManagerService service, DisplayContent displayContent, 241 DisplayPolicy displayPolicy, DisplayWindowSettings displayWindowSettings, 242 Context context, Object lock) { 243 mService = service; 244 mDisplayContent = displayContent; 245 mDisplayPolicy = displayPolicy; 246 mDisplayWindowSettings = displayWindowSettings; 247 mContext = context; 248 mLock = lock; 249 isDefaultDisplay = displayContent.isDefaultDisplay; 250 251 mSupportAutoRotation = 252 mContext.getResources().getBoolean(R.bool.config_supportAutoRotation); 253 mLidOpenRotation = readRotation(R.integer.config_lidOpenRotation); 254 mCarDockRotation = readRotation(R.integer.config_carDockRotation); 255 mDeskDockRotation = readRotation(R.integer.config_deskDockRotation); 256 mUndockedHdmiRotation = readRotation(R.integer.config_undockedHdmiRotation); 257 258 if (isDefaultDisplay) { 259 final Handler uiHandler = UiThread.getHandler(); 260 mOrientationListener = new OrientationListener(mContext, uiHandler); 261 mOrientationListener.setCurrentRotation(mRotation); 262 mSettingsObserver = new SettingsObserver(uiHandler); 263 mSettingsObserver.observe(); 264 } 265 } 266 readRotation(int resID)267 private int readRotation(int resID) { 268 try { 269 final int rotation = mContext.getResources().getInteger(resID); 270 switch (rotation) { 271 case 0: 272 return Surface.ROTATION_0; 273 case 90: 274 return Surface.ROTATION_90; 275 case 180: 276 return Surface.ROTATION_180; 277 case 270: 278 return Surface.ROTATION_270; 279 } 280 } catch (Resources.NotFoundException e) { 281 // fall through 282 } 283 return -1; 284 } 285 286 /** 287 * Updates the configuration which may have different values depending on current user, e.g. 288 * runtime resource overlay. 289 */ updateUserDependentConfiguration(Resources currentUserRes)290 void updateUserDependentConfiguration(Resources currentUserRes) { 291 mAllowSeamlessRotationDespiteNavBarMoving = 292 currentUserRes.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving); 293 } 294 configure(int width, int height, int shortSizeDp, int longSizeDp)295 void configure(int width, int height, int shortSizeDp, int longSizeDp) { 296 final Resources res = mContext.getResources(); 297 if (width > height) { 298 mLandscapeRotation = Surface.ROTATION_0; 299 mSeascapeRotation = Surface.ROTATION_180; 300 if (res.getBoolean(R.bool.config_reverseDefaultRotation)) { 301 mPortraitRotation = Surface.ROTATION_90; 302 mUpsideDownRotation = Surface.ROTATION_270; 303 } else { 304 mPortraitRotation = Surface.ROTATION_270; 305 mUpsideDownRotation = Surface.ROTATION_90; 306 } 307 } else { 308 mPortraitRotation = Surface.ROTATION_0; 309 mUpsideDownRotation = Surface.ROTATION_180; 310 if (res.getBoolean(R.bool.config_reverseDefaultRotation)) { 311 mLandscapeRotation = Surface.ROTATION_270; 312 mSeascapeRotation = Surface.ROTATION_90; 313 } else { 314 mLandscapeRotation = Surface.ROTATION_90; 315 mSeascapeRotation = Surface.ROTATION_270; 316 } 317 } 318 319 // For demo purposes, allow the rotation of the HDMI display to be controlled. 320 // By default, HDMI locks rotation to landscape. 321 if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) { 322 mDemoHdmiRotation = mPortraitRotation; 323 } else { 324 mDemoHdmiRotation = mLandscapeRotation; 325 } 326 mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false); 327 328 // For demo purposes, allow the rotation of the remote display to be controlled. 329 // By default, remote display locks rotation to landscape. 330 if ("portrait".equals(SystemProperties.get("persist.demo.remoterotation"))) { 331 mDemoRotation = mPortraitRotation; 332 } else { 333 mDemoRotation = mLandscapeRotation; 334 } 335 mDemoRotationLock = SystemProperties.getBoolean("persist.demo.rotationlock", false); 336 337 // It's physically impossible to rotate the car's screen. 338 final boolean isCar = mContext.getPackageManager().hasSystemFeature( 339 PackageManager.FEATURE_AUTOMOTIVE); 340 // It's also not likely to rotate a TV screen. 341 final boolean isTv = mContext.getPackageManager().hasSystemFeature( 342 PackageManager.FEATURE_LEANBACK); 343 mDefaultFixedToUserRotation = 344 (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode()) 345 // For debug purposes the next line turns this feature off with: 346 // $ adb shell setprop config.override_forced_orient true 347 // $ adb shell wm size reset 348 && !"true".equals(SystemProperties.get("config.override_forced_orient")); 349 } 350 applyCurrentRotation(@urface.Rotation int rotation)351 void applyCurrentRotation(@Surface.Rotation int rotation) { 352 if (mOrientationListener != null) { 353 mOrientationListener.setCurrentRotation(rotation); 354 } 355 } 356 357 @VisibleForTesting setRotation(@urface.Rotation int rotation)358 void setRotation(@Surface.Rotation int rotation) { 359 mRotation = rotation; 360 } 361 362 @Surface.Rotation getRotation()363 int getRotation() { 364 return mRotation; 365 } 366 367 @ScreenOrientation getLastOrientation()368 int getLastOrientation() { 369 return mLastOrientation; 370 } 371 updateOrientation(@creenOrientation int newOrientation, boolean forceUpdate)372 boolean updateOrientation(@ScreenOrientation int newOrientation, boolean forceUpdate) { 373 if (newOrientation == mLastOrientation && !forceUpdate) { 374 return false; 375 } 376 mLastOrientation = newOrientation; 377 if (newOrientation != mCurrentAppOrientation) { 378 mCurrentAppOrientation = newOrientation; 379 if (isDefaultDisplay) { 380 updateOrientationListenerLw(); 381 } 382 } 383 return updateRotationUnchecked(forceUpdate); 384 } 385 386 /** 387 * Update rotation of the display and send configuration if the rotation is changed. 388 * 389 * @return {@code true} if the rotation has been changed and the new config is sent. 390 */ updateRotationAndSendNewConfigIfChanged()391 boolean updateRotationAndSendNewConfigIfChanged() { 392 final boolean changed = updateRotationUnchecked(false /* forceUpdate */); 393 if (changed) { 394 mDisplayContent.sendNewConfiguration(); 395 } 396 return changed; 397 } 398 399 /** 400 * Update rotation with an option to force the update. This updates the container's perception 401 * of rotation and, depending on the top activities, will freeze the screen or start seamless 402 * rotation. The display itself gets rotated in {@link DisplayContent#applyRotationLocked} 403 * during {@link DisplayContent#sendNewConfiguration}. 404 * 405 * @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating 406 * orientation because we're waiting for some rotation to finish or display 407 * to unfreeze, which results in configuration of the previously visible 408 * activity being applied to a newly visible one. Forcing the rotation 409 * update allows to workaround this issue. 410 * @return {@code true} if the rotation has been changed. In this case YOU MUST CALL 411 * {@link DisplayContent#sendNewConfiguration} TO COMPLETE THE ROTATION AND UNFREEZE 412 * THE SCREEN. 413 */ updateRotationUnchecked(boolean forceUpdate)414 boolean updateRotationUnchecked(boolean forceUpdate) { 415 final boolean useShellTransitions = 416 mDisplayContent.mTransitionController.isShellTransitionsEnabled(); 417 418 final int displayId = mDisplayContent.getDisplayId(); 419 if (!forceUpdate && !useShellTransitions) { 420 if (mDeferredRotationPauseCount > 0) { 421 // Rotation updates have been paused temporarily. Defer the update until updates 422 // have been resumed. 423 ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, rotation is paused."); 424 return false; 425 } 426 427 final ScreenRotationAnimation screenRotationAnimation = 428 mDisplayContent.getRotationAnimation(); 429 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) { 430 // Rotation updates cannot be performed while the previous rotation change animation 431 // is still in progress. Skip this update. We will try updating again after the 432 // animation is finished and the display is unfrozen. 433 ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, animation in progress."); 434 return false; 435 } 436 if (mService.mDisplayFrozen) { 437 // Even if the screen rotation animation has finished (e.g. isAnimating returns 438 // false), there is still some time where we haven't yet unfrozen the display. We 439 // also need to abort rotation here. 440 ProtoLog.v(WM_DEBUG_ORIENTATION, 441 "Deferring rotation, still finishing previous rotation"); 442 return false; 443 } 444 445 final RecentsAnimationController recentsAnimController = 446 mService.getRecentsAnimationController(); 447 if (recentsAnimController != null && mDisplayContent.mFixedRotationTransitionListener 448 .isTopFixedOrientationRecentsAnimating() 449 // If screen is off or the device is going to sleep, then still allow to update. 450 && mService.mPolicy.okToAnimate(false /* ignoreScreenOn */)) { 451 // During the recents animation, the closing app might still be considered on top. 452 // In order to ignore its requested orientation to avoid a sensor led rotation (e.g 453 // user rotating the device while the recents animation is running), we ignore 454 // rotation update while the animation is running. 455 recentsAnimController.setCheckRotationAfterCleanup(); 456 return false; 457 } 458 } 459 460 if (!mService.mDisplayEnabled) { 461 // No point choosing a rotation if the display is not enabled. 462 ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, display is not enabled."); 463 return false; 464 } 465 466 final int oldRotation = mRotation; 467 final int lastOrientation = mLastOrientation; 468 final int rotation = rotationForOrientation(lastOrientation, oldRotation); 469 ProtoLog.v(WM_DEBUG_ORIENTATION, 470 "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and " 471 + "oldRotation=%s (%d)", 472 Surface.rotationToString(rotation), rotation, 473 displayId, 474 ActivityInfo.screenOrientationToString(lastOrientation), lastOrientation, 475 Surface.rotationToString(oldRotation), oldRotation); 476 477 ProtoLog.v(WM_DEBUG_ORIENTATION, 478 "Display id=%d selected orientation %s (%d), got rotation %s (%d)", displayId, 479 ActivityInfo.screenOrientationToString(lastOrientation), lastOrientation, 480 Surface.rotationToString(rotation), rotation); 481 482 if (oldRotation == rotation) { 483 // No change. 484 return false; 485 } 486 487 // Preemptively cancel the running recents animation -- SysUI can't currently handle this 488 // case properly since the signals it receives all happen post-change. We do this earlier 489 // in the rotation flow, since DisplayContent.updateDisplayOverrideConfigurationLocked seems 490 // to happen too late. 491 final RecentsAnimationController recentsAnimationController = 492 mService.getRecentsAnimationController(); 493 if (recentsAnimationController != null) { 494 recentsAnimationController.cancelAnimationForDisplayChange(); 495 } 496 497 ProtoLog.v(WM_DEBUG_ORIENTATION, 498 "Display id=%d rotation changed to %d from %d, lastOrientation=%d", 499 displayId, rotation, oldRotation, lastOrientation); 500 501 if (deltaRotation(oldRotation, rotation) != Surface.ROTATION_180) { 502 mDisplayContent.mWaitingForConfig = true; 503 } 504 505 mRotation = rotation; 506 507 mDisplayContent.setLayoutNeeded(); 508 509 if (useShellTransitions) { 510 final boolean wasInTransition = mDisplayContent.inTransition(); 511 mDisplayContent.requestChangeTransitionIfNeeded( 512 ActivityInfo.CONFIG_WINDOW_CONFIGURATION); 513 if (wasInTransition) { 514 // Use remote-rotation infra since the transition has already been requested 515 // TODO(shell-transitions): Remove this once lifecycle management can cover all 516 // rotation cases. 517 startRemoteRotation(oldRotation, mRotation); 518 } 519 return true; 520 } 521 522 mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE; 523 mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT, 524 mDisplayContent, WINDOW_FREEZE_TIMEOUT_DURATION); 525 526 if (shouldRotateSeamlessly(oldRotation, rotation, forceUpdate)) { 527 // The screen rotation animation uses a screenshot to freeze the screen while windows 528 // resize underneath. When we are rotating seamlessly, we allow the elements to 529 // transition to their rotated state independently and without a freeze required. 530 prepareSeamlessRotation(); 531 } else { 532 prepareNormalRotationAnimation(); 533 } 534 535 // Give a remote handler (system ui) some time to reposition things. 536 startRemoteRotation(oldRotation, mRotation); 537 538 return true; 539 } 540 541 /** 542 * Utility to get a rotating displaycontent from a Transition. 543 * @return null if the transition doesn't contain a rotating display. 544 */ getDisplayFromTransition(Transition transition)545 static DisplayContent getDisplayFromTransition(Transition transition) { 546 for (int i = transition.mParticipants.size() - 1; i >= 0; --i) { 547 final WindowContainer wc = transition.mParticipants.valueAt(i); 548 if (!(wc instanceof DisplayContent)) continue; 549 return (DisplayContent) wc; 550 } 551 return null; 552 } 553 554 /** 555 * A Remote rotation is when we are waiting for some registered (remote) 556 * {@link IDisplayWindowRotationController} to calculate and return some hierarchy operations 557 * to perform in sync with the rotation. 558 */ isWaitingForRemoteRotation()559 boolean isWaitingForRemoteRotation() { 560 return mIsWaitingForRemoteRotation; 561 } 562 startRemoteRotation(int fromRotation, int toRotation)563 private void startRemoteRotation(int fromRotation, int toRotation) { 564 if (mService.mDisplayRotationController == null) { 565 return; 566 } 567 mIsWaitingForRemoteRotation = true; 568 try { 569 mService.mDisplayRotationController.onRotateDisplay(mDisplayContent.getDisplayId(), 570 fromRotation, toRotation, mRemoteRotationCallback); 571 mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout); 572 mService.mH.postDelayed(mDisplayRotationHandlerTimeout, REMOTE_ROTATION_TIMEOUT_MS); 573 } catch (RemoteException e) { 574 mIsWaitingForRemoteRotation = false; 575 return; 576 } 577 } 578 continueRotation(int targetRotation, WindowContainerTransaction t)579 private void continueRotation(int targetRotation, WindowContainerTransaction t) { 580 synchronized (mService.mGlobalLock) { 581 if (targetRotation != mRotation || !mIsWaitingForRemoteRotation) { 582 // Drop it, this is either coming from an outdated remote rotation; or, we've 583 // already moved on. 584 return; 585 } 586 mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout); 587 mIsWaitingForRemoteRotation = false; 588 589 if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) { 590 if (!mDisplayContent.mTransitionController.isCollecting()) { 591 throw new IllegalStateException("Trying to rotate outside a transition"); 592 } 593 mDisplayContent.mTransitionController.collect(mDisplayContent); 594 // Go through all tasks and collect them before the rotation 595 // TODO(shell-transitions): move collect() to onConfigurationChange once wallpaper 596 // handling is synchronized. 597 mDisplayContent.forAllTasks(task -> { 598 if (task.isVisible()) { 599 mDisplayContent.mTransitionController.collect(task); 600 } 601 }); 602 mDisplayContent.getInsetsStateController().addProvidersToTransition(); 603 } 604 mService.mAtmService.deferWindowLayout(); 605 try { 606 mDisplayContent.sendNewConfiguration(); 607 if (t != null) { 608 mService.mAtmService.mWindowOrganizerController.applyTransaction(t); 609 } 610 } finally { 611 mService.mAtmService.continueWindowLayout(); 612 } 613 } 614 } 615 prepareNormalRotationAnimation()616 void prepareNormalRotationAnimation() { 617 cancelSeamlessRotation(); 618 final RotationAnimationPair anim = selectRotationAnimation(); 619 mService.startFreezingDisplay(anim.mExit, anim.mEnter, mDisplayContent); 620 } 621 622 /** 623 * This ensures that normal rotation animation is used. E.g. {@link #mRotatingSeamlessly} was 624 * set by previous {@link #updateRotationUnchecked}, but another orientation change happens 625 * before calling {@link DisplayContent#sendNewConfiguration} (remote rotation hasn't finished) 626 * and it doesn't choose seamless rotation. 627 */ cancelSeamlessRotation()628 void cancelSeamlessRotation() { 629 if (!mRotatingSeamlessly) { 630 return; 631 } 632 mDisplayContent.forAllWindows(w -> { 633 if (w.mSeamlesslyRotated) { 634 w.cancelSeamlessRotation(); 635 w.mSeamlesslyRotated = false; 636 } 637 }, true /* traverseTopToBottom */); 638 mSeamlessRotationCount = 0; 639 mRotatingSeamlessly = false; 640 mDisplayContent.finishFadeRotationAnimationIfPossible(); 641 } 642 prepareSeamlessRotation()643 private void prepareSeamlessRotation() { 644 // We are careful to reset this in case a window was removed before it finished 645 // seamless rotation. 646 mSeamlessRotationCount = 0; 647 mRotatingSeamlessly = true; 648 } 649 isRotatingSeamlessly()650 boolean isRotatingSeamlessly() { 651 return mRotatingSeamlessly; 652 } 653 hasSeamlessRotatingWindow()654 boolean hasSeamlessRotatingWindow() { 655 return mSeamlessRotationCount > 0; 656 } 657 658 @VisibleForTesting shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate)659 boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) { 660 // Display doesn't need to be frozen because application has been started in correct 661 // rotation already, so the rest of the windows can use seamless rotation. 662 if (mDisplayContent.hasTopFixedRotationLaunchingApp()) { 663 return true; 664 } 665 666 final WindowState w = mDisplayPolicy.getTopFullscreenOpaqueWindow(); 667 if (w == null || w != mDisplayContent.mCurrentFocus) { 668 return false; 669 } 670 // We only enable seamless rotation if the top window has requested it and is in the 671 // fullscreen opaque state. Seamless rotation requires freezing various Surface states and 672 // won't work well with animations, so we disable it in the animation case for now. 673 if (w.getAttrs().rotationAnimation != ROTATION_ANIMATION_SEAMLESS || w.isAnimatingLw()) { 674 return false; 675 } 676 677 // For the upside down rotation we don't rotate seamlessly as the navigation bar moves 678 // position. Note most apps (using orientation:sensor or user as opposed to fullSensor) 679 // will not enter the reverse portrait orientation, so actually the orientation won't change 680 // at all. 681 if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) { 682 return false; 683 } 684 685 // If the navigation bar can't change sides, then it will jump when we change orientations 686 // and we don't rotate seamlessly - unless that is allowed, eg. with gesture navigation 687 // where the navbar is low-profile enough that this isn't very noticeable. 688 if (!mAllowSeamlessRotationDespiteNavBarMoving && !mDisplayPolicy.navigationBarCanMove()) { 689 return false; 690 } 691 692 // If the bounds of activity window is different from its parent, then reject to be seamless 693 // because the window position may change after rotation that will look like a sudden jump. 694 if (w.mActivityRecord != null && !w.mActivityRecord.matchParentBounds()) { 695 return false; 696 } 697 698 // In the presence of the PINNED root task or System Alert windows we unfortunately can not 699 // seamlessly rotate. 700 if (mDisplayContent.getDefaultTaskDisplayArea().hasPinnedTask() 701 || mDisplayContent.hasAlertWindowSurfaces()) { 702 return false; 703 } 704 705 // We can't rotate (seamlessly or not) while waiting for the last seamless rotation to 706 // complete (that is, waiting for windows to redraw). It's tempting to check 707 // mSeamlessRotationCount but that could be incorrect in the case of window-removal. 708 if (!forceUpdate && mDisplayContent.getWindow(win -> win.mSeamlesslyRotated) != null) { 709 return false; 710 } 711 712 return true; 713 } 714 markForSeamlessRotation(WindowState w, boolean seamlesslyRotated)715 void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) { 716 if (seamlesslyRotated == w.mSeamlesslyRotated || w.mForceSeamlesslyRotate) { 717 return; 718 } 719 720 w.mSeamlesslyRotated = seamlesslyRotated; 721 if (seamlesslyRotated) { 722 mSeamlessRotationCount++; 723 } else { 724 mSeamlessRotationCount--; 725 } 726 if (mSeamlessRotationCount == 0) { 727 ProtoLog.i(WM_DEBUG_ORIENTATION, 728 "Performing post-rotate rotation after seamless rotation"); 729 // Finish seamless rotation. 730 mRotatingSeamlessly = false; 731 mDisplayContent.finishFadeRotationAnimationIfPossible(); 732 733 updateRotationAndSendNewConfigIfChanged(); 734 } 735 } 736 737 /** 738 * Returns the animation to run for a rotation transition based on the top fullscreen windows 739 * {@link android.view.WindowManager.LayoutParams#rotationAnimation} and whether it is currently 740 * fullscreen and frontmost. 741 */ selectRotationAnimation()742 private RotationAnimationPair selectRotationAnimation() { 743 // If the screen is off or non-interactive, force a jumpcut. 744 final boolean forceJumpcut = !mDisplayPolicy.isScreenOnFully() 745 || !mService.mPolicy.okToAnimate(false /* ignoreScreenOn */); 746 final WindowState topFullscreen = mDisplayPolicy.getTopFullscreenOpaqueWindow(); 747 if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation topFullscreen=" 748 + topFullscreen + " rotationAnimation=" 749 + (topFullscreen == null ? 0 : topFullscreen.getAttrs().rotationAnimation) 750 + " forceJumpcut=" + forceJumpcut); 751 if (forceJumpcut) { 752 mTmpRotationAnim.mExit = R.anim.rotation_animation_jump_exit; 753 mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter; 754 return mTmpRotationAnim; 755 } 756 if (topFullscreen != null) { 757 int animationHint = topFullscreen.getRotationAnimationHint(); 758 if (animationHint < 0 && mDisplayPolicy.isTopLayoutFullscreen()) { 759 animationHint = topFullscreen.getAttrs().rotationAnimation; 760 } 761 switch (animationHint) { 762 case ROTATION_ANIMATION_CROSSFADE: 763 case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless. 764 mTmpRotationAnim.mExit = R.anim.rotation_animation_xfade_exit; 765 mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter; 766 break; 767 case ROTATION_ANIMATION_JUMPCUT: 768 mTmpRotationAnim.mExit = R.anim.rotation_animation_jump_exit; 769 mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter; 770 break; 771 case ROTATION_ANIMATION_ROTATE: 772 default: 773 mTmpRotationAnim.mExit = mTmpRotationAnim.mEnter = 0; 774 break; 775 } 776 } else { 777 mTmpRotationAnim.mExit = mTmpRotationAnim.mEnter = 0; 778 } 779 return mTmpRotationAnim; 780 } 781 782 /** 783 * Validate whether the current top fullscreen has specified the same 784 * {@link android.view.WindowManager.LayoutParams#rotationAnimation} value as that being passed 785 * in from the previous top fullscreen window. 786 * 787 * @param exitAnimId exiting resource id from the previous window. 788 * @param enterAnimId entering resource id from the previous window. 789 * @param forceDefault For rotation animations only, if true ignore the animation values and 790 * just return false. 791 * @return {@code true} if the previous values are still valid, false if they should be replaced 792 * with the default. 793 */ validateRotationAnimation(int exitAnimId, int enterAnimId, boolean forceDefault)794 boolean validateRotationAnimation(int exitAnimId, int enterAnimId, boolean forceDefault) { 795 switch (exitAnimId) { 796 case R.anim.rotation_animation_xfade_exit: 797 case R.anim.rotation_animation_jump_exit: 798 // These are the only cases that matter. 799 if (forceDefault) { 800 return false; 801 } 802 final RotationAnimationPair anim = selectRotationAnimation(); 803 return exitAnimId == anim.mExit && enterAnimId == anim.mEnter; 804 default: 805 return true; 806 } 807 } 808 restoreSettings(int userRotationMode, int userRotation, int fixedToUserRotation)809 void restoreSettings(int userRotationMode, int userRotation, int fixedToUserRotation) { 810 mFixedToUserRotation = fixedToUserRotation; 811 812 // We will retrieve user rotation and user rotation mode from settings for default display. 813 if (isDefaultDisplay) { 814 return; 815 } 816 if (userRotationMode != WindowManagerPolicy.USER_ROTATION_FREE 817 && userRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) { 818 Slog.w(TAG, "Trying to restore an invalid user rotation mode " + userRotationMode 819 + " for " + mDisplayContent); 820 userRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; 821 } 822 if (userRotation < Surface.ROTATION_0 || userRotation > Surface.ROTATION_270) { 823 Slog.w(TAG, "Trying to restore an invalid user rotation " + userRotation 824 + " for " + mDisplayContent); 825 userRotation = Surface.ROTATION_0; 826 } 827 mUserRotationMode = userRotationMode; 828 mUserRotation = userRotation; 829 } 830 setFixedToUserRotation(int fixedToUserRotation)831 void setFixedToUserRotation(int fixedToUserRotation) { 832 if (mFixedToUserRotation == fixedToUserRotation) { 833 return; 834 } 835 836 mFixedToUserRotation = fixedToUserRotation; 837 mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent, fixedToUserRotation); 838 if (mDisplayContent.mFocusedApp != null) { 839 // We record the last focused TDA that respects orientation request, check if this 840 // change may affect it. 841 mDisplayContent.onLastFocusedTaskDisplayAreaChanged( 842 mDisplayContent.mFocusedApp.getDisplayArea()); 843 } 844 mDisplayContent.updateOrientation(); 845 } 846 847 @VisibleForTesting setUserRotation(int userRotationMode, int userRotation)848 void setUserRotation(int userRotationMode, int userRotation) { 849 if (isDefaultDisplay) { 850 // We'll be notified via settings listener, so we don't need to update internal values. 851 final ContentResolver res = mContext.getContentResolver(); 852 final int accelerometerRotation = 853 userRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED ? 0 : 1; 854 Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION, 855 accelerometerRotation, UserHandle.USER_CURRENT); 856 Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation, 857 UserHandle.USER_CURRENT); 858 return; 859 } 860 861 boolean changed = false; 862 if (mUserRotationMode != userRotationMode) { 863 mUserRotationMode = userRotationMode; 864 changed = true; 865 } 866 if (mUserRotation != userRotation) { 867 mUserRotation = userRotation; 868 changed = true; 869 } 870 mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode, 871 userRotation); 872 if (changed) { 873 mService.updateRotation(true /* alwaysSendConfiguration */, 874 false /* forceRelayout */); 875 } 876 } 877 freezeRotation(int rotation)878 void freezeRotation(int rotation) { 879 rotation = (rotation == -1) ? mRotation : rotation; 880 setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation); 881 } 882 thawRotation()883 void thawRotation() { 884 setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation); 885 } 886 isRotationFrozen()887 boolean isRotationFrozen() { 888 if (!isDefaultDisplay) { 889 return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED; 890 } 891 892 return Settings.System.getIntForUser(mContext.getContentResolver(), 893 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0; 894 } 895 isFixedToUserRotation()896 boolean isFixedToUserRotation() { 897 switch (mFixedToUserRotation) { 898 case IWindowManager.FIXED_TO_USER_ROTATION_DISABLED: 899 return false; 900 case IWindowManager.FIXED_TO_USER_ROTATION_ENABLED: 901 return true; 902 default: 903 return mDefaultFixedToUserRotation; 904 } 905 } 906 getFixedToUserRotationMode()907 int getFixedToUserRotationMode() { 908 return mFixedToUserRotation; 909 } 910 getLandscapeRotation()911 public int getLandscapeRotation() { 912 return mLandscapeRotation; 913 } 914 getSeascapeRotation()915 public int getSeascapeRotation() { 916 return mSeascapeRotation; 917 } 918 getPortraitRotation()919 public int getPortraitRotation() { 920 return mPortraitRotation; 921 } 922 getUpsideDownRotation()923 public int getUpsideDownRotation() { 924 return mUpsideDownRotation; 925 } 926 getCurrentAppOrientation()927 public int getCurrentAppOrientation() { 928 return mCurrentAppOrientation; 929 } 930 getDisplayPolicy()931 public DisplayPolicy getDisplayPolicy() { 932 return mDisplayPolicy; 933 } 934 getOrientationListener()935 public WindowOrientationListener getOrientationListener() { 936 return mOrientationListener; 937 } 938 getUserRotation()939 public int getUserRotation() { 940 return mUserRotation; 941 } 942 getUserRotationMode()943 public int getUserRotationMode() { 944 return mUserRotationMode; 945 } 946 updateOrientationListener()947 public void updateOrientationListener() { 948 synchronized (mLock) { 949 updateOrientationListenerLw(); 950 } 951 } 952 953 /** 954 * Temporarily pauses rotation changes until resumed. 955 * <p> 956 * This can be used to prevent rotation changes from occurring while the user is performing 957 * certain operations, such as drag and drop. 958 * <p> 959 * This call nests and must be matched by an equal number of calls to {@link #resume}. 960 */ pause()961 void pause() { 962 mDeferredRotationPauseCount++; 963 } 964 965 /** Resumes normal rotation changes after being paused. */ resume()966 void resume() { 967 if (mDeferredRotationPauseCount <= 0) { 968 return; 969 } 970 971 mDeferredRotationPauseCount--; 972 if (mDeferredRotationPauseCount == 0) { 973 updateRotationAndSendNewConfigIfChanged(); 974 } 975 } 976 977 /** 978 * Various use cases for invoking this function: 979 * <li>Screen turning off, should always disable listeners if already enabled.</li> 980 * <li>Screen turned on and current app has sensor based orientation, enable listeners 981 * if not already enabled.</li> 982 * <li>Screen turned on and current app does not have sensor orientation, disable listeners 983 * if already enabled.</li> 984 * <li>Screen turning on and current app has sensor based orientation, enable listeners 985 * if needed.</li> 986 * <li>screen turning on and current app has nosensor based orientation, do nothing.</li> 987 */ updateOrientationListenerLw()988 private void updateOrientationListenerLw() { 989 if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) { 990 // If sensor is turned off or nonexistent for some reason. 991 return; 992 } 993 994 final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly(); 995 final boolean awake = mDisplayPolicy.isAwake(); 996 final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete(); 997 final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete(); 998 999 // Could have been invoked due to screen turning on or off or 1000 // change of the currently visible window's orientation. 1001 ProtoLog.v(WM_DEBUG_ORIENTATION, 1002 "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, " 1003 + "orientationSensorEnabled=%b, keyguardDrawComplete=%b, " 1004 + "windowManagerDrawComplete=%b", 1005 screenOnEarly, awake, mCurrentAppOrientation, mOrientationListener.mEnabled, 1006 keyguardDrawComplete, windowManagerDrawComplete); 1007 1008 boolean disable = true; 1009 1010 // If the orientation listener uses a wake sensor, keep the orientation listener on if the 1011 // screen is on (regardless of wake state). This allows the AoD to rotate. 1012 // 1013 // Note: We postpone the rotating of the screen until the keyguard as well as the 1014 // window manager have reported a draw complete or the keyguard is going away in dismiss 1015 // mode. 1016 if (screenOnEarly 1017 && (awake || mOrientationListener.shouldStayEnabledWhileDreaming()) 1018 && ((keyguardDrawComplete && windowManagerDrawComplete))) { 1019 if (needSensorRunning()) { 1020 disable = false; 1021 // Enable listener if not already enabled. 1022 if (!mOrientationListener.mEnabled) { 1023 // Don't clear the current sensor orientation if the keyguard is going away in 1024 // dismiss mode. This allows window manager to use the last sensor reading to 1025 // determine the orientation vs. falling back to the last known orientation if 1026 // the sensor reading was cleared which can cause it to relaunch the app that 1027 // will show in the wrong orientation first before correcting leading to app 1028 // launch delays. 1029 mOrientationListener.enable(true /* clearCurrentRotation */); 1030 } 1031 } 1032 } 1033 // Check if sensors need to be disabled. 1034 if (disable) { 1035 mOrientationListener.disable(); 1036 } 1037 } 1038 1039 /** 1040 * We always let the sensor be switched on by default except when 1041 * the user has explicitly disabled sensor based rotation or when the 1042 * screen is switched off. 1043 */ needSensorRunning()1044 private boolean needSensorRunning() { 1045 if (isFixedToUserRotation()) { 1046 // We are sure we only respect user rotation settings, so we are sure we will not 1047 // support sensor rotation. 1048 return false; 1049 } 1050 1051 if (mSupportAutoRotation) { 1052 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR 1053 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR 1054 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT 1055 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) { 1056 // If the application has explicitly requested to follow the 1057 // orientation, then we need to turn the sensor on. 1058 return true; 1059 } 1060 } 1061 1062 final int dockMode = mDisplayPolicy.getDockMode(); 1063 if ((mDisplayPolicy.isCarDockEnablesAccelerometer() 1064 && dockMode == Intent.EXTRA_DOCK_STATE_CAR) 1065 || (mDisplayPolicy.isDeskDockEnablesAccelerometer() 1066 && (dockMode == Intent.EXTRA_DOCK_STATE_DESK 1067 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK 1068 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) { 1069 // Enable accelerometer if we are docked in a dock that enables accelerometer 1070 // orientation management. 1071 return true; 1072 } 1073 1074 if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) { 1075 // If the setting for using the sensor by default is enabled, then 1076 // we will always leave it on. Note that the user could go to 1077 // a window that forces an orientation that does not use the 1078 // sensor and in theory we could turn it off... however, when next 1079 // turning it on we won't have a good value for the current 1080 // orientation for a little bit, which can cause orientation 1081 // changes to lag, so we'd like to keep it always on. (It will 1082 // still be turned off when the screen is off.) 1083 1084 // When locked we can provide rotation suggestions users can approve to change the 1085 // current screen rotation. To do this the sensor needs to be running. 1086 return mSupportAutoRotation && 1087 mShowRotationSuggestions == Settings.Secure.SHOW_ROTATION_SUGGESTIONS_ENABLED; 1088 } 1089 return mSupportAutoRotation; 1090 } 1091 1092 /** 1093 * If this is true we have updated our desired orientation, but not yet changed the real 1094 * orientation our applied our screen rotation animation. For example, because a previous 1095 * screen rotation was in progress. 1096 * 1097 * @return {@code true} if the there is an ongoing rotation change. 1098 */ needsUpdate()1099 boolean needsUpdate() { 1100 final int oldRotation = mRotation; 1101 final int rotation = rotationForOrientation(mLastOrientation, oldRotation); 1102 return oldRotation != rotation; 1103 } 1104 1105 /** 1106 * Given an orientation constant, returns the appropriate surface rotation, taking into account 1107 * sensors, docking mode, rotation lock, and other factors. 1108 * 1109 * @param orientation An orientation constant, such as 1110 * {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. 1111 * @param lastRotation The most recently used rotation. 1112 * @return The surface rotation to use. 1113 */ 1114 @VisibleForTesting 1115 @Surface.Rotation rotationForOrientation(@creenOrientation int orientation, @Surface.Rotation int lastRotation)1116 int rotationForOrientation(@ScreenOrientation int orientation, 1117 @Surface.Rotation int lastRotation) { 1118 ProtoLog.v(WM_DEBUG_ORIENTATION, 1119 "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s", 1120 ActivityInfo.screenOrientationToString(orientation), orientation, 1121 Surface.rotationToString(lastRotation), lastRotation, 1122 Surface.rotationToString(mUserRotation), mUserRotation, 1123 mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED 1124 ? "USER_ROTATION_LOCKED" : ""); 1125 1126 if (isFixedToUserRotation()) { 1127 return mUserRotation; 1128 } 1129 1130 int sensorRotation = mOrientationListener != null 1131 ? mOrientationListener.getProposedRotation() // may be -1 1132 : -1; 1133 if (sensorRotation < 0) { 1134 sensorRotation = lastRotation; 1135 } 1136 1137 final int lidState = mDisplayPolicy.getLidState(); 1138 final int dockMode = mDisplayPolicy.getDockMode(); 1139 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged(); 1140 final boolean carDockEnablesAccelerometer = 1141 mDisplayPolicy.isCarDockEnablesAccelerometer(); 1142 final boolean deskDockEnablesAccelerometer = 1143 mDisplayPolicy.isDeskDockEnablesAccelerometer(); 1144 1145 final int preferredRotation; 1146 if (!isDefaultDisplay) { 1147 // For secondary displays we ignore things like displays sensors, docking mode and 1148 // rotation lock, and always prefer user rotation. 1149 preferredRotation = mUserRotation; 1150 } else if (lidState == LID_OPEN && mLidOpenRotation >= 0) { 1151 // Ignore sensor when lid switch is open and rotation is forced. 1152 preferredRotation = mLidOpenRotation; 1153 } else if (dockMode == Intent.EXTRA_DOCK_STATE_CAR 1154 && (carDockEnablesAccelerometer || mCarDockRotation >= 0)) { 1155 // Ignore sensor when in car dock unless explicitly enabled. 1156 // This case can override the behavior of NOSENSOR, and can also 1157 // enable 180 degree rotation while docked. 1158 preferredRotation = carDockEnablesAccelerometer ? sensorRotation : mCarDockRotation; 1159 } else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK 1160 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK 1161 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK) 1162 && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)) { 1163 // Ignore sensor when in desk dock unless explicitly enabled. 1164 // This case can override the behavior of NOSENSOR, and can also 1165 // enable 180 degree rotation while docked. 1166 preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation; 1167 } else if (hdmiPlugged && mDemoHdmiRotationLock) { 1168 // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled. 1169 // Note that the dock orientation overrides the HDMI orientation. 1170 preferredRotation = mDemoHdmiRotation; 1171 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED 1172 && mUndockedHdmiRotation >= 0) { 1173 // Ignore sensor when plugged into HDMI and an undocked orientation has 1174 // been specified in the configuration (only for legacy devices without 1175 // full multi-display support). 1176 // Note that the dock orientation overrides the HDMI orientation. 1177 preferredRotation = mUndockedHdmiRotation; 1178 } else if (mDemoRotationLock) { 1179 // Ignore sensor when demo rotation lock is enabled. 1180 // Note that the dock orientation and HDMI rotation lock override this. 1181 preferredRotation = mDemoRotation; 1182 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) { 1183 // While in VR, apps always prefer a portrait rotation. This does not change 1184 // any apps that explicitly set landscape, but does cause sensors be ignored, 1185 // and ignored any orientation lock that the user has set (this conditional 1186 // should remain above the ORIENTATION_LOCKED conditional below). 1187 preferredRotation = mPortraitRotation; 1188 } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { 1189 // Application just wants to remain locked in the last rotation. 1190 preferredRotation = lastRotation; 1191 } else if (!mSupportAutoRotation) { 1192 // If we don't support auto-rotation then bail out here and ignore 1193 // the sensor and any rotation lock settings. 1194 preferredRotation = -1; 1195 } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE 1196 && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER 1197 || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED 1198 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE 1199 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT 1200 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER)) 1201 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR 1202 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR 1203 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE 1204 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) { 1205 // Otherwise, use sensor only if requested by the application or enabled 1206 // by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR. 1207 if (mAllowAllRotations == ALLOW_ALL_ROTATIONS_UNDEFINED) { 1208 // Can't read this during init() because the context doesn't have display metrics at 1209 // that time so we cannot determine tablet vs. phone then. 1210 mAllowAllRotations = mContext.getResources().getBoolean( 1211 R.bool.config_allowAllRotations) 1212 ? ALLOW_ALL_ROTATIONS_ENABLED 1213 : ALLOW_ALL_ROTATIONS_DISABLED; 1214 } 1215 if (sensorRotation != Surface.ROTATION_180 1216 || mAllowAllRotations == ALLOW_ALL_ROTATIONS_ENABLED 1217 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR 1218 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) { 1219 preferredRotation = sensorRotation; 1220 } else { 1221 preferredRotation = lastRotation; 1222 } 1223 } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED 1224 && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR 1225 && orientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE 1226 && orientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT 1227 && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE 1228 && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) { 1229 // Apply rotation lock. Does not apply to NOSENSOR or specific rotations. 1230 // The idea is that the user rotation expresses a weak preference for the direction 1231 // of gravity and as NOSENSOR is never affected by gravity, then neither should 1232 // NOSENSOR be affected by rotation lock (although it will be affected by docks). 1233 // Also avoid setting user rotation when app has preference over one particular rotation 1234 // to avoid leaving the rotation to the reverse of it which has the compatible 1235 // orientation, but isn't what app wants, when the user rotation is the reverse of the 1236 // preferred rotation. 1237 preferredRotation = mUserRotation; 1238 } else { 1239 // No overriding preference. 1240 // We will do exactly what the application asked us to do. 1241 preferredRotation = -1; 1242 } 1243 1244 switch (orientation) { 1245 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: 1246 // Return portrait unless overridden. 1247 if (isAnyPortrait(preferredRotation)) { 1248 return preferredRotation; 1249 } 1250 return mPortraitRotation; 1251 1252 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: 1253 // Return landscape unless overridden. 1254 if (isLandscapeOrSeascape(preferredRotation)) { 1255 return preferredRotation; 1256 } 1257 return mLandscapeRotation; 1258 1259 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: 1260 // Return reverse portrait unless overridden. 1261 if (isAnyPortrait(preferredRotation)) { 1262 return preferredRotation; 1263 } 1264 return mUpsideDownRotation; 1265 1266 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: 1267 // Return seascape unless overridden. 1268 if (isLandscapeOrSeascape(preferredRotation)) { 1269 return preferredRotation; 1270 } 1271 return mSeascapeRotation; 1272 1273 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: 1274 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE: 1275 // Return either landscape rotation. 1276 if (isLandscapeOrSeascape(preferredRotation)) { 1277 return preferredRotation; 1278 } 1279 if (isLandscapeOrSeascape(lastRotation)) { 1280 return lastRotation; 1281 } 1282 return mLandscapeRotation; 1283 1284 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: 1285 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT: 1286 // Return either portrait rotation. 1287 if (isAnyPortrait(preferredRotation)) { 1288 return preferredRotation; 1289 } 1290 if (isAnyPortrait(lastRotation)) { 1291 return lastRotation; 1292 } 1293 return mPortraitRotation; 1294 1295 default: 1296 // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR, 1297 // just return the preferred orientation we already calculated. 1298 if (preferredRotation >= 0) { 1299 return preferredRotation; 1300 } 1301 return Surface.ROTATION_0; 1302 } 1303 } 1304 isLandscapeOrSeascape(int rotation)1305 private boolean isLandscapeOrSeascape(int rotation) { 1306 return rotation == mLandscapeRotation || rotation == mSeascapeRotation; 1307 } 1308 isAnyPortrait(int rotation)1309 private boolean isAnyPortrait(int rotation) { 1310 return rotation == mPortraitRotation || rotation == mUpsideDownRotation; 1311 } 1312 isValidRotationChoice(final int preferredRotation)1313 private boolean isValidRotationChoice(final int preferredRotation) { 1314 // Determine if the given app orientation is compatible with the provided rotation choice. 1315 switch (mCurrentAppOrientation) { 1316 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER: 1317 // Works with any of the 4 rotations. 1318 return preferredRotation >= 0; 1319 1320 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT: 1321 // It's possible for the user pref to be set at 180 because of FULL_USER. This would 1322 // make switching to USER_PORTRAIT appear at 180. Provide choice to back to portrait 1323 // but never to go to 180. 1324 return preferredRotation == mPortraitRotation; 1325 1326 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE: 1327 // Works landscape or seascape. 1328 return isLandscapeOrSeascape(preferredRotation); 1329 1330 case ActivityInfo.SCREEN_ORIENTATION_USER: 1331 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED: 1332 // Works with any rotation except upside down. 1333 return (preferredRotation >= 0) && (preferredRotation != Surface.ROTATION_180); 1334 } 1335 1336 return false; 1337 } 1338 isRotationChoicePossible(int orientation)1339 private boolean isRotationChoicePossible(int orientation) { 1340 // Rotation choice is only shown when the user is in locked mode. 1341 if (mUserRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) return false; 1342 1343 // We should only enable rotation choice if the rotation isn't forced by the lid, dock, 1344 // demo, hdmi, vr, etc mode. 1345 1346 // Determine if the rotation is currently forced. 1347 if (isFixedToUserRotation()) { 1348 return false; // Rotation is forced to user settings. 1349 } 1350 1351 final int lidState = mDisplayPolicy.getLidState(); 1352 if (lidState == LID_OPEN && mLidOpenRotation >= 0) { 1353 return false; // Rotation is forced mLidOpenRotation. 1354 } 1355 1356 final int dockMode = mDisplayPolicy.getDockMode(); 1357 final boolean carDockEnablesAccelerometer = false; 1358 if (dockMode == Intent.EXTRA_DOCK_STATE_CAR && !carDockEnablesAccelerometer) { 1359 return false; // Rotation forced to mCarDockRotation. 1360 } 1361 1362 final boolean deskDockEnablesAccelerometer = 1363 mDisplayPolicy.isDeskDockEnablesAccelerometer(); 1364 if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK 1365 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK 1366 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK) 1367 && !deskDockEnablesAccelerometer) { 1368 return false; // Rotation forced to mDeskDockRotation. 1369 } 1370 1371 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged(); 1372 if (hdmiPlugged && mDemoHdmiRotationLock) { 1373 return false; // Rotation forced to mDemoHdmiRotation. 1374 1375 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED 1376 && mUndockedHdmiRotation >= 0) { 1377 return false; // Rotation forced to mUndockedHdmiRotation. 1378 1379 } else if (mDemoRotationLock) { 1380 return false; // Rotation forced to mDemoRotation. 1381 1382 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) { 1383 return false; // Rotation forced to mPortraitRotation. 1384 1385 } else if (!mSupportAutoRotation) { 1386 return false; 1387 } 1388 1389 // Ensure that some rotation choice is possible for the given orientation. 1390 switch (orientation) { 1391 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER: 1392 case ActivityInfo.SCREEN_ORIENTATION_USER: 1393 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED: 1394 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE: 1395 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT: 1396 // NOSENSOR description is ambiguous, in reality WM ignores user choice. 1397 return true; 1398 } 1399 1400 // Rotation is forced, should be controlled by system. 1401 return false; 1402 } 1403 1404 /** Notify the StatusBar that system rotation suggestion has changed. */ sendProposedRotationChangeToStatusBarInternal(int rotation, boolean isValid)1405 private void sendProposedRotationChangeToStatusBarInternal(int rotation, boolean isValid) { 1406 if (mStatusBarManagerInternal == null) { 1407 mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class); 1408 } 1409 if (mStatusBarManagerInternal != null) { 1410 mStatusBarManagerInternal.onProposedRotationChanged(rotation, isValid); 1411 } 1412 } 1413 allowAllRotationsToString(int allowAll)1414 private static String allowAllRotationsToString(int allowAll) { 1415 switch (allowAll) { 1416 case -1: 1417 return "unknown"; 1418 case 0: 1419 return "false"; 1420 case 1: 1421 return "true"; 1422 default: 1423 return Integer.toString(allowAll); 1424 } 1425 } 1426 onUserSwitch()1427 public void onUserSwitch() { 1428 if (mSettingsObserver != null) { 1429 mSettingsObserver.onChange(false); 1430 } 1431 } 1432 1433 /** Return whether the rotation settings has changed. */ updateSettings()1434 private boolean updateSettings() { 1435 final ContentResolver resolver = mContext.getContentResolver(); 1436 boolean shouldUpdateRotation = false; 1437 1438 synchronized (mLock) { 1439 boolean shouldUpdateOrientationListener = false; 1440 1441 // Configure rotation suggestions. 1442 final int showRotationSuggestions = 1443 ActivityManager.isLowRamDeviceStatic() 1444 ? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED 1445 : Settings.Secure.getIntForUser(resolver, 1446 Settings.Secure.SHOW_ROTATION_SUGGESTIONS, 1447 Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT, 1448 UserHandle.USER_CURRENT); 1449 if (mShowRotationSuggestions != showRotationSuggestions) { 1450 mShowRotationSuggestions = showRotationSuggestions; 1451 shouldUpdateOrientationListener = true; 1452 } 1453 1454 // Configure rotation lock. 1455 final int userRotation = Settings.System.getIntForUser(resolver, 1456 Settings.System.USER_ROTATION, Surface.ROTATION_0, 1457 UserHandle.USER_CURRENT); 1458 if (mUserRotation != userRotation) { 1459 mUserRotation = userRotation; 1460 shouldUpdateRotation = true; 1461 } 1462 1463 final int userRotationMode = Settings.System.getIntForUser(resolver, 1464 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 1465 ? WindowManagerPolicy.USER_ROTATION_FREE 1466 : WindowManagerPolicy.USER_ROTATION_LOCKED; 1467 if (mUserRotationMode != userRotationMode) { 1468 mUserRotationMode = userRotationMode; 1469 shouldUpdateOrientationListener = true; 1470 shouldUpdateRotation = true; 1471 } 1472 1473 if (shouldUpdateOrientationListener) { 1474 updateOrientationListenerLw(); // Enable or disable the orientation listener. 1475 } 1476 1477 final int cameraRotationMode = Settings.Secure.getIntForUser(resolver, 1478 Settings.Secure.CAMERA_AUTOROTATE, 0, 1479 UserHandle.USER_CURRENT); 1480 if (mCameraRotationMode != cameraRotationMode) { 1481 mCameraRotationMode = cameraRotationMode; 1482 shouldUpdateRotation = true; 1483 } 1484 } 1485 1486 return shouldUpdateRotation; 1487 } 1488 dump(String prefix, PrintWriter pw)1489 void dump(String prefix, PrintWriter pw) { 1490 pw.println(prefix + "DisplayRotation"); 1491 pw.println(prefix + " mCurrentAppOrientation=" 1492 + ActivityInfo.screenOrientationToString(mCurrentAppOrientation)); 1493 pw.println(prefix + " mLastOrientation=" + mLastOrientation); 1494 pw.print(prefix + " mRotation=" + mRotation); 1495 pw.println(" mDeferredRotationPauseCount=" + mDeferredRotationPauseCount); 1496 1497 pw.print(prefix + " mLandscapeRotation=" + Surface.rotationToString(mLandscapeRotation)); 1498 pw.println(" mSeascapeRotation=" + Surface.rotationToString(mSeascapeRotation)); 1499 pw.print(prefix + " mPortraitRotation=" + Surface.rotationToString(mPortraitRotation)); 1500 pw.println(" mUpsideDownRotation=" + Surface.rotationToString(mUpsideDownRotation)); 1501 1502 pw.println(prefix + " mSupportAutoRotation=" + mSupportAutoRotation); 1503 if (mOrientationListener != null) { 1504 mOrientationListener.dump(pw, prefix + " "); 1505 } 1506 pw.println(); 1507 1508 pw.print(prefix + " mCarDockRotation=" + Surface.rotationToString(mCarDockRotation)); 1509 pw.println(" mDeskDockRotation=" + Surface.rotationToString(mDeskDockRotation)); 1510 pw.print(prefix + " mUserRotationMode=" 1511 + WindowManagerPolicy.userRotationModeToString(mUserRotationMode)); 1512 pw.print(" mUserRotation=" + Surface.rotationToString(mUserRotation)); 1513 pw.print(" mCameraRotationMode=" + mCameraRotationMode); 1514 pw.println(" mAllowAllRotations=" + allowAllRotationsToString(mAllowAllRotations)); 1515 1516 pw.print(prefix + " mDemoHdmiRotation=" + Surface.rotationToString(mDemoHdmiRotation)); 1517 pw.print(" mDemoHdmiRotationLock=" + mDemoHdmiRotationLock); 1518 pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation)); 1519 pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation)); 1520 pw.println(prefix + " mFixedToUserRotation=" + isFixedToUserRotation()); 1521 } 1522 dumpDebug(ProtoOutputStream proto, long fieldId)1523 void dumpDebug(ProtoOutputStream proto, long fieldId) { 1524 final long token = proto.start(fieldId); 1525 proto.write(ROTATION, getRotation()); 1526 proto.write(FROZEN_TO_USER_ROTATION, isRotationFrozen()); 1527 proto.write(USER_ROTATION, getUserRotation()); 1528 proto.write(FIXED_TO_USER_ROTATION_MODE, mFixedToUserRotation); 1529 proto.write(LAST_ORIENTATION, mLastOrientation); 1530 proto.end(token); 1531 } 1532 1533 private class OrientationListener extends WindowOrientationListener { 1534 final SparseArray<Runnable> mRunnableCache = new SparseArray<>(5); 1535 boolean mEnabled; 1536 OrientationListener(Context context, Handler handler)1537 OrientationListener(Context context, Handler handler) { 1538 super(context, handler); 1539 } 1540 1541 private class UpdateRunnable implements Runnable { 1542 final int mRotation; 1543 UpdateRunnable(int rotation)1544 UpdateRunnable(int rotation) { 1545 mRotation = rotation; 1546 } 1547 1548 @Override run()1549 public void run() { 1550 // Send interaction power boost to improve redraw performance. 1551 mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0); 1552 if (isRotationChoicePossible(mCurrentAppOrientation)) { 1553 final boolean isValid = isValidRotationChoice(mRotation); 1554 sendProposedRotationChangeToStatusBarInternal(mRotation, isValid); 1555 } else { 1556 mService.updateRotation(false /* alwaysSendConfiguration */, 1557 false /* forceRelayout */); 1558 } 1559 } 1560 } 1561 1562 @Override isKeyguardLocked()1563 public boolean isKeyguardLocked() { 1564 return mService.isKeyguardLocked(); 1565 } 1566 1567 @Override isRotationResolverEnabled()1568 public boolean isRotationResolverEnabled() { 1569 return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE 1570 && mCameraRotationMode == CAMERA_ROTATION_ENABLED 1571 && !mService.mPowerManager.isPowerSaveMode(); 1572 } 1573 1574 1575 @Override onProposedRotationChanged(int rotation)1576 public void onProposedRotationChanged(int rotation) { 1577 ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation); 1578 Runnable r = mRunnableCache.get(rotation, null); 1579 if (r == null) { 1580 r = new UpdateRunnable(rotation); 1581 mRunnableCache.put(rotation, r); 1582 } 1583 getHandler().post(r); 1584 } 1585 1586 @Override enable(boolean clearCurrentRotation)1587 public void enable(boolean clearCurrentRotation) { 1588 super.enable(clearCurrentRotation); 1589 mEnabled = true; 1590 ProtoLog.v(WM_DEBUG_ORIENTATION, "Enabling listeners"); 1591 } 1592 1593 @Override disable()1594 public void disable() { 1595 super.disable(); 1596 mEnabled = false; 1597 ProtoLog.v(WM_DEBUG_ORIENTATION, "Disabling listeners"); 1598 } 1599 } 1600 1601 private class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler)1602 SettingsObserver(Handler handler) { 1603 super(handler); 1604 } 1605 observe()1606 void observe() { 1607 final ContentResolver resolver = mContext.getContentResolver(); 1608 resolver.registerContentObserver(Settings.Secure.getUriFor( 1609 Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this, 1610 UserHandle.USER_ALL); 1611 resolver.registerContentObserver(Settings.System.getUriFor( 1612 Settings.System.ACCELEROMETER_ROTATION), false, this, 1613 UserHandle.USER_ALL); 1614 resolver.registerContentObserver(Settings.System.getUriFor( 1615 Settings.System.USER_ROTATION), false, this, 1616 UserHandle.USER_ALL); 1617 resolver.registerContentObserver( 1618 Settings.Secure.getUriFor(Settings.Secure.CAMERA_AUTOROTATE), false, this, 1619 UserHandle.USER_ALL); 1620 1621 updateSettings(); 1622 } 1623 1624 @Override onChange(boolean selfChange)1625 public void onChange(boolean selfChange) { 1626 if (updateSettings()) { 1627 mService.updateRotation(true /* alwaysSendConfiguration */, 1628 false /* forceRelayout */); 1629 } 1630 } 1631 } 1632 1633 @VisibleForTesting 1634 interface ContentObserverRegister { registerContentObserver(Uri uri, boolean notifyForDescendants, ContentObserver observer, @UserIdInt int userHandle)1635 void registerContentObserver(Uri uri, boolean notifyForDescendants, 1636 ContentObserver observer, @UserIdInt int userHandle); 1637 } 1638 } 1639