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