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