blob: c76d03cf27cb3fd28098e92a61f0a6b37d751f7f [file] [log] [blame]
Riddle Hsuad256a12018-07-18 16:11:30 +08001/*
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
17package com.android.server.wm;
18
Riddle Hsuccf09402019-08-13 00:33:06 +080019import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
20import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
21import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
22import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
23import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
24
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080025import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
Adrian Roosb125e0b2019-10-02 14:55:14 +020026import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
Riddle Hsuccf09402019-08-13 00:33:06 +080027import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080028import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
29import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Riddle Hsuccf09402019-08-13 00:33:06 +080030import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE;
31import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080032
Riddle Hsuccf09402019-08-13 00:33:06 +080033import android.annotation.AnimRes;
Garfield Tan7fbca052019-02-19 10:45:35 -080034import android.annotation.IntDef;
Garfield Tanff362222018-11-14 17:52:32 -080035import android.annotation.UserIdInt;
Rajeev Kumarb2ff8e82018-08-06 11:45:05 -070036import android.app.ActivityManager;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080037import android.content.ContentResolver;
Riddle Hsuad256a12018-07-18 16:11:30 +080038import android.content.Context;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080039import android.content.Intent;
Riddle Hsuad256a12018-07-18 16:11:30 +080040import android.content.pm.ActivityInfo;
Riddle Hsuccf09402019-08-13 00:33:06 +080041import android.content.pm.ActivityInfo.ScreenOrientation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080042import android.content.pm.PackageManager;
Riddle Hsuad256a12018-07-18 16:11:30 +080043import android.content.res.Resources;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080044import android.database.ContentObserver;
45import android.hardware.power.V1_0.PowerHint;
Garfield Tanff362222018-11-14 17:52:32 -080046import android.net.Uri;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080047import android.os.Handler;
Evan Rosky69cace42019-09-20 16:28:13 -070048import android.os.RemoteException;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080049import android.os.SystemProperties;
50import android.os.UserHandle;
51import android.provider.Settings;
52import android.util.Slog;
53import android.util.SparseArray;
Evan Rosky69cace42019-09-20 16:28:13 -070054import android.view.IDisplayWindowRotationCallback;
Riddle Hsuad256a12018-07-18 16:11:30 +080055import android.view.Surface;
Evan Rosky69cace42019-09-20 16:28:13 -070056import android.view.WindowContainerTransaction;
Riddle Hsuad256a12018-07-18 16:11:30 +080057
Riddle Hsuccf09402019-08-13 00:33:06 +080058import com.android.internal.R;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080059import com.android.internal.annotations.VisibleForTesting;
Evan Rosky69cace42019-09-20 16:28:13 -070060import com.android.internal.util.function.pooled.PooledLambda;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080061import com.android.server.LocalServices;
62import com.android.server.UiThread;
Riddle Hsuad256a12018-07-18 16:11:30 +080063import com.android.server.policy.WindowManagerPolicy;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080064import com.android.server.policy.WindowOrientationListener;
Adrian Roosb125e0b2019-10-02 14:55:14 +020065import com.android.server.protolog.common.ProtoLog;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080066import com.android.server.statusbar.StatusBarManagerInternal;
Riddle Hsuad256a12018-07-18 16:11:30 +080067
68import java.io.PrintWriter;
Garfield Tan7fbca052019-02-19 10:45:35 -080069import java.lang.annotation.Retention;
70import java.lang.annotation.RetentionPolicy;
Riddle Hsuad256a12018-07-18 16:11:30 +080071
72/**
73 * Defines the mapping between orientation and rotation of a display.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080074 * Non-public methods are assumed to run inside WM lock.
Riddle Hsuad256a12018-07-18 16:11:30 +080075 */
76public class DisplayRotation {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080077 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM;
Riddle Hsuad256a12018-07-18 16:11:30 +080078
Riddle Hsuccf09402019-08-13 00:33:06 +080079 private static class RotationAnimationPair {
80 @AnimRes
81 int mEnter;
82 @AnimRes
83 int mExit;
84 }
85
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080086 private final WindowManagerService mService;
Garfield Tan90c90052018-10-08 12:29:41 -070087 private final DisplayContent mDisplayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080088 private final DisplayPolicy mDisplayPolicy;
Garfield Tanff362222018-11-14 17:52:32 -080089 private final DisplayWindowSettings mDisplayWindowSettings;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080090 private final Context mContext;
91 private final Object mLock;
92
93 public final boolean isDefaultDisplay;
94 private final boolean mSupportAutoRotation;
95 private final int mLidOpenRotation;
96 private final int mCarDockRotation;
97 private final int mDeskDockRotation;
98 private final int mUndockedHdmiRotation;
Riddle Hsuccf09402019-08-13 00:33:06 +080099 private final RotationAnimationPair mTmpRotationAnim = new RotationAnimationPair();
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800100
101 private OrientationListener mOrientationListener;
102 private StatusBarManagerInternal mStatusBarManagerInternal;
103 private SettingsObserver mSettingsObserver;
104
Riddle Hsuccf09402019-08-13 00:33:06 +0800105 @ScreenOrientation
106 private int mCurrentAppOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
107
108 /**
109 * Last applied orientation of the display.
110 *
111 * @see #updateOrientationFromApp
112 */
113 @ScreenOrientation
114 private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
115
116 /**
117 * Current rotation of the display.
118 *
119 * @see #updateRotationUnchecked
120 */
121 @Surface.Rotation
122 private int mRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800123
124 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +0800125 int mLandscapeRotation; // default landscape
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800126 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +0800127 int mSeascapeRotation; // "other" landscape, 180 degrees from mLandscapeRotation
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800128 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +0800129 int mPortraitRotation; // default portrait
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800130 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +0800131 int mUpsideDownRotation; // "other" portrait
132
Riddle Hsuccf09402019-08-13 00:33:06 +0800133 private boolean mAllowSeamlessRotationDespiteNavBarMoving;
134
135 private int mDeferredRotationPauseCount;
136
137 /**
138 * A count of the windows which are 'seamlessly rotated', e.g. a surface at an old orientation
139 * is being transformed. We freeze orientation updates while any windows are seamlessly rotated,
140 * so we need to track when this hits zero so we can apply deferred orientation updates.
141 */
142 private int mSeamlessRotationCount;
143
144 /**
145 * True in the interval from starting seamless rotation until the last rotated window draws in
146 * the new orientation.
147 */
148 private boolean mRotatingSeamlessly;
149
150 /**
151 * Behavior of rotation suggestions.
152 *
153 * @see Settings.Secure#SHOW_ROTATION_SUGGESTIONS
154 */
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800155 private int mShowRotationSuggestions;
156
Riddle Hsuccf09402019-08-13 00:33:06 +0800157 private static final int ALLOW_ALL_ROTATIONS_UNDEFINED = -1;
158 private static final int ALLOW_ALL_ROTATIONS_DISABLED = 0;
159 private static final int ALLOW_ALL_ROTATIONS_ENABLED = 1;
160
161 @IntDef({ ALLOW_ALL_ROTATIONS_UNDEFINED, ALLOW_ALL_ROTATIONS_DISABLED,
162 ALLOW_ALL_ROTATIONS_ENABLED })
163 @Retention(RetentionPolicy.SOURCE)
164 private @interface AllowAllRotations {}
165
166 /**
167 * Whether to allow the screen to rotate to all rotations (including 180 degree) according to
168 * the sensor even when the current orientation is not
169 * {@link ActivityInfo#SCREEN_ORIENTATION_FULL_SENSOR} or
170 * {@link ActivityInfo#SCREEN_ORIENTATION_FULL_USER}.
171 */
172 @AllowAllRotations
173 private int mAllowAllRotations = ALLOW_ALL_ROTATIONS_UNDEFINED;
174
175 @WindowManagerPolicy.UserRotationMode
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800176 private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
Riddle Hsuccf09402019-08-13 00:33:06 +0800177
178 @Surface.Rotation
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800179 private int mUserRotation = Surface.ROTATION_0;
180
Garfield Tanff362222018-11-14 17:52:32 -0800181 /**
Garfield Tan7fbca052019-02-19 10:45:35 -0800182 * Flag that indicates this is a display that may run better when fixed to user rotation.
183 */
184 private boolean mDefaultFixedToUserRotation;
185
186 /**
187 * No overridden behavior is provided in terms of fixing rotation to user rotation. Use other
188 * flags to derive the default behavior, such as {@link WindowManagerService#mIsPc} and
189 * {@link WindowManagerService#mForceDesktopModeOnExternalDisplays}.
190 */
191 static final int FIXED_TO_USER_ROTATION_DEFAULT = 0;
192 /**
193 * Don't fix display rotation to {@link #mUserRotation} only. Always allow other factors to play
194 * a role in deciding display rotation.
195 */
196 static final int FIXED_TO_USER_ROTATION_DISABLED = 1;
197 /**
198 * Only use {@link #mUserRotation} as the display rotation.
199 */
200 static final int FIXED_TO_USER_ROTATION_ENABLED = 2;
201 @IntDef({ FIXED_TO_USER_ROTATION_DEFAULT, FIXED_TO_USER_ROTATION_DISABLED,
202 FIXED_TO_USER_ROTATION_ENABLED })
203 @Retention(RetentionPolicy.SOURCE)
204 @interface FixedToUserRotation {}
205
206 /**
Garfield Tanff362222018-11-14 17:52:32 -0800207 * A flag to indicate if the display rotation should be fixed to user specified rotation
208 * regardless of all other states (including app requrested orientation). {@code true} the
209 * display rotation should be fixed to user specified rotation, {@code false} otherwise.
210 */
Riddle Hsuccf09402019-08-13 00:33:06 +0800211 @FixedToUserRotation
Garfield Tan7fbca052019-02-19 10:45:35 -0800212 private int mFixedToUserRotation = FIXED_TO_USER_ROTATION_DEFAULT;
Garfield Tanff362222018-11-14 17:52:32 -0800213
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800214 private int mDemoHdmiRotation;
215 private int mDemoRotation;
216 private boolean mDemoHdmiRotationLock;
217 private boolean mDemoRotationLock;
218
Evan Rosky69cace42019-09-20 16:28:13 -0700219 private static final int REMOTE_ROTATION_TIMEOUT_MS = 800;
220
221 private boolean mIsWaitingForRemoteRotation = false;
222
223 private final Runnable mDisplayRotationHandlerTimeout =
224 new Runnable() {
225 @Override
226 public void run() {
227 continueRotation(mRotation, null /* transaction */);
228 }
229 };
230
231 private final IDisplayWindowRotationCallback mRemoteRotationCallback =
232 new IDisplayWindowRotationCallback.Stub() {
233 @Override
234 public void continueRotateDisplay(int targetRotation,
235 WindowContainerTransaction t) {
236 synchronized (mService.getWindowManagerLock()) {
237 mService.mH.sendMessage(PooledLambda.obtainMessage(
238 DisplayRotation::continueRotation, DisplayRotation.this,
239 targetRotation, t));
240 }
241 }
242 };
243
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800244 DisplayRotation(WindowManagerService service, DisplayContent displayContent) {
245 this(service, displayContent, displayContent.getDisplayPolicy(),
Garfield Tanff362222018-11-14 17:52:32 -0800246 service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
Riddle Hsuad256a12018-07-18 16:11:30 +0800247 }
248
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800249 @VisibleForTesting
250 DisplayRotation(WindowManagerService service, DisplayContent displayContent,
Garfield Tanff362222018-11-14 17:52:32 -0800251 DisplayPolicy displayPolicy, DisplayWindowSettings displayWindowSettings,
252 Context context, Object lock) {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800253 mService = service;
Garfield Tan90c90052018-10-08 12:29:41 -0700254 mDisplayContent = displayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800255 mDisplayPolicy = displayPolicy;
Garfield Tanff362222018-11-14 17:52:32 -0800256 mDisplayWindowSettings = displayWindowSettings;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800257 mContext = context;
258 mLock = lock;
259 isDefaultDisplay = displayContent.isDefaultDisplay;
Riddle Hsuad256a12018-07-18 16:11:30 +0800260
Riddle Hsuccf09402019-08-13 00:33:06 +0800261 mSupportAutoRotation =
262 mContext.getResources().getBoolean(R.bool.config_supportAutoRotation);
263 mLidOpenRotation = readRotation(R.integer.config_lidOpenRotation);
264 mCarDockRotation = readRotation(R.integer.config_carDockRotation);
265 mDeskDockRotation = readRotation(R.integer.config_deskDockRotation);
266 mUndockedHdmiRotation = readRotation(R.integer.config_undockedHdmiRotation);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800267
268 if (isDefaultDisplay) {
269 final Handler uiHandler = UiThread.getHandler();
270 mOrientationListener = new OrientationListener(mContext, uiHandler);
Riddle Hsuccf09402019-08-13 00:33:06 +0800271 mOrientationListener.setCurrentRotation(mRotation);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800272 mSettingsObserver = new SettingsObserver(uiHandler);
273 mSettingsObserver.observe();
274 }
275 }
276
277 private int readRotation(int resID) {
278 try {
279 final int rotation = mContext.getResources().getInteger(resID);
280 switch (rotation) {
281 case 0:
282 return Surface.ROTATION_0;
283 case 90:
284 return Surface.ROTATION_90;
285 case 180:
286 return Surface.ROTATION_180;
287 case 270:
288 return Surface.ROTATION_270;
289 }
290 } catch (Resources.NotFoundException e) {
291 // fall through
292 }
293 return -1;
294 }
295
Riddle Hsuccf09402019-08-13 00:33:06 +0800296 /**
297 * Updates the configuration which may have different values depending on current user, e.g.
298 * runtime resource overlay.
299 */
300 void updateUserDependentConfiguration(Resources currentUserRes) {
301 mAllowSeamlessRotationDespiteNavBarMoving =
302 currentUserRes.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving);
303 }
304
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800305 void configure(int width, int height, int shortSizeDp, int longSizeDp) {
Riddle Hsuad256a12018-07-18 16:11:30 +0800306 final Resources res = mContext.getResources();
307 if (width > height) {
308 mLandscapeRotation = Surface.ROTATION_0;
309 mSeascapeRotation = Surface.ROTATION_180;
Riddle Hsuccf09402019-08-13 00:33:06 +0800310 if (res.getBoolean(R.bool.config_reverseDefaultRotation)) {
Riddle Hsuad256a12018-07-18 16:11:30 +0800311 mPortraitRotation = Surface.ROTATION_90;
312 mUpsideDownRotation = Surface.ROTATION_270;
313 } else {
314 mPortraitRotation = Surface.ROTATION_270;
315 mUpsideDownRotation = Surface.ROTATION_90;
316 }
317 } else {
318 mPortraitRotation = Surface.ROTATION_0;
319 mUpsideDownRotation = Surface.ROTATION_180;
Riddle Hsuccf09402019-08-13 00:33:06 +0800320 if (res.getBoolean(R.bool.config_reverseDefaultRotation)) {
Riddle Hsuad256a12018-07-18 16:11:30 +0800321 mLandscapeRotation = Surface.ROTATION_270;
322 mSeascapeRotation = Surface.ROTATION_90;
323 } else {
324 mLandscapeRotation = Surface.ROTATION_90;
325 mSeascapeRotation = Surface.ROTATION_270;
326 }
327 }
328
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800329 // For demo purposes, allow the rotation of the HDMI display to be controlled.
330 // By default, HDMI locks rotation to landscape.
331 if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
332 mDemoHdmiRotation = mPortraitRotation;
333 } else {
334 mDemoHdmiRotation = mLandscapeRotation;
335 }
336 mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
337
338 // For demo purposes, allow the rotation of the remote display to be controlled.
339 // By default, remote display locks rotation to landscape.
340 if ("portrait".equals(SystemProperties.get("persist.demo.remoterotation"))) {
341 mDemoRotation = mPortraitRotation;
342 } else {
343 mDemoRotation = mLandscapeRotation;
344 }
345 mDemoRotationLock = SystemProperties.getBoolean("persist.demo.rotationlock", false);
346
Garfield Tan12b12f7a2019-02-22 16:33:27 -0800347 // It's physically impossible to rotate the car's screen.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800348 final boolean isCar = mContext.getPackageManager().hasSystemFeature(
349 PackageManager.FEATURE_AUTOMOTIVE);
Garfield Tan12b12f7a2019-02-22 16:33:27 -0800350 // It's also not likely to rotate a TV screen.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800351 final boolean isTv = mContext.getPackageManager().hasSystemFeature(
352 PackageManager.FEATURE_LEANBACK);
Garfield Tan7fbca052019-02-19 10:45:35 -0800353 final boolean forceDesktopMode =
354 mService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay;
355 mDefaultFixedToUserRotation =
Tiger Huang86e6d072019-05-02 20:23:47 +0800356 (isCar || isTv || mService.mIsPc || forceDesktopMode)
Garfield Tan7fbca052019-02-19 10:45:35 -0800357 // For debug purposes the next line turns this feature off with:
358 // $ adb shell setprop config.override_forced_orient true
359 // $ adb shell wm size reset
360 && !"true".equals(SystemProperties.get("config.override_forced_orient"));
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800361 }
362
Riddle Hsuccf09402019-08-13 00:33:06 +0800363 void applyCurrentRotation(@Surface.Rotation int rotation) {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800364 if (mOrientationListener != null) {
365 mOrientationListener.setCurrentRotation(rotation);
366 }
367 }
368
Riddle Hsuccf09402019-08-13 00:33:06 +0800369 @VisibleForTesting
370 void setRotation(@Surface.Rotation int rotation) {
371 mRotation = rotation;
372 }
373
374 @Surface.Rotation
375 int getRotation() {
376 return mRotation;
377 }
378
379 @ScreenOrientation
380 int getLastOrientation() {
381 return mLastOrientation;
382 }
383
384 boolean updateOrientation(@ScreenOrientation int newOrientation, boolean forceUpdate) {
385 if (newOrientation == mLastOrientation && !forceUpdate) {
386 return false;
387 }
388 mLastOrientation = newOrientation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800389 if (newOrientation != mCurrentAppOrientation) {
390 mCurrentAppOrientation = newOrientation;
391 if (isDefaultDisplay) {
392 updateOrientationListenerLw();
393 }
394 }
Riddle Hsuccf09402019-08-13 00:33:06 +0800395 return updateRotationUnchecked(forceUpdate);
396 }
397
398 /**
399 * Update rotation of the display and send configuration if the rotation is changed.
400 *
401 * @return {@code true} if the rotation has been changed and the new config is sent.
402 */
403 boolean updateRotationAndSendNewConfigIfChanged() {
404 final boolean changed = updateRotationUnchecked(false /* forceUpdate */);
405 if (changed) {
406 mDisplayContent.sendNewConfiguration();
407 }
408 return changed;
409 }
410
411 /**
412 * Update rotation with an option to force the update. This updates the container's perception
413 * of rotation and, depending on the top activities, will freeze the screen or start seamless
414 * rotation. The display itself gets rotated in {@link DisplayContent#applyRotationLocked}
415 * during {@link DisplayContent#sendNewConfiguration}.
416 *
417 * @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating
418 * orientation because we're waiting for some rotation to finish or display
419 * to unfreeze, which results in configuration of the previously visible
420 * activity being applied to a newly visible one. Forcing the rotation
421 * update allows to workaround this issue.
422 * @return {@code true} if the rotation has been changed. In this case YOU MUST CALL
423 * {@link DisplayContent#sendNewConfiguration} TO COMPLETE THE ROTATION AND UNFREEZE
424 * THE SCREEN.
425 */
426 boolean updateRotationUnchecked(boolean forceUpdate) {
427 final int displayId = mDisplayContent.getDisplayId();
428 if (!forceUpdate) {
429 if (mDeferredRotationPauseCount > 0) {
430 // Rotation updates have been paused temporarily. Defer the update until updates
431 // have been resumed.
Adrian Roosb125e0b2019-10-02 14:55:14 +0200432 ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, rotation is paused.");
Riddle Hsuccf09402019-08-13 00:33:06 +0800433 return false;
434 }
435
436 final ScreenRotationAnimation screenRotationAnimation =
Vadim Caenb3715832019-08-13 17:06:38 +0200437 mDisplayContent.getRotationAnimation();
Riddle Hsuccf09402019-08-13 00:33:06 +0800438 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
439 // Rotation updates cannot be performed while the previous rotation change animation
440 // is still in progress. Skip this update. We will try updating again after the
441 // animation is finished and the display is unfrozen.
Adrian Roosb125e0b2019-10-02 14:55:14 +0200442 ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, animation in progress.");
Riddle Hsuccf09402019-08-13 00:33:06 +0800443 return false;
444 }
445 if (mService.mDisplayFrozen) {
446 // Even if the screen rotation animation has finished (e.g. isAnimating returns
447 // false), there is still some time where we haven't yet unfrozen the display. We
448 // also need to abort rotation here.
Adrian Roosb125e0b2019-10-02 14:55:14 +0200449 ProtoLog.v(WM_DEBUG_ORIENTATION,
Riddle Hsuccf09402019-08-13 00:33:06 +0800450 "Deferring rotation, still finishing previous rotation");
451 return false;
452 }
453 }
454
455 if (!mService.mDisplayEnabled) {
456 // No point choosing a rotation if the display is not enabled.
Adrian Roosb125e0b2019-10-02 14:55:14 +0200457 ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, display is not enabled.");
Riddle Hsuccf09402019-08-13 00:33:06 +0800458 return false;
459 }
460
461 final int oldRotation = mRotation;
462 final int lastOrientation = mLastOrientation;
463 final int rotation = rotationForOrientation(lastOrientation, oldRotation);
Adrian Roosb125e0b2019-10-02 14:55:14 +0200464 ProtoLog.v(WM_DEBUG_ORIENTATION,
465 "Computed rotation=%d for display id=%d based on lastOrientation=%d and "
466 + "oldRotation=%d",
467 rotation, displayId, lastOrientation, oldRotation);
Riddle Hsuccf09402019-08-13 00:33:06 +0800468
Adrian Roosb125e0b2019-10-02 14:55:14 +0200469 ProtoLog.v(WM_DEBUG_ORIENTATION,
470 "Display id=%d selected orientation %d, got rotation %d", displayId,
471 lastOrientation, rotation);
Riddle Hsuccf09402019-08-13 00:33:06 +0800472
473 if (oldRotation == rotation) {
474 // No change.
475 return false;
476 }
477
Adrian Roosb125e0b2019-10-02 14:55:14 +0200478 ProtoLog.v(WM_DEBUG_ORIENTATION,
479 "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
480 displayId, rotation, oldRotation, lastOrientation);
Riddle Hsuccf09402019-08-13 00:33:06 +0800481
482 if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
483 mDisplayContent.mWaitingForConfig = true;
484 }
485
486 mRotation = rotation;
487
488 mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
489 mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
490 mDisplayContent, WINDOW_FREEZE_TIMEOUT_DURATION);
491
492 mDisplayContent.setLayoutNeeded();
493
494 if (shouldRotateSeamlessly(oldRotation, rotation, forceUpdate)) {
495 // The screen rotation animation uses a screenshot to freeze the screen while windows
496 // resize underneath. When we are rotating seamlessly, we allow the elements to
497 // transition to their rotated state independently and without a freeze required.
498 prepareSeamlessRotation();
499 } else {
500 prepareNormalRotationAnimation();
501 }
502
Evan Rosky69cace42019-09-20 16:28:13 -0700503 // The display is frozen now, give a remote handler (system ui) some time to reposition
504 // things.
505 startRemoteRotation(oldRotation, mRotation);
506
Riddle Hsuccf09402019-08-13 00:33:06 +0800507 return true;
508 }
509
Evan Rosky69cace42019-09-20 16:28:13 -0700510 /**
511 * A Remote rotation is when we are waiting for some registered (remote)
512 * {@link IDisplayWindowRotationController} to calculate and return some hierarchy operations
513 * to perform in sync with the rotation.
514 */
515 boolean isWaitingForRemoteRotation() {
516 return mIsWaitingForRemoteRotation;
517 }
518
519 private void startRemoteRotation(int fromRotation, int toRotation) {
520 if (mService.mDisplayRotationController == null) {
521 return;
522 }
523 mIsWaitingForRemoteRotation = true;
524 try {
525 mService.mDisplayRotationController.onRotateDisplay(mDisplayContent.getDisplayId(),
526 fromRotation, toRotation, mRemoteRotationCallback);
527 mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
528 mService.mH.postDelayed(mDisplayRotationHandlerTimeout, REMOTE_ROTATION_TIMEOUT_MS);
529 } catch (RemoteException e) {
530 mIsWaitingForRemoteRotation = false;
531 return;
532 }
533 }
534
535 private void continueRotation(int targetRotation, WindowContainerTransaction t) {
536 synchronized (mService.mGlobalLock) {
537 if (targetRotation != mRotation || !mIsWaitingForRemoteRotation) {
538 // Drop it, this is either coming from an outdated remote rotation; or, we've
539 // already moved on.
540 return;
541 }
542 mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
543 mIsWaitingForRemoteRotation = false;
Evan Rosky69cace42019-09-20 16:28:13 -0700544 mDisplayContent.sendNewConfiguration();
Evan Rosky70213702019-11-05 10:26:24 -0800545 mService.mAtmService.applyContainerTransaction(t);
Evan Rosky69cace42019-09-20 16:28:13 -0700546 }
547 }
548
Riddle Hsuccf09402019-08-13 00:33:06 +0800549 void prepareNormalRotationAnimation() {
550 final RotationAnimationPair anim = selectRotationAnimation();
551 mService.startFreezingDisplayLocked(anim.mExit, anim.mEnter, mDisplayContent);
552 }
553
554 private void prepareSeamlessRotation() {
555 // We are careful to reset this in case a window was removed before it finished
556 // seamless rotation.
557 mSeamlessRotationCount = 0;
558 mRotatingSeamlessly = true;
559 }
560
561 boolean isRotatingSeamlessly() {
562 return mRotatingSeamlessly;
563 }
564
565 @VisibleForTesting
566 boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) {
567 final WindowState w = mDisplayPolicy.getTopFullscreenOpaqueWindow();
568 if (w == null || w != mDisplayContent.mCurrentFocus) {
569 return false;
570 }
571 // We only enable seamless rotation if the top window has requested it and is in the
572 // fullscreen opaque state. Seamless rotation requires freezing various Surface states and
573 // won't work well with animations, so we disable it in the animation case for now.
574 if (w.getAttrs().rotationAnimation != ROTATION_ANIMATION_SEAMLESS || w.isAnimatingLw()) {
575 return false;
576 }
577
578 // For the upside down rotation we don't rotate seamlessly as the navigation bar moves
579 // position. Note most apps (using orientation:sensor or user as opposed to fullSensor)
580 // will not enter the reverse portrait orientation, so actually the orientation won't change
581 // at all.
582 if (oldRotation == mUpsideDownRotation || newRotation == mUpsideDownRotation) {
583 return false;
584 }
585
586 // If the navigation bar can't change sides, then it will jump when we change orientations
587 // and we don't rotate seamlessly - unless that is allowed, eg. with gesture navigation
588 // where the navbar is low-profile enough that this isn't very noticeable.
589 if (!mAllowSeamlessRotationDespiteNavBarMoving && !mDisplayPolicy.navigationBarCanMove()) {
590 return false;
591 }
592
593 // If the bounds of activity window is different from its parent, then reject to be seamless
594 // because the window position may change after rotation that will look like a sudden jump.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700595 if (w.mActivityRecord != null && !w.mActivityRecord.matchParentBounds()) {
Riddle Hsuccf09402019-08-13 00:33:06 +0800596 return false;
597 }
598
599 // In the presence of the PINNED stack or System Alert windows we unfortunately can not
600 // seamlessly rotate.
601 if (mDisplayContent.hasPinnedStack() || mDisplayContent.hasAlertWindowSurfaces()) {
602 return false;
603 }
604
605 // We can't rotate (seamlessly or not) while waiting for the last seamless rotation to
606 // complete (that is, waiting for windows to redraw). It's tempting to check
607 // mSeamlessRotationCount but that could be incorrect in the case of window-removal.
608 if (!forceUpdate && mDisplayContent.getWindow(win -> win.mSeamlesslyRotated) != null) {
609 return false;
610 }
611
612 return true;
613 }
614
615 void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) {
616 if (seamlesslyRotated == w.mSeamlesslyRotated || w.mForceSeamlesslyRotate) {
617 return;
618 }
619
620 w.mSeamlesslyRotated = seamlesslyRotated;
621 if (seamlesslyRotated) {
622 mSeamlessRotationCount++;
623 } else {
624 mSeamlessRotationCount--;
625 }
626 if (mSeamlessRotationCount == 0) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200627 ProtoLog.i(WM_DEBUG_ORIENTATION,
628 "Performing post-rotate rotation after seamless rotation");
Riddle Hsuccf09402019-08-13 00:33:06 +0800629 // Finish seamless rotation.
630 mRotatingSeamlessly = false;
631
632 updateRotationAndSendNewConfigIfChanged();
633 }
634 }
635
636 void onSeamlessRotationTimeout() {
637 final boolean[] isLayoutNeeded = { false };
638
639 mDisplayContent.forAllWindows(w -> {
640 if (!w.mSeamlesslyRotated) {
641 return;
642 }
643 isLayoutNeeded[0] = true;
644 w.setDisplayLayoutNeeded();
645 w.finishSeamlessRotation(true /* timeout */);
646 markForSeamlessRotation(w, false /* seamlesslyRotated */);
647 }, true /* traverseTopToBottom */);
648
649 if (isLayoutNeeded[0]) {
650 mService.mWindowPlacerLocked.performSurfacePlacement();
651 }
652 }
653
654 /**
655 * Returns the animation to run for a rotation transition based on the top fullscreen windows
656 * {@link android.view.WindowManager.LayoutParams#rotationAnimation} and whether it is currently
657 * fullscreen and frontmost.
658 */
659 private RotationAnimationPair selectRotationAnimation() {
660 // If the screen is off or non-interactive, force a jumpcut.
661 final boolean forceJumpcut = !mDisplayPolicy.isScreenOnFully()
662 || !mService.mPolicy.okToAnimate();
663 final WindowState topFullscreen = mDisplayPolicy.getTopFullscreenOpaqueWindow();
664 if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation topFullscreen="
665 + topFullscreen + " rotationAnimation="
666 + (topFullscreen == null ? 0 : topFullscreen.getAttrs().rotationAnimation)
667 + " forceJumpcut=" + forceJumpcut);
668 if (forceJumpcut) {
669 mTmpRotationAnim.mExit = R.anim.rotation_animation_jump_exit;
670 mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter;
671 return mTmpRotationAnim;
672 }
673 if (topFullscreen != null) {
674 int animationHint = topFullscreen.getRotationAnimationHint();
675 if (animationHint < 0 && mDisplayPolicy.isTopLayoutFullscreen()) {
676 animationHint = topFullscreen.getAttrs().rotationAnimation;
677 }
678 switch (animationHint) {
679 case ROTATION_ANIMATION_CROSSFADE:
680 case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
681 mTmpRotationAnim.mExit = R.anim.rotation_animation_xfade_exit;
682 mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter;
683 break;
684 case ROTATION_ANIMATION_JUMPCUT:
685 mTmpRotationAnim.mExit = R.anim.rotation_animation_jump_exit;
686 mTmpRotationAnim.mEnter = R.anim.rotation_animation_enter;
687 break;
688 case ROTATION_ANIMATION_ROTATE:
689 default:
690 mTmpRotationAnim.mExit = mTmpRotationAnim.mEnter = 0;
691 break;
692 }
693 } else {
694 mTmpRotationAnim.mExit = mTmpRotationAnim.mEnter = 0;
695 }
696 return mTmpRotationAnim;
697 }
698
699 /**
700 * Validate whether the current top fullscreen has specified the same
701 * {@link android.view.WindowManager.LayoutParams#rotationAnimation} value as that being passed
702 * in from the previous top fullscreen window.
703 *
704 * @param exitAnimId exiting resource id from the previous window.
705 * @param enterAnimId entering resource id from the previous window.
706 * @param forceDefault For rotation animations only, if true ignore the animation values and
707 * just return false.
708 * @return {@code true} if the previous values are still valid, false if they should be replaced
709 * with the default.
710 */
711 boolean validateRotationAnimation(int exitAnimId, int enterAnimId, boolean forceDefault) {
712 switch (exitAnimId) {
713 case R.anim.rotation_animation_xfade_exit:
714 case R.anim.rotation_animation_jump_exit:
715 // These are the only cases that matter.
716 if (forceDefault) {
717 return false;
718 }
719 final RotationAnimationPair anim = selectRotationAnimation();
720 return exitAnimId == anim.mExit && enterAnimId == anim.mEnter;
721 default:
722 return true;
723 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800724 }
725
Garfield Tanff362222018-11-14 17:52:32 -0800726 void restoreSettings(int userRotationMode, int userRotation,
Garfield Tan7fbca052019-02-19 10:45:35 -0800727 @FixedToUserRotation int fixedToUserRotation) {
Garfield Tanff362222018-11-14 17:52:32 -0800728 mFixedToUserRotation = fixedToUserRotation;
729
730 // We will retrieve user rotation and user rotation mode from settings for default display.
731 if (isDefaultDisplay) {
732 return;
733 }
Garfield Tan90c90052018-10-08 12:29:41 -0700734 if (userRotationMode != WindowManagerPolicy.USER_ROTATION_FREE
735 && userRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) {
736 Slog.w(TAG, "Trying to restore an invalid user rotation mode " + userRotationMode
737 + " for " + mDisplayContent);
738 userRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
739 }
740 if (userRotation < Surface.ROTATION_0 || userRotation > Surface.ROTATION_270) {
741 Slog.w(TAG, "Trying to restore an invalid user rotation " + userRotation
742 + " for " + mDisplayContent);
743 userRotation = Surface.ROTATION_0;
744 }
745 mUserRotationMode = userRotationMode;
746 mUserRotation = userRotation;
747 }
748
Garfield Tan7fbca052019-02-19 10:45:35 -0800749 void setFixedToUserRotation(@FixedToUserRotation int fixedToUserRotation) {
Garfield Tanff362222018-11-14 17:52:32 -0800750 if (mFixedToUserRotation == fixedToUserRotation) {
751 return;
752 }
753
754 mFixedToUserRotation = fixedToUserRotation;
Garfield Tan7fbca052019-02-19 10:45:35 -0800755 mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent, fixedToUserRotation);
Garfield Tanff362222018-11-14 17:52:32 -0800756 mService.updateRotation(true /* alwaysSendConfiguration */,
757 false /* forceRelayout */);
758 }
759
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700760 @VisibleForTesting
761 void setUserRotation(int userRotationMode, int userRotation) {
Garfield Tan90c90052018-10-08 12:29:41 -0700762 if (isDefaultDisplay) {
763 // We'll be notified via settings listener, so we don't need to update internal values.
764 final ContentResolver res = mContext.getContentResolver();
765 final int accelerometerRotation =
766 userRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED ? 0 : 1;
767 Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION,
768 accelerometerRotation, UserHandle.USER_CURRENT);
769 Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation,
770 UserHandle.USER_CURRENT);
771 return;
772 }
773
774 boolean changed = false;
775 if (mUserRotationMode != userRotationMode) {
776 mUserRotationMode = userRotationMode;
777 changed = true;
778 }
779 if (mUserRotation != userRotation) {
780 mUserRotation = userRotation;
781 changed = true;
782 }
Garfield Tanff362222018-11-14 17:52:32 -0800783 mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode,
Chilun8753ad32018-10-09 15:56:45 +0800784 userRotation);
Garfield Tan90c90052018-10-08 12:29:41 -0700785 if (changed) {
786 mService.updateRotation(true /* alwaysSendConfiguration */,
787 false /* forceRelayout */);
Garfield Tan90c90052018-10-08 12:29:41 -0700788 }
789 }
790
791 void freezeRotation(int rotation) {
Riddle Hsuccf09402019-08-13 00:33:06 +0800792 rotation = (rotation == -1) ? mRotation : rotation;
Garfield Tan90c90052018-10-08 12:29:41 -0700793 setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation);
794 }
795
796 void thawRotation() {
797 setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation);
798 }
799
800 boolean isRotationFrozen() {
801 if (!isDefaultDisplay) {
802 return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED;
803 }
804
805 return Settings.System.getIntForUser(mContext.getContentResolver(),
806 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0;
807 }
808
Garfield Tanff362222018-11-14 17:52:32 -0800809 boolean isFixedToUserRotation() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800810 switch (mFixedToUserRotation) {
811 case FIXED_TO_USER_ROTATION_DISABLED:
812 return false;
813 case FIXED_TO_USER_ROTATION_ENABLED:
814 return true;
815 default:
816 return mDefaultFixedToUserRotation;
817 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800818 }
819
Garfield Tan49dae102019-02-04 09:51:59 -0800820 /**
821 * Returns {@code true} if this display rotation takes app requested orientation into
822 * consideration; {@code false} otherwise. For the time being the only case where this is {@code
823 * false} is when {@link #isFixedToUserRotation()} is {@code true}.
824 */
825 boolean respectAppRequestedOrientation() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800826 return !isFixedToUserRotation();
Garfield Tan49dae102019-02-04 09:51:59 -0800827 }
828
Riddle Hsuad256a12018-07-18 16:11:30 +0800829 public int getLandscapeRotation() {
830 return mLandscapeRotation;
831 }
832
833 public int getSeascapeRotation() {
834 return mSeascapeRotation;
835 }
836
837 public int getPortraitRotation() {
838 return mPortraitRotation;
839 }
840
841 public int getUpsideDownRotation() {
842 return mUpsideDownRotation;
843 }
844
845 public int getCurrentAppOrientation() {
846 return mCurrentAppOrientation;
847 }
848
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800849 public DisplayPolicy getDisplayPolicy() {
850 return mDisplayPolicy;
Riddle Hsuad256a12018-07-18 16:11:30 +0800851 }
852
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800853 public WindowOrientationListener getOrientationListener() {
854 return mOrientationListener;
Riddle Hsuad256a12018-07-18 16:11:30 +0800855 }
856
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800857 public int getUserRotation() {
858 return mUserRotation;
859 }
860
861 public int getUserRotationMode() {
862 return mUserRotationMode;
863 }
864
865 public void updateOrientationListener() {
866 synchronized (mLock) {
867 updateOrientationListenerLw();
Riddle Hsuad256a12018-07-18 16:11:30 +0800868 }
869 }
870
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800871 /**
Riddle Hsuccf09402019-08-13 00:33:06 +0800872 * Temporarily pauses rotation changes until resumed.
873 * <p>
874 * This can be used to prevent rotation changes from occurring while the user is performing
875 * certain operations, such as drag and drop.
876 * <p>
877 * This call nests and must be matched by an equal number of calls to {@link #resume}.
878 */
879 void pause() {
880 mDeferredRotationPauseCount++;
881 }
882
883 /** Resumes normal rotation changes after being paused. */
884 void resume() {
885 if (mDeferredRotationPauseCount <= 0) {
886 return;
887 }
888
889 mDeferredRotationPauseCount--;
890 if (mDeferredRotationPauseCount == 0) {
891 updateRotationAndSendNewConfigIfChanged();
892 }
893 }
894
895 /**
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800896 * Various use cases for invoking this function:
897 * <li>Screen turning off, should always disable listeners if already enabled.</li>
898 * <li>Screen turned on and current app has sensor based orientation, enable listeners
899 * if not already enabled.</li>
900 * <li>Screen turned on and current app does not have sensor orientation, disable listeners
901 * if already enabled.</li>
902 * <li>Screen turning on and current app has sensor based orientation, enable listeners
903 * if needed.</li>
904 * <li>screen turning on and current app has nosensor based orientation, do nothing.</li>
905 */
906 private void updateOrientationListenerLw() {
907 if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {
908 // If sensor is turned off or nonexistent for some reason.
909 return;
910 }
911
912 final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();
913 final boolean awake = mDisplayPolicy.isAwake();
914 final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();
915 final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();
916
917 // Could have been invoked due to screen turning on or off or
918 // change of the currently visible window's orientation.
Adrian Roosb125e0b2019-10-02 14:55:14 +0200919 ProtoLog.v(WM_DEBUG_ORIENTATION,
920 "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, "
921 + "orientationSensorEnabled=%b, keyguardDrawComplete=%b, "
922 + "windowManagerDrawComplete=%b",
923 screenOnEarly, awake, mCurrentAppOrientation, mOrientationListener.mEnabled,
924 keyguardDrawComplete, windowManagerDrawComplete);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800925
926 boolean disable = true;
927 // Note: We postpone the rotating of the screen until the keyguard as well as the
928 // window manager have reported a draw complete or the keyguard is going away in dismiss
929 // mode.
930 if (screenOnEarly && awake && ((keyguardDrawComplete && windowManagerDrawComplete))) {
931 if (needSensorRunning()) {
932 disable = false;
933 // Enable listener if not already enabled.
934 if (!mOrientationListener.mEnabled) {
935 // Don't clear the current sensor orientation if the keyguard is going away in
936 // dismiss mode. This allows window manager to use the last sensor reading to
937 // determine the orientation vs. falling back to the last known orientation if
938 // the sensor reading was cleared which can cause it to relaunch the app that
939 // will show in the wrong orientation first before correcting leading to app
940 // launch delays.
941 mOrientationListener.enable(true /* clearCurrentRotation */);
942 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800943 }
944 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800945 // Check if sensors need to be disabled.
946 if (disable && mOrientationListener.mEnabled) {
947 mOrientationListener.disable();
948 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800949 }
950
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800951 /**
952 * We always let the sensor be switched on by default except when
953 * the user has explicitly disabled sensor based rotation or when the
954 * screen is switched off.
955 */
956 private boolean needSensorRunning() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800957 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800958 // We are sure we only respect user rotation settings, so we are sure we will not
959 // support sensor rotation.
960 return false;
961 }
962
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800963 if (mSupportAutoRotation) {
964 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
965 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
966 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
967 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
968 // If the application has explicitly requested to follow the
969 // orientation, then we need to turn the sensor on.
970 return true;
971 }
972 }
973
974 final int dockMode = mDisplayPolicy.getDockMode();
975 if ((mDisplayPolicy.isCarDockEnablesAccelerometer()
976 && dockMode == Intent.EXTRA_DOCK_STATE_CAR)
977 || (mDisplayPolicy.isDeskDockEnablesAccelerometer()
978 && (dockMode == Intent.EXTRA_DOCK_STATE_DESK
979 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
980 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) {
981 // Enable accelerometer if we are docked in a dock that enables accelerometer
982 // orientation management.
983 return true;
984 }
985
986 if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
987 // If the setting for using the sensor by default is enabled, then
988 // we will always leave it on. Note that the user could go to
989 // a window that forces an orientation that does not use the
990 // sensor and in theory we could turn it off... however, when next
991 // turning it on we won't have a good value for the current
992 // orientation for a little bit, which can cause orientation
993 // changes to lag, so we'd like to keep it always on. (It will
994 // still be turned off when the screen is off.)
995
996 // When locked we can provide rotation suggestions users can approve to change the
997 // current screen rotation. To do this the sensor needs to be running.
998 return mSupportAutoRotation &&
999 mShowRotationSuggestions == Settings.Secure.SHOW_ROTATION_SUGGESTIONS_ENABLED;
1000 }
1001 return mSupportAutoRotation;
1002 }
1003
1004 /**
Riddle Hsuccf09402019-08-13 00:33:06 +08001005 * If this is true we have updated our desired orientation, but not yet changed the real
1006 * orientation our applied our screen rotation animation. For example, because a previous
1007 * screen rotation was in progress.
1008 *
1009 * @return {@code true} if the there is an ongoing rotation change.
1010 */
1011 boolean needsUpdate() {
1012 final int oldRotation = mRotation;
1013 final int rotation = rotationForOrientation(mLastOrientation, oldRotation);
1014 return oldRotation != rotation;
1015 }
1016
1017 /**
1018 * Given an orientation constant, returns the appropriate surface rotation, taking into account
1019 * sensors, docking mode, rotation lock, and other factors.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001020 *
1021 * @param orientation An orientation constant, such as
Riddle Hsuccf09402019-08-13 00:33:06 +08001022 * {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001023 * @param lastRotation The most recently used rotation.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001024 * @return The surface rotation to use.
1025 */
Riddle Hsuccf09402019-08-13 00:33:06 +08001026 @VisibleForTesting
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001027 int rotationForOrientation(int orientation, int lastRotation) {
Adrian Roosb125e0b2019-10-02 14:55:14 +02001028 ProtoLog.v(WM_DEBUG_ORIENTATION, "rotationForOrientation(orient=%d, last=%d); user=%d %s",
1029 orientation, lastRotation, mUserRotation,
1030 mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
1031 ? "USER_ROTATION_LOCKED" : ""
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001032 );
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001033
Garfield Tan7fbca052019-02-19 10:45:35 -08001034 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -08001035 return mUserRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001036 }
1037
1038 int sensorRotation = mOrientationListener != null
1039 ? mOrientationListener.getProposedRotation() // may be -1
1040 : -1;
1041 if (sensorRotation < 0) {
1042 sensorRotation = lastRotation;
1043 }
1044
1045 final int lidState = mDisplayPolicy.getLidState();
1046 final int dockMode = mDisplayPolicy.getDockMode();
1047 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
1048 final boolean carDockEnablesAccelerometer =
1049 mDisplayPolicy.isCarDockEnablesAccelerometer();
1050 final boolean deskDockEnablesAccelerometer =
1051 mDisplayPolicy.isDeskDockEnablesAccelerometer();
1052
1053 final int preferredRotation;
1054 if (!isDefaultDisplay) {
1055 // For secondary displays we ignore things like displays sensors, docking mode and
Garfield Tan90c90052018-10-08 12:29:41 -07001056 // rotation lock, and always prefer user rotation.
1057 preferredRotation = mUserRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001058 } else if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
1059 // Ignore sensor when lid switch is open and rotation is forced.
1060 preferredRotation = mLidOpenRotation;
1061 } else if (dockMode == Intent.EXTRA_DOCK_STATE_CAR
1062 && (carDockEnablesAccelerometer || mCarDockRotation >= 0)) {
1063 // Ignore sensor when in car dock unless explicitly enabled.
1064 // This case can override the behavior of NOSENSOR, and can also
1065 // enable 180 degree rotation while docked.
1066 preferredRotation = carDockEnablesAccelerometer ? sensorRotation : mCarDockRotation;
1067 } else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
1068 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
1069 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
1070 && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
1071 // Ignore sensor when in desk dock unless explicitly enabled.
1072 // This case can override the behavior of NOSENSOR, and can also
1073 // enable 180 degree rotation while docked.
1074 preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation;
1075 } else if (hdmiPlugged && mDemoHdmiRotationLock) {
1076 // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
1077 // Note that the dock orientation overrides the HDMI orientation.
1078 preferredRotation = mDemoHdmiRotation;
1079 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
1080 && mUndockedHdmiRotation >= 0) {
1081 // Ignore sensor when plugged into HDMI and an undocked orientation has
1082 // been specified in the configuration (only for legacy devices without
1083 // full multi-display support).
1084 // Note that the dock orientation overrides the HDMI orientation.
1085 preferredRotation = mUndockedHdmiRotation;
1086 } else if (mDemoRotationLock) {
1087 // Ignore sensor when demo rotation lock is enabled.
1088 // Note that the dock orientation and HDMI rotation lock override this.
1089 preferredRotation = mDemoRotation;
1090 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
1091 // While in VR, apps always prefer a portrait rotation. This does not change
1092 // any apps that explicitly set landscape, but does cause sensors be ignored,
1093 // and ignored any orientation lock that the user has set (this conditional
1094 // should remain above the ORIENTATION_LOCKED conditional below).
1095 preferredRotation = mPortraitRotation;
1096 } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
1097 // Application just wants to remain locked in the last rotation.
1098 preferredRotation = lastRotation;
1099 } else if (!mSupportAutoRotation) {
1100 // If we don't support auto-rotation then bail out here and ignore
1101 // the sensor and any rotation lock settings.
1102 preferredRotation = -1;
1103 } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
1104 && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
1105 || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
1106 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
1107 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
1108 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))
1109 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
1110 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
1111 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
1112 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
1113 // Otherwise, use sensor only if requested by the application or enabled
1114 // by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR.
Riddle Hsuccf09402019-08-13 00:33:06 +08001115 if (mAllowAllRotations == ALLOW_ALL_ROTATIONS_UNDEFINED) {
1116 // Can't read this during init() because the context doesn't have display metrics at
1117 // that time so we cannot determine tablet vs. phone then.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001118 mAllowAllRotations = mContext.getResources().getBoolean(
Riddle Hsuccf09402019-08-13 00:33:06 +08001119 R.bool.config_allowAllRotations)
1120 ? ALLOW_ALL_ROTATIONS_ENABLED
1121 : ALLOW_ALL_ROTATIONS_DISABLED;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001122 }
1123 if (sensorRotation != Surface.ROTATION_180
Riddle Hsuccf09402019-08-13 00:33:06 +08001124 || mAllowAllRotations == ALLOW_ALL_ROTATIONS_ENABLED
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001125 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
1126 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
1127 preferredRotation = sensorRotation;
1128 } else {
1129 preferredRotation = lastRotation;
1130 }
1131 } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
Tetsutoki Shiozawa3e595fe2019-05-07 18:27:25 +09001132 && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
1133 && orientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
1134 && orientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
1135 && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
1136 && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {
1137 // Apply rotation lock. Does not apply to NOSENSOR or specific rotations.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001138 // The idea is that the user rotation expresses a weak preference for the direction
1139 // of gravity and as NOSENSOR is never affected by gravity, then neither should
1140 // NOSENSOR be affected by rotation lock (although it will be affected by docks).
Tetsutoki Shiozawa3e595fe2019-05-07 18:27:25 +09001141 // Also avoid setting user rotation when app has preference over one particular rotation
1142 // to avoid leaving the rotation to the reverse of it which has the compatible
1143 // orientation, but isn't what app wants, when the user rotation is the reverse of the
1144 // preferred rotation.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001145 preferredRotation = mUserRotation;
1146 } else {
1147 // No overriding preference.
1148 // We will do exactly what the application asked us to do.
1149 preferredRotation = -1;
1150 }
1151
Riddle Hsuad256a12018-07-18 16:11:30 +08001152 switch (orientation) {
1153 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
1154 // Return portrait unless overridden.
1155 if (isAnyPortrait(preferredRotation)) {
1156 return preferredRotation;
1157 }
1158 return mPortraitRotation;
1159
1160 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
1161 // Return landscape unless overridden.
1162 if (isLandscapeOrSeascape(preferredRotation)) {
1163 return preferredRotation;
1164 }
1165 return mLandscapeRotation;
1166
1167 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
1168 // Return reverse portrait unless overridden.
1169 if (isAnyPortrait(preferredRotation)) {
1170 return preferredRotation;
1171 }
1172 return mUpsideDownRotation;
1173
1174 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
1175 // Return seascape unless overridden.
1176 if (isLandscapeOrSeascape(preferredRotation)) {
1177 return preferredRotation;
1178 }
1179 return mSeascapeRotation;
1180
1181 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
1182 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
1183 // Return either landscape rotation.
1184 if (isLandscapeOrSeascape(preferredRotation)) {
1185 return preferredRotation;
1186 }
1187 if (isLandscapeOrSeascape(lastRotation)) {
1188 return lastRotation;
1189 }
1190 return mLandscapeRotation;
1191
1192 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
1193 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
1194 // Return either portrait rotation.
1195 if (isAnyPortrait(preferredRotation)) {
1196 return preferredRotation;
1197 }
1198 if (isAnyPortrait(lastRotation)) {
1199 return lastRotation;
1200 }
1201 return mPortraitRotation;
1202
1203 default:
1204 // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
1205 // just return the preferred orientation we already calculated.
1206 if (preferredRotation >= 0) {
1207 return preferredRotation;
1208 }
1209 return Surface.ROTATION_0;
1210 }
1211 }
1212
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001213 private boolean isLandscapeOrSeascape(int rotation) {
1214 return rotation == mLandscapeRotation || rotation == mSeascapeRotation;
1215 }
1216
1217 private boolean isAnyPortrait(int rotation) {
1218 return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
1219 }
1220
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001221 private boolean isValidRotationChoice(final int preferredRotation) {
Riddle Hsuad256a12018-07-18 16:11:30 +08001222 // Determine if the given app orientation is compatible with the provided rotation choice.
1223 switch (mCurrentAppOrientation) {
1224 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
1225 // Works with any of the 4 rotations.
1226 return preferredRotation >= 0;
1227
1228 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
1229 // It's possible for the user pref to be set at 180 because of FULL_USER. This would
1230 // make switching to USER_PORTRAIT appear at 180. Provide choice to back to portrait
1231 // but never to go to 180.
1232 return preferredRotation == mPortraitRotation;
1233
1234 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
1235 // Works landscape or seascape.
1236 return isLandscapeOrSeascape(preferredRotation);
1237
1238 case ActivityInfo.SCREEN_ORIENTATION_USER:
1239 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
1240 // Works with any rotation except upside down.
1241 return (preferredRotation >= 0) && (preferredRotation != mUpsideDownRotation);
1242 }
1243
1244 return false;
1245 }
1246
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001247 private boolean isRotationChoicePossible(int orientation) {
1248 // Rotation choice is only shown when the user is in locked mode.
1249 if (mUserRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) return false;
1250
1251 // We should only enable rotation choice if the rotation isn't forced by the lid, dock,
1252 // demo, hdmi, vr, etc mode.
1253
1254 // Determine if the rotation is currently forced.
Garfield Tan7fbca052019-02-19 10:45:35 -08001255 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -08001256 return false; // Rotation is forced to user settings.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001257 }
1258
1259 final int lidState = mDisplayPolicy.getLidState();
1260 if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
1261 return false; // Rotation is forced mLidOpenRotation.
1262 }
1263
1264 final int dockMode = mDisplayPolicy.getDockMode();
1265 final boolean carDockEnablesAccelerometer = false;
1266 if (dockMode == Intent.EXTRA_DOCK_STATE_CAR && !carDockEnablesAccelerometer) {
1267 return false; // Rotation forced to mCarDockRotation.
1268 }
1269
1270 final boolean deskDockEnablesAccelerometer =
1271 mDisplayPolicy.isDeskDockEnablesAccelerometer();
1272 if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
1273 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
1274 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
1275 && !deskDockEnablesAccelerometer) {
1276 return false; // Rotation forced to mDeskDockRotation.
1277 }
1278
1279 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
1280 if (hdmiPlugged && mDemoHdmiRotationLock) {
1281 return false; // Rotation forced to mDemoHdmiRotation.
1282
1283 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
1284 && mUndockedHdmiRotation >= 0) {
1285 return false; // Rotation forced to mUndockedHdmiRotation.
1286
1287 } else if (mDemoRotationLock) {
1288 return false; // Rotation forced to mDemoRotation.
1289
1290 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
1291 return false; // Rotation forced to mPortraitRotation.
1292
1293 } else if (!mSupportAutoRotation) {
1294 return false;
1295 }
1296
1297 // Ensure that some rotation choice is possible for the given orientation.
1298 switch (orientation) {
1299 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
1300 case ActivityInfo.SCREEN_ORIENTATION_USER:
1301 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
1302 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
1303 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
1304 // NOSENSOR description is ambiguous, in reality WM ignores user choice.
1305 return true;
1306 }
1307
1308 // Rotation is forced, should be controlled by system.
1309 return false;
Riddle Hsuad256a12018-07-18 16:11:30 +08001310 }
1311
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001312 /** Notify the StatusBar that system rotation suggestion has changed. */
1313 private void sendProposedRotationChangeToStatusBarInternal(int rotation, boolean isValid) {
1314 if (mStatusBarManagerInternal == null) {
1315 mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class);
1316 }
1317 if (mStatusBarManagerInternal != null) {
1318 mStatusBarManagerInternal.onProposedRotationChanged(rotation, isValid);
1319 }
1320 }
1321
1322 private static String allowAllRotationsToString(int allowAll) {
1323 switch (allowAll) {
1324 case -1:
1325 return "unknown";
1326 case 0:
1327 return "false";
1328 case 1:
1329 return "true";
1330 default:
1331 return Integer.toString(allowAll);
1332 }
1333 }
1334
1335 public void onUserSwitch() {
1336 if (mSettingsObserver != null) {
1337 mSettingsObserver.onChange(false);
1338 }
1339 }
1340
1341 /** Return whether the rotation settings has changed. */
1342 private boolean updateSettings() {
1343 final ContentResolver resolver = mContext.getContentResolver();
1344 boolean shouldUpdateRotation = false;
1345
1346 synchronized (mLock) {
1347 boolean shouldUpdateOrientationListener = false;
1348
1349 // Configure rotation suggestions.
Rajeev Kumarb2ff8e82018-08-06 11:45:05 -07001350 final int showRotationSuggestions =
1351 ActivityManager.isLowRamDeviceStatic()
1352 ? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED
1353 : Settings.Secure.getIntForUser(resolver,
1354 Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
1355 Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
1356 UserHandle.USER_CURRENT);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001357 if (mShowRotationSuggestions != showRotationSuggestions) {
1358 mShowRotationSuggestions = showRotationSuggestions;
1359 shouldUpdateOrientationListener = true;
1360 }
1361
1362 // Configure rotation lock.
1363 final int userRotation = Settings.System.getIntForUser(resolver,
1364 Settings.System.USER_ROTATION, Surface.ROTATION_0,
1365 UserHandle.USER_CURRENT);
1366 if (mUserRotation != userRotation) {
1367 mUserRotation = userRotation;
1368 shouldUpdateRotation = true;
1369 }
1370
1371 final int userRotationMode = Settings.System.getIntForUser(resolver,
1372 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0
1373 ? WindowManagerPolicy.USER_ROTATION_FREE
1374 : WindowManagerPolicy.USER_ROTATION_LOCKED;
1375 if (mUserRotationMode != userRotationMode) {
1376 mUserRotationMode = userRotationMode;
1377 shouldUpdateOrientationListener = true;
1378 shouldUpdateRotation = true;
1379 }
1380
1381 if (shouldUpdateOrientationListener) {
1382 updateOrientationListenerLw(); // Enable or disable the orientation listener.
1383 }
1384 }
1385
1386 return shouldUpdateRotation;
Riddle Hsuad256a12018-07-18 16:11:30 +08001387 }
1388
1389 void dump(String prefix, PrintWriter pw) {
1390 pw.println(prefix + "DisplayRotation");
1391 pw.println(prefix + " mCurrentAppOrientation="
1392 + ActivityInfo.screenOrientationToString(mCurrentAppOrientation));
Riddle Hsuccf09402019-08-13 00:33:06 +08001393 pw.println(prefix + " mLastOrientation=" + mLastOrientation);
1394 pw.print(prefix + " mRotation=" + mRotation);
1395 pw.println(" mDeferredRotationPauseCount=" + mDeferredRotationPauseCount);
1396
Riddle Hsuad256a12018-07-18 16:11:30 +08001397 pw.print(prefix + " mLandscapeRotation=" + Surface.rotationToString(mLandscapeRotation));
1398 pw.println(" mSeascapeRotation=" + Surface.rotationToString(mSeascapeRotation));
1399 pw.print(prefix + " mPortraitRotation=" + Surface.rotationToString(mPortraitRotation));
1400 pw.println(" mUpsideDownRotation=" + Surface.rotationToString(mUpsideDownRotation));
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001401
Tiger Huang7c610aa2018-10-27 00:01:01 +08001402 pw.println(prefix + " mSupportAutoRotation=" + mSupportAutoRotation);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001403 if (mOrientationListener != null) {
Tiger Huang7c610aa2018-10-27 00:01:01 +08001404 mOrientationListener.dump(pw, prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001405 }
1406 pw.println();
1407
1408 pw.print(prefix + " mCarDockRotation=" + Surface.rotationToString(mCarDockRotation));
1409 pw.println(" mDeskDockRotation=" + Surface.rotationToString(mDeskDockRotation));
1410 pw.print(prefix + " mUserRotationMode="
1411 + WindowManagerPolicy.userRotationModeToString(mUserRotationMode));
1412 pw.print(" mUserRotation=" + Surface.rotationToString(mUserRotation));
1413 pw.println(" mAllowAllRotations=" + allowAllRotationsToString(mAllowAllRotations));
1414
1415 pw.print(prefix + " mDemoHdmiRotation=" + Surface.rotationToString(mDemoHdmiRotation));
1416 pw.print(" mDemoHdmiRotationLock=" + mDemoHdmiRotationLock);
1417 pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation));
1418 pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation));
Garfield Tan7fbca052019-02-19 10:45:35 -08001419 pw.println(prefix + " mFixedToUserRotation=" + isFixedToUserRotation());
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001420 }
1421
1422 private class OrientationListener extends WindowOrientationListener {
1423 final SparseArray<Runnable> mRunnableCache = new SparseArray<>(5);
1424 boolean mEnabled;
1425
1426 OrientationListener(Context context, Handler handler) {
1427 super(context, handler);
1428 }
1429
1430 private class UpdateRunnable implements Runnable {
1431 final int mRotation;
1432
1433 UpdateRunnable(int rotation) {
1434 mRotation = rotation;
1435 }
1436
1437 @Override
1438 public void run() {
1439 // Send interaction hint to improve redraw performance.
1440 mService.mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
1441 if (isRotationChoicePossible(mCurrentAppOrientation)) {
1442 final boolean isValid = isValidRotationChoice(mRotation);
1443 sendProposedRotationChangeToStatusBarInternal(mRotation, isValid);
1444 } else {
1445 mService.updateRotation(false /* alwaysSendConfiguration */,
1446 false /* forceRelayout */);
1447 }
1448 }
1449 }
1450
1451 @Override
1452 public void onProposedRotationChanged(int rotation) {
Adrian Roosb125e0b2019-10-02 14:55:14 +02001453 ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001454 Runnable r = mRunnableCache.get(rotation, null);
1455 if (r == null) {
1456 r = new UpdateRunnable(rotation);
1457 mRunnableCache.put(rotation, r);
1458 }
1459 getHandler().post(r);
1460 }
1461
1462 @Override
1463 public void enable(boolean clearCurrentRotation) {
1464 super.enable(clearCurrentRotation);
1465 mEnabled = true;
Adrian Roosb125e0b2019-10-02 14:55:14 +02001466 ProtoLog.v(WM_DEBUG_ORIENTATION, "Enabling listeners");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001467 }
1468
1469 @Override
1470 public void disable() {
1471 super.disable();
1472 mEnabled = false;
Adrian Roosb125e0b2019-10-02 14:55:14 +02001473 ProtoLog.v(WM_DEBUG_ORIENTATION, "Disabling listeners");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +08001474 }
1475 }
1476
1477 private class SettingsObserver extends ContentObserver {
1478 SettingsObserver(Handler handler) {
1479 super(handler);
1480 }
1481
1482 void observe() {
1483 final ContentResolver resolver = mContext.getContentResolver();
1484 resolver.registerContentObserver(Settings.Secure.getUriFor(
1485 Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,
1486 UserHandle.USER_ALL);
1487 resolver.registerContentObserver(Settings.System.getUriFor(
1488 Settings.System.ACCELEROMETER_ROTATION), false, this,
1489 UserHandle.USER_ALL);
1490 resolver.registerContentObserver(Settings.System.getUriFor(
1491 Settings.System.USER_ROTATION), false, this,
1492 UserHandle.USER_ALL);
1493 updateSettings();
1494 }
1495
1496 @Override
1497 public void onChange(boolean selfChange) {
1498 if (updateSettings()) {
1499 mService.updateRotation(true /* alwaysSendConfiguration */,
1500 false /* forceRelayout */);
1501 }
1502 }
Riddle Hsuad256a12018-07-18 16:11:30 +08001503 }
Garfield Tanff362222018-11-14 17:52:32 -08001504
1505 @VisibleForTesting
1506 interface ContentObserverRegister {
1507 void registerContentObserver(Uri uri, boolean notifyForDescendants,
1508 ContentObserver observer, @UserIdInt int userHandle);
1509 }
Riddle Hsuad256a12018-07-18 16:11:30 +08001510}