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