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.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 20 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 21 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 22 import static android.view.Display.TYPE_EXTERNAL; 23 import static android.view.Display.TYPE_OVERLAY; 24 import static android.view.Display.TYPE_VIRTUAL; 25 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; 26 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT; 27 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; 28 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; 29 30 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM; 31 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; 32 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN; 33 import static com.android.server.wm.DisplayRotationProto.FIXED_TO_USER_ROTATION_MODE; 34 import static com.android.server.wm.DisplayRotationProto.FROZEN_TO_USER_ROTATION; 35 import static com.android.server.wm.DisplayRotationProto.IS_FIXED_TO_USER_ROTATION; 36 import static com.android.server.wm.DisplayRotationProto.LAST_ORIENTATION; 37 import static com.android.server.wm.DisplayRotationProto.ROTATION; 38 import static com.android.server.wm.DisplayRotationProto.USER_ROTATION; 39 import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_CAMERA_COMPAT; 40 import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_HALF_FOLD; 41 import static com.android.server.wm.DisplayRotationReversionController.REVERSION_TYPE_NOSENSOR; 42 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 43 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 44 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE; 45 import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION; 46 47 import android.annotation.AnimRes; 48 import android.annotation.IntDef; 49 import android.annotation.NonNull; 50 import android.annotation.Nullable; 51 import android.app.ActivityManager; 52 import android.content.ContentResolver; 53 import android.content.Context; 54 import android.content.Intent; 55 import android.content.pm.ActivityInfo; 56 import android.content.pm.ActivityInfo.ScreenOrientation; 57 import android.content.pm.PackageManager; 58 import android.content.res.Resources; 59 import android.database.ContentObserver; 60 import android.hardware.Sensor; 61 import android.hardware.SensorEvent; 62 import android.hardware.SensorEventListener; 63 import android.hardware.SensorManager; 64 import android.hardware.power.Boost; 65 import android.os.Handler; 66 import android.os.SystemClock; 67 import android.os.SystemProperties; 68 import android.os.UserHandle; 69 import android.provider.Settings; 70 import android.util.ArraySet; 71 import android.util.RotationUtils; 72 import android.util.Slog; 73 import android.util.TimeUtils; 74 import android.util.proto.ProtoOutputStream; 75 import android.view.DisplayAddress; 76 import android.view.IWindowManager; 77 import android.view.Surface; 78 import android.window.TransitionRequestInfo; 79 import android.window.WindowContainerTransaction; 80 81 import com.android.internal.R; 82 import com.android.internal.annotations.VisibleForTesting; 83 import com.android.internal.protolog.common.ProtoLog; 84 import com.android.server.LocalServices; 85 import com.android.server.UiThread; 86 import com.android.server.policy.WindowManagerPolicy; 87 import com.android.server.statusbar.StatusBarManagerInternal; 88 89 import java.io.PrintWriter; 90 import java.lang.annotation.Retention; 91 import java.lang.annotation.RetentionPolicy; 92 import java.util.ArrayDeque; 93 import java.util.Set; 94 95 /** 96 * Defines the mapping between orientation and rotation of a display. 97 * Non-public methods are assumed to run inside WM lock. 98 */ 99 public class DisplayRotation { 100 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM; 101 102 // Delay in milliseconds when updating config due to folding events. This prevents 103 // config changes and unexpected jumps while folding the device to closed state. 104 private static final int FOLDING_RECOMPUTE_CONFIG_DELAY_MS = 800; 105 106 private static final int ROTATION_UNDEFINED = -1; 107 108 private static class RotationAnimationPair { 109 @AnimRes 110 int mEnter; 111 @AnimRes 112 int mExit; 113 } 114 115 @Nullable 116 final FoldController mFoldController; 117 118 private final WindowManagerService mService; 119 private final DisplayContent mDisplayContent; 120 private final DisplayPolicy mDisplayPolicy; 121 private final DisplayWindowSettings mDisplayWindowSettings; 122 private final Context mContext; 123 private final Object mLock; 124 @Nullable 125 private final DisplayRotationImmersiveAppCompatPolicy mCompatPolicyForImmersiveApps; 126 127 public final boolean isDefaultDisplay; 128 private final boolean mSupportAutoRotation; 129 private final boolean mAllowRotationResolver; 130 private final int mLidOpenRotation; 131 private final int mCarDockRotation; 132 private final int mDeskDockRotation; 133 private final int mUndockedHdmiRotation; 134 private final RotationAnimationPair mTmpRotationAnim = new RotationAnimationPair(); 135 private final RotationHistory mRotationHistory = new RotationHistory(); 136 private final RotationLockHistory mRotationLockHistory = new RotationLockHistory(); 137 138 private OrientationListener mOrientationListener; 139 private StatusBarManagerInternal mStatusBarManagerInternal; 140 private SettingsObserver mSettingsObserver; 141 @NonNull 142 private final DeviceStateController mDeviceStateController; 143 @NonNull 144 private final DisplayRotationCoordinator mDisplayRotationCoordinator; 145 @NonNull 146 @VisibleForTesting 147 final Runnable mDefaultDisplayRotationChangedCallback; 148 149 @ScreenOrientation 150 private int mCurrentAppOrientation = SCREEN_ORIENTATION_UNSPECIFIED; 151 152 /** 153 * Last applied orientation of the display. 154 * 155 * @see #updateOrientationFromApp 156 */ 157 @ScreenOrientation 158 private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED; 159 160 /** 161 * Current rotation of the display. 162 * 163 * @see #updateRotationUnchecked 164 */ 165 @Surface.Rotation 166 private int mRotation; 167 168 @VisibleForTesting 169 int mLandscapeRotation; // default landscape 170 @VisibleForTesting 171 int mSeascapeRotation; // "other" landscape, 180 degrees from mLandscapeRotation 172 @VisibleForTesting 173 int mPortraitRotation; // default portrait 174 @VisibleForTesting 175 int mUpsideDownRotation; // "other" portrait 176 177 int mLastSensorRotation = -1; 178 179 private boolean mAllowSeamlessRotationDespiteNavBarMoving; 180 181 private int mDeferredRotationPauseCount; 182 183 /** 184 * A count of the windows which are 'seamlessly rotated', e.g. a surface at an old orientation 185 * is being transformed. We freeze orientation updates while any windows are seamlessly rotated, 186 * so we need to track when this hits zero so we can apply deferred orientation updates. 187 */ 188 private int mSeamlessRotationCount; 189 190 /** 191 * True in the interval from starting seamless rotation until the last rotated window draws in 192 * the new orientation. 193 */ 194 private boolean mRotatingSeamlessly; 195 196 /** 197 * Behavior of rotation suggestions. 198 * 199 * @see Settings.Secure#SHOW_ROTATION_SUGGESTIONS 200 */ 201 private int mShowRotationSuggestions; 202 203 /** 204 * The most recent {@link Surface.Rotation} choice shown to the user for confirmation, or 205 * {@link #ROTATION_UNDEFINED} 206 */ 207 private int mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; 208 209 private static final int ALLOW_ALL_ROTATIONS_UNDEFINED = -1; 210 private static final int ALLOW_ALL_ROTATIONS_DISABLED = 0; 211 private static final int ALLOW_ALL_ROTATIONS_ENABLED = 1; 212 213 @IntDef({ ALLOW_ALL_ROTATIONS_UNDEFINED, ALLOW_ALL_ROTATIONS_DISABLED, 214 ALLOW_ALL_ROTATIONS_ENABLED }) 215 @Retention(RetentionPolicy.SOURCE) 216 private @interface AllowAllRotations {} 217 218 /** 219 * Whether to allow the screen to rotate to all rotations (including 180 degree) according to 220 * the sensor even when the current orientation is not 221 * {@link ActivityInfo#SCREEN_ORIENTATION_FULL_SENSOR} or 222 * {@link ActivityInfo#SCREEN_ORIENTATION_FULL_USER}. 223 */ 224 @AllowAllRotations 225 private int mAllowAllRotations = ALLOW_ALL_ROTATIONS_UNDEFINED; 226 227 @WindowManagerPolicy.UserRotationMode 228 private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; 229 230 @Surface.Rotation 231 private int mUserRotation = Surface.ROTATION_0; 232 233 private static final int CAMERA_ROTATION_DISABLED = 0; 234 private static final int CAMERA_ROTATION_ENABLED = 1; 235 private int mCameraRotationMode = CAMERA_ROTATION_DISABLED; 236 237 /** 238 * Flag that indicates this is a display that may run better when fixed to user rotation. 239 */ 240 private boolean mDefaultFixedToUserRotation; 241 242 /** 243 * A flag to indicate if the display rotation should be fixed to user specified rotation 244 * regardless of all other states (including app requested orientation). {@code true} the 245 * display rotation should be fixed to user specified rotation, {@code false} otherwise. 246 */ 247 private int mFixedToUserRotation = IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT; 248 249 private int mDemoHdmiRotation; 250 private int mDemoRotation; 251 private boolean mDemoHdmiRotationLock; 252 private boolean mDemoRotationLock; 253 DisplayRotation(WindowManagerService service, DisplayContent displayContent, DisplayAddress displayAddress, @NonNull DeviceStateController deviceStateController, @NonNull DisplayRotationCoordinator displayRotationCoordinator)254 DisplayRotation(WindowManagerService service, DisplayContent displayContent, 255 DisplayAddress displayAddress, @NonNull DeviceStateController deviceStateController, 256 @NonNull DisplayRotationCoordinator displayRotationCoordinator) { 257 this(service, displayContent, displayAddress, displayContent.getDisplayPolicy(), 258 service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock(), 259 deviceStateController, displayRotationCoordinator); 260 } 261 262 @VisibleForTesting DisplayRotation(WindowManagerService service, DisplayContent displayContent, DisplayAddress displayAddress, DisplayPolicy displayPolicy, DisplayWindowSettings displayWindowSettings, Context context, Object lock, @NonNull DeviceStateController deviceStateController, @NonNull DisplayRotationCoordinator displayRotationCoordinator)263 DisplayRotation(WindowManagerService service, DisplayContent displayContent, 264 DisplayAddress displayAddress, DisplayPolicy displayPolicy, 265 DisplayWindowSettings displayWindowSettings, Context context, Object lock, 266 @NonNull DeviceStateController deviceStateController, 267 @NonNull DisplayRotationCoordinator displayRotationCoordinator) { 268 mService = service; 269 mDisplayContent = displayContent; 270 mDisplayPolicy = displayPolicy; 271 mDisplayWindowSettings = displayWindowSettings; 272 mContext = context; 273 mLock = lock; 274 mDeviceStateController = deviceStateController; 275 isDefaultDisplay = displayContent.isDefaultDisplay; 276 mCompatPolicyForImmersiveApps = initImmersiveAppCompatPolicy(service, displayContent); 277 278 mSupportAutoRotation = 279 mContext.getResources().getBoolean(R.bool.config_supportAutoRotation); 280 mAllowRotationResolver = 281 mContext.getResources().getBoolean(R.bool.config_allowRotationResolver); 282 mLidOpenRotation = readRotation(R.integer.config_lidOpenRotation); 283 mCarDockRotation = readRotation(R.integer.config_carDockRotation); 284 mDeskDockRotation = readRotation(R.integer.config_deskDockRotation); 285 mUndockedHdmiRotation = readRotation(R.integer.config_undockedHdmiRotation); 286 287 int defaultRotation = readDefaultDisplayRotation(displayAddress, displayContent); 288 mRotation = defaultRotation; 289 290 mDisplayRotationCoordinator = displayRotationCoordinator; 291 if (isDefaultDisplay) { 292 mDisplayRotationCoordinator.setDefaultDisplayDefaultRotation(mRotation); 293 } 294 mDefaultDisplayRotationChangedCallback = this::updateRotationAndSendNewConfigIfChanged; 295 296 if (DisplayRotationCoordinator.isSecondaryInternalDisplay(displayContent) 297 && mDeviceStateController 298 .shouldMatchBuiltInDisplayOrientationToReverseDefaultDisplay()) { 299 mDisplayRotationCoordinator.setDefaultDisplayRotationChangedCallback( 300 mDefaultDisplayRotationChangedCallback); 301 } 302 303 if (isDefaultDisplay) { 304 final Handler uiHandler = UiThread.getHandler(); 305 mOrientationListener = 306 new OrientationListener(mContext, uiHandler, defaultRotation); 307 mOrientationListener.setCurrentRotation(mRotation); 308 mSettingsObserver = new SettingsObserver(uiHandler); 309 mSettingsObserver.observe(); 310 if (mSupportAutoRotation && isFoldable(mContext)) { 311 mFoldController = new FoldController(); 312 } else { 313 mFoldController = null; 314 } 315 } else { 316 mFoldController = null; 317 } 318 } 319 isFoldable(Context context)320 private static boolean isFoldable(Context context) { 321 return context.getResources().getIntArray(R.array.config_foldedDeviceStates).length > 0; 322 } 323 324 @VisibleForTesting 325 @Nullable initImmersiveAppCompatPolicy( WindowManagerService service, DisplayContent displayContent)326 DisplayRotationImmersiveAppCompatPolicy initImmersiveAppCompatPolicy( 327 WindowManagerService service, DisplayContent displayContent) { 328 return DisplayRotationImmersiveAppCompatPolicy.createIfNeeded( 329 service.mLetterboxConfiguration, this, displayContent); 330 } 331 332 // Change the default value to the value specified in the sysprop 333 // ro.bootanim.set_orientation_<physical_display_id> or 334 // ro.bootanim.set_orientation_logical_<logical_display_id>. 335 // Four values are supported: ORIENTATION_0, 336 // ORIENTATION_90, ORIENTATION_180 and ORIENTATION_270. 337 // If the value isn't specified or is ORIENTATION_0, nothing will be changed. 338 // This is needed to support having default orientation different from the natural 339 // device orientation. For example, on tablets that may want to keep natural orientation 340 // portrait for applications compatibility but have landscape orientation as a default choice 341 // from the UX perspective. 342 // On watches that may want to keep the wrist orientation as the default. 343 @Surface.Rotation readDefaultDisplayRotation(DisplayAddress displayAddress, DisplayContent displayContent)344 private int readDefaultDisplayRotation(DisplayAddress displayAddress, 345 DisplayContent displayContent) { 346 String syspropValue = ""; 347 if (displayAddress instanceof DisplayAddress.Physical) { 348 final DisplayAddress.Physical physicalAddress = 349 (DisplayAddress.Physical) displayAddress; 350 syspropValue = SystemProperties.get( 351 "ro.bootanim.set_orientation_" + physicalAddress.getPhysicalDisplayId(), ""); 352 } 353 if ("".equals(syspropValue) && displayContent.isDefaultDisplay) { 354 syspropValue = SystemProperties.get( 355 "ro.bootanim.set_orientation_logical_" + displayContent.getDisplayId(), ""); 356 } 357 358 if (syspropValue.equals("ORIENTATION_90")) { 359 return Surface.ROTATION_90; 360 } else if (syspropValue.equals("ORIENTATION_180")) { 361 return Surface.ROTATION_180; 362 } else if (syspropValue.equals("ORIENTATION_270")) { 363 return Surface.ROTATION_270; 364 } 365 return Surface.ROTATION_0; 366 } 367 readRotation(int resID)368 private int readRotation(int resID) { 369 try { 370 final int rotation = mContext.getResources().getInteger(resID); 371 switch (rotation) { 372 case 0: 373 return Surface.ROTATION_0; 374 case 90: 375 return Surface.ROTATION_90; 376 case 180: 377 return Surface.ROTATION_180; 378 case 270: 379 return Surface.ROTATION_270; 380 } 381 } catch (Resources.NotFoundException e) { 382 // fall through 383 } 384 return -1; 385 } 386 387 @VisibleForTesting useDefaultSettingsProvider()388 boolean useDefaultSettingsProvider() { 389 return isDefaultDisplay; 390 } 391 392 /** 393 * Updates the configuration which may have different values depending on current user, e.g. 394 * runtime resource overlay. 395 */ updateUserDependentConfiguration(Resources currentUserRes)396 void updateUserDependentConfiguration(Resources currentUserRes) { 397 mAllowSeamlessRotationDespiteNavBarMoving = 398 currentUserRes.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving); 399 } 400 configure(int width, int height)401 void configure(int width, int height) { 402 final Resources res = mContext.getResources(); 403 if (width > height) { 404 mLandscapeRotation = Surface.ROTATION_0; 405 mSeascapeRotation = Surface.ROTATION_180; 406 if (res.getBoolean(R.bool.config_reverseDefaultRotation)) { 407 mPortraitRotation = Surface.ROTATION_90; 408 mUpsideDownRotation = Surface.ROTATION_270; 409 } else { 410 mPortraitRotation = Surface.ROTATION_270; 411 mUpsideDownRotation = Surface.ROTATION_90; 412 } 413 } else { 414 mPortraitRotation = Surface.ROTATION_0; 415 mUpsideDownRotation = Surface.ROTATION_180; 416 if (res.getBoolean(R.bool.config_reverseDefaultRotation)) { 417 mLandscapeRotation = Surface.ROTATION_270; 418 mSeascapeRotation = Surface.ROTATION_90; 419 } else { 420 mLandscapeRotation = Surface.ROTATION_90; 421 mSeascapeRotation = Surface.ROTATION_270; 422 } 423 } 424 425 // For demo purposes, allow the rotation of the HDMI display to be controlled. 426 // By default, HDMI locks rotation to landscape. 427 if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) { 428 mDemoHdmiRotation = mPortraitRotation; 429 } else { 430 mDemoHdmiRotation = mLandscapeRotation; 431 } 432 mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false); 433 434 // For demo purposes, allow the rotation of the remote display to be controlled. 435 // By default, remote display locks rotation to landscape. 436 if ("portrait".equals(SystemProperties.get("persist.demo.remoterotation"))) { 437 mDemoRotation = mPortraitRotation; 438 } else { 439 mDemoRotation = mLandscapeRotation; 440 } 441 mDemoRotationLock = SystemProperties.getBoolean("persist.demo.rotationlock", false); 442 443 // It's physically impossible to rotate the car's screen. 444 final boolean isCar = mContext.getPackageManager().hasSystemFeature( 445 PackageManager.FEATURE_AUTOMOTIVE); 446 // It's also not likely to rotate a TV screen. 447 final boolean isTv = mContext.getPackageManager().hasSystemFeature( 448 PackageManager.FEATURE_LEANBACK); 449 mDefaultFixedToUserRotation = 450 (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode() 451 || !mDisplayContent.shouldRotateWithContent()) 452 // For debug purposes the next line turns this feature off with: 453 // $ adb shell setprop config.override_forced_orient true 454 // $ adb shell wm size reset 455 && !"true".equals(SystemProperties.get("config.override_forced_orient")); 456 } 457 applyCurrentRotation(@urface.Rotation int rotation)458 void applyCurrentRotation(@Surface.Rotation int rotation) { 459 mRotationHistory.addRecord(this, rotation); 460 if (mOrientationListener != null) { 461 mOrientationListener.setCurrentRotation(rotation); 462 } 463 } 464 465 @VisibleForTesting setRotation(@urface.Rotation int rotation)466 void setRotation(@Surface.Rotation int rotation) { 467 mRotation = rotation; 468 } 469 470 @Surface.Rotation getRotation()471 int getRotation() { 472 return mRotation; 473 } 474 475 @ScreenOrientation getLastOrientation()476 int getLastOrientation() { 477 return mLastOrientation; 478 } 479 updateOrientation(@creenOrientation int newOrientation, boolean forceUpdate)480 boolean updateOrientation(@ScreenOrientation int newOrientation, boolean forceUpdate) { 481 if (newOrientation == mLastOrientation && !forceUpdate) { 482 return false; 483 } 484 mLastOrientation = newOrientation; 485 if (newOrientation != mCurrentAppOrientation) { 486 mCurrentAppOrientation = newOrientation; 487 if (isDefaultDisplay) { 488 updateOrientationListenerLw(); 489 } 490 } 491 return updateRotationUnchecked(forceUpdate); 492 } 493 494 /** 495 * Update rotation of the display and send configuration if the rotation is changed. 496 * 497 * @return {@code true} if the rotation has been changed and the new config is sent. 498 */ updateRotationAndSendNewConfigIfChanged()499 boolean updateRotationAndSendNewConfigIfChanged() { 500 final boolean changed = updateRotationUnchecked(false /* forceUpdate */); 501 if (changed) { 502 mDisplayContent.sendNewConfiguration(); 503 } 504 return changed; 505 } 506 507 /** 508 * Update rotation with an option to force the update. This updates the container's perception 509 * of rotation and, depending on the top activities, will freeze the screen or start seamless 510 * rotation. The display itself gets rotated in {@link DisplayContent#applyRotationLocked} 511 * during {@link DisplayContent#sendNewConfiguration}. 512 * 513 * @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating 514 * orientation because we're waiting for some rotation to finish or display 515 * to unfreeze, which results in configuration of the previously visible 516 * activity being applied to a newly visible one. Forcing the rotation 517 * update allows to workaround this issue. 518 * @return {@code true} if the rotation has been changed. In this case YOU MUST CALL 519 * {@link DisplayContent#sendNewConfiguration} TO COMPLETE THE ROTATION AND UNFREEZE 520 * THE SCREEN. 521 */ updateRotationUnchecked(boolean forceUpdate)522 boolean updateRotationUnchecked(boolean forceUpdate) { 523 final int displayId = mDisplayContent.getDisplayId(); 524 if (!forceUpdate) { 525 if (mDeferredRotationPauseCount > 0) { 526 // Rotation updates have been paused temporarily. Defer the update until updates 527 // have been resumed. 528 ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, rotation is paused."); 529 return false; 530 } 531 532 if (mDisplayContent.inTransition() 533 && mDisplayContent.getDisplayPolicy().isScreenOnFully() 534 && !mDisplayContent.mTransitionController.useShellTransitionsRotation()) { 535 // Rotation updates cannot be performed while the previous rotation change animation 536 // is still in progress. Skip this update. We will try updating again after the 537 // animation is finished and the display is unfrozen. 538 ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, animation in progress."); 539 return false; 540 } 541 if (mService.mDisplayFrozen) { 542 // Even if the screen rotation animation has finished (e.g. isAnimating returns 543 // false), there is still some time where we haven't yet unfrozen the display. We 544 // also need to abort rotation here. 545 ProtoLog.v(WM_DEBUG_ORIENTATION, 546 "Deferring rotation, still finishing previous rotation"); 547 return false; 548 } 549 550 if (mDisplayContent.mFixedRotationTransitionListener.shouldDeferRotation()) { 551 // Makes sure that after the transition is finished, updateOrientation() can see 552 // the difference from the latest orientation source. 553 mLastOrientation = SCREEN_ORIENTATION_UNSET; 554 // During the recents animation, the closing app might still be considered on top. 555 // In order to ignore its requested orientation to avoid a sensor led rotation (e.g 556 // user rotating the device while the recents animation is running), we ignore 557 // rotation update while the animation is running. 558 return false; 559 } 560 } 561 562 if (!mService.mDisplayEnabled) { 563 // No point choosing a rotation if the display is not enabled. 564 ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, display is not enabled."); 565 return false; 566 } 567 568 @Surface.Rotation 569 final int oldRotation = mRotation; 570 @ScreenOrientation 571 final int lastOrientation = mLastOrientation; 572 @Surface.Rotation 573 int rotation = rotationForOrientation(lastOrientation, oldRotation); 574 // Use the saved rotation for tabletop mode, if set. 575 if (mFoldController != null && mFoldController.shouldRevertOverriddenRotation()) { 576 int prevRotation = rotation; 577 rotation = mFoldController.revertOverriddenRotation(); 578 ProtoLog.v(WM_DEBUG_ORIENTATION, 579 "Reverting orientation. Rotating to %s from %s rather than %s.", 580 Surface.rotationToString(rotation), 581 Surface.rotationToString(oldRotation), 582 Surface.rotationToString(prevRotation)); 583 } 584 585 if (DisplayRotationCoordinator.isSecondaryInternalDisplay(mDisplayContent) 586 && mDeviceStateController 587 .shouldMatchBuiltInDisplayOrientationToReverseDefaultDisplay()) { 588 rotation = RotationUtils.reverseRotationDirectionAroundZAxis( 589 mDisplayRotationCoordinator.getDefaultDisplayCurrentRotation()); 590 } 591 592 ProtoLog.v(WM_DEBUG_ORIENTATION, 593 "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and " 594 + "oldRotation=%s (%d)", 595 Surface.rotationToString(rotation), rotation, 596 displayId, 597 ActivityInfo.screenOrientationToString(lastOrientation), lastOrientation, 598 Surface.rotationToString(oldRotation), oldRotation); 599 600 ProtoLog.v(WM_DEBUG_ORIENTATION, 601 "Display id=%d selected orientation %s (%d), got rotation %s (%d)", displayId, 602 ActivityInfo.screenOrientationToString(lastOrientation), lastOrientation, 603 Surface.rotationToString(rotation), rotation); 604 605 if (oldRotation == rotation) { 606 // No change. 607 return false; 608 } 609 610 if (isDefaultDisplay) { 611 mDisplayRotationCoordinator.onDefaultDisplayRotationChanged(rotation); 612 } 613 614 // Preemptively cancel the running recents animation -- SysUI can't currently handle this 615 // case properly since the signals it receives all happen post-change. We do this earlier 616 // in the rotation flow, since DisplayContent.updateDisplayOverrideConfigurationLocked seems 617 // to happen too late. 618 final RecentsAnimationController recentsAnimationController = 619 mService.getRecentsAnimationController(); 620 if (recentsAnimationController != null) { 621 recentsAnimationController.cancelAnimationForDisplayChange(); 622 } 623 624 ProtoLog.v(WM_DEBUG_ORIENTATION, 625 "Display id=%d rotation changed to %d from %d, lastOrientation=%d", 626 displayId, rotation, oldRotation, lastOrientation); 627 628 mRotation = rotation; 629 630 mDisplayContent.setLayoutNeeded(); 631 mDisplayContent.mWaitingForConfig = true; 632 633 if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) { 634 final boolean wasCollecting = mDisplayContent.mTransitionController.isCollecting(); 635 if (!wasCollecting) { 636 if (mDisplayContent.getLastHasContent()) { 637 final TransitionRequestInfo.DisplayChange change = 638 new TransitionRequestInfo.DisplayChange(mDisplayContent.getDisplayId(), 639 oldRotation, mRotation); 640 mDisplayContent.requestChangeTransition( 641 ActivityInfo.CONFIG_WINDOW_CONFIGURATION, change); 642 } 643 } else { 644 mDisplayContent.collectDisplayChange( 645 mDisplayContent.mTransitionController.getCollectingTransition()); 646 // Use remote-rotation infra since the transition has already been requested 647 // TODO(shell-transitions): Remove this once lifecycle management can cover all 648 // rotation cases. 649 startRemoteRotation(oldRotation, mRotation); 650 } 651 return true; 652 } 653 654 mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE; 655 mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT, 656 mDisplayContent, WINDOW_FREEZE_TIMEOUT_DURATION); 657 658 if (shouldRotateSeamlessly(oldRotation, rotation, forceUpdate)) { 659 // The screen rotation animation uses a screenshot to freeze the screen while windows 660 // resize underneath. When we are rotating seamlessly, we allow the elements to 661 // transition to their rotated state independently and without a freeze required. 662 prepareSeamlessRotation(); 663 } else { 664 prepareNormalRotationAnimation(); 665 } 666 667 // Give a remote handler (system ui) some time to reposition things. 668 startRemoteRotation(oldRotation, mRotation); 669 670 return true; 671 } 672 startRemoteRotation(int fromRotation, int toRotation)673 private void startRemoteRotation(int fromRotation, int toRotation) { 674 mDisplayContent.mRemoteDisplayChangeController.performRemoteDisplayChange( 675 fromRotation, toRotation, null /* newDisplayAreaInfo */, 676 (transaction) -> continueRotation(toRotation, transaction) 677 ); 678 } 679 continueRotation(int targetRotation, WindowContainerTransaction t)680 private void continueRotation(int targetRotation, WindowContainerTransaction t) { 681 if (targetRotation != mRotation) { 682 // Drop it, this is either coming from an outdated remote rotation; or, we've 683 // already moved on. 684 return; 685 } 686 687 if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) { 688 if (!mDisplayContent.mTransitionController.isCollecting()) { 689 // The remote may be too slow to response before transition timeout. 690 Slog.e(TAG, "Trying to continue rotation outside a transition"); 691 } 692 mDisplayContent.mTransitionController.collect(mDisplayContent); 693 } 694 mService.mAtmService.deferWindowLayout(); 695 try { 696 mDisplayContent.sendNewConfiguration(); 697 if (t != null) { 698 mService.mAtmService.mWindowOrganizerController.applyTransaction(t); 699 } 700 } finally { 701 mService.mAtmService.continueWindowLayout(); 702 } 703 } 704 prepareNormalRotationAnimation()705 void prepareNormalRotationAnimation() { 706 cancelSeamlessRotation(); 707 final RotationAnimationPair anim = selectRotationAnimation(); 708 mService.startFreezingDisplay(anim.mExit, anim.mEnter, mDisplayContent); 709 } 710 711 /** 712 * This ensures that normal rotation animation is used. E.g. {@link #mRotatingSeamlessly} was 713 * set by previous {@link #updateRotationUnchecked}, but another orientation change happens 714 * before calling {@link DisplayContent#sendNewConfiguration} (remote rotation hasn't finished) 715 * and it doesn't choose seamless rotation. 716 */ cancelSeamlessRotation()717 void cancelSeamlessRotation() { 718 if (!mRotatingSeamlessly) { 719 return; 720 } 721 mDisplayContent.forAllWindows(w -> { 722 if (w.mSeamlesslyRotated) { 723 w.cancelSeamlessRotation(); 724 w.mSeamlesslyRotated = false; 725 } 726 }, true /* traverseTopToBottom */); 727 mSeamlessRotationCount = 0; 728 mRotatingSeamlessly = false; 729 mDisplayContent.finishAsyncRotationIfPossible(); 730 } 731 prepareSeamlessRotation()732 private void prepareSeamlessRotation() { 733 // We are careful to reset this in case a window was removed before it finished 734 // seamless rotation. 735 mSeamlessRotationCount = 0; 736 mRotatingSeamlessly = true; 737 } 738 isRotatingSeamlessly()739 boolean isRotatingSeamlessly() { 740 return mRotatingSeamlessly; 741 } 742 hasSeamlessRotatingWindow()743 boolean hasSeamlessRotatingWindow() { 744 return mSeamlessRotationCount > 0; 745 } 746 747 @VisibleForTesting shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate)748 boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) { 749 // Display doesn't need to be frozen because application has been started in correct 750 // rotation already, so the rest of the windows can use seamless rotation. 751 if (mDisplayContent.hasTopFixedRotationLaunchingApp()) { 752 return true; 753 } 754 755 final WindowState w = mDisplayPolicy.getTopFullscreenOpaqueWindow(); 756 if (w == null || w != mDisplayContent.mCurrentFocus) { 757 return false; 758 } 759 // We only enable seamless rotation if the top window has requested it and is in the 760 // fullscreen opaque state. Seamless rotation requires freezing various Surface states and 761 // won't work well with animations, so we disable it in the animation case for now. 762 if (w.getAttrs().rotationAnimation != ROTATION_ANIMATION_SEAMLESS || w.inMultiWindowMode() 763 || w.isAnimatingLw()) { 764 return false; 765 } 766 767 if (!canRotateSeamlessly(oldRotation, newRotation)) { 768 return false; 769 } 770 771 // If the bounds of activity window is different from its parent, then reject to be seamless 772 // because the window position may change after rotation that will look like a sudden jump. 773 if (w.mActivityRecord != null && !w.mActivityRecord.matchParentBounds()) { 774 return false; 775 } 776 777 // In the presence of the PINNED root task or System Alert windows we unfortunately can not 778 // seamlessly rotate. 779 if (mDisplayContent.getDefaultTaskDisplayArea().hasPinnedTask() 780 || mDisplayContent.hasAlertWindowSurfaces()) { 781 return false; 782 } 783 784 // We can't rotate (seamlessly or not) while waiting for the last seamless rotation to 785 // complete (that is, waiting for windows to redraw). It's tempting to check 786 // mSeamlessRotationCount but that could be incorrect in the case of window-removal. 787 if (!forceUpdate && mDisplayContent.getWindow(win -> win.mSeamlesslyRotated) != null) { 788 return false; 789 } 790 791 return true; 792 } 793 canRotateSeamlessly(int oldRotation, int newRotation)794 boolean canRotateSeamlessly(int oldRotation, int newRotation) { 795 // If the navigation bar can't change sides, then it will jump when we change orientations 796 // and we don't rotate seamlessly - unless that is allowed, eg. with gesture navigation 797 // where the navbar is low-profile enough that this isn't very noticeable. 798 if (mAllowSeamlessRotationDespiteNavBarMoving || mDisplayPolicy.navigationBarCanMove()) { 799 return true; 800 } 801 // For the upside down rotation we don't rotate seamlessly as the navigation bar moves 802 // position. Note most apps (using orientation:sensor or user as opposed to fullSensor) 803 // will not enter the reverse portrait orientation, so actually the orientation won't change 804 // at all. 805 return oldRotation != Surface.ROTATION_180 && newRotation != Surface.ROTATION_180; 806 } 807 markForSeamlessRotation(WindowState w, boolean seamlesslyRotated)808 void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) { 809 if (seamlesslyRotated == w.mSeamlesslyRotated || w.mForceSeamlesslyRotate) { 810 return; 811 } 812 813 w.mSeamlesslyRotated = seamlesslyRotated; 814 if (seamlesslyRotated) { 815 mSeamlessRotationCount++; 816 } else { 817 mSeamlessRotationCount--; 818 } 819 if (mSeamlessRotationCount == 0) { 820 ProtoLog.i(WM_DEBUG_ORIENTATION, 821 "Performing post-rotate rotation after seamless rotation"); 822 // Finish seamless rotation. 823 mRotatingSeamlessly = false; 824 mDisplayContent.finishAsyncRotationIfPossible(); 825 826 updateRotationAndSendNewConfigIfChanged(); 827 } 828 } 829 830 /** 831 * Returns the animation to run for a rotation transition based on the top fullscreen windows 832 * {@link android.view.WindowManager.LayoutParams#rotationAnimation} and whether it is currently 833 * fullscreen and frontmost. 834 */ selectRotationAnimation()835 private RotationAnimationPair selectRotationAnimation() { 836 // If the screen is off or non-interactive, force a jumpcut. 837 final boolean forceJumpcut = !mDisplayPolicy.isScreenOnFully() 838 || !mService.mPolicy.okToAnimate(false /* ignoreScreenOn */); 839 final WindowState topFullscreen = mDisplayPolicy.getTopFullscreenOpaqueWindow(); 840 ProtoLog.i(WM_DEBUG_ANIM, "selectRotationAnimation topFullscreen=%s" 841 + " rotationAnimation=%d forceJumpcut=%b", 842 topFullscreen, 843 topFullscreen == null ? 0 : topFullscreen.getAttrs().rotationAnimation, 844 forceJumpcut); 845 if (forceJumpcut) { 846 mTmpRotationAnim.mExit = R.anim.rotation_animation_jump_exit; 847 mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter; 848 return mTmpRotationAnim; 849 } 850 if (topFullscreen != null) { 851 int animationHint = topFullscreen.getRotationAnimationHint(); 852 if (animationHint < 0 && mDisplayPolicy.isTopLayoutFullscreen()) { 853 animationHint = topFullscreen.getAttrs().rotationAnimation; 854 } 855 switch (animationHint) { 856 case ROTATION_ANIMATION_CROSSFADE: 857 case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless. 858 mTmpRotationAnim.mExit = R.anim.rotation_animation_xfade_exit; 859 mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter; 860 break; 861 case ROTATION_ANIMATION_JUMPCUT: 862 mTmpRotationAnim.mExit = R.anim.rotation_animation_jump_exit; 863 mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter; 864 break; 865 case ROTATION_ANIMATION_ROTATE: 866 default: 867 mTmpRotationAnim.mExit = mTmpRotationAnim.mEnter = 0; 868 break; 869 } 870 } else { 871 mTmpRotationAnim.mExit = mTmpRotationAnim.mEnter = 0; 872 } 873 return mTmpRotationAnim; 874 } 875 876 /** 877 * Validate whether the current top fullscreen has specified the same 878 * {@link android.view.WindowManager.LayoutParams#rotationAnimation} value as that being passed 879 * in from the previous top fullscreen window. 880 * 881 * @param exitAnimId exiting resource id from the previous window. 882 * @param enterAnimId entering resource id from the previous window. 883 * @param forceDefault For rotation animations only, if true ignore the animation values and 884 * just return false. 885 * @return {@code true} if the previous values are still valid, false if they should be replaced 886 * with the default. 887 */ validateRotationAnimation(int exitAnimId, int enterAnimId, boolean forceDefault)888 boolean validateRotationAnimation(int exitAnimId, int enterAnimId, boolean forceDefault) { 889 switch (exitAnimId) { 890 case R.anim.rotation_animation_xfade_exit: 891 case R.anim.rotation_animation_jump_exit: 892 // These are the only cases that matter. 893 if (forceDefault) { 894 return false; 895 } 896 final RotationAnimationPair anim = selectRotationAnimation(); 897 return exitAnimId == anim.mExit && enterAnimId == anim.mEnter; 898 default: 899 return true; 900 } 901 } 902 restoreSettings(int userRotationMode, int userRotation, int fixedToUserRotation)903 void restoreSettings(int userRotationMode, int userRotation, int fixedToUserRotation) { 904 mFixedToUserRotation = fixedToUserRotation; 905 906 // We will retrieve user rotation and user rotation mode from settings for default display. 907 if (isDefaultDisplay) { 908 return; 909 } 910 if (userRotationMode != WindowManagerPolicy.USER_ROTATION_FREE 911 && userRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) { 912 Slog.w(TAG, "Trying to restore an invalid user rotation mode " + userRotationMode 913 + " for " + mDisplayContent); 914 userRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; 915 } 916 if (userRotation < Surface.ROTATION_0 || userRotation > Surface.ROTATION_270) { 917 Slog.w(TAG, "Trying to restore an invalid user rotation " + userRotation 918 + " for " + mDisplayContent); 919 userRotation = Surface.ROTATION_0; 920 } 921 final int userRotationOverride = getUserRotationOverride(); 922 if (userRotationOverride != 0) { 923 userRotationMode = WindowManagerPolicy.USER_ROTATION_LOCKED; 924 userRotation = userRotationOverride; 925 } 926 mUserRotationMode = userRotationMode; 927 mUserRotation = userRotation; 928 } 929 setFixedToUserRotation(int fixedToUserRotation)930 void setFixedToUserRotation(int fixedToUserRotation) { 931 if (mFixedToUserRotation == fixedToUserRotation) { 932 return; 933 } 934 935 mFixedToUserRotation = fixedToUserRotation; 936 mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent, fixedToUserRotation); 937 if (mDisplayContent.mFocusedApp != null) { 938 // We record the last focused TDA that respects orientation request, check if this 939 // change may affect it. 940 mDisplayContent.onLastFocusedTaskDisplayAreaChanged( 941 mDisplayContent.mFocusedApp.getDisplayArea()); 942 } 943 mDisplayContent.updateOrientation(); 944 } 945 946 @VisibleForTesting setUserRotation(int userRotationMode, int userRotation, String caller)947 void setUserRotation(int userRotationMode, int userRotation, String caller) { 948 mRotationLockHistory.addRecord(userRotationMode, userRotation, caller); 949 mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; 950 if (useDefaultSettingsProvider()) { 951 // We'll be notified via settings listener, so we don't need to update internal values. 952 final ContentResolver res = mContext.getContentResolver(); 953 final int accelerometerRotation = 954 userRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED ? 0 : 1; 955 Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION, 956 accelerometerRotation, UserHandle.USER_CURRENT); 957 Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation, 958 UserHandle.USER_CURRENT); 959 return; 960 } 961 962 boolean changed = false; 963 if (mUserRotationMode != userRotationMode) { 964 mUserRotationMode = userRotationMode; 965 changed = true; 966 } 967 if (mUserRotation != userRotation) { 968 mUserRotation = userRotation; 969 changed = true; 970 } 971 mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode, 972 userRotation); 973 if (changed) { 974 mService.updateRotation(false /* alwaysSendConfiguration */, 975 false /* forceRelayout */); 976 // ContentRecorder.onConfigurationChanged and Device.setProjectionLocked are called 977 // during updateRotation above. But onConfigurationChanged is called before 978 // Device.setProjectionLocked, which means that the onConfigurationChanged will 979 // not have the new rotation when it calls getDisplaySurfaceDefaultSize. 980 // To make sure that mirroring takes the new rotation of the output surface 981 // into account we need to call onConfigurationChanged again. 982 mDisplayContent.onMirrorOutputSurfaceOrientationChanged(); 983 } 984 } 985 freezeRotation(int rotation, String caller)986 void freezeRotation(int rotation, String caller) { 987 if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis(mDisplayContent)) { 988 rotation = RotationUtils.reverseRotationDirectionAroundZAxis(rotation); 989 } 990 991 rotation = (rotation == -1) ? mRotation : rotation; 992 setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation, caller); 993 } 994 thawRotation(String caller)995 void thawRotation(String caller) { 996 setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation, caller); 997 } 998 isRotationFrozen()999 boolean isRotationFrozen() { 1000 if (!isDefaultDisplay) { 1001 return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED; 1002 } 1003 1004 return Settings.System.getIntForUser(mContext.getContentResolver(), 1005 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0; 1006 } 1007 isFixedToUserRotation()1008 boolean isFixedToUserRotation() { 1009 switch (mFixedToUserRotation) { 1010 case IWindowManager.FIXED_TO_USER_ROTATION_DISABLED: 1011 return false; 1012 case IWindowManager.FIXED_TO_USER_ROTATION_ENABLED: 1013 return true; 1014 case IWindowManager.FIXED_TO_USER_ROTATION_IF_NO_AUTO_ROTATION: 1015 return false; 1016 default: 1017 return mDefaultFixedToUserRotation; 1018 } 1019 } 1020 getFixedToUserRotationMode()1021 int getFixedToUserRotationMode() { 1022 return mFixedToUserRotation; 1023 } 1024 getLandscapeRotation()1025 public int getLandscapeRotation() { 1026 return mLandscapeRotation; 1027 } 1028 getSeascapeRotation()1029 public int getSeascapeRotation() { 1030 return mSeascapeRotation; 1031 } 1032 getPortraitRotation()1033 public int getPortraitRotation() { 1034 return mPortraitRotation; 1035 } 1036 getUpsideDownRotation()1037 public int getUpsideDownRotation() { 1038 return mUpsideDownRotation; 1039 } 1040 getCurrentAppOrientation()1041 public int getCurrentAppOrientation() { 1042 return mCurrentAppOrientation; 1043 } 1044 getDisplayPolicy()1045 public DisplayPolicy getDisplayPolicy() { 1046 return mDisplayPolicy; 1047 } 1048 getOrientationListener()1049 public WindowOrientationListener getOrientationListener() { 1050 return mOrientationListener; 1051 } 1052 getUserRotation()1053 public int getUserRotation() { 1054 return mUserRotation; 1055 } 1056 getUserRotationMode()1057 public int getUserRotationMode() { 1058 return mUserRotationMode; 1059 } 1060 updateOrientationListener()1061 public void updateOrientationListener() { 1062 synchronized (mLock) { 1063 updateOrientationListenerLw(); 1064 } 1065 } 1066 1067 /** 1068 * Temporarily pauses rotation changes until resumed. 1069 * <p> 1070 * This can be used to prevent rotation changes from occurring while the user is performing 1071 * certain operations, such as drag and drop. 1072 * <p> 1073 * This call nests and must be matched by an equal number of calls to {@link #resume}. 1074 */ pause()1075 void pause() { 1076 mDeferredRotationPauseCount++; 1077 } 1078 1079 /** Resumes normal rotation changes after being paused. */ resume()1080 void resume() { 1081 if (mDeferredRotationPauseCount <= 0) { 1082 return; 1083 } 1084 1085 mDeferredRotationPauseCount--; 1086 if (mDeferredRotationPauseCount == 0) { 1087 updateRotationAndSendNewConfigIfChanged(); 1088 } 1089 } 1090 1091 /** 1092 * Various use cases for invoking this function: 1093 * <li>Screen turning off, should always disable listeners if already enabled.</li> 1094 * <li>Screen turned on and current app has sensor based orientation, enable listeners 1095 * if not already enabled.</li> 1096 * <li>Screen turned on and current app does not have sensor orientation, disable listeners 1097 * if already enabled.</li> 1098 * <li>Screen turning on and current app has sensor based orientation, enable listeners 1099 * if needed.</li> 1100 * <li>screen turning on and current app has nosensor based orientation, do nothing.</li> 1101 */ updateOrientationListenerLw()1102 private void updateOrientationListenerLw() { 1103 if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) { 1104 // If sensor is turned off or nonexistent for some reason. 1105 return; 1106 } 1107 1108 final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly(); 1109 final boolean awake = mDisplayPolicy.isAwake(); 1110 final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete(); 1111 final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete(); 1112 1113 // Could have been invoked due to screen turning on or off or 1114 // change of the currently visible window's orientation. 1115 ProtoLog.v(WM_DEBUG_ORIENTATION, 1116 "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, " 1117 + "orientationSensorEnabled=%b, keyguardDrawComplete=%b, " 1118 + "windowManagerDrawComplete=%b", 1119 screenOnEarly, awake, mCurrentAppOrientation, mOrientationListener.mEnabled, 1120 keyguardDrawComplete, windowManagerDrawComplete); 1121 1122 boolean disable = true; 1123 1124 // If the orientation listener uses a wake sensor, keep the orientation listener on if the 1125 // screen is on (regardless of wake state). This allows the AoD to rotate. 1126 // 1127 // Note: We postpone the rotating of the screen until the keyguard as well as the 1128 // window manager have reported a draw complete or the keyguard is going away in dismiss 1129 // mode. 1130 if (screenOnEarly 1131 && (awake || mOrientationListener.shouldStayEnabledWhileDreaming()) 1132 && ((keyguardDrawComplete && windowManagerDrawComplete))) { 1133 if (needSensorRunning()) { 1134 disable = false; 1135 // Enable listener if not already enabled. 1136 if (!mOrientationListener.mEnabled) { 1137 mOrientationListener.enable(); 1138 } 1139 } 1140 } 1141 // Check if sensors need to be disabled. 1142 if (disable) { 1143 mOrientationListener.disable(); 1144 } 1145 } 1146 1147 /** 1148 * We always let the sensor be switched on by default except when 1149 * the user has explicitly disabled sensor based rotation or when the 1150 * screen is switched off. 1151 */ needSensorRunning()1152 private boolean needSensorRunning() { 1153 if (isFixedToUserRotation()) { 1154 // We are sure we only respect user rotation settings, so we are sure we will not 1155 // support sensor rotation. 1156 return false; 1157 } 1158 1159 if (mFoldController != null && mFoldController.shouldDisableRotationSensor()) { 1160 return false; 1161 } 1162 1163 if (mSupportAutoRotation) { 1164 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR 1165 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR 1166 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT 1167 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) { 1168 // If the application has explicitly requested to follow the 1169 // orientation, then we need to turn the sensor on. 1170 return true; 1171 } 1172 } 1173 1174 final int dockMode = mDisplayPolicy.getDockMode(); 1175 if ((mDisplayPolicy.isCarDockEnablesAccelerometer() 1176 && dockMode == Intent.EXTRA_DOCK_STATE_CAR) 1177 || (mDisplayPolicy.isDeskDockEnablesAccelerometer() 1178 && (dockMode == Intent.EXTRA_DOCK_STATE_DESK 1179 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK 1180 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) { 1181 // Enable accelerometer if we are docked in a dock that enables accelerometer 1182 // orientation management. 1183 return true; 1184 } 1185 1186 if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) { 1187 // If the setting for using the sensor by default is enabled, then 1188 // we will always leave it on. Note that the user could go to 1189 // a window that forces an orientation that does not use the 1190 // sensor and in theory we could turn it off... however, when next 1191 // turning it on we won't have a good value for the current 1192 // orientation for a little bit, which can cause orientation 1193 // changes to lag, so we'd like to keep it always on. (It will 1194 // still be turned off when the screen is off.) 1195 1196 // When locked we can provide rotation suggestions users can approve to change the 1197 // current screen rotation. To do this the sensor needs to be running. 1198 return mSupportAutoRotation && 1199 mShowRotationSuggestions == Settings.Secure.SHOW_ROTATION_SUGGESTIONS_ENABLED; 1200 } 1201 return mSupportAutoRotation; 1202 } 1203 1204 /** 1205 * If this is true we have updated our desired orientation, but not yet changed the real 1206 * orientation our applied our screen rotation animation. For example, because a previous 1207 * screen rotation was in progress. 1208 * 1209 * @return {@code true} if the there is an ongoing rotation change. 1210 */ needsUpdate()1211 boolean needsUpdate() { 1212 final int oldRotation = mRotation; 1213 final int rotation = rotationForOrientation(mLastOrientation, oldRotation); 1214 return oldRotation != rotation; 1215 } 1216 1217 1218 /** 1219 * Resets whether the screen can be rotated via the accelerometer in all 4 rotations as the 1220 * default behavior. 1221 * 1222 * To be called if there is potential that the value changed. For example if the active display 1223 * changed. 1224 * 1225 * At the moment it is called from 1226 * {@link DisplayWindowSettings#applyRotationSettingsToDisplayLocked}. 1227 */ resetAllowAllRotations()1228 void resetAllowAllRotations() { 1229 mAllowAllRotations = ALLOW_ALL_ROTATIONS_UNDEFINED; 1230 } 1231 1232 /** 1233 * Given an orientation constant, returns the appropriate surface rotation, taking into account 1234 * sensors, docking mode, rotation lock, and other factors. 1235 * 1236 * @param orientation An orientation constant, such as 1237 * {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. 1238 * @param lastRotation The most recently used rotation. 1239 * @return The surface rotation to use. 1240 */ 1241 @VisibleForTesting 1242 @Surface.Rotation rotationForOrientation(@creenOrientation int orientation, @Surface.Rotation int lastRotation)1243 int rotationForOrientation(@ScreenOrientation int orientation, 1244 @Surface.Rotation int lastRotation) { 1245 ProtoLog.v(WM_DEBUG_ORIENTATION, 1246 "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s", 1247 ActivityInfo.screenOrientationToString(orientation), orientation, 1248 Surface.rotationToString(lastRotation), lastRotation, 1249 Surface.rotationToString(mUserRotation), mUserRotation, 1250 mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED 1251 ? "USER_ROTATION_LOCKED" : ""); 1252 1253 if (isFixedToUserRotation()) { 1254 return mUserRotation; 1255 } 1256 1257 @Surface.Rotation 1258 int sensorRotation = mOrientationListener != null 1259 ? mOrientationListener.getProposedRotation() // may be -1 1260 : -1; 1261 if (mFoldController != null && mFoldController.shouldIgnoreSensorRotation()) { 1262 sensorRotation = -1; 1263 } 1264 if (mDeviceStateController.shouldReverseRotationDirectionAroundZAxis(mDisplayContent)) { 1265 sensorRotation = RotationUtils.reverseRotationDirectionAroundZAxis(sensorRotation); 1266 } 1267 mLastSensorRotation = sensorRotation; 1268 if (sensorRotation < 0) { 1269 sensorRotation = lastRotation; 1270 } 1271 1272 final int lidState = mDisplayPolicy.getLidState(); 1273 final int dockMode = mDisplayPolicy.getDockMode(); 1274 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged(); 1275 final boolean carDockEnablesAccelerometer = 1276 mDisplayPolicy.isCarDockEnablesAccelerometer(); 1277 final boolean deskDockEnablesAccelerometer = 1278 mDisplayPolicy.isDeskDockEnablesAccelerometer(); 1279 1280 @Surface.Rotation 1281 final int preferredRotation; 1282 if (!isDefaultDisplay) { 1283 // For secondary displays we ignore things like displays sensors, docking mode and 1284 // rotation lock, and always prefer user rotation. 1285 preferredRotation = mUserRotation; 1286 } else if (lidState == LID_OPEN && mLidOpenRotation >= 0) { 1287 // Ignore sensor when lid switch is open and rotation is forced. 1288 preferredRotation = mLidOpenRotation; 1289 } else if (dockMode == Intent.EXTRA_DOCK_STATE_CAR 1290 && (carDockEnablesAccelerometer || mCarDockRotation >= 0)) { 1291 // Ignore sensor when in car dock unless explicitly enabled. 1292 // This case can override the behavior of NOSENSOR, and can also 1293 // enable 180 degree rotation while docked. 1294 preferredRotation = carDockEnablesAccelerometer ? sensorRotation : mCarDockRotation; 1295 } else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK 1296 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK 1297 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK) 1298 && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0) 1299 && !(orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED 1300 || orientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)) { 1301 // Ignore sensor when in desk dock unless explicitly enabled. 1302 // This case can enable 180 degree rotation while docked. 1303 preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation; 1304 } else if (hdmiPlugged && mDemoHdmiRotationLock) { 1305 // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled. 1306 // Note that the dock orientation overrides the HDMI orientation. 1307 preferredRotation = mDemoHdmiRotation; 1308 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED 1309 && mUndockedHdmiRotation >= 0) { 1310 // Ignore sensor when plugged into HDMI and an undocked orientation has 1311 // been specified in the configuration (only for legacy devices without 1312 // full multi-display support). 1313 // Note that the dock orientation overrides the HDMI orientation. 1314 preferredRotation = mUndockedHdmiRotation; 1315 } else if (mDemoRotationLock) { 1316 // Ignore sensor when demo rotation lock is enabled. 1317 // Note that the dock orientation and HDMI rotation lock override this. 1318 preferredRotation = mDemoRotation; 1319 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) { 1320 // While in VR, apps always prefer a portrait rotation. This does not change 1321 // any apps that explicitly set landscape, but does cause sensors be ignored, 1322 // and ignored any orientation lock that the user has set (this conditional 1323 // should remain above the ORIENTATION_LOCKED conditional below). 1324 preferredRotation = mPortraitRotation; 1325 } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { 1326 // Application just wants to remain locked in the last rotation. 1327 preferredRotation = lastRotation; 1328 } else if (!mSupportAutoRotation) { 1329 if (mFixedToUserRotation == IWindowManager.FIXED_TO_USER_ROTATION_IF_NO_AUTO_ROTATION) { 1330 preferredRotation = mUserRotation; 1331 } else { 1332 // If we don't support auto-rotation then bail out here and ignore 1333 // the sensor and any rotation lock settings. 1334 preferredRotation = -1; 1335 } 1336 } else if (((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE 1337 || isTabletopAutoRotateOverrideEnabled()) 1338 && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER 1339 || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED 1340 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE 1341 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT 1342 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER)) 1343 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR 1344 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR 1345 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE 1346 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) { 1347 // Otherwise, use sensor only if requested by the application or enabled 1348 // by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR. 1349 if (sensorRotation != Surface.ROTATION_180 1350 || getAllowAllRotations() == ALLOW_ALL_ROTATIONS_ENABLED 1351 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR 1352 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) { 1353 preferredRotation = sensorRotation; 1354 } else { 1355 preferredRotation = lastRotation; 1356 } 1357 } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED 1358 && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR 1359 && orientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE 1360 && orientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT 1361 && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE 1362 && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) { 1363 // Apply rotation lock. Does not apply to NOSENSOR or specific rotations. 1364 // The idea is that the user rotation expresses a weak preference for the direction 1365 // of gravity and as NOSENSOR is never affected by gravity, then neither should 1366 // NOSENSOR be affected by rotation lock (although it will be affected by docks). 1367 // Also avoid setting user rotation when app has preference over one particular rotation 1368 // to avoid leaving the rotation to the reverse of it which has the compatible 1369 // orientation, but isn't what app wants, when the user rotation is the reverse of the 1370 // preferred rotation. 1371 preferredRotation = mUserRotation; 1372 } else { 1373 // No overriding preference. 1374 // We will do exactly what the application asked us to do. 1375 preferredRotation = -1; 1376 } 1377 1378 switch (orientation) { 1379 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: 1380 // Return portrait unless overridden. 1381 if (isAnyPortrait(preferredRotation)) { 1382 return preferredRotation; 1383 } 1384 return mPortraitRotation; 1385 1386 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: 1387 // Return landscape unless overridden. 1388 if (isLandscapeOrSeascape(preferredRotation)) { 1389 return preferredRotation; 1390 } 1391 return mLandscapeRotation; 1392 1393 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: 1394 // Return reverse portrait unless overridden. 1395 if (isAnyPortrait(preferredRotation)) { 1396 return preferredRotation; 1397 } 1398 return mUpsideDownRotation; 1399 1400 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: 1401 // Return seascape unless overridden. 1402 if (isLandscapeOrSeascape(preferredRotation)) { 1403 return preferredRotation; 1404 } 1405 return mSeascapeRotation; 1406 1407 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: 1408 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE: 1409 // Return either landscape rotation. 1410 if (isLandscapeOrSeascape(preferredRotation)) { 1411 return preferredRotation; 1412 } 1413 if (isLandscapeOrSeascape(lastRotation)) { 1414 return lastRotation; 1415 } 1416 return mLandscapeRotation; 1417 1418 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: 1419 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT: 1420 // Return either portrait rotation. 1421 if (isAnyPortrait(preferredRotation)) { 1422 return preferredRotation; 1423 } 1424 if (isAnyPortrait(lastRotation)) { 1425 return lastRotation; 1426 } 1427 return mPortraitRotation; 1428 1429 default: 1430 // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR, 1431 // just return the preferred orientation we already calculated. 1432 if (preferredRotation >= 0) { 1433 return preferredRotation; 1434 } 1435 return Surface.ROTATION_0; 1436 } 1437 } 1438 getAllowAllRotations()1439 private int getAllowAllRotations() { 1440 if (mAllowAllRotations == ALLOW_ALL_ROTATIONS_UNDEFINED) { 1441 // Can't read this during init() because the context doesn't have display metrics at 1442 // that time so we cannot determine tablet vs. phone then. 1443 mAllowAllRotations = mContext.getResources().getBoolean( 1444 R.bool.config_allowAllRotations) 1445 ? ALLOW_ALL_ROTATIONS_ENABLED 1446 : ALLOW_ALL_ROTATIONS_DISABLED; 1447 } 1448 1449 return mAllowAllRotations; 1450 } 1451 isLandscapeOrSeascape(@urface.Rotation final int rotation)1452 boolean isLandscapeOrSeascape(@Surface.Rotation final int rotation) { 1453 return rotation == mLandscapeRotation || rotation == mSeascapeRotation; 1454 } 1455 isAnyPortrait(@urface.Rotation final int rotation)1456 boolean isAnyPortrait(@Surface.Rotation final int rotation) { 1457 return rotation == mPortraitRotation || rotation == mUpsideDownRotation; 1458 } 1459 isValidRotationChoice(final int preferredRotation)1460 private boolean isValidRotationChoice(final int preferredRotation) { 1461 // Determine if the given app orientation is compatible with the provided rotation choice. 1462 switch (mCurrentAppOrientation) { 1463 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER: 1464 // Works with any of the 4 rotations. 1465 return preferredRotation >= 0; 1466 1467 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT: 1468 // It's possible for the user pref to be set at 180 because of FULL_USER. This would 1469 // make switching to USER_PORTRAIT appear at 180. Provide choice to back to portrait 1470 // but never to go to 180. 1471 return preferredRotation == mPortraitRotation; 1472 1473 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE: 1474 // Works landscape or seascape. 1475 return isLandscapeOrSeascape(preferredRotation); 1476 1477 case ActivityInfo.SCREEN_ORIENTATION_USER: 1478 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED: 1479 // When all rotations enabled it works with any of the 4 rotations 1480 if (getAllowAllRotations() == ALLOW_ALL_ROTATIONS_ENABLED) { 1481 return preferredRotation >= 0; 1482 } 1483 1484 // Works with any rotation except upside down. 1485 return (preferredRotation >= 0) && (preferredRotation != Surface.ROTATION_180); 1486 } 1487 1488 return false; 1489 } 1490 isTabletopAutoRotateOverrideEnabled()1491 private boolean isTabletopAutoRotateOverrideEnabled() { 1492 return mFoldController != null && mFoldController.overrideFrozenRotation(); 1493 } 1494 isRotationChoiceAllowed(@urface.Rotation final int proposedRotation)1495 private boolean isRotationChoiceAllowed(@Surface.Rotation final int proposedRotation) { 1496 final boolean isRotationLockEnforced = mCompatPolicyForImmersiveApps != null 1497 && mCompatPolicyForImmersiveApps.isRotationLockEnforced(proposedRotation); 1498 1499 // Don't show rotation choice button if 1500 if (!isRotationLockEnforced // not enforcing locked rotation 1501 // and the screen rotation is not locked by the user. 1502 && mUserRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) { 1503 return false; 1504 } 1505 1506 // Don't show rotation choice if we are in tabletop or book modes. 1507 if (isTabletopAutoRotateOverrideEnabled()) return false; 1508 1509 // We should only enable rotation choice if the rotation isn't forced by the lid, dock, 1510 // demo, hdmi, vr, etc mode. 1511 1512 // Determine if the rotation is currently forced. 1513 if (isFixedToUserRotation()) { 1514 return false; // Rotation is forced to user settings. 1515 } 1516 1517 final int lidState = mDisplayPolicy.getLidState(); 1518 if (lidState == LID_OPEN && mLidOpenRotation >= 0) { 1519 return false; // Rotation is forced mLidOpenRotation. 1520 } 1521 1522 final int dockMode = mDisplayPolicy.getDockMode(); 1523 final boolean carDockEnablesAccelerometer = false; 1524 if (dockMode == Intent.EXTRA_DOCK_STATE_CAR && !carDockEnablesAccelerometer) { 1525 return false; // Rotation forced to mCarDockRotation. 1526 } 1527 1528 final boolean deskDockEnablesAccelerometer = 1529 mDisplayPolicy.isDeskDockEnablesAccelerometer(); 1530 if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK 1531 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK 1532 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK) 1533 && !deskDockEnablesAccelerometer) { 1534 return false; // Rotation forced to mDeskDockRotation. 1535 } 1536 1537 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged(); 1538 if (hdmiPlugged && mDemoHdmiRotationLock) { 1539 return false; // Rotation forced to mDemoHdmiRotation. 1540 1541 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED 1542 && mUndockedHdmiRotation >= 0) { 1543 return false; // Rotation forced to mUndockedHdmiRotation. 1544 1545 } else if (mDemoRotationLock) { 1546 return false; // Rotation forced to mDemoRotation. 1547 1548 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) { 1549 return false; // Rotation forced to mPortraitRotation. 1550 1551 } else if (!mSupportAutoRotation) { 1552 return false; 1553 } 1554 1555 // Ensure that some rotation choice is possible for the given orientation. 1556 switch (mCurrentAppOrientation) { 1557 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER: 1558 case ActivityInfo.SCREEN_ORIENTATION_USER: 1559 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED: 1560 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE: 1561 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT: 1562 // NOSENSOR description is ambiguous, in reality WM ignores user choice. 1563 return true; 1564 } 1565 1566 // Rotation is forced, should be controlled by system. 1567 return false; 1568 } 1569 1570 /** Notify the StatusBar that system rotation suggestion has changed. */ sendProposedRotationChangeToStatusBarInternal(int rotation, boolean isValid)1571 private void sendProposedRotationChangeToStatusBarInternal(int rotation, boolean isValid) { 1572 if (mStatusBarManagerInternal == null) { 1573 mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class); 1574 } 1575 if (mStatusBarManagerInternal != null) { 1576 mStatusBarManagerInternal.onProposedRotationChanged(rotation, isValid); 1577 } 1578 } 1579 dispatchProposedRotation(@urface.Rotation int rotation)1580 void dispatchProposedRotation(@Surface.Rotation int rotation) { 1581 if (mService.mRotationWatcherController.hasProposedRotationListeners()) { 1582 synchronized (mLock) { 1583 mService.mRotationWatcherController.dispatchProposedRotation( 1584 mDisplayContent, rotation); 1585 } 1586 } 1587 } 1588 allowAllRotationsToString(int allowAll)1589 private static String allowAllRotationsToString(int allowAll) { 1590 switch (allowAll) { 1591 case -1: 1592 return "unknown"; 1593 case 0: 1594 return "false"; 1595 case 1: 1596 return "true"; 1597 default: 1598 return Integer.toString(allowAll); 1599 } 1600 } 1601 onUserSwitch()1602 public void onUserSwitch() { 1603 if (mSettingsObserver != null) { 1604 mSettingsObserver.onChange(false); 1605 } 1606 } 1607 onDisplayRemoved()1608 void onDisplayRemoved() { 1609 removeDefaultDisplayRotationChangedCallback(); 1610 if (mFoldController != null) { 1611 mFoldController.onDisplayRemoved(); 1612 } 1613 } 1614 1615 /** Return whether the rotation settings has changed. */ updateSettings()1616 private boolean updateSettings() { 1617 final ContentResolver resolver = mContext.getContentResolver(); 1618 boolean shouldUpdateRotation = false; 1619 1620 synchronized (mLock) { 1621 boolean shouldUpdateOrientationListener = false; 1622 1623 // Configure rotation suggestions. 1624 final int showRotationSuggestions = 1625 ActivityManager.isLowRamDeviceStatic() 1626 ? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED 1627 : Settings.Secure.getIntForUser(resolver, 1628 Settings.Secure.SHOW_ROTATION_SUGGESTIONS, 1629 Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT, 1630 UserHandle.USER_CURRENT); 1631 if (mShowRotationSuggestions != showRotationSuggestions) { 1632 mShowRotationSuggestions = showRotationSuggestions; 1633 shouldUpdateOrientationListener = true; 1634 } 1635 1636 // Configure rotation lock. 1637 final int userRotation = Settings.System.getIntForUser(resolver, 1638 Settings.System.USER_ROTATION, Surface.ROTATION_0, 1639 UserHandle.USER_CURRENT); 1640 if (mUserRotation != userRotation) { 1641 mUserRotation = userRotation; 1642 shouldUpdateRotation = true; 1643 } 1644 1645 final int userRotationMode = Settings.System.getIntForUser(resolver, 1646 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0 1647 ? WindowManagerPolicy.USER_ROTATION_FREE 1648 : WindowManagerPolicy.USER_ROTATION_LOCKED; 1649 if (mUserRotationMode != userRotationMode) { 1650 mUserRotationMode = userRotationMode; 1651 shouldUpdateOrientationListener = true; 1652 shouldUpdateRotation = true; 1653 } 1654 1655 if (shouldUpdateOrientationListener) { 1656 updateOrientationListenerLw(); // Enable or disable the orientation listener. 1657 } 1658 1659 final int cameraRotationMode = Settings.Secure.getIntForUser(resolver, 1660 Settings.Secure.CAMERA_AUTOROTATE, 0, 1661 UserHandle.USER_CURRENT); 1662 if (mCameraRotationMode != cameraRotationMode) { 1663 mCameraRotationMode = cameraRotationMode; 1664 shouldUpdateRotation = true; 1665 } 1666 } 1667 1668 return shouldUpdateRotation; 1669 } 1670 removeDefaultDisplayRotationChangedCallback()1671 void removeDefaultDisplayRotationChangedCallback() { 1672 if (DisplayRotationCoordinator.isSecondaryInternalDisplay(mDisplayContent)) { 1673 mDisplayRotationCoordinator.removeDefaultDisplayRotationChangedCallback(); 1674 } 1675 } 1676 1677 /** 1678 * Called from {@link ActivityRecord#setRequestedOrientation(int)} 1679 */ onSetRequestedOrientation()1680 void onSetRequestedOrientation() { 1681 if (mCompatPolicyForImmersiveApps == null 1682 || mRotationChoiceShownToUserForConfirmation == ROTATION_UNDEFINED) { 1683 return; 1684 } 1685 mOrientationListener.onProposedRotationChanged(mRotationChoiceShownToUserForConfirmation); 1686 } 1687 dump(String prefix, PrintWriter pw)1688 void dump(String prefix, PrintWriter pw) { 1689 pw.println(prefix + "DisplayRotation"); 1690 pw.println(prefix + " mCurrentAppOrientation=" 1691 + ActivityInfo.screenOrientationToString(mCurrentAppOrientation)); 1692 pw.println(prefix + " mLastOrientation=" + mLastOrientation); 1693 pw.print(prefix + " mRotation=" + mRotation); 1694 pw.println(" mDeferredRotationPauseCount=" + mDeferredRotationPauseCount); 1695 1696 pw.print(prefix + " mLandscapeRotation=" + Surface.rotationToString(mLandscapeRotation)); 1697 pw.println(" mSeascapeRotation=" + Surface.rotationToString(mSeascapeRotation)); 1698 pw.print(prefix + " mPortraitRotation=" + Surface.rotationToString(mPortraitRotation)); 1699 pw.println(" mUpsideDownRotation=" + Surface.rotationToString(mUpsideDownRotation)); 1700 1701 pw.println(prefix + " mSupportAutoRotation=" + mSupportAutoRotation); 1702 if (mOrientationListener != null) { 1703 mOrientationListener.dump(pw, prefix + " "); 1704 } 1705 pw.println(); 1706 1707 pw.print(prefix + " mCarDockRotation=" + Surface.rotationToString(mCarDockRotation)); 1708 pw.println(" mDeskDockRotation=" + Surface.rotationToString(mDeskDockRotation)); 1709 pw.print(prefix + " mUserRotationMode=" 1710 + WindowManagerPolicy.userRotationModeToString(mUserRotationMode)); 1711 pw.print(" mUserRotation=" + Surface.rotationToString(mUserRotation)); 1712 pw.print(" mCameraRotationMode=" + mCameraRotationMode); 1713 pw.println(" mAllowAllRotations=" + allowAllRotationsToString(mAllowAllRotations)); 1714 1715 pw.print(prefix + " mDemoHdmiRotation=" + Surface.rotationToString(mDemoHdmiRotation)); 1716 pw.print(" mDemoHdmiRotationLock=" + mDemoHdmiRotationLock); 1717 pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation)); 1718 pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation)); 1719 pw.println(prefix + " mFixedToUserRotation=" + isFixedToUserRotation()); 1720 1721 if (mFoldController != null) { 1722 pw.println(prefix + "FoldController"); 1723 pw.println(prefix + " mPauseAutorotationDuringUnfolding=" 1724 + mFoldController.mPauseAutorotationDuringUnfolding); 1725 pw.println(prefix + " mShouldDisableRotationSensor=" 1726 + mFoldController.mShouldDisableRotationSensor); 1727 pw.println(prefix + " mShouldIgnoreSensorRotation=" 1728 + mFoldController.mShouldIgnoreSensorRotation); 1729 pw.println(prefix + " mLastDisplaySwitchTime=" 1730 + mFoldController.mLastDisplaySwitchTime); 1731 pw.println(prefix + " mLastHingeAngleEventTime=" 1732 + mFoldController.mLastHingeAngleEventTime); 1733 pw.println(prefix + " mDeviceState=" 1734 + mFoldController.mDeviceState); 1735 } 1736 1737 if (!mRotationHistory.mRecords.isEmpty()) { 1738 pw.println(); 1739 pw.println(prefix + " RotationHistory"); 1740 prefix = " " + prefix; 1741 for (RotationHistory.Record r : mRotationHistory.mRecords) { 1742 r.dump(prefix, pw); 1743 } 1744 } 1745 1746 if (!mRotationLockHistory.mRecords.isEmpty()) { 1747 pw.println(); 1748 pw.println(prefix + " RotationLockHistory"); 1749 prefix = " " + prefix; 1750 for (RotationLockHistory.Record r : mRotationLockHistory.mRecords) { 1751 r.dump(prefix, pw); 1752 } 1753 } 1754 } 1755 dumpDebug(ProtoOutputStream proto, long fieldId)1756 void dumpDebug(ProtoOutputStream proto, long fieldId) { 1757 final long token = proto.start(fieldId); 1758 proto.write(ROTATION, getRotation()); 1759 proto.write(FROZEN_TO_USER_ROTATION, isRotationFrozen()); 1760 proto.write(USER_ROTATION, getUserRotation()); 1761 proto.write(FIXED_TO_USER_ROTATION_MODE, mFixedToUserRotation); 1762 proto.write(LAST_ORIENTATION, mLastOrientation); 1763 proto.write(IS_FIXED_TO_USER_ROTATION, isFixedToUserRotation()); 1764 proto.end(token); 1765 } 1766 isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop)1767 boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) { 1768 if (mFoldController == null) return false; 1769 return mFoldController.isDeviceInPosture(state, isTabletop); 1770 } 1771 isDisplaySeparatingHinge()1772 boolean isDisplaySeparatingHinge() { 1773 return mFoldController != null && mFoldController.isSeparatingHinge(); 1774 } 1775 1776 /** 1777 * Called by the display manager just before it applied the device state, it is guaranteed 1778 * that in case of physical display change the {@link DisplayRotation#physicalDisplayChanged} 1779 * method will be invoked *after* this one. 1780 */ foldStateChanged(DeviceStateController.DeviceState deviceState)1781 void foldStateChanged(DeviceStateController.DeviceState deviceState) { 1782 if (mFoldController != null) { 1783 synchronized (mLock) { 1784 mFoldController.foldStateChanged(deviceState); 1785 } 1786 } 1787 } 1788 1789 /** 1790 * Called by the DisplayContent when the physical display changes 1791 */ physicalDisplayChanged()1792 void physicalDisplayChanged() { 1793 if (mFoldController != null) { 1794 mFoldController.onPhysicalDisplayChanged(); 1795 } 1796 } 1797 1798 @VisibleForTesting getDemoUserRotationOverride()1799 int getDemoUserRotationOverride() { 1800 return SystemProperties.getInt("persist.demo.userrotation", Surface.ROTATION_0); 1801 } 1802 1803 @VisibleForTesting 1804 @NonNull getDemoUserRotationPackage()1805 String getDemoUserRotationPackage() { 1806 return SystemProperties.get("persist.demo.userrotation.package_name"); 1807 } 1808 1809 @Surface.Rotation getUserRotationOverride()1810 private int getUserRotationOverride() { 1811 final int userRotationOverride = getDemoUserRotationOverride(); 1812 if (userRotationOverride == Surface.ROTATION_0) { 1813 return userRotationOverride; 1814 } 1815 1816 final var display = mDisplayContent.getDisplay(); 1817 if (display.getType() == TYPE_EXTERNAL || display.getType() == TYPE_OVERLAY) { 1818 return userRotationOverride; 1819 } 1820 1821 if (display.getType() == TYPE_VIRTUAL) { 1822 final var packageName = getDemoUserRotationPackage(); 1823 if (!packageName.isEmpty() && packageName.equals(display.getOwnerPackageName())) { 1824 return userRotationOverride; 1825 } 1826 } 1827 1828 return Surface.ROTATION_0; 1829 } 1830 1831 @VisibleForTesting uptimeMillis()1832 long uptimeMillis() { 1833 return SystemClock.uptimeMillis(); 1834 } 1835 1836 class FoldController { 1837 private final boolean mPauseAutorotationDuringUnfolding; 1838 @Surface.Rotation 1839 private int mHalfFoldSavedRotation = -1; // No saved rotation 1840 private DeviceStateController.DeviceState mDeviceState = 1841 DeviceStateController.DeviceState.UNKNOWN; 1842 private long mLastHingeAngleEventTime = 0; 1843 private long mLastDisplaySwitchTime = 0; 1844 private boolean mShouldIgnoreSensorRotation; 1845 private boolean mShouldDisableRotationSensor; 1846 private boolean mInHalfFoldTransition = false; 1847 private int mDisplaySwitchRotationBlockTimeMs; 1848 private int mHingeAngleRotationBlockTimeMs; 1849 private int mMaxHingeAngle; 1850 private final boolean mIsDisplayAlwaysSeparatingHinge; 1851 private SensorManager mSensorManager; 1852 private SensorEventListener mHingeAngleSensorEventListener; 1853 private final Set<Integer> mTabletopRotations; 1854 private final Runnable mActivityBoundsUpdateCallback; 1855 private final boolean mAllowHalfFoldAutoRotationOverride; 1856 FoldController()1857 FoldController() { 1858 mAllowHalfFoldAutoRotationOverride = mContext.getResources().getBoolean( 1859 R.bool.config_windowManagerHalfFoldAutoRotateOverride); 1860 mTabletopRotations = new ArraySet<>(); 1861 int[] tabletop_rotations = mContext.getResources().getIntArray( 1862 R.array.config_deviceTabletopRotations); 1863 if (tabletop_rotations != null) { 1864 for (int angle : tabletop_rotations) { 1865 switch (angle) { 1866 case 0: 1867 mTabletopRotations.add(Surface.ROTATION_0); 1868 break; 1869 case 90: 1870 mTabletopRotations.add(Surface.ROTATION_90); 1871 break; 1872 case 180: 1873 mTabletopRotations.add(Surface.ROTATION_180); 1874 break; 1875 case 270: 1876 mTabletopRotations.add(Surface.ROTATION_270); 1877 break; 1878 default: 1879 ProtoLog.e(WM_DEBUG_ORIENTATION, 1880 "Invalid surface rotation angle in " 1881 + "config_deviceTabletopRotations: %d", 1882 angle); 1883 } 1884 } 1885 } else { 1886 ProtoLog.w(WM_DEBUG_ORIENTATION, 1887 "config_deviceTabletopRotations is not defined. Half-fold " 1888 + "letterboxing will work inconsistently."); 1889 } 1890 mIsDisplayAlwaysSeparatingHinge = mContext.getResources().getBoolean( 1891 R.bool.config_isDisplayHingeAlwaysSeparating); 1892 1893 mActivityBoundsUpdateCallback = new Runnable() { 1894 public void run() { 1895 if (mDeviceState == DeviceStateController.DeviceState.OPEN 1896 || mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) { 1897 synchronized (mLock) { 1898 final Task topFullscreenTask = 1899 mDisplayContent.getTask( 1900 t -> t.getWindowingMode() == WINDOWING_MODE_FULLSCREEN); 1901 if (topFullscreenTask != null) { 1902 final ActivityRecord top = 1903 topFullscreenTask.topRunningActivity(); 1904 if (top != null) { 1905 top.recomputeConfiguration(); 1906 } 1907 } 1908 } 1909 } 1910 } 1911 }; 1912 1913 mPauseAutorotationDuringUnfolding = mContext.getResources().getBoolean( 1914 R.bool.config_windowManagerPauseRotationWhenUnfolding); 1915 1916 if (mPauseAutorotationDuringUnfolding) { 1917 mDisplaySwitchRotationBlockTimeMs = mContext.getResources().getInteger( 1918 R.integer.config_pauseRotationWhenUnfolding_displaySwitchTimeout); 1919 mHingeAngleRotationBlockTimeMs = mContext.getResources().getInteger( 1920 R.integer.config_pauseRotationWhenUnfolding_hingeEventTimeout); 1921 mMaxHingeAngle = mContext.getResources().getInteger( 1922 R.integer.config_pauseRotationWhenUnfolding_maxHingeAngle); 1923 registerSensorManager(); 1924 } 1925 } 1926 registerSensorManager()1927 private void registerSensorManager() { 1928 mSensorManager = mContext.getSystemService(SensorManager.class); 1929 if (mSensorManager != null) { 1930 final Sensor hingeAngleSensor = mSensorManager 1931 .getDefaultSensor(Sensor.TYPE_HINGE_ANGLE); 1932 1933 if (hingeAngleSensor != null) { 1934 mHingeAngleSensorEventListener = new SensorEventListener() { 1935 @Override 1936 public void onSensorChanged(SensorEvent event) { 1937 onHingeAngleChanged(event.values[0]); 1938 } 1939 1940 @Override 1941 public void onAccuracyChanged(Sensor sensor, int accuracy) { 1942 } 1943 }; 1944 mSensorManager.registerListener(mHingeAngleSensorEventListener, 1945 hingeAngleSensor, SensorManager.SENSOR_DELAY_FASTEST, getHandler()); 1946 } 1947 } 1948 } 1949 onDisplayRemoved()1950 void onDisplayRemoved() { 1951 if (mSensorManager != null && mHingeAngleSensorEventListener != null) { 1952 mSensorManager.unregisterListener(mHingeAngleSensorEventListener); 1953 } 1954 } 1955 isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop)1956 boolean isDeviceInPosture(DeviceStateController.DeviceState state, boolean isTabletop) { 1957 if (state != mDeviceState) { 1958 return false; 1959 } 1960 if (mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED) { 1961 return isTabletop == mTabletopRotations.contains(mRotation); 1962 } 1963 return true; 1964 } 1965 getFoldState()1966 DeviceStateController.DeviceState getFoldState() { 1967 return mDeviceState; 1968 } 1969 isSeparatingHinge()1970 boolean isSeparatingHinge() { 1971 return mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED 1972 || (mDeviceState == DeviceStateController.DeviceState.OPEN 1973 && mIsDisplayAlwaysSeparatingHinge); 1974 } 1975 overrideFrozenRotation()1976 boolean overrideFrozenRotation() { 1977 return mAllowHalfFoldAutoRotationOverride 1978 && mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED; 1979 } 1980 shouldRevertOverriddenRotation()1981 boolean shouldRevertOverriddenRotation() { 1982 // When transitioning to open. 1983 return mAllowHalfFoldAutoRotationOverride 1984 && mDeviceState == DeviceStateController.DeviceState.OPEN 1985 && !mShouldIgnoreSensorRotation // Ignore if the hinge angle still moving 1986 && mInHalfFoldTransition 1987 && mDisplayContent.getRotationReversionController().isOverrideActive( 1988 REVERSION_TYPE_HALF_FOLD) 1989 && mUserRotationMode 1990 == WindowManagerPolicy.USER_ROTATION_LOCKED; // Ignore if we're unlocked. 1991 } 1992 revertOverriddenRotation()1993 int revertOverriddenRotation() { 1994 int savedRotation = mHalfFoldSavedRotation; 1995 mHalfFoldSavedRotation = -1; 1996 mDisplayContent.getRotationReversionController() 1997 .revertOverride(REVERSION_TYPE_HALF_FOLD); 1998 mInHalfFoldTransition = false; 1999 return savedRotation; 2000 } 2001 foldStateChanged(DeviceStateController.DeviceState newState)2002 void foldStateChanged(DeviceStateController.DeviceState newState) { 2003 ProtoLog.v(WM_DEBUG_ORIENTATION, 2004 "foldStateChanged: displayId %d, halfFoldStateChanged %s, " 2005 + "saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, " 2006 + "mLastOrientation: %d, mRotation: %d", 2007 mDisplayContent.getDisplayId(), newState.name(), mHalfFoldSavedRotation, 2008 mUserRotation, mLastSensorRotation, mLastOrientation, mRotation); 2009 if (mDeviceState == DeviceStateController.DeviceState.UNKNOWN) { 2010 mDeviceState = newState; 2011 return; 2012 } 2013 if (newState == DeviceStateController.DeviceState.HALF_FOLDED 2014 && mDeviceState != DeviceStateController.DeviceState.HALF_FOLDED) { 2015 // The device has transitioned to HALF_FOLDED state: save the current rotation and 2016 // update the device rotation. 2017 mDisplayContent.getRotationReversionController().beforeOverrideApplied( 2018 REVERSION_TYPE_HALF_FOLD); 2019 mHalfFoldSavedRotation = mRotation; 2020 mDeviceState = newState; 2021 // Now mFoldState is set to HALF_FOLDED, the overrideFrozenRotation function will 2022 // return true, so rotation is unlocked. 2023 mService.updateRotation(false /* alwaysSendConfiguration */, 2024 false /* forceRelayout */); 2025 } else { 2026 mInHalfFoldTransition = true; 2027 mDeviceState = newState; 2028 // Tell the device to update its orientation. 2029 mService.updateRotation(false /* alwaysSendConfiguration */, 2030 false /* forceRelayout */); 2031 } 2032 // Alert the activity of possible new bounds. 2033 UiThread.getHandler().removeCallbacks(mActivityBoundsUpdateCallback); 2034 UiThread.getHandler().postDelayed(mActivityBoundsUpdateCallback, 2035 FOLDING_RECOMPUTE_CONFIG_DELAY_MS); 2036 } 2037 shouldIgnoreSensorRotation()2038 boolean shouldIgnoreSensorRotation() { 2039 return mShouldIgnoreSensorRotation; 2040 } 2041 shouldDisableRotationSensor()2042 boolean shouldDisableRotationSensor() { 2043 return mShouldDisableRotationSensor; 2044 } 2045 updateSensorRotationBlockIfNeeded()2046 private void updateSensorRotationBlockIfNeeded() { 2047 final long currentTime = uptimeMillis(); 2048 final boolean newShouldIgnoreRotation = 2049 currentTime - mLastDisplaySwitchTime < mDisplaySwitchRotationBlockTimeMs 2050 || currentTime - mLastHingeAngleEventTime < mHingeAngleRotationBlockTimeMs; 2051 2052 if (newShouldIgnoreRotation != mShouldIgnoreSensorRotation) { 2053 mShouldIgnoreSensorRotation = newShouldIgnoreRotation; 2054 2055 // Resuming the autorotation 2056 if (!mShouldIgnoreSensorRotation) { 2057 if (mShouldDisableRotationSensor) { 2058 // Sensor was disabled, let's re-enable it 2059 mShouldDisableRotationSensor = false; 2060 updateOrientationListenerLw(); 2061 } else { 2062 // Sensor was not disabled, let's update the rotation in case if we received 2063 // some rotation sensor updates when autorotate was disabled 2064 updateRotationAndSendNewConfigIfChanged(); 2065 } 2066 } 2067 } 2068 } 2069 2070 void onPhysicalDisplayChanged() { 2071 if (!mPauseAutorotationDuringUnfolding) return; 2072 2073 mLastDisplaySwitchTime = uptimeMillis(); 2074 2075 final boolean isUnfolding = 2076 mDeviceState == DeviceStateController.DeviceState.OPEN 2077 || mDeviceState == DeviceStateController.DeviceState.HALF_FOLDED; 2078 2079 if (isUnfolding) { 2080 // Temporary disable rotation sensor updates when unfolding 2081 mShouldDisableRotationSensor = true; 2082 updateOrientationListenerLw(); 2083 } 2084 2085 updateSensorRotationBlockIfNeeded(); 2086 getHandler().postDelayed(() -> { 2087 synchronized (mLock) { 2088 updateSensorRotationBlockIfNeeded(); 2089 }; 2090 }, mDisplaySwitchRotationBlockTimeMs); 2091 } 2092 2093 void onHingeAngleChanged(float hingeAngle) { 2094 if (hingeAngle < mMaxHingeAngle) { 2095 mLastHingeAngleEventTime = uptimeMillis(); 2096 2097 updateSensorRotationBlockIfNeeded(); 2098 2099 getHandler().postDelayed(() -> { 2100 synchronized (mLock) { 2101 updateSensorRotationBlockIfNeeded(); 2102 }; 2103 }, mHingeAngleRotationBlockTimeMs); 2104 } 2105 } 2106 } 2107 2108 @VisibleForTesting 2109 Handler getHandler() { 2110 return mService.mH; 2111 } 2112 2113 private class OrientationListener extends WindowOrientationListener implements Runnable { 2114 transient boolean mEnabled; 2115 2116 OrientationListener(Context context, Handler handler, 2117 @Surface.Rotation int defaultRotation) { 2118 super(context, handler, defaultRotation); 2119 } 2120 2121 @Override 2122 public boolean isKeyguardShowingAndNotOccluded() { 2123 return mService.isKeyguardShowingAndNotOccluded(); 2124 } 2125 2126 @Override 2127 public boolean isRotationResolverEnabled() { 2128 return mAllowRotationResolver 2129 && mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE 2130 && mCameraRotationMode == CAMERA_ROTATION_ENABLED 2131 && !mService.mPowerManager.isPowerSaveMode(); 2132 } 2133 2134 2135 @Override 2136 public void onProposedRotationChanged(@Surface.Rotation int rotation) { 2137 ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation); 2138 // Send interaction power boost to improve redraw performance. 2139 mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0); 2140 dispatchProposedRotation(rotation); 2141 if (isRotationChoiceAllowed(rotation)) { 2142 mRotationChoiceShownToUserForConfirmation = rotation; 2143 final boolean isValid = isValidRotationChoice(rotation); 2144 sendProposedRotationChangeToStatusBarInternal(rotation, isValid); 2145 } else { 2146 mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED; 2147 mService.updateRotation(false /* alwaysSendConfiguration */, 2148 false /* forceRelayout */); 2149 } 2150 } 2151 2152 @Override 2153 public void enable() { 2154 mEnabled = true; 2155 getHandler().post(this); 2156 ProtoLog.v(WM_DEBUG_ORIENTATION, "Enabling listeners"); 2157 } 2158 2159 @Override 2160 public void disable() { 2161 mEnabled = false; 2162 getHandler().post(this); 2163 ProtoLog.v(WM_DEBUG_ORIENTATION, "Disabling listeners"); 2164 } 2165 2166 @Override 2167 public void run() { 2168 if (mEnabled) { 2169 super.enable(); 2170 } else { 2171 super.disable(); 2172 } 2173 } 2174 } 2175 2176 private class SettingsObserver extends ContentObserver { 2177 SettingsObserver(Handler handler) { 2178 super(handler); 2179 } 2180 2181 void observe() { 2182 final ContentResolver resolver = mContext.getContentResolver(); 2183 resolver.registerContentObserver(Settings.Secure.getUriFor( 2184 Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this, 2185 UserHandle.USER_ALL); 2186 resolver.registerContentObserver(Settings.System.getUriFor( 2187 Settings.System.ACCELEROMETER_ROTATION), false, this, 2188 UserHandle.USER_ALL); 2189 resolver.registerContentObserver(Settings.System.getUriFor( 2190 Settings.System.USER_ROTATION), false, this, 2191 UserHandle.USER_ALL); 2192 resolver.registerContentObserver( 2193 Settings.Secure.getUriFor(Settings.Secure.CAMERA_AUTOROTATE), false, this, 2194 UserHandle.USER_ALL); 2195 2196 updateSettings(); 2197 } 2198 2199 @Override 2200 public void onChange(boolean selfChange) { 2201 if (updateSettings()) { 2202 mService.updateRotation(false /* alwaysSendConfiguration */, 2203 false /* forceRelayout */); 2204 } 2205 } 2206 } 2207 2208 private static class RotationLockHistory { 2209 private static final int MAX_SIZE = 8; 2210 2211 private static class Record { 2212 @WindowManagerPolicy.UserRotationMode final int mUserRotationMode; 2213 @Surface.Rotation final int mUserRotation; 2214 final String mCaller; 2215 final long mTimestamp = System.currentTimeMillis(); 2216 2217 private Record(int userRotationMode, int userRotation, String caller) { 2218 mUserRotationMode = userRotationMode; 2219 mUserRotation = userRotation; 2220 mCaller = caller; 2221 } 2222 2223 void dump(String prefix, PrintWriter pw) { 2224 pw.println(prefix + TimeUtils.logTimeOfDay(mTimestamp) + ": " 2225 + "mode=" + WindowManagerPolicy.userRotationModeToString(mUserRotationMode) 2226 + ", rotation=" + Surface.rotationToString(mUserRotation) 2227 + ", caller=" + mCaller); 2228 } 2229 } 2230 2231 private final ArrayDeque<RotationLockHistory.Record> mRecords = new ArrayDeque<>(MAX_SIZE); 2232 2233 void addRecord(@WindowManagerPolicy.UserRotationMode int userRotationMode, 2234 @Surface.Rotation int userRotation, String caller) { 2235 if (mRecords.size() >= MAX_SIZE) { 2236 mRecords.removeFirst(); 2237 } 2238 mRecords.addLast(new Record(userRotationMode, userRotation, caller)); 2239 } 2240 } 2241 2242 private static class RotationHistory { 2243 private static final int MAX_SIZE = 8; 2244 private static final int NO_FOLD_CONTROLLER = -2; 2245 private static class Record { 2246 final @Surface.Rotation int mFromRotation; 2247 final @Surface.Rotation int mToRotation; 2248 final @Surface.Rotation int mUserRotation; 2249 final @WindowManagerPolicy.UserRotationMode int mUserRotationMode; 2250 final int mSensorRotation; 2251 final boolean mIgnoreOrientationRequest; 2252 final String mNonDefaultRequestingTaskDisplayArea; 2253 final String mLastOrientationSource; 2254 final @ActivityInfo.ScreenOrientation int mSourceOrientation; 2255 final long mTimestamp = System.currentTimeMillis(); 2256 final int mHalfFoldSavedRotation; 2257 final boolean mInHalfFoldTransition; 2258 final DeviceStateController.DeviceState mDeviceState; 2259 @Nullable final boolean[] mRotationReversionSlots; 2260 2261 @Nullable final String mDisplayRotationCompatPolicySummary; 2262 Record(DisplayRotation dr, int fromRotation, int toRotation)2263 Record(DisplayRotation dr, int fromRotation, int toRotation) { 2264 mFromRotation = fromRotation; 2265 mToRotation = toRotation; 2266 mUserRotation = dr.mUserRotation; 2267 mUserRotationMode = dr.mUserRotationMode; 2268 final OrientationListener listener = dr.mOrientationListener; 2269 mSensorRotation = (listener == null || !listener.mEnabled) 2270 ? -2 /* disabled */ : dr.mLastSensorRotation; 2271 final DisplayContent dc = dr.mDisplayContent; 2272 mIgnoreOrientationRequest = dc.getIgnoreOrientationRequest(); 2273 final TaskDisplayArea requestingTda = dc.getOrientationRequestingTaskDisplayArea(); 2274 mNonDefaultRequestingTaskDisplayArea = requestingTda == null 2275 ? "none" : requestingTda != dc.getDefaultTaskDisplayArea() 2276 ? requestingTda.toString() : null; 2277 final WindowContainer<?> source = dc.getLastOrientationSource(); 2278 if (source != null) { 2279 mLastOrientationSource = source.toString(); 2280 final WindowState w = source.asWindowState(); 2281 mSourceOrientation = w != null 2282 ? w.mAttrs.screenOrientation 2283 : source.getOverrideOrientation(); 2284 } else { 2285 mLastOrientationSource = null; 2286 mSourceOrientation = SCREEN_ORIENTATION_UNSET; 2287 } 2288 if (dr.mFoldController != null) { 2289 mHalfFoldSavedRotation = dr.mFoldController.mHalfFoldSavedRotation; 2290 mInHalfFoldTransition = dr.mFoldController.mInHalfFoldTransition; 2291 mDeviceState = dr.mFoldController.mDeviceState; 2292 } else { 2293 mHalfFoldSavedRotation = NO_FOLD_CONTROLLER; 2294 mInHalfFoldTransition = false; 2295 mDeviceState = DeviceStateController.DeviceState.UNKNOWN; 2296 } 2297 mDisplayRotationCompatPolicySummary = dc.mDisplayRotationCompatPolicy == null 2298 ? null 2299 : dc.mDisplayRotationCompatPolicy 2300 .getSummaryForDisplayRotationHistoryRecord(); 2301 mRotationReversionSlots = 2302 dr.mDisplayContent.getRotationReversionController().getSlotsCopy(); 2303 } 2304 dump(String prefix, PrintWriter pw)2305 void dump(String prefix, PrintWriter pw) { 2306 pw.println(prefix + TimeUtils.logTimeOfDay(mTimestamp) 2307 + " " + Surface.rotationToString(mFromRotation) 2308 + " to " + Surface.rotationToString(mToRotation)); 2309 pw.println(prefix + " source=" + mLastOrientationSource 2310 + " " + ActivityInfo.screenOrientationToString(mSourceOrientation)); 2311 pw.println(prefix + " mode=" 2312 + WindowManagerPolicy.userRotationModeToString(mUserRotationMode) 2313 + " user=" + Surface.rotationToString(mUserRotation) 2314 + " sensor=" + Surface.rotationToString(mSensorRotation)); 2315 if (mIgnoreOrientationRequest) pw.println(prefix + " ignoreRequest=true"); 2316 if (mNonDefaultRequestingTaskDisplayArea != null) { 2317 pw.println(prefix + " requestingTda=" + mNonDefaultRequestingTaskDisplayArea); 2318 } 2319 if (mHalfFoldSavedRotation != NO_FOLD_CONTROLLER) { 2320 pw.println(prefix + " halfFoldSavedRotation=" 2321 + mHalfFoldSavedRotation 2322 + " mInHalfFoldTransition=" + mInHalfFoldTransition 2323 + " mFoldState=" + mDeviceState); 2324 } 2325 if (mDisplayRotationCompatPolicySummary != null) { 2326 pw.println(prefix + mDisplayRotationCompatPolicySummary); 2327 } 2328 if (mRotationReversionSlots != null) { 2329 pw.println(prefix + " reversionSlots= NOSENSOR " 2330 + mRotationReversionSlots[REVERSION_TYPE_NOSENSOR] + ", CAMERA " 2331 + mRotationReversionSlots[REVERSION_TYPE_CAMERA_COMPAT] + " HALF_FOLD " 2332 + mRotationReversionSlots[REVERSION_TYPE_HALF_FOLD]); 2333 } 2334 } 2335 } 2336 2337 final ArrayDeque<Record> mRecords = new ArrayDeque<>(MAX_SIZE); 2338 addRecord(DisplayRotation dr, int toRotation)2339 void addRecord(DisplayRotation dr, int toRotation) { 2340 if (mRecords.size() >= MAX_SIZE) { 2341 mRecords.removeFirst(); 2342 } 2343 final int fromRotation = dr.mDisplayContent.getWindowConfiguration().getRotation(); 2344 mRecords.addLast(new Record(dr, fromRotation, toRotation)); 2345 } 2346 } 2347 } 2348