blob: c6b7060fe649e137c6d88039227882e7d1a3c159 [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
239 // Only force the default orientation if the screen is xlarge, at least 960dp x 720dp, per
240 // http://developer.android.com/guide/practices/screens_support.html#range
241 // For car, ignore the dp limitation. It's physically impossible to rotate the car's screen
242 // so if the orientation is forced, we need to respect that no matter what.
243 final boolean isCar = mContext.getPackageManager().hasSystemFeature(
244 PackageManager.FEATURE_AUTOMOTIVE);
245 // For TV, it's usually 960dp x 540dp, ignore the size limitation.
246 // so if the orientation is forced, we need to respect that no matter what.
247 final boolean isTv = mContext.getPackageManager().hasSystemFeature(
248 PackageManager.FEATURE_LEANBACK);
Tiger Huang3d2b8982019-01-29 22:56:48 +0800249 final boolean isCloseToSquare =
250 isNonDecorDisplayCloseToSquare(Surface.ROTATION_0, width, height);
Garfield Tan7fbca052019-02-19 10:45:35 -0800251 final boolean forceDesktopMode =
252 mService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay;
253 mDefaultFixedToUserRotation =
254 (isCar || isTv || mService.mIsPc || forceDesktopMode || isCloseToSquare)
255 // For debug purposes the next line turns this feature off with:
256 // $ adb shell setprop config.override_forced_orient true
257 // $ adb shell wm size reset
258 && !"true".equals(SystemProperties.get("config.override_forced_orient"));
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800259 }
260
Tiger Huang3d2b8982019-01-29 22:56:48 +0800261 private boolean isNonDecorDisplayCloseToSquare(int rotation, int width, int height) {
262 final DisplayCutout displayCutout =
263 mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
264 final int uiMode = mService.mPolicy.getUiMode();
265 final int w = mDisplayPolicy.getNonDecorDisplayWidth(
266 width, height, rotation, uiMode, displayCutout);
267 final int h = mDisplayPolicy.getNonDecorDisplayHeight(
268 width, height, rotation, uiMode, displayCutout);
269 final float aspectRatio = Math.max(w, h) / (float) Math.min(w, h);
270 return aspectRatio <= mCloseToSquareMaxAspectRatio;
271 }
272
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800273 void setRotation(int rotation) {
274 if (mOrientationListener != null) {
275 mOrientationListener.setCurrentRotation(rotation);
276 }
277 }
278
279 void setCurrentOrientation(int newOrientation) {
280 if (newOrientation != mCurrentAppOrientation) {
281 mCurrentAppOrientation = newOrientation;
282 if (isDefaultDisplay) {
283 updateOrientationListenerLw();
284 }
285 }
286 }
287
Garfield Tanff362222018-11-14 17:52:32 -0800288 void restoreSettings(int userRotationMode, int userRotation,
Garfield Tan7fbca052019-02-19 10:45:35 -0800289 @FixedToUserRotation int fixedToUserRotation) {
Garfield Tanff362222018-11-14 17:52:32 -0800290 mFixedToUserRotation = fixedToUserRotation;
291
292 // We will retrieve user rotation and user rotation mode from settings for default display.
293 if (isDefaultDisplay) {
294 return;
295 }
Garfield Tan90c90052018-10-08 12:29:41 -0700296 if (userRotationMode != WindowManagerPolicy.USER_ROTATION_FREE
297 && userRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) {
298 Slog.w(TAG, "Trying to restore an invalid user rotation mode " + userRotationMode
299 + " for " + mDisplayContent);
300 userRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
301 }
302 if (userRotation < Surface.ROTATION_0 || userRotation > Surface.ROTATION_270) {
303 Slog.w(TAG, "Trying to restore an invalid user rotation " + userRotation
304 + " for " + mDisplayContent);
305 userRotation = Surface.ROTATION_0;
306 }
307 mUserRotationMode = userRotationMode;
308 mUserRotation = userRotation;
309 }
310
Garfield Tan7fbca052019-02-19 10:45:35 -0800311 void setFixedToUserRotation(@FixedToUserRotation int fixedToUserRotation) {
Garfield Tanff362222018-11-14 17:52:32 -0800312 if (mFixedToUserRotation == fixedToUserRotation) {
313 return;
314 }
315
316 mFixedToUserRotation = fixedToUserRotation;
Garfield Tan7fbca052019-02-19 10:45:35 -0800317 mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent, fixedToUserRotation);
Garfield Tanff362222018-11-14 17:52:32 -0800318 mService.updateRotation(true /* alwaysSendConfiguration */,
319 false /* forceRelayout */);
320 }
321
Garfield Tan90c90052018-10-08 12:29:41 -0700322 private void setUserRotation(int userRotationMode, int userRotation) {
323 if (isDefaultDisplay) {
324 // We'll be notified via settings listener, so we don't need to update internal values.
325 final ContentResolver res = mContext.getContentResolver();
326 final int accelerometerRotation =
327 userRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED ? 0 : 1;
328 Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION,
329 accelerometerRotation, UserHandle.USER_CURRENT);
330 Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation,
331 UserHandle.USER_CURRENT);
332 return;
333 }
334
335 boolean changed = false;
336 if (mUserRotationMode != userRotationMode) {
337 mUserRotationMode = userRotationMode;
338 changed = true;
339 }
340 if (mUserRotation != userRotation) {
341 mUserRotation = userRotation;
342 changed = true;
343 }
Garfield Tanff362222018-11-14 17:52:32 -0800344 mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode,
Chilun8753ad32018-10-09 15:56:45 +0800345 userRotation);
Garfield Tan90c90052018-10-08 12:29:41 -0700346 if (changed) {
347 mService.updateRotation(true /* alwaysSendConfiguration */,
348 false /* forceRelayout */);
Garfield Tan90c90052018-10-08 12:29:41 -0700349 }
350 }
351
352 void freezeRotation(int rotation) {
353 rotation = (rotation == -1) ? mDisplayContent.getRotation() : rotation;
354 setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation);
355 }
356
357 void thawRotation() {
358 setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation);
359 }
360
361 boolean isRotationFrozen() {
362 if (!isDefaultDisplay) {
363 return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED;
364 }
365
366 return Settings.System.getIntForUser(mContext.getContentResolver(),
367 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0;
368 }
369
Garfield Tanff362222018-11-14 17:52:32 -0800370 boolean isFixedToUserRotation() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800371 switch (mFixedToUserRotation) {
372 case FIXED_TO_USER_ROTATION_DISABLED:
373 return false;
374 case FIXED_TO_USER_ROTATION_ENABLED:
375 return true;
376 default:
377 return mDefaultFixedToUserRotation;
378 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800379 }
380
Garfield Tan49dae102019-02-04 09:51:59 -0800381 /**
382 * Returns {@code true} if this display rotation takes app requested orientation into
383 * consideration; {@code false} otherwise. For the time being the only case where this is {@code
384 * false} is when {@link #isFixedToUserRotation()} is {@code true}.
385 */
386 boolean respectAppRequestedOrientation() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800387 return !isFixedToUserRotation();
Garfield Tan49dae102019-02-04 09:51:59 -0800388 }
389
Riddle Hsuad256a12018-07-18 16:11:30 +0800390 public int getLandscapeRotation() {
391 return mLandscapeRotation;
392 }
393
394 public int getSeascapeRotation() {
395 return mSeascapeRotation;
396 }
397
398 public int getPortraitRotation() {
399 return mPortraitRotation;
400 }
401
402 public int getUpsideDownRotation() {
403 return mUpsideDownRotation;
404 }
405
406 public int getCurrentAppOrientation() {
407 return mCurrentAppOrientation;
408 }
409
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800410 public DisplayPolicy getDisplayPolicy() {
411 return mDisplayPolicy;
Riddle Hsuad256a12018-07-18 16:11:30 +0800412 }
413
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800414 public WindowOrientationListener getOrientationListener() {
415 return mOrientationListener;
Riddle Hsuad256a12018-07-18 16:11:30 +0800416 }
417
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800418 public int getUserRotation() {
419 return mUserRotation;
420 }
421
422 public int getUserRotationMode() {
423 return mUserRotationMode;
424 }
425
426 public void updateOrientationListener() {
427 synchronized (mLock) {
428 updateOrientationListenerLw();
Riddle Hsuad256a12018-07-18 16:11:30 +0800429 }
430 }
431
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800432 /**
433 * Various use cases for invoking this function:
434 * <li>Screen turning off, should always disable listeners if already enabled.</li>
435 * <li>Screen turned on and current app has sensor based orientation, enable listeners
436 * if not already enabled.</li>
437 * <li>Screen turned on and current app does not have sensor orientation, disable listeners
438 * if already enabled.</li>
439 * <li>Screen turning on and current app has sensor based orientation, enable listeners
440 * if needed.</li>
441 * <li>screen turning on and current app has nosensor based orientation, do nothing.</li>
442 */
443 private void updateOrientationListenerLw() {
444 if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {
445 // If sensor is turned off or nonexistent for some reason.
446 return;
447 }
448
449 final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();
450 final boolean awake = mDisplayPolicy.isAwake();
451 final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();
452 final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();
453
454 // Could have been invoked due to screen turning on or off or
455 // change of the currently visible window's orientation.
456 if (DEBUG_ORIENTATION) Slog.v(TAG, "screenOnEarly=" + screenOnEarly
457 + ", awake=" + awake + ", currentAppOrientation=" + mCurrentAppOrientation
458 + ", orientationSensorEnabled=" + mOrientationListener.mEnabled
459 + ", keyguardDrawComplete=" + keyguardDrawComplete
460 + ", windowManagerDrawComplete=" + windowManagerDrawComplete);
461
462 boolean disable = true;
463 // Note: We postpone the rotating of the screen until the keyguard as well as the
464 // window manager have reported a draw complete or the keyguard is going away in dismiss
465 // mode.
466 if (screenOnEarly && awake && ((keyguardDrawComplete && windowManagerDrawComplete))) {
467 if (needSensorRunning()) {
468 disable = false;
469 // Enable listener if not already enabled.
470 if (!mOrientationListener.mEnabled) {
471 // Don't clear the current sensor orientation if the keyguard is going away in
472 // dismiss mode. This allows window manager to use the last sensor reading to
473 // determine the orientation vs. falling back to the last known orientation if
474 // the sensor reading was cleared which can cause it to relaunch the app that
475 // will show in the wrong orientation first before correcting leading to app
476 // launch delays.
477 mOrientationListener.enable(true /* clearCurrentRotation */);
478 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800479 }
480 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800481 // Check if sensors need to be disabled.
482 if (disable && mOrientationListener.mEnabled) {
483 mOrientationListener.disable();
484 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800485 }
486
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800487 /**
488 * We always let the sensor be switched on by default except when
489 * the user has explicitly disabled sensor based rotation or when the
490 * screen is switched off.
491 */
492 private boolean needSensorRunning() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800493 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800494 // We are sure we only respect user rotation settings, so we are sure we will not
495 // support sensor rotation.
496 return false;
497 }
498
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800499 if (mSupportAutoRotation) {
500 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
501 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
502 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
503 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
504 // If the application has explicitly requested to follow the
505 // orientation, then we need to turn the sensor on.
506 return true;
507 }
508 }
509
510 final int dockMode = mDisplayPolicy.getDockMode();
511 if ((mDisplayPolicy.isCarDockEnablesAccelerometer()
512 && dockMode == Intent.EXTRA_DOCK_STATE_CAR)
513 || (mDisplayPolicy.isDeskDockEnablesAccelerometer()
514 && (dockMode == Intent.EXTRA_DOCK_STATE_DESK
515 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
516 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) {
517 // Enable accelerometer if we are docked in a dock that enables accelerometer
518 // orientation management.
519 return true;
520 }
521
522 if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
523 // If the setting for using the sensor by default is enabled, then
524 // we will always leave it on. Note that the user could go to
525 // a window that forces an orientation that does not use the
526 // sensor and in theory we could turn it off... however, when next
527 // turning it on we won't have a good value for the current
528 // orientation for a little bit, which can cause orientation
529 // changes to lag, so we'd like to keep it always on. (It will
530 // still be turned off when the screen is off.)
531
532 // When locked we can provide rotation suggestions users can approve to change the
533 // current screen rotation. To do this the sensor needs to be running.
534 return mSupportAutoRotation &&
535 mShowRotationSuggestions == Settings.Secure.SHOW_ROTATION_SUGGESTIONS_ENABLED;
536 }
537 return mSupportAutoRotation;
538 }
539
540 /**
541 * Given an orientation constant, returns the appropriate surface rotation,
542 * taking into account sensors, docking mode, rotation lock, and other factors.
543 *
544 * @param orientation An orientation constant, such as
545 * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
546 * @param lastRotation The most recently used rotation.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800547 * @return The surface rotation to use.
548 */
549 int rotationForOrientation(int orientation, int lastRotation) {
550 if (DEBUG_ORIENTATION) {
551 Slog.v(TAG, "rotationForOrientation(orient="
552 + orientation + ", last=" + lastRotation
553 + "); user=" + mUserRotation + " "
554 + (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
555 ? "USER_ROTATION_LOCKED" : "")
556 );
557 }
558
Garfield Tan7fbca052019-02-19 10:45:35 -0800559 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800560 return mUserRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800561 }
562
563 int sensorRotation = mOrientationListener != null
564 ? mOrientationListener.getProposedRotation() // may be -1
565 : -1;
566 if (sensorRotation < 0) {
567 sensorRotation = lastRotation;
568 }
569
570 final int lidState = mDisplayPolicy.getLidState();
571 final int dockMode = mDisplayPolicy.getDockMode();
572 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
573 final boolean carDockEnablesAccelerometer =
574 mDisplayPolicy.isCarDockEnablesAccelerometer();
575 final boolean deskDockEnablesAccelerometer =
576 mDisplayPolicy.isDeskDockEnablesAccelerometer();
577
578 final int preferredRotation;
579 if (!isDefaultDisplay) {
580 // For secondary displays we ignore things like displays sensors, docking mode and
Garfield Tan90c90052018-10-08 12:29:41 -0700581 // rotation lock, and always prefer user rotation.
582 preferredRotation = mUserRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800583 } else if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
584 // Ignore sensor when lid switch is open and rotation is forced.
585 preferredRotation = mLidOpenRotation;
586 } else if (dockMode == Intent.EXTRA_DOCK_STATE_CAR
587 && (carDockEnablesAccelerometer || mCarDockRotation >= 0)) {
588 // Ignore sensor when in car dock unless explicitly enabled.
589 // This case can override the behavior of NOSENSOR, and can also
590 // enable 180 degree rotation while docked.
591 preferredRotation = carDockEnablesAccelerometer ? sensorRotation : mCarDockRotation;
592 } else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
593 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
594 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
595 && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
596 // Ignore sensor when in desk dock unless explicitly enabled.
597 // This case can override the behavior of NOSENSOR, and can also
598 // enable 180 degree rotation while docked.
599 preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation;
600 } else if (hdmiPlugged && mDemoHdmiRotationLock) {
601 // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
602 // Note that the dock orientation overrides the HDMI orientation.
603 preferredRotation = mDemoHdmiRotation;
604 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
605 && mUndockedHdmiRotation >= 0) {
606 // Ignore sensor when plugged into HDMI and an undocked orientation has
607 // been specified in the configuration (only for legacy devices without
608 // full multi-display support).
609 // Note that the dock orientation overrides the HDMI orientation.
610 preferredRotation = mUndockedHdmiRotation;
611 } else if (mDemoRotationLock) {
612 // Ignore sensor when demo rotation lock is enabled.
613 // Note that the dock orientation and HDMI rotation lock override this.
614 preferredRotation = mDemoRotation;
615 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
616 // While in VR, apps always prefer a portrait rotation. This does not change
617 // any apps that explicitly set landscape, but does cause sensors be ignored,
618 // and ignored any orientation lock that the user has set (this conditional
619 // should remain above the ORIENTATION_LOCKED conditional below).
620 preferredRotation = mPortraitRotation;
621 } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
622 // Application just wants to remain locked in the last rotation.
623 preferredRotation = lastRotation;
624 } else if (!mSupportAutoRotation) {
625 // If we don't support auto-rotation then bail out here and ignore
626 // the sensor and any rotation lock settings.
627 preferredRotation = -1;
628 } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
629 && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
630 || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
631 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
632 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
633 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))
634 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
635 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
636 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
637 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
638 // Otherwise, use sensor only if requested by the application or enabled
639 // by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR.
640 if (mAllowAllRotations < 0) {
641 // Can't read this during init() because the context doesn't
642 // have display metrics at that time so we cannot determine
643 // tablet vs. phone then.
644 mAllowAllRotations = mContext.getResources().getBoolean(
645 com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;
646 }
647 if (sensorRotation != Surface.ROTATION_180
648 || mAllowAllRotations == 1
649 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
650 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
651 preferredRotation = sensorRotation;
652 } else {
653 preferredRotation = lastRotation;
654 }
655 } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
656 && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
657 // Apply rotation lock. Does not apply to NOSENSOR.
658 // The idea is that the user rotation expresses a weak preference for the direction
659 // of gravity and as NOSENSOR is never affected by gravity, then neither should
660 // NOSENSOR be affected by rotation lock (although it will be affected by docks).
661 preferredRotation = mUserRotation;
662 } else {
663 // No overriding preference.
664 // We will do exactly what the application asked us to do.
665 preferredRotation = -1;
666 }
667
Riddle Hsuad256a12018-07-18 16:11:30 +0800668 switch (orientation) {
669 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
670 // Return portrait unless overridden.
671 if (isAnyPortrait(preferredRotation)) {
672 return preferredRotation;
673 }
674 return mPortraitRotation;
675
676 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
677 // Return landscape unless overridden.
678 if (isLandscapeOrSeascape(preferredRotation)) {
679 return preferredRotation;
680 }
681 return mLandscapeRotation;
682
683 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
684 // Return reverse portrait unless overridden.
685 if (isAnyPortrait(preferredRotation)) {
686 return preferredRotation;
687 }
688 return mUpsideDownRotation;
689
690 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
691 // Return seascape unless overridden.
692 if (isLandscapeOrSeascape(preferredRotation)) {
693 return preferredRotation;
694 }
695 return mSeascapeRotation;
696
697 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
698 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
699 // Return either landscape rotation.
700 if (isLandscapeOrSeascape(preferredRotation)) {
701 return preferredRotation;
702 }
703 if (isLandscapeOrSeascape(lastRotation)) {
704 return lastRotation;
705 }
706 return mLandscapeRotation;
707
708 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
709 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
710 // Return either portrait rotation.
711 if (isAnyPortrait(preferredRotation)) {
712 return preferredRotation;
713 }
714 if (isAnyPortrait(lastRotation)) {
715 return lastRotation;
716 }
717 return mPortraitRotation;
718
719 default:
720 // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
721 // just return the preferred orientation we already calculated.
722 if (preferredRotation >= 0) {
723 return preferredRotation;
724 }
725 return Surface.ROTATION_0;
726 }
727 }
728
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800729 private boolean isLandscapeOrSeascape(int rotation) {
730 return rotation == mLandscapeRotation || rotation == mSeascapeRotation;
731 }
732
733 private boolean isAnyPortrait(int rotation) {
734 return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
735 }
736
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800737 private boolean isValidRotationChoice(final int preferredRotation) {
Riddle Hsuad256a12018-07-18 16:11:30 +0800738 // Determine if the given app orientation is compatible with the provided rotation choice.
739 switch (mCurrentAppOrientation) {
740 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
741 // Works with any of the 4 rotations.
742 return preferredRotation >= 0;
743
744 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
745 // It's possible for the user pref to be set at 180 because of FULL_USER. This would
746 // make switching to USER_PORTRAIT appear at 180. Provide choice to back to portrait
747 // but never to go to 180.
748 return preferredRotation == mPortraitRotation;
749
750 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
751 // Works landscape or seascape.
752 return isLandscapeOrSeascape(preferredRotation);
753
754 case ActivityInfo.SCREEN_ORIENTATION_USER:
755 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
756 // Works with any rotation except upside down.
757 return (preferredRotation >= 0) && (preferredRotation != mUpsideDownRotation);
758 }
759
760 return false;
761 }
762
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800763 private boolean isRotationChoicePossible(int orientation) {
764 // Rotation choice is only shown when the user is in locked mode.
765 if (mUserRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) return false;
766
767 // We should only enable rotation choice if the rotation isn't forced by the lid, dock,
768 // demo, hdmi, vr, etc mode.
769
770 // Determine if the rotation is currently forced.
Garfield Tan7fbca052019-02-19 10:45:35 -0800771 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800772 return false; // Rotation is forced to user settings.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800773 }
774
775 final int lidState = mDisplayPolicy.getLidState();
776 if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
777 return false; // Rotation is forced mLidOpenRotation.
778 }
779
780 final int dockMode = mDisplayPolicy.getDockMode();
781 final boolean carDockEnablesAccelerometer = false;
782 if (dockMode == Intent.EXTRA_DOCK_STATE_CAR && !carDockEnablesAccelerometer) {
783 return false; // Rotation forced to mCarDockRotation.
784 }
785
786 final boolean deskDockEnablesAccelerometer =
787 mDisplayPolicy.isDeskDockEnablesAccelerometer();
788 if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
789 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
790 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
791 && !deskDockEnablesAccelerometer) {
792 return false; // Rotation forced to mDeskDockRotation.
793 }
794
795 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
796 if (hdmiPlugged && mDemoHdmiRotationLock) {
797 return false; // Rotation forced to mDemoHdmiRotation.
798
799 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
800 && mUndockedHdmiRotation >= 0) {
801 return false; // Rotation forced to mUndockedHdmiRotation.
802
803 } else if (mDemoRotationLock) {
804 return false; // Rotation forced to mDemoRotation.
805
806 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
807 return false; // Rotation forced to mPortraitRotation.
808
809 } else if (!mSupportAutoRotation) {
810 return false;
811 }
812
813 // Ensure that some rotation choice is possible for the given orientation.
814 switch (orientation) {
815 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
816 case ActivityInfo.SCREEN_ORIENTATION_USER:
817 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
818 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
819 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
820 // NOSENSOR description is ambiguous, in reality WM ignores user choice.
821 return true;
822 }
823
824 // Rotation is forced, should be controlled by system.
825 return false;
Riddle Hsuad256a12018-07-18 16:11:30 +0800826 }
827
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800828 /** Notify the StatusBar that system rotation suggestion has changed. */
829 private void sendProposedRotationChangeToStatusBarInternal(int rotation, boolean isValid) {
830 if (mStatusBarManagerInternal == null) {
831 mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class);
832 }
833 if (mStatusBarManagerInternal != null) {
834 mStatusBarManagerInternal.onProposedRotationChanged(rotation, isValid);
835 }
836 }
837
838 private static String allowAllRotationsToString(int allowAll) {
839 switch (allowAll) {
840 case -1:
841 return "unknown";
842 case 0:
843 return "false";
844 case 1:
845 return "true";
846 default:
847 return Integer.toString(allowAll);
848 }
849 }
850
851 public void onUserSwitch() {
852 if (mSettingsObserver != null) {
853 mSettingsObserver.onChange(false);
854 }
855 }
856
857 /** Return whether the rotation settings has changed. */
858 private boolean updateSettings() {
859 final ContentResolver resolver = mContext.getContentResolver();
860 boolean shouldUpdateRotation = false;
861
862 synchronized (mLock) {
863 boolean shouldUpdateOrientationListener = false;
864
865 // Configure rotation suggestions.
Rajeev Kumarb2ff8e82018-08-06 11:45:05 -0700866 final int showRotationSuggestions =
867 ActivityManager.isLowRamDeviceStatic()
868 ? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED
869 : Settings.Secure.getIntForUser(resolver,
870 Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
871 Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
872 UserHandle.USER_CURRENT);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800873 if (mShowRotationSuggestions != showRotationSuggestions) {
874 mShowRotationSuggestions = showRotationSuggestions;
875 shouldUpdateOrientationListener = true;
876 }
877
878 // Configure rotation lock.
879 final int userRotation = Settings.System.getIntForUser(resolver,
880 Settings.System.USER_ROTATION, Surface.ROTATION_0,
881 UserHandle.USER_CURRENT);
882 if (mUserRotation != userRotation) {
883 mUserRotation = userRotation;
884 shouldUpdateRotation = true;
885 }
886
887 final int userRotationMode = Settings.System.getIntForUser(resolver,
888 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0
889 ? WindowManagerPolicy.USER_ROTATION_FREE
890 : WindowManagerPolicy.USER_ROTATION_LOCKED;
891 if (mUserRotationMode != userRotationMode) {
892 mUserRotationMode = userRotationMode;
893 shouldUpdateOrientationListener = true;
894 shouldUpdateRotation = true;
895 }
896
897 if (shouldUpdateOrientationListener) {
898 updateOrientationListenerLw(); // Enable or disable the orientation listener.
899 }
900 }
901
902 return shouldUpdateRotation;
Riddle Hsuad256a12018-07-18 16:11:30 +0800903 }
904
905 void dump(String prefix, PrintWriter pw) {
906 pw.println(prefix + "DisplayRotation");
907 pw.println(prefix + " mCurrentAppOrientation="
908 + ActivityInfo.screenOrientationToString(mCurrentAppOrientation));
909 pw.print(prefix + " mLandscapeRotation=" + Surface.rotationToString(mLandscapeRotation));
910 pw.println(" mSeascapeRotation=" + Surface.rotationToString(mSeascapeRotation));
911 pw.print(prefix + " mPortraitRotation=" + Surface.rotationToString(mPortraitRotation));
912 pw.println(" mUpsideDownRotation=" + Surface.rotationToString(mUpsideDownRotation));
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800913
Tiger Huang7c610aa2018-10-27 00:01:01 +0800914 pw.println(prefix + " mSupportAutoRotation=" + mSupportAutoRotation);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800915 if (mOrientationListener != null) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800916 mOrientationListener.dump(pw, prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800917 }
918 pw.println();
919
920 pw.print(prefix + " mCarDockRotation=" + Surface.rotationToString(mCarDockRotation));
921 pw.println(" mDeskDockRotation=" + Surface.rotationToString(mDeskDockRotation));
922 pw.print(prefix + " mUserRotationMode="
923 + WindowManagerPolicy.userRotationModeToString(mUserRotationMode));
924 pw.print(" mUserRotation=" + Surface.rotationToString(mUserRotation));
925 pw.println(" mAllowAllRotations=" + allowAllRotationsToString(mAllowAllRotations));
926
927 pw.print(prefix + " mDemoHdmiRotation=" + Surface.rotationToString(mDemoHdmiRotation));
928 pw.print(" mDemoHdmiRotationLock=" + mDemoHdmiRotationLock);
929 pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation));
930 pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation));
Garfield Tan7fbca052019-02-19 10:45:35 -0800931 pw.println(prefix + " mFixedToUserRotation=" + isFixedToUserRotation());
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800932 }
933
934 private class OrientationListener extends WindowOrientationListener {
935 final SparseArray<Runnable> mRunnableCache = new SparseArray<>(5);
936 boolean mEnabled;
937
938 OrientationListener(Context context, Handler handler) {
939 super(context, handler);
940 }
941
942 private class UpdateRunnable implements Runnable {
943 final int mRotation;
944
945 UpdateRunnable(int rotation) {
946 mRotation = rotation;
947 }
948
949 @Override
950 public void run() {
951 // Send interaction hint to improve redraw performance.
952 mService.mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
953 if (isRotationChoicePossible(mCurrentAppOrientation)) {
954 final boolean isValid = isValidRotationChoice(mRotation);
955 sendProposedRotationChangeToStatusBarInternal(mRotation, isValid);
956 } else {
957 mService.updateRotation(false /* alwaysSendConfiguration */,
958 false /* forceRelayout */);
959 }
960 }
961 }
962
963 @Override
964 public void onProposedRotationChanged(int rotation) {
965 if (DEBUG_ORIENTATION) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
966 Runnable r = mRunnableCache.get(rotation, null);
967 if (r == null) {
968 r = new UpdateRunnable(rotation);
969 mRunnableCache.put(rotation, r);
970 }
971 getHandler().post(r);
972 }
973
974 @Override
975 public void enable(boolean clearCurrentRotation) {
976 super.enable(clearCurrentRotation);
977 mEnabled = true;
978 if (DEBUG_ORIENTATION) Slog.v(TAG, "Enabling listeners");
979 }
980
981 @Override
982 public void disable() {
983 super.disable();
984 mEnabled = false;
985 if (DEBUG_ORIENTATION) Slog.v(TAG, "Disabling listeners");
986 }
987 }
988
989 private class SettingsObserver extends ContentObserver {
990 SettingsObserver(Handler handler) {
991 super(handler);
992 }
993
994 void observe() {
995 final ContentResolver resolver = mContext.getContentResolver();
996 resolver.registerContentObserver(Settings.Secure.getUriFor(
997 Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,
998 UserHandle.USER_ALL);
999 resolver.registerContentObserver(Settings.System.getUriFor(
1000 Settings.System.ACCELEROMETER_ROTATION), false, this,
1001 UserHandle.USER_ALL);
1002 resolver.registerContentObserver(Settings.System.getUriFor(
1003 Settings.System.USER_ROTATION), false, this,
1004 UserHandle.USER_ALL);
1005 updateSettings();
1006 }
1007
1008 @Override
1009 public void onChange(boolean selfChange) {
1010 if (updateSettings()) {
1011 mService.updateRotation(true /* alwaysSendConfiguration */,
1012 false /* forceRelayout */);
1013 }
1014 }
Riddle Hsuad256a12018-07-18 16:11:30 +08001015 }
Garfield Tanff362222018-11-14 17:52:32 -08001016
1017 @VisibleForTesting
1018 interface ContentObserverRegister {
1019 void registerContentObserver(Uri uri, boolean notifyForDescendants,
1020 ContentObserver observer, @UserIdInt int userHandle);
1021 }
Riddle Hsuad256a12018-07-18 16:11:30 +08001022}