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