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