blob: 34a480291863b60ba895184814d841341d4b3649 [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 Hsu5ce4bb32018-07-18 16:11:30 +080019import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
20import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
21import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
22import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
23
Garfield Tan7fbca052019-02-19 10:45:35 -080024import android.annotation.IntDef;
Garfield Tanff362222018-11-14 17:52:32 -080025import android.annotation.UserIdInt;
Rajeev Kumarb2ff8e82018-08-06 11:45:05 -070026import android.app.ActivityManager;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080027import android.content.ContentResolver;
Riddle Hsuad256a12018-07-18 16:11:30 +080028import android.content.Context;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080029import android.content.Intent;
Riddle Hsuad256a12018-07-18 16:11:30 +080030import android.content.pm.ActivityInfo;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080031import android.content.pm.PackageManager;
Riddle Hsuad256a12018-07-18 16:11:30 +080032import android.content.res.Resources;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080033import android.database.ContentObserver;
34import android.hardware.power.V1_0.PowerHint;
Garfield Tanff362222018-11-14 17:52:32 -080035import android.net.Uri;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080036import android.os.Handler;
37import android.os.SystemProperties;
38import android.os.UserHandle;
39import android.provider.Settings;
40import android.util.Slog;
41import android.util.SparseArray;
Tiger Huang3d2b8982019-01-29 22:56:48 +080042import android.view.DisplayCutout;
Riddle Hsuad256a12018-07-18 16:11:30 +080043import android.view.Surface;
44
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080045import com.android.internal.annotations.VisibleForTesting;
46import com.android.server.LocalServices;
47import com.android.server.UiThread;
Riddle Hsuad256a12018-07-18 16:11:30 +080048import com.android.server.policy.WindowManagerPolicy;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080049import com.android.server.policy.WindowOrientationListener;
50import com.android.server.statusbar.StatusBarManagerInternal;
Riddle Hsuad256a12018-07-18 16:11:30 +080051
52import java.io.PrintWriter;
Garfield Tan7fbca052019-02-19 10:45:35 -080053import java.lang.annotation.Retention;
54import java.lang.annotation.RetentionPolicy;
Riddle Hsuad256a12018-07-18 16:11:30 +080055
56/**
57 * Defines the mapping between orientation and rotation of a display.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080058 * Non-public methods are assumed to run inside WM lock.
Riddle Hsuad256a12018-07-18 16:11:30 +080059 */
60public class DisplayRotation {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080061 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM;
Riddle Hsuad256a12018-07-18 16:11:30 +080062
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080063 private final WindowManagerService mService;
Garfield Tan90c90052018-10-08 12:29:41 -070064 private final DisplayContent mDisplayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080065 private final DisplayPolicy mDisplayPolicy;
Garfield Tanff362222018-11-14 17:52:32 -080066 private final DisplayWindowSettings mDisplayWindowSettings;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080067 private final Context mContext;
68 private final Object mLock;
69
70 public final boolean isDefaultDisplay;
71 private final boolean mSupportAutoRotation;
72 private final int mLidOpenRotation;
73 private final int mCarDockRotation;
74 private final int mDeskDockRotation;
75 private final int mUndockedHdmiRotation;
76
Tiger Huang3d2b8982019-01-29 22:56:48 +080077 private final float mCloseToSquareMaxAspectRatio;
78
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080079 private OrientationListener mOrientationListener;
80 private StatusBarManagerInternal mStatusBarManagerInternal;
81 private SettingsObserver mSettingsObserver;
82
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080083 private int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
84
85 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +080086 int mLandscapeRotation; // default landscape
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080087 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +080088 int mSeascapeRotation; // "other" landscape, 180 degrees from mLandscapeRotation
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080089 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +080090 int mPortraitRotation; // default portrait
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080091 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +080092 int mUpsideDownRotation; // "other" portrait
93
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080094 // Behavior of rotation suggestions. (See Settings.Secure.SHOW_ROTATION_SUGGESTION)
95 private int mShowRotationSuggestions;
96
97 private int mAllowAllRotations = -1;
98 private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
99 private int mUserRotation = Surface.ROTATION_0;
100
Garfield Tanff362222018-11-14 17:52:32 -0800101 /**
Garfield Tan7fbca052019-02-19 10:45:35 -0800102 * Flag that indicates this is a display that may run better when fixed to user rotation.
103 */
104 private boolean mDefaultFixedToUserRotation;
105
106 /**
107 * No overridden behavior is provided in terms of fixing rotation to user rotation. Use other
108 * flags to derive the default behavior, such as {@link WindowManagerService#mIsPc} and
109 * {@link WindowManagerService#mForceDesktopModeOnExternalDisplays}.
110 */
111 static final int FIXED_TO_USER_ROTATION_DEFAULT = 0;
112 /**
113 * Don't fix display rotation to {@link #mUserRotation} only. Always allow other factors to play
114 * a role in deciding display rotation.
115 */
116 static final int FIXED_TO_USER_ROTATION_DISABLED = 1;
117 /**
118 * Only use {@link #mUserRotation} as the display rotation.
119 */
120 static final int FIXED_TO_USER_ROTATION_ENABLED = 2;
121 @IntDef({ FIXED_TO_USER_ROTATION_DEFAULT, FIXED_TO_USER_ROTATION_DISABLED,
122 FIXED_TO_USER_ROTATION_ENABLED })
123 @Retention(RetentionPolicy.SOURCE)
124 @interface FixedToUserRotation {}
125
126 /**
Garfield Tanff362222018-11-14 17:52:32 -0800127 * A flag to indicate if the display rotation should be fixed to user specified rotation
128 * regardless of all other states (including app requrested orientation). {@code true} the
129 * display rotation should be fixed to user specified rotation, {@code false} otherwise.
130 */
Garfield Tan7fbca052019-02-19 10:45:35 -0800131 private int mFixedToUserRotation = FIXED_TO_USER_ROTATION_DEFAULT;
Garfield Tanff362222018-11-14 17:52:32 -0800132
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800133 private int mDemoHdmiRotation;
134 private int mDemoRotation;
135 private boolean mDemoHdmiRotationLock;
136 private boolean mDemoRotationLock;
137
138 DisplayRotation(WindowManagerService service, DisplayContent displayContent) {
139 this(service, displayContent, displayContent.getDisplayPolicy(),
Garfield Tanff362222018-11-14 17:52:32 -0800140 service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
Riddle Hsuad256a12018-07-18 16:11:30 +0800141 }
142
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800143 @VisibleForTesting
144 DisplayRotation(WindowManagerService service, DisplayContent displayContent,
Garfield Tanff362222018-11-14 17:52:32 -0800145 DisplayPolicy displayPolicy, DisplayWindowSettings displayWindowSettings,
146 Context context, Object lock) {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800147 mService = service;
Garfield Tan90c90052018-10-08 12:29:41 -0700148 mDisplayContent = displayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800149 mDisplayPolicy = displayPolicy;
Garfield Tanff362222018-11-14 17:52:32 -0800150 mDisplayWindowSettings = displayWindowSettings;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800151 mContext = context;
152 mLock = lock;
153 isDefaultDisplay = displayContent.isDefaultDisplay;
Riddle Hsuad256a12018-07-18 16:11:30 +0800154
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800155 mSupportAutoRotation = mContext.getResources().getBoolean(
156 com.android.internal.R.bool.config_supportAutoRotation);
157 mLidOpenRotation = readRotation(
158 com.android.internal.R.integer.config_lidOpenRotation);
159 mCarDockRotation = readRotation(
160 com.android.internal.R.integer.config_carDockRotation);
161 mDeskDockRotation = readRotation(
162 com.android.internal.R.integer.config_deskDockRotation);
163 mUndockedHdmiRotation = readRotation(
164 com.android.internal.R.integer.config_undockedHdmiRotation);
165
Tiger Huang3d2b8982019-01-29 22:56:48 +0800166 mCloseToSquareMaxAspectRatio = mContext.getResources().getFloat(
167 com.android.internal.R.dimen.config_closeToSquareDisplayMaxAspectRatio);
168
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800169 if (isDefaultDisplay) {
170 final Handler uiHandler = UiThread.getHandler();
171 mOrientationListener = new OrientationListener(mContext, uiHandler);
172 mOrientationListener.setCurrentRotation(displayContent.getRotation());
173 mSettingsObserver = new SettingsObserver(uiHandler);
174 mSettingsObserver.observe();
175 }
176 }
177
178 private int readRotation(int resID) {
179 try {
180 final int rotation = mContext.getResources().getInteger(resID);
181 switch (rotation) {
182 case 0:
183 return Surface.ROTATION_0;
184 case 90:
185 return Surface.ROTATION_90;
186 case 180:
187 return Surface.ROTATION_180;
188 case 270:
189 return Surface.ROTATION_270;
190 }
191 } catch (Resources.NotFoundException e) {
192 // fall through
193 }
194 return -1;
195 }
196
197 void configure(int width, int height, int shortSizeDp, int longSizeDp) {
Riddle Hsuad256a12018-07-18 16:11:30 +0800198 final Resources res = mContext.getResources();
199 if (width > height) {
200 mLandscapeRotation = Surface.ROTATION_0;
201 mSeascapeRotation = Surface.ROTATION_180;
202 if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
203 mPortraitRotation = Surface.ROTATION_90;
204 mUpsideDownRotation = Surface.ROTATION_270;
205 } else {
206 mPortraitRotation = Surface.ROTATION_270;
207 mUpsideDownRotation = Surface.ROTATION_90;
208 }
209 } else {
210 mPortraitRotation = Surface.ROTATION_0;
211 mUpsideDownRotation = Surface.ROTATION_180;
212 if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
213 mLandscapeRotation = Surface.ROTATION_270;
214 mSeascapeRotation = Surface.ROTATION_90;
215 } else {
216 mLandscapeRotation = Surface.ROTATION_90;
217 mSeascapeRotation = Surface.ROTATION_270;
218 }
219 }
220
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800221 // For demo purposes, allow the rotation of the HDMI display to be controlled.
222 // By default, HDMI locks rotation to landscape.
223 if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
224 mDemoHdmiRotation = mPortraitRotation;
225 } else {
226 mDemoHdmiRotation = mLandscapeRotation;
227 }
228 mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
229
230 // For demo purposes, allow the rotation of the remote display to be controlled.
231 // By default, remote display locks rotation to landscape.
232 if ("portrait".equals(SystemProperties.get("persist.demo.remoterotation"))) {
233 mDemoRotation = mPortraitRotation;
234 } else {
235 mDemoRotation = mLandscapeRotation;
236 }
237 mDemoRotationLock = SystemProperties.getBoolean("persist.demo.rotationlock", false);
238
Garfield Tan12b12f7a2019-02-22 16:33:27 -0800239 // It's physically impossible to rotate the car's screen.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800240 final boolean isCar = mContext.getPackageManager().hasSystemFeature(
241 PackageManager.FEATURE_AUTOMOTIVE);
Garfield Tan12b12f7a2019-02-22 16:33:27 -0800242 // It's also not likely to rotate a TV screen.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800243 final boolean isTv = mContext.getPackageManager().hasSystemFeature(
244 PackageManager.FEATURE_LEANBACK);
Garfield Tan12b12f7a2019-02-22 16:33:27 -0800245 // Not much of use to rotate the display since it's close to square.
Tiger Huang3d2b8982019-01-29 22:56:48 +0800246 final boolean isCloseToSquare =
247 isNonDecorDisplayCloseToSquare(Surface.ROTATION_0, width, height);
Garfield Tan7fbca052019-02-19 10:45:35 -0800248 final boolean forceDesktopMode =
249 mService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay;
250 mDefaultFixedToUserRotation =
251 (isCar || isTv || mService.mIsPc || forceDesktopMode || isCloseToSquare)
252 // For debug purposes the next line turns this feature off with:
253 // $ adb shell setprop config.override_forced_orient true
254 // $ adb shell wm size reset
255 && !"true".equals(SystemProperties.get("config.override_forced_orient"));
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800256 }
257
Tiger Huang3d2b8982019-01-29 22:56:48 +0800258 private boolean isNonDecorDisplayCloseToSquare(int rotation, int width, int height) {
259 final DisplayCutout displayCutout =
260 mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
261 final int uiMode = mService.mPolicy.getUiMode();
262 final int w = mDisplayPolicy.getNonDecorDisplayWidth(
263 width, height, rotation, uiMode, displayCutout);
264 final int h = mDisplayPolicy.getNonDecorDisplayHeight(
265 width, height, rotation, uiMode, displayCutout);
266 final float aspectRatio = Math.max(w, h) / (float) Math.min(w, h);
267 return aspectRatio <= mCloseToSquareMaxAspectRatio;
268 }
269
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800270 void setRotation(int rotation) {
271 if (mOrientationListener != null) {
272 mOrientationListener.setCurrentRotation(rotation);
273 }
274 }
275
276 void setCurrentOrientation(int newOrientation) {
277 if (newOrientation != mCurrentAppOrientation) {
278 mCurrentAppOrientation = newOrientation;
279 if (isDefaultDisplay) {
280 updateOrientationListenerLw();
281 }
282 }
283 }
284
Garfield Tanff362222018-11-14 17:52:32 -0800285 void restoreSettings(int userRotationMode, int userRotation,
Garfield Tan7fbca052019-02-19 10:45:35 -0800286 @FixedToUserRotation int fixedToUserRotation) {
Garfield Tanff362222018-11-14 17:52:32 -0800287 mFixedToUserRotation = fixedToUserRotation;
288
289 // We will retrieve user rotation and user rotation mode from settings for default display.
290 if (isDefaultDisplay) {
291 return;
292 }
Garfield Tan90c90052018-10-08 12:29:41 -0700293 if (userRotationMode != WindowManagerPolicy.USER_ROTATION_FREE
294 && userRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) {
295 Slog.w(TAG, "Trying to restore an invalid user rotation mode " + userRotationMode
296 + " for " + mDisplayContent);
297 userRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
298 }
299 if (userRotation < Surface.ROTATION_0 || userRotation > Surface.ROTATION_270) {
300 Slog.w(TAG, "Trying to restore an invalid user rotation " + userRotation
301 + " for " + mDisplayContent);
302 userRotation = Surface.ROTATION_0;
303 }
304 mUserRotationMode = userRotationMode;
305 mUserRotation = userRotation;
306 }
307
Garfield Tan7fbca052019-02-19 10:45:35 -0800308 void setFixedToUserRotation(@FixedToUserRotation int fixedToUserRotation) {
Garfield Tanff362222018-11-14 17:52:32 -0800309 if (mFixedToUserRotation == fixedToUserRotation) {
310 return;
311 }
312
313 mFixedToUserRotation = fixedToUserRotation;
Garfield Tan7fbca052019-02-19 10:45:35 -0800314 mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent, fixedToUserRotation);
Garfield Tanff362222018-11-14 17:52:32 -0800315 mService.updateRotation(true /* alwaysSendConfiguration */,
316 false /* forceRelayout */);
317 }
318
Garfield Tan90c90052018-10-08 12:29:41 -0700319 private void setUserRotation(int userRotationMode, int userRotation) {
320 if (isDefaultDisplay) {
321 // We'll be notified via settings listener, so we don't need to update internal values.
322 final ContentResolver res = mContext.getContentResolver();
323 final int accelerometerRotation =
324 userRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED ? 0 : 1;
325 Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION,
326 accelerometerRotation, UserHandle.USER_CURRENT);
327 Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation,
328 UserHandle.USER_CURRENT);
329 return;
330 }
331
332 boolean changed = false;
333 if (mUserRotationMode != userRotationMode) {
334 mUserRotationMode = userRotationMode;
335 changed = true;
336 }
337 if (mUserRotation != userRotation) {
338 mUserRotation = userRotation;
339 changed = true;
340 }
Garfield Tanff362222018-11-14 17:52:32 -0800341 mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode,
Chilun8753ad32018-10-09 15:56:45 +0800342 userRotation);
Garfield Tan90c90052018-10-08 12:29:41 -0700343 if (changed) {
344 mService.updateRotation(true /* alwaysSendConfiguration */,
345 false /* forceRelayout */);
Garfield Tan90c90052018-10-08 12:29:41 -0700346 }
347 }
348
349 void freezeRotation(int rotation) {
350 rotation = (rotation == -1) ? mDisplayContent.getRotation() : rotation;
351 setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation);
352 }
353
354 void thawRotation() {
355 setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation);
356 }
357
358 boolean isRotationFrozen() {
359 if (!isDefaultDisplay) {
360 return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED;
361 }
362
363 return Settings.System.getIntForUser(mContext.getContentResolver(),
364 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0;
365 }
366
Garfield Tanff362222018-11-14 17:52:32 -0800367 boolean isFixedToUserRotation() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800368 switch (mFixedToUserRotation) {
369 case FIXED_TO_USER_ROTATION_DISABLED:
370 return false;
371 case FIXED_TO_USER_ROTATION_ENABLED:
372 return true;
373 default:
374 return mDefaultFixedToUserRotation;
375 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800376 }
377
Garfield Tan49dae102019-02-04 09:51:59 -0800378 /**
379 * Returns {@code true} if this display rotation takes app requested orientation into
380 * consideration; {@code false} otherwise. For the time being the only case where this is {@code
381 * false} is when {@link #isFixedToUserRotation()} is {@code true}.
382 */
383 boolean respectAppRequestedOrientation() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800384 return !isFixedToUserRotation();
Garfield Tan49dae102019-02-04 09:51:59 -0800385 }
386
Riddle Hsuad256a12018-07-18 16:11:30 +0800387 public int getLandscapeRotation() {
388 return mLandscapeRotation;
389 }
390
391 public int getSeascapeRotation() {
392 return mSeascapeRotation;
393 }
394
395 public int getPortraitRotation() {
396 return mPortraitRotation;
397 }
398
399 public int getUpsideDownRotation() {
400 return mUpsideDownRotation;
401 }
402
403 public int getCurrentAppOrientation() {
404 return mCurrentAppOrientation;
405 }
406
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800407 public DisplayPolicy getDisplayPolicy() {
408 return mDisplayPolicy;
Riddle Hsuad256a12018-07-18 16:11:30 +0800409 }
410
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800411 public WindowOrientationListener getOrientationListener() {
412 return mOrientationListener;
Riddle Hsuad256a12018-07-18 16:11:30 +0800413 }
414
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800415 public int getUserRotation() {
416 return mUserRotation;
417 }
418
419 public int getUserRotationMode() {
420 return mUserRotationMode;
421 }
422
423 public void updateOrientationListener() {
424 synchronized (mLock) {
425 updateOrientationListenerLw();
Riddle Hsuad256a12018-07-18 16:11:30 +0800426 }
427 }
428
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800429 /**
430 * Various use cases for invoking this function:
431 * <li>Screen turning off, should always disable listeners if already enabled.</li>
432 * <li>Screen turned on and current app has sensor based orientation, enable listeners
433 * if not already enabled.</li>
434 * <li>Screen turned on and current app does not have sensor orientation, disable listeners
435 * if already enabled.</li>
436 * <li>Screen turning on and current app has sensor based orientation, enable listeners
437 * if needed.</li>
438 * <li>screen turning on and current app has nosensor based orientation, do nothing.</li>
439 */
440 private void updateOrientationListenerLw() {
441 if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {
442 // If sensor is turned off or nonexistent for some reason.
443 return;
444 }
445
446 final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();
447 final boolean awake = mDisplayPolicy.isAwake();
448 final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();
449 final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();
450
451 // Could have been invoked due to screen turning on or off or
452 // change of the currently visible window's orientation.
453 if (DEBUG_ORIENTATION) Slog.v(TAG, "screenOnEarly=" + screenOnEarly
454 + ", awake=" + awake + ", currentAppOrientation=" + mCurrentAppOrientation
455 + ", orientationSensorEnabled=" + mOrientationListener.mEnabled
456 + ", keyguardDrawComplete=" + keyguardDrawComplete
457 + ", windowManagerDrawComplete=" + windowManagerDrawComplete);
458
459 boolean disable = true;
460 // Note: We postpone the rotating of the screen until the keyguard as well as the
461 // window manager have reported a draw complete or the keyguard is going away in dismiss
462 // mode.
463 if (screenOnEarly && awake && ((keyguardDrawComplete && windowManagerDrawComplete))) {
464 if (needSensorRunning()) {
465 disable = false;
466 // Enable listener if not already enabled.
467 if (!mOrientationListener.mEnabled) {
468 // Don't clear the current sensor orientation if the keyguard is going away in
469 // dismiss mode. This allows window manager to use the last sensor reading to
470 // determine the orientation vs. falling back to the last known orientation if
471 // the sensor reading was cleared which can cause it to relaunch the app that
472 // will show in the wrong orientation first before correcting leading to app
473 // launch delays.
474 mOrientationListener.enable(true /* clearCurrentRotation */);
475 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800476 }
477 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800478 // Check if sensors need to be disabled.
479 if (disable && mOrientationListener.mEnabled) {
480 mOrientationListener.disable();
481 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800482 }
483
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800484 /**
485 * We always let the sensor be switched on by default except when
486 * the user has explicitly disabled sensor based rotation or when the
487 * screen is switched off.
488 */
489 private boolean needSensorRunning() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800490 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800491 // We are sure we only respect user rotation settings, so we are sure we will not
492 // support sensor rotation.
493 return false;
494 }
495
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800496 if (mSupportAutoRotation) {
497 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
498 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
499 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
500 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
501 // If the application has explicitly requested to follow the
502 // orientation, then we need to turn the sensor on.
503 return true;
504 }
505 }
506
507 final int dockMode = mDisplayPolicy.getDockMode();
508 if ((mDisplayPolicy.isCarDockEnablesAccelerometer()
509 && dockMode == Intent.EXTRA_DOCK_STATE_CAR)
510 || (mDisplayPolicy.isDeskDockEnablesAccelerometer()
511 && (dockMode == Intent.EXTRA_DOCK_STATE_DESK
512 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
513 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) {
514 // Enable accelerometer if we are docked in a dock that enables accelerometer
515 // orientation management.
516 return true;
517 }
518
519 if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
520 // If the setting for using the sensor by default is enabled, then
521 // we will always leave it on. Note that the user could go to
522 // a window that forces an orientation that does not use the
523 // sensor and in theory we could turn it off... however, when next
524 // turning it on we won't have a good value for the current
525 // orientation for a little bit, which can cause orientation
526 // changes to lag, so we'd like to keep it always on. (It will
527 // still be turned off when the screen is off.)
528
529 // When locked we can provide rotation suggestions users can approve to change the
530 // current screen rotation. To do this the sensor needs to be running.
531 return mSupportAutoRotation &&
532 mShowRotationSuggestions == Settings.Secure.SHOW_ROTATION_SUGGESTIONS_ENABLED;
533 }
534 return mSupportAutoRotation;
535 }
536
537 /**
538 * Given an orientation constant, returns the appropriate surface rotation,
539 * taking into account sensors, docking mode, rotation lock, and other factors.
540 *
541 * @param orientation An orientation constant, such as
542 * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
543 * @param lastRotation The most recently used rotation.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800544 * @return The surface rotation to use.
545 */
546 int rotationForOrientation(int orientation, int lastRotation) {
547 if (DEBUG_ORIENTATION) {
548 Slog.v(TAG, "rotationForOrientation(orient="
549 + orientation + ", last=" + lastRotation
550 + "); user=" + mUserRotation + " "
551 + (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
552 ? "USER_ROTATION_LOCKED" : "")
553 );
554 }
555
Garfield Tan7fbca052019-02-19 10:45:35 -0800556 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800557 return mUserRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800558 }
559
560 int sensorRotation = mOrientationListener != null
561 ? mOrientationListener.getProposedRotation() // may be -1
562 : -1;
563 if (sensorRotation < 0) {
564 sensorRotation = lastRotation;
565 }
566
567 final int lidState = mDisplayPolicy.getLidState();
568 final int dockMode = mDisplayPolicy.getDockMode();
569 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
570 final boolean carDockEnablesAccelerometer =
571 mDisplayPolicy.isCarDockEnablesAccelerometer();
572 final boolean deskDockEnablesAccelerometer =
573 mDisplayPolicy.isDeskDockEnablesAccelerometer();
574
575 final int preferredRotation;
576 if (!isDefaultDisplay) {
577 // For secondary displays we ignore things like displays sensors, docking mode and
Garfield Tan90c90052018-10-08 12:29:41 -0700578 // rotation lock, and always prefer user rotation.
579 preferredRotation = mUserRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800580 } else if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
581 // Ignore sensor when lid switch is open and rotation is forced.
582 preferredRotation = mLidOpenRotation;
583 } else if (dockMode == Intent.EXTRA_DOCK_STATE_CAR
584 && (carDockEnablesAccelerometer || mCarDockRotation >= 0)) {
585 // Ignore sensor when in car dock unless explicitly enabled.
586 // This case can override the behavior of NOSENSOR, and can also
587 // enable 180 degree rotation while docked.
588 preferredRotation = carDockEnablesAccelerometer ? sensorRotation : mCarDockRotation;
589 } else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
590 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
591 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
592 && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
593 // Ignore sensor when in desk dock unless explicitly enabled.
594 // This case can override the behavior of NOSENSOR, and can also
595 // enable 180 degree rotation while docked.
596 preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation;
597 } else if (hdmiPlugged && mDemoHdmiRotationLock) {
598 // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
599 // Note that the dock orientation overrides the HDMI orientation.
600 preferredRotation = mDemoHdmiRotation;
601 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
602 && mUndockedHdmiRotation >= 0) {
603 // Ignore sensor when plugged into HDMI and an undocked orientation has
604 // been specified in the configuration (only for legacy devices without
605 // full multi-display support).
606 // Note that the dock orientation overrides the HDMI orientation.
607 preferredRotation = mUndockedHdmiRotation;
608 } else if (mDemoRotationLock) {
609 // Ignore sensor when demo rotation lock is enabled.
610 // Note that the dock orientation and HDMI rotation lock override this.
611 preferredRotation = mDemoRotation;
612 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
613 // While in VR, apps always prefer a portrait rotation. This does not change
614 // any apps that explicitly set landscape, but does cause sensors be ignored,
615 // and ignored any orientation lock that the user has set (this conditional
616 // should remain above the ORIENTATION_LOCKED conditional below).
617 preferredRotation = mPortraitRotation;
618 } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
619 // Application just wants to remain locked in the last rotation.
620 preferredRotation = lastRotation;
621 } else if (!mSupportAutoRotation) {
622 // If we don't support auto-rotation then bail out here and ignore
623 // the sensor and any rotation lock settings.
624 preferredRotation = -1;
625 } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
626 && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
627 || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
628 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
629 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
630 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))
631 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
632 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
633 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
634 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
635 // Otherwise, use sensor only if requested by the application or enabled
636 // by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR.
637 if (mAllowAllRotations < 0) {
638 // Can't read this during init() because the context doesn't
639 // have display metrics at that time so we cannot determine
640 // tablet vs. phone then.
641 mAllowAllRotations = mContext.getResources().getBoolean(
642 com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;
643 }
644 if (sensorRotation != Surface.ROTATION_180
645 || mAllowAllRotations == 1
646 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
647 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
648 preferredRotation = sensorRotation;
649 } else {
650 preferredRotation = lastRotation;
651 }
652 } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
653 && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
654 // Apply rotation lock. Does not apply to NOSENSOR.
655 // The idea is that the user rotation expresses a weak preference for the direction
656 // of gravity and as NOSENSOR is never affected by gravity, then neither should
657 // NOSENSOR be affected by rotation lock (although it will be affected by docks).
658 preferredRotation = mUserRotation;
659 } else {
660 // No overriding preference.
661 // We will do exactly what the application asked us to do.
662 preferredRotation = -1;
663 }
664
Riddle Hsuad256a12018-07-18 16:11:30 +0800665 switch (orientation) {
666 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
667 // Return portrait unless overridden.
668 if (isAnyPortrait(preferredRotation)) {
669 return preferredRotation;
670 }
671 return mPortraitRotation;
672
673 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
674 // Return landscape unless overridden.
675 if (isLandscapeOrSeascape(preferredRotation)) {
676 return preferredRotation;
677 }
678 return mLandscapeRotation;
679
680 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
681 // Return reverse portrait unless overridden.
682 if (isAnyPortrait(preferredRotation)) {
683 return preferredRotation;
684 }
685 return mUpsideDownRotation;
686
687 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
688 // Return seascape unless overridden.
689 if (isLandscapeOrSeascape(preferredRotation)) {
690 return preferredRotation;
691 }
692 return mSeascapeRotation;
693
694 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
695 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
696 // Return either landscape rotation.
697 if (isLandscapeOrSeascape(preferredRotation)) {
698 return preferredRotation;
699 }
700 if (isLandscapeOrSeascape(lastRotation)) {
701 return lastRotation;
702 }
703 return mLandscapeRotation;
704
705 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
706 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
707 // Return either portrait rotation.
708 if (isAnyPortrait(preferredRotation)) {
709 return preferredRotation;
710 }
711 if (isAnyPortrait(lastRotation)) {
712 return lastRotation;
713 }
714 return mPortraitRotation;
715
716 default:
717 // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
718 // just return the preferred orientation we already calculated.
719 if (preferredRotation >= 0) {
720 return preferredRotation;
721 }
722 return Surface.ROTATION_0;
723 }
724 }
725
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800726 private boolean isLandscapeOrSeascape(int rotation) {
727 return rotation == mLandscapeRotation || rotation == mSeascapeRotation;
728 }
729
730 private boolean isAnyPortrait(int rotation) {
731 return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
732 }
733
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800734 private boolean isValidRotationChoice(final int preferredRotation) {
Riddle Hsuad256a12018-07-18 16:11:30 +0800735 // Determine if the given app orientation is compatible with the provided rotation choice.
736 switch (mCurrentAppOrientation) {
737 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
738 // Works with any of the 4 rotations.
739 return preferredRotation >= 0;
740
741 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
742 // It's possible for the user pref to be set at 180 because of FULL_USER. This would
743 // make switching to USER_PORTRAIT appear at 180. Provide choice to back to portrait
744 // but never to go to 180.
745 return preferredRotation == mPortraitRotation;
746
747 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
748 // Works landscape or seascape.
749 return isLandscapeOrSeascape(preferredRotation);
750
751 case ActivityInfo.SCREEN_ORIENTATION_USER:
752 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
753 // Works with any rotation except upside down.
754 return (preferredRotation >= 0) && (preferredRotation != mUpsideDownRotation);
755 }
756
757 return false;
758 }
759
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800760 private boolean isRotationChoicePossible(int orientation) {
761 // Rotation choice is only shown when the user is in locked mode.
762 if (mUserRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) return false;
763
764 // We should only enable rotation choice if the rotation isn't forced by the lid, dock,
765 // demo, hdmi, vr, etc mode.
766
767 // Determine if the rotation is currently forced.
Garfield Tan7fbca052019-02-19 10:45:35 -0800768 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800769 return false; // Rotation is forced to user settings.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800770 }
771
772 final int lidState = mDisplayPolicy.getLidState();
773 if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
774 return false; // Rotation is forced mLidOpenRotation.
775 }
776
777 final int dockMode = mDisplayPolicy.getDockMode();
778 final boolean carDockEnablesAccelerometer = false;
779 if (dockMode == Intent.EXTRA_DOCK_STATE_CAR && !carDockEnablesAccelerometer) {
780 return false; // Rotation forced to mCarDockRotation.
781 }
782
783 final boolean deskDockEnablesAccelerometer =
784 mDisplayPolicy.isDeskDockEnablesAccelerometer();
785 if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
786 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
787 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
788 && !deskDockEnablesAccelerometer) {
789 return false; // Rotation forced to mDeskDockRotation.
790 }
791
792 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
793 if (hdmiPlugged && mDemoHdmiRotationLock) {
794 return false; // Rotation forced to mDemoHdmiRotation.
795
796 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
797 && mUndockedHdmiRotation >= 0) {
798 return false; // Rotation forced to mUndockedHdmiRotation.
799
800 } else if (mDemoRotationLock) {
801 return false; // Rotation forced to mDemoRotation.
802
803 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
804 return false; // Rotation forced to mPortraitRotation.
805
806 } else if (!mSupportAutoRotation) {
807 return false;
808 }
809
810 // Ensure that some rotation choice is possible for the given orientation.
811 switch (orientation) {
812 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
813 case ActivityInfo.SCREEN_ORIENTATION_USER:
814 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
815 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
816 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
817 // NOSENSOR description is ambiguous, in reality WM ignores user choice.
818 return true;
819 }
820
821 // Rotation is forced, should be controlled by system.
822 return false;
Riddle Hsuad256a12018-07-18 16:11:30 +0800823 }
824
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800825 /** Notify the StatusBar that system rotation suggestion has changed. */
826 private void sendProposedRotationChangeToStatusBarInternal(int rotation, boolean isValid) {
827 if (mStatusBarManagerInternal == null) {
828 mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class);
829 }
830 if (mStatusBarManagerInternal != null) {
831 mStatusBarManagerInternal.onProposedRotationChanged(rotation, isValid);
832 }
833 }
834
835 private static String allowAllRotationsToString(int allowAll) {
836 switch (allowAll) {
837 case -1:
838 return "unknown";
839 case 0:
840 return "false";
841 case 1:
842 return "true";
843 default:
844 return Integer.toString(allowAll);
845 }
846 }
847
848 public void onUserSwitch() {
849 if (mSettingsObserver != null) {
850 mSettingsObserver.onChange(false);
851 }
852 }
853
854 /** Return whether the rotation settings has changed. */
855 private boolean updateSettings() {
856 final ContentResolver resolver = mContext.getContentResolver();
857 boolean shouldUpdateRotation = false;
858
859 synchronized (mLock) {
860 boolean shouldUpdateOrientationListener = false;
861
862 // Configure rotation suggestions.
Rajeev Kumarb2ff8e82018-08-06 11:45:05 -0700863 final int showRotationSuggestions =
864 ActivityManager.isLowRamDeviceStatic()
865 ? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED
866 : Settings.Secure.getIntForUser(resolver,
867 Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
868 Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
869 UserHandle.USER_CURRENT);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800870 if (mShowRotationSuggestions != showRotationSuggestions) {
871 mShowRotationSuggestions = showRotationSuggestions;
872 shouldUpdateOrientationListener = true;
873 }
874
875 // Configure rotation lock.
876 final int userRotation = Settings.System.getIntForUser(resolver,
877 Settings.System.USER_ROTATION, Surface.ROTATION_0,
878 UserHandle.USER_CURRENT);
879 if (mUserRotation != userRotation) {
880 mUserRotation = userRotation;
881 shouldUpdateRotation = true;
882 }
883
884 final int userRotationMode = Settings.System.getIntForUser(resolver,
885 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0
886 ? WindowManagerPolicy.USER_ROTATION_FREE
887 : WindowManagerPolicy.USER_ROTATION_LOCKED;
888 if (mUserRotationMode != userRotationMode) {
889 mUserRotationMode = userRotationMode;
890 shouldUpdateOrientationListener = true;
891 shouldUpdateRotation = true;
892 }
893
894 if (shouldUpdateOrientationListener) {
895 updateOrientationListenerLw(); // Enable or disable the orientation listener.
896 }
897 }
898
899 return shouldUpdateRotation;
Riddle Hsuad256a12018-07-18 16:11:30 +0800900 }
901
902 void dump(String prefix, PrintWriter pw) {
903 pw.println(prefix + "DisplayRotation");
904 pw.println(prefix + " mCurrentAppOrientation="
905 + ActivityInfo.screenOrientationToString(mCurrentAppOrientation));
906 pw.print(prefix + " mLandscapeRotation=" + Surface.rotationToString(mLandscapeRotation));
907 pw.println(" mSeascapeRotation=" + Surface.rotationToString(mSeascapeRotation));
908 pw.print(prefix + " mPortraitRotation=" + Surface.rotationToString(mPortraitRotation));
909 pw.println(" mUpsideDownRotation=" + Surface.rotationToString(mUpsideDownRotation));
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800910
Tiger Huang7c610aa2018-10-27 00:01:01 +0800911 pw.println(prefix + " mSupportAutoRotation=" + mSupportAutoRotation);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800912 if (mOrientationListener != null) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800913 mOrientationListener.dump(pw, prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800914 }
915 pw.println();
916
917 pw.print(prefix + " mCarDockRotation=" + Surface.rotationToString(mCarDockRotation));
918 pw.println(" mDeskDockRotation=" + Surface.rotationToString(mDeskDockRotation));
919 pw.print(prefix + " mUserRotationMode="
920 + WindowManagerPolicy.userRotationModeToString(mUserRotationMode));
921 pw.print(" mUserRotation=" + Surface.rotationToString(mUserRotation));
922 pw.println(" mAllowAllRotations=" + allowAllRotationsToString(mAllowAllRotations));
923
924 pw.print(prefix + " mDemoHdmiRotation=" + Surface.rotationToString(mDemoHdmiRotation));
925 pw.print(" mDemoHdmiRotationLock=" + mDemoHdmiRotationLock);
926 pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation));
927 pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation));
Garfield Tan7fbca052019-02-19 10:45:35 -0800928 pw.println(prefix + " mFixedToUserRotation=" + isFixedToUserRotation());
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800929 }
930
931 private class OrientationListener extends WindowOrientationListener {
932 final SparseArray<Runnable> mRunnableCache = new SparseArray<>(5);
933 boolean mEnabled;
934
935 OrientationListener(Context context, Handler handler) {
936 super(context, handler);
937 }
938
939 private class UpdateRunnable implements Runnable {
940 final int mRotation;
941
942 UpdateRunnable(int rotation) {
943 mRotation = rotation;
944 }
945
946 @Override
947 public void run() {
948 // Send interaction hint to improve redraw performance.
949 mService.mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
950 if (isRotationChoicePossible(mCurrentAppOrientation)) {
951 final boolean isValid = isValidRotationChoice(mRotation);
952 sendProposedRotationChangeToStatusBarInternal(mRotation, isValid);
953 } else {
954 mService.updateRotation(false /* alwaysSendConfiguration */,
955 false /* forceRelayout */);
956 }
957 }
958 }
959
960 @Override
961 public void onProposedRotationChanged(int rotation) {
962 if (DEBUG_ORIENTATION) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
963 Runnable r = mRunnableCache.get(rotation, null);
964 if (r == null) {
965 r = new UpdateRunnable(rotation);
966 mRunnableCache.put(rotation, r);
967 }
968 getHandler().post(r);
969 }
970
971 @Override
972 public void enable(boolean clearCurrentRotation) {
973 super.enable(clearCurrentRotation);
974 mEnabled = true;
975 if (DEBUG_ORIENTATION) Slog.v(TAG, "Enabling listeners");
976 }
977
978 @Override
979 public void disable() {
980 super.disable();
981 mEnabled = false;
982 if (DEBUG_ORIENTATION) Slog.v(TAG, "Disabling listeners");
983 }
984 }
985
986 private class SettingsObserver extends ContentObserver {
987 SettingsObserver(Handler handler) {
988 super(handler);
989 }
990
991 void observe() {
992 final ContentResolver resolver = mContext.getContentResolver();
993 resolver.registerContentObserver(Settings.Secure.getUriFor(
994 Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,
995 UserHandle.USER_ALL);
996 resolver.registerContentObserver(Settings.System.getUriFor(
997 Settings.System.ACCELEROMETER_ROTATION), false, this,
998 UserHandle.USER_ALL);
999 resolver.registerContentObserver(Settings.System.getUriFor(
1000 Settings.System.USER_ROTATION), false, this,
1001 UserHandle.USER_ALL);
1002 updateSettings();
1003 }
1004
1005 @Override
1006 public void onChange(boolean selfChange) {
1007 if (updateSettings()) {
1008 mService.updateRotation(true /* alwaysSendConfiguration */,
1009 false /* forceRelayout */);
1010 }
1011 }
Riddle Hsuad256a12018-07-18 16:11:30 +08001012 }
Garfield Tanff362222018-11-14 17:52:32 -08001013
1014 @VisibleForTesting
1015 interface ContentObserverRegister {
1016 void registerContentObserver(Uri uri, boolean notifyForDescendants,
1017 ContentObserver observer, @UserIdInt int userHandle);
1018 }
Riddle Hsuad256a12018-07-18 16:11:30 +08001019}