blob: 410cc94869d882f5bc9445cebec676abdc0487b7 [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;
Riddle Hsuad256a12018-07-18 16:11:30 +080042import android.view.Surface;
43
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080044import com.android.internal.annotations.VisibleForTesting;
45import com.android.server.LocalServices;
46import com.android.server.UiThread;
Riddle Hsuad256a12018-07-18 16:11:30 +080047import com.android.server.policy.WindowManagerPolicy;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080048import com.android.server.policy.WindowOrientationListener;
49import com.android.server.statusbar.StatusBarManagerInternal;
Riddle Hsuad256a12018-07-18 16:11:30 +080050
51import java.io.PrintWriter;
Garfield Tan7fbca052019-02-19 10:45:35 -080052import java.lang.annotation.Retention;
53import java.lang.annotation.RetentionPolicy;
Riddle Hsuad256a12018-07-18 16:11:30 +080054
55/**
56 * Defines the mapping between orientation and rotation of a display.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080057 * Non-public methods are assumed to run inside WM lock.
Riddle Hsuad256a12018-07-18 16:11:30 +080058 */
59public class DisplayRotation {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080060 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayRotation" : TAG_WM;
Riddle Hsuad256a12018-07-18 16:11:30 +080061
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080062 private final WindowManagerService mService;
Garfield Tan90c90052018-10-08 12:29:41 -070063 private final DisplayContent mDisplayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080064 private final DisplayPolicy mDisplayPolicy;
Garfield Tanff362222018-11-14 17:52:32 -080065 private final DisplayWindowSettings mDisplayWindowSettings;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080066 private final Context mContext;
67 private final Object mLock;
68
69 public final boolean isDefaultDisplay;
70 private final boolean mSupportAutoRotation;
71 private final int mLidOpenRotation;
72 private final int mCarDockRotation;
73 private final int mDeskDockRotation;
74 private final int mUndockedHdmiRotation;
75
76 private OrientationListener mOrientationListener;
77 private StatusBarManagerInternal mStatusBarManagerInternal;
78 private SettingsObserver mSettingsObserver;
79
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080080 private int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
81
82 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +080083 int mLandscapeRotation; // default landscape
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080084 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +080085 int mSeascapeRotation; // "other" landscape, 180 degrees from mLandscapeRotation
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080086 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +080087 int mPortraitRotation; // default portrait
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080088 @VisibleForTesting
Riddle Hsuad256a12018-07-18 16:11:30 +080089 int mUpsideDownRotation; // "other" portrait
90
Riddle Hsu5ce4bb32018-07-18 16:11:30 +080091 // Behavior of rotation suggestions. (See Settings.Secure.SHOW_ROTATION_SUGGESTION)
92 private int mShowRotationSuggestions;
93
94 private int mAllowAllRotations = -1;
95 private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
96 private int mUserRotation = Surface.ROTATION_0;
97
Garfield Tanff362222018-11-14 17:52:32 -080098 /**
Garfield Tan7fbca052019-02-19 10:45:35 -080099 * Flag that indicates this is a display that may run better when fixed to user rotation.
100 */
101 private boolean mDefaultFixedToUserRotation;
102
103 /**
104 * No overridden behavior is provided in terms of fixing rotation to user rotation. Use other
105 * flags to derive the default behavior, such as {@link WindowManagerService#mIsPc} and
106 * {@link WindowManagerService#mForceDesktopModeOnExternalDisplays}.
107 */
108 static final int FIXED_TO_USER_ROTATION_DEFAULT = 0;
109 /**
110 * Don't fix display rotation to {@link #mUserRotation} only. Always allow other factors to play
111 * a role in deciding display rotation.
112 */
113 static final int FIXED_TO_USER_ROTATION_DISABLED = 1;
114 /**
115 * Only use {@link #mUserRotation} as the display rotation.
116 */
117 static final int FIXED_TO_USER_ROTATION_ENABLED = 2;
118 @IntDef({ FIXED_TO_USER_ROTATION_DEFAULT, FIXED_TO_USER_ROTATION_DISABLED,
119 FIXED_TO_USER_ROTATION_ENABLED })
120 @Retention(RetentionPolicy.SOURCE)
121 @interface FixedToUserRotation {}
122
123 /**
Garfield Tanff362222018-11-14 17:52:32 -0800124 * A flag to indicate if the display rotation should be fixed to user specified rotation
125 * regardless of all other states (including app requrested orientation). {@code true} the
126 * display rotation should be fixed to user specified rotation, {@code false} otherwise.
127 */
Garfield Tan7fbca052019-02-19 10:45:35 -0800128 private int mFixedToUserRotation = FIXED_TO_USER_ROTATION_DEFAULT;
Garfield Tanff362222018-11-14 17:52:32 -0800129
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800130 private int mDemoHdmiRotation;
131 private int mDemoRotation;
132 private boolean mDemoHdmiRotationLock;
133 private boolean mDemoRotationLock;
134
135 DisplayRotation(WindowManagerService service, DisplayContent displayContent) {
136 this(service, displayContent, displayContent.getDisplayPolicy(),
Garfield Tanff362222018-11-14 17:52:32 -0800137 service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
Riddle Hsuad256a12018-07-18 16:11:30 +0800138 }
139
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800140 @VisibleForTesting
141 DisplayRotation(WindowManagerService service, DisplayContent displayContent,
Garfield Tanff362222018-11-14 17:52:32 -0800142 DisplayPolicy displayPolicy, DisplayWindowSettings displayWindowSettings,
143 Context context, Object lock) {
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800144 mService = service;
Garfield Tan90c90052018-10-08 12:29:41 -0700145 mDisplayContent = displayContent;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800146 mDisplayPolicy = displayPolicy;
Garfield Tanff362222018-11-14 17:52:32 -0800147 mDisplayWindowSettings = displayWindowSettings;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800148 mContext = context;
149 mLock = lock;
150 isDefaultDisplay = displayContent.isDefaultDisplay;
Riddle Hsuad256a12018-07-18 16:11:30 +0800151
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800152 mSupportAutoRotation = mContext.getResources().getBoolean(
153 com.android.internal.R.bool.config_supportAutoRotation);
154 mLidOpenRotation = readRotation(
155 com.android.internal.R.integer.config_lidOpenRotation);
156 mCarDockRotation = readRotation(
157 com.android.internal.R.integer.config_carDockRotation);
158 mDeskDockRotation = readRotation(
159 com.android.internal.R.integer.config_deskDockRotation);
160 mUndockedHdmiRotation = readRotation(
161 com.android.internal.R.integer.config_undockedHdmiRotation);
162
163 if (isDefaultDisplay) {
164 final Handler uiHandler = UiThread.getHandler();
165 mOrientationListener = new OrientationListener(mContext, uiHandler);
166 mOrientationListener.setCurrentRotation(displayContent.getRotation());
167 mSettingsObserver = new SettingsObserver(uiHandler);
168 mSettingsObserver.observe();
169 }
170 }
171
172 private int readRotation(int resID) {
173 try {
174 final int rotation = mContext.getResources().getInteger(resID);
175 switch (rotation) {
176 case 0:
177 return Surface.ROTATION_0;
178 case 90:
179 return Surface.ROTATION_90;
180 case 180:
181 return Surface.ROTATION_180;
182 case 270:
183 return Surface.ROTATION_270;
184 }
185 } catch (Resources.NotFoundException e) {
186 // fall through
187 }
188 return -1;
189 }
190
191 void configure(int width, int height, int shortSizeDp, int longSizeDp) {
Riddle Hsuad256a12018-07-18 16:11:30 +0800192 final Resources res = mContext.getResources();
193 if (width > height) {
194 mLandscapeRotation = Surface.ROTATION_0;
195 mSeascapeRotation = Surface.ROTATION_180;
196 if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
197 mPortraitRotation = Surface.ROTATION_90;
198 mUpsideDownRotation = Surface.ROTATION_270;
199 } else {
200 mPortraitRotation = Surface.ROTATION_270;
201 mUpsideDownRotation = Surface.ROTATION_90;
202 }
203 } else {
204 mPortraitRotation = Surface.ROTATION_0;
205 mUpsideDownRotation = Surface.ROTATION_180;
206 if (res.getBoolean(com.android.internal.R.bool.config_reverseDefaultRotation)) {
207 mLandscapeRotation = Surface.ROTATION_270;
208 mSeascapeRotation = Surface.ROTATION_90;
209 } else {
210 mLandscapeRotation = Surface.ROTATION_90;
211 mSeascapeRotation = Surface.ROTATION_270;
212 }
213 }
214
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800215 // For demo purposes, allow the rotation of the HDMI display to be controlled.
216 // By default, HDMI locks rotation to landscape.
217 if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
218 mDemoHdmiRotation = mPortraitRotation;
219 } else {
220 mDemoHdmiRotation = mLandscapeRotation;
221 }
222 mDemoHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", false);
223
224 // For demo purposes, allow the rotation of the remote display to be controlled.
225 // By default, remote display locks rotation to landscape.
226 if ("portrait".equals(SystemProperties.get("persist.demo.remoterotation"))) {
227 mDemoRotation = mPortraitRotation;
228 } else {
229 mDemoRotation = mLandscapeRotation;
230 }
231 mDemoRotationLock = SystemProperties.getBoolean("persist.demo.rotationlock", false);
232
Garfield Tan12b12f7a2019-02-22 16:33:27 -0800233 // It's physically impossible to rotate the car's screen.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800234 final boolean isCar = mContext.getPackageManager().hasSystemFeature(
235 PackageManager.FEATURE_AUTOMOTIVE);
Garfield Tan12b12f7a2019-02-22 16:33:27 -0800236 // It's also not likely to rotate a TV screen.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800237 final boolean isTv = mContext.getPackageManager().hasSystemFeature(
238 PackageManager.FEATURE_LEANBACK);
Garfield Tan7fbca052019-02-19 10:45:35 -0800239 final boolean forceDesktopMode =
240 mService.mForceDesktopModeOnExternalDisplays && !isDefaultDisplay;
241 mDefaultFixedToUserRotation =
Tiger Huang86e6d072019-05-02 20:23:47 +0800242 (isCar || isTv || mService.mIsPc || forceDesktopMode)
Garfield Tan7fbca052019-02-19 10:45:35 -0800243 // For debug purposes the next line turns this feature off with:
244 // $ adb shell setprop config.override_forced_orient true
245 // $ adb shell wm size reset
246 && !"true".equals(SystemProperties.get("config.override_forced_orient"));
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800247 }
248
249 void setRotation(int rotation) {
250 if (mOrientationListener != null) {
251 mOrientationListener.setCurrentRotation(rotation);
252 }
253 }
254
255 void setCurrentOrientation(int newOrientation) {
256 if (newOrientation != mCurrentAppOrientation) {
257 mCurrentAppOrientation = newOrientation;
258 if (isDefaultDisplay) {
259 updateOrientationListenerLw();
260 }
261 }
262 }
263
Garfield Tanff362222018-11-14 17:52:32 -0800264 void restoreSettings(int userRotationMode, int userRotation,
Garfield Tan7fbca052019-02-19 10:45:35 -0800265 @FixedToUserRotation int fixedToUserRotation) {
Garfield Tanff362222018-11-14 17:52:32 -0800266 mFixedToUserRotation = fixedToUserRotation;
267
268 // We will retrieve user rotation and user rotation mode from settings for default display.
269 if (isDefaultDisplay) {
270 return;
271 }
Garfield Tan90c90052018-10-08 12:29:41 -0700272 if (userRotationMode != WindowManagerPolicy.USER_ROTATION_FREE
273 && userRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) {
274 Slog.w(TAG, "Trying to restore an invalid user rotation mode " + userRotationMode
275 + " for " + mDisplayContent);
276 userRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
277 }
278 if (userRotation < Surface.ROTATION_0 || userRotation > Surface.ROTATION_270) {
279 Slog.w(TAG, "Trying to restore an invalid user rotation " + userRotation
280 + " for " + mDisplayContent);
281 userRotation = Surface.ROTATION_0;
282 }
283 mUserRotationMode = userRotationMode;
284 mUserRotation = userRotation;
285 }
286
Garfield Tan7fbca052019-02-19 10:45:35 -0800287 void setFixedToUserRotation(@FixedToUserRotation int fixedToUserRotation) {
Garfield Tanff362222018-11-14 17:52:32 -0800288 if (mFixedToUserRotation == fixedToUserRotation) {
289 return;
290 }
291
292 mFixedToUserRotation = fixedToUserRotation;
Garfield Tan7fbca052019-02-19 10:45:35 -0800293 mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent, fixedToUserRotation);
Garfield Tanff362222018-11-14 17:52:32 -0800294 mService.updateRotation(true /* alwaysSendConfiguration */,
295 false /* forceRelayout */);
296 }
297
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700298 @VisibleForTesting
299 void setUserRotation(int userRotationMode, int userRotation) {
Garfield Tan90c90052018-10-08 12:29:41 -0700300 if (isDefaultDisplay) {
301 // We'll be notified via settings listener, so we don't need to update internal values.
302 final ContentResolver res = mContext.getContentResolver();
303 final int accelerometerRotation =
304 userRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED ? 0 : 1;
305 Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION,
306 accelerometerRotation, UserHandle.USER_CURRENT);
307 Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation,
308 UserHandle.USER_CURRENT);
309 return;
310 }
311
312 boolean changed = false;
313 if (mUserRotationMode != userRotationMode) {
314 mUserRotationMode = userRotationMode;
315 changed = true;
316 }
317 if (mUserRotation != userRotation) {
318 mUserRotation = userRotation;
319 changed = true;
320 }
Garfield Tanff362222018-11-14 17:52:32 -0800321 mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode,
Chilun8753ad32018-10-09 15:56:45 +0800322 userRotation);
Garfield Tan90c90052018-10-08 12:29:41 -0700323 if (changed) {
324 mService.updateRotation(true /* alwaysSendConfiguration */,
325 false /* forceRelayout */);
Garfield Tan90c90052018-10-08 12:29:41 -0700326 }
327 }
328
329 void freezeRotation(int rotation) {
330 rotation = (rotation == -1) ? mDisplayContent.getRotation() : rotation;
331 setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation);
332 }
333
334 void thawRotation() {
335 setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation);
336 }
337
338 boolean isRotationFrozen() {
339 if (!isDefaultDisplay) {
340 return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED;
341 }
342
343 return Settings.System.getIntForUser(mContext.getContentResolver(),
344 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0;
345 }
346
Garfield Tanff362222018-11-14 17:52:32 -0800347 boolean isFixedToUserRotation() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800348 switch (mFixedToUserRotation) {
349 case FIXED_TO_USER_ROTATION_DISABLED:
350 return false;
351 case FIXED_TO_USER_ROTATION_ENABLED:
352 return true;
353 default:
354 return mDefaultFixedToUserRotation;
355 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800356 }
357
Garfield Tan49dae102019-02-04 09:51:59 -0800358 /**
359 * Returns {@code true} if this display rotation takes app requested orientation into
360 * consideration; {@code false} otherwise. For the time being the only case where this is {@code
361 * false} is when {@link #isFixedToUserRotation()} is {@code true}.
362 */
363 boolean respectAppRequestedOrientation() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800364 return !isFixedToUserRotation();
Garfield Tan49dae102019-02-04 09:51:59 -0800365 }
366
Riddle Hsuad256a12018-07-18 16:11:30 +0800367 public int getLandscapeRotation() {
368 return mLandscapeRotation;
369 }
370
371 public int getSeascapeRotation() {
372 return mSeascapeRotation;
373 }
374
375 public int getPortraitRotation() {
376 return mPortraitRotation;
377 }
378
379 public int getUpsideDownRotation() {
380 return mUpsideDownRotation;
381 }
382
383 public int getCurrentAppOrientation() {
384 return mCurrentAppOrientation;
385 }
386
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800387 public DisplayPolicy getDisplayPolicy() {
388 return mDisplayPolicy;
Riddle Hsuad256a12018-07-18 16:11:30 +0800389 }
390
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800391 public WindowOrientationListener getOrientationListener() {
392 return mOrientationListener;
Riddle Hsuad256a12018-07-18 16:11:30 +0800393 }
394
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800395 public int getUserRotation() {
396 return mUserRotation;
397 }
398
399 public int getUserRotationMode() {
400 return mUserRotationMode;
401 }
402
403 public void updateOrientationListener() {
404 synchronized (mLock) {
405 updateOrientationListenerLw();
Riddle Hsuad256a12018-07-18 16:11:30 +0800406 }
407 }
408
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800409 /**
410 * Various use cases for invoking this function:
411 * <li>Screen turning off, should always disable listeners if already enabled.</li>
412 * <li>Screen turned on and current app has sensor based orientation, enable listeners
413 * if not already enabled.</li>
414 * <li>Screen turned on and current app does not have sensor orientation, disable listeners
415 * if already enabled.</li>
416 * <li>Screen turning on and current app has sensor based orientation, enable listeners
417 * if needed.</li>
418 * <li>screen turning on and current app has nosensor based orientation, do nothing.</li>
419 */
420 private void updateOrientationListenerLw() {
421 if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {
422 // If sensor is turned off or nonexistent for some reason.
423 return;
424 }
425
426 final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();
427 final boolean awake = mDisplayPolicy.isAwake();
428 final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();
429 final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();
430
431 // Could have been invoked due to screen turning on or off or
432 // change of the currently visible window's orientation.
433 if (DEBUG_ORIENTATION) Slog.v(TAG, "screenOnEarly=" + screenOnEarly
434 + ", awake=" + awake + ", currentAppOrientation=" + mCurrentAppOrientation
435 + ", orientationSensorEnabled=" + mOrientationListener.mEnabled
436 + ", keyguardDrawComplete=" + keyguardDrawComplete
437 + ", windowManagerDrawComplete=" + windowManagerDrawComplete);
438
439 boolean disable = true;
440 // Note: We postpone the rotating of the screen until the keyguard as well as the
441 // window manager have reported a draw complete or the keyguard is going away in dismiss
442 // mode.
443 if (screenOnEarly && awake && ((keyguardDrawComplete && windowManagerDrawComplete))) {
444 if (needSensorRunning()) {
445 disable = false;
446 // Enable listener if not already enabled.
447 if (!mOrientationListener.mEnabled) {
448 // Don't clear the current sensor orientation if the keyguard is going away in
449 // dismiss mode. This allows window manager to use the last sensor reading to
450 // determine the orientation vs. falling back to the last known orientation if
451 // the sensor reading was cleared which can cause it to relaunch the app that
452 // will show in the wrong orientation first before correcting leading to app
453 // launch delays.
454 mOrientationListener.enable(true /* clearCurrentRotation */);
455 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800456 }
457 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800458 // Check if sensors need to be disabled.
459 if (disable && mOrientationListener.mEnabled) {
460 mOrientationListener.disable();
461 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800462 }
463
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800464 /**
465 * We always let the sensor be switched on by default except when
466 * the user has explicitly disabled sensor based rotation or when the
467 * screen is switched off.
468 */
469 private boolean needSensorRunning() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800470 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800471 // We are sure we only respect user rotation settings, so we are sure we will not
472 // support sensor rotation.
473 return false;
474 }
475
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800476 if (mSupportAutoRotation) {
477 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
478 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
479 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
480 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
481 // If the application has explicitly requested to follow the
482 // orientation, then we need to turn the sensor on.
483 return true;
484 }
485 }
486
487 final int dockMode = mDisplayPolicy.getDockMode();
488 if ((mDisplayPolicy.isCarDockEnablesAccelerometer()
489 && dockMode == Intent.EXTRA_DOCK_STATE_CAR)
490 || (mDisplayPolicy.isDeskDockEnablesAccelerometer()
491 && (dockMode == Intent.EXTRA_DOCK_STATE_DESK
492 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
493 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) {
494 // Enable accelerometer if we are docked in a dock that enables accelerometer
495 // orientation management.
496 return true;
497 }
498
499 if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
500 // If the setting for using the sensor by default is enabled, then
501 // we will always leave it on. Note that the user could go to
502 // a window that forces an orientation that does not use the
503 // sensor and in theory we could turn it off... however, when next
504 // turning it on we won't have a good value for the current
505 // orientation for a little bit, which can cause orientation
506 // changes to lag, so we'd like to keep it always on. (It will
507 // still be turned off when the screen is off.)
508
509 // When locked we can provide rotation suggestions users can approve to change the
510 // current screen rotation. To do this the sensor needs to be running.
511 return mSupportAutoRotation &&
512 mShowRotationSuggestions == Settings.Secure.SHOW_ROTATION_SUGGESTIONS_ENABLED;
513 }
514 return mSupportAutoRotation;
515 }
516
517 /**
518 * Given an orientation constant, returns the appropriate surface rotation,
519 * taking into account sensors, docking mode, rotation lock, and other factors.
520 *
521 * @param orientation An orientation constant, such as
522 * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
523 * @param lastRotation The most recently used rotation.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800524 * @return The surface rotation to use.
525 */
526 int rotationForOrientation(int orientation, int lastRotation) {
527 if (DEBUG_ORIENTATION) {
528 Slog.v(TAG, "rotationForOrientation(orient="
529 + orientation + ", last=" + lastRotation
530 + "); user=" + mUserRotation + " "
531 + (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
532 ? "USER_ROTATION_LOCKED" : "")
533 );
534 }
535
Garfield Tan7fbca052019-02-19 10:45:35 -0800536 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800537 return mUserRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800538 }
539
540 int sensorRotation = mOrientationListener != null
541 ? mOrientationListener.getProposedRotation() // may be -1
542 : -1;
543 if (sensorRotation < 0) {
544 sensorRotation = lastRotation;
545 }
546
547 final int lidState = mDisplayPolicy.getLidState();
548 final int dockMode = mDisplayPolicy.getDockMode();
549 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
550 final boolean carDockEnablesAccelerometer =
551 mDisplayPolicy.isCarDockEnablesAccelerometer();
552 final boolean deskDockEnablesAccelerometer =
553 mDisplayPolicy.isDeskDockEnablesAccelerometer();
554
555 final int preferredRotation;
556 if (!isDefaultDisplay) {
557 // For secondary displays we ignore things like displays sensors, docking mode and
Garfield Tan90c90052018-10-08 12:29:41 -0700558 // rotation lock, and always prefer user rotation.
559 preferredRotation = mUserRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800560 } else if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
561 // Ignore sensor when lid switch is open and rotation is forced.
562 preferredRotation = mLidOpenRotation;
563 } else if (dockMode == Intent.EXTRA_DOCK_STATE_CAR
564 && (carDockEnablesAccelerometer || mCarDockRotation >= 0)) {
565 // Ignore sensor when in car dock unless explicitly enabled.
566 // This case can override the behavior of NOSENSOR, and can also
567 // enable 180 degree rotation while docked.
568 preferredRotation = carDockEnablesAccelerometer ? sensorRotation : mCarDockRotation;
569 } else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
570 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
571 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
572 && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
573 // Ignore sensor when in desk dock unless explicitly enabled.
574 // This case can override the behavior of NOSENSOR, and can also
575 // enable 180 degree rotation while docked.
576 preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation;
577 } else if (hdmiPlugged && mDemoHdmiRotationLock) {
578 // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
579 // Note that the dock orientation overrides the HDMI orientation.
580 preferredRotation = mDemoHdmiRotation;
581 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
582 && mUndockedHdmiRotation >= 0) {
583 // Ignore sensor when plugged into HDMI and an undocked orientation has
584 // been specified in the configuration (only for legacy devices without
585 // full multi-display support).
586 // Note that the dock orientation overrides the HDMI orientation.
587 preferredRotation = mUndockedHdmiRotation;
588 } else if (mDemoRotationLock) {
589 // Ignore sensor when demo rotation lock is enabled.
590 // Note that the dock orientation and HDMI rotation lock override this.
591 preferredRotation = mDemoRotation;
592 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
593 // While in VR, apps always prefer a portrait rotation. This does not change
594 // any apps that explicitly set landscape, but does cause sensors be ignored,
595 // and ignored any orientation lock that the user has set (this conditional
596 // should remain above the ORIENTATION_LOCKED conditional below).
597 preferredRotation = mPortraitRotation;
598 } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
599 // Application just wants to remain locked in the last rotation.
600 preferredRotation = lastRotation;
601 } else if (!mSupportAutoRotation) {
602 // If we don't support auto-rotation then bail out here and ignore
603 // the sensor and any rotation lock settings.
604 preferredRotation = -1;
605 } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
606 && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
607 || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
608 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
609 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
610 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))
611 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
612 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
613 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
614 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
615 // Otherwise, use sensor only if requested by the application or enabled
616 // by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR.
617 if (mAllowAllRotations < 0) {
618 // Can't read this during init() because the context doesn't
619 // have display metrics at that time so we cannot determine
620 // tablet vs. phone then.
621 mAllowAllRotations = mContext.getResources().getBoolean(
622 com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;
623 }
624 if (sensorRotation != Surface.ROTATION_180
625 || mAllowAllRotations == 1
626 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
627 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
628 preferredRotation = sensorRotation;
629 } else {
630 preferredRotation = lastRotation;
631 }
632 } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
633 && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
634 // Apply rotation lock. Does not apply to NOSENSOR.
635 // The idea is that the user rotation expresses a weak preference for the direction
636 // of gravity and as NOSENSOR is never affected by gravity, then neither should
637 // NOSENSOR be affected by rotation lock (although it will be affected by docks).
638 preferredRotation = mUserRotation;
639 } else {
640 // No overriding preference.
641 // We will do exactly what the application asked us to do.
642 preferredRotation = -1;
643 }
644
Riddle Hsuad256a12018-07-18 16:11:30 +0800645 switch (orientation) {
646 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
647 // Return portrait unless overridden.
648 if (isAnyPortrait(preferredRotation)) {
649 return preferredRotation;
650 }
651 return mPortraitRotation;
652
653 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
654 // Return landscape unless overridden.
655 if (isLandscapeOrSeascape(preferredRotation)) {
656 return preferredRotation;
657 }
658 return mLandscapeRotation;
659
660 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
661 // Return reverse portrait unless overridden.
662 if (isAnyPortrait(preferredRotation)) {
663 return preferredRotation;
664 }
665 return mUpsideDownRotation;
666
667 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
668 // Return seascape unless overridden.
669 if (isLandscapeOrSeascape(preferredRotation)) {
670 return preferredRotation;
671 }
672 return mSeascapeRotation;
673
674 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
675 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
676 // Return either landscape rotation.
677 if (isLandscapeOrSeascape(preferredRotation)) {
678 return preferredRotation;
679 }
680 if (isLandscapeOrSeascape(lastRotation)) {
681 return lastRotation;
682 }
683 return mLandscapeRotation;
684
685 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
686 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
687 // Return either portrait rotation.
688 if (isAnyPortrait(preferredRotation)) {
689 return preferredRotation;
690 }
691 if (isAnyPortrait(lastRotation)) {
692 return lastRotation;
693 }
694 return mPortraitRotation;
695
696 default:
697 // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
698 // just return the preferred orientation we already calculated.
699 if (preferredRotation >= 0) {
700 return preferredRotation;
701 }
702 return Surface.ROTATION_0;
703 }
704 }
705
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800706 private boolean isLandscapeOrSeascape(int rotation) {
707 return rotation == mLandscapeRotation || rotation == mSeascapeRotation;
708 }
709
710 private boolean isAnyPortrait(int rotation) {
711 return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
712 }
713
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800714 private boolean isValidRotationChoice(final int preferredRotation) {
Riddle Hsuad256a12018-07-18 16:11:30 +0800715 // Determine if the given app orientation is compatible with the provided rotation choice.
716 switch (mCurrentAppOrientation) {
717 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
718 // Works with any of the 4 rotations.
719 return preferredRotation >= 0;
720
721 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
722 // It's possible for the user pref to be set at 180 because of FULL_USER. This would
723 // make switching to USER_PORTRAIT appear at 180. Provide choice to back to portrait
724 // but never to go to 180.
725 return preferredRotation == mPortraitRotation;
726
727 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
728 // Works landscape or seascape.
729 return isLandscapeOrSeascape(preferredRotation);
730
731 case ActivityInfo.SCREEN_ORIENTATION_USER:
732 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
733 // Works with any rotation except upside down.
734 return (preferredRotation >= 0) && (preferredRotation != mUpsideDownRotation);
735 }
736
737 return false;
738 }
739
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800740 private boolean isRotationChoicePossible(int orientation) {
741 // Rotation choice is only shown when the user is in locked mode.
742 if (mUserRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) return false;
743
744 // We should only enable rotation choice if the rotation isn't forced by the lid, dock,
745 // demo, hdmi, vr, etc mode.
746
747 // Determine if the rotation is currently forced.
Garfield Tan7fbca052019-02-19 10:45:35 -0800748 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800749 return false; // Rotation is forced to user settings.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800750 }
751
752 final int lidState = mDisplayPolicy.getLidState();
753 if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
754 return false; // Rotation is forced mLidOpenRotation.
755 }
756
757 final int dockMode = mDisplayPolicy.getDockMode();
758 final boolean carDockEnablesAccelerometer = false;
759 if (dockMode == Intent.EXTRA_DOCK_STATE_CAR && !carDockEnablesAccelerometer) {
760 return false; // Rotation forced to mCarDockRotation.
761 }
762
763 final boolean deskDockEnablesAccelerometer =
764 mDisplayPolicy.isDeskDockEnablesAccelerometer();
765 if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
766 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
767 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
768 && !deskDockEnablesAccelerometer) {
769 return false; // Rotation forced to mDeskDockRotation.
770 }
771
772 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
773 if (hdmiPlugged && mDemoHdmiRotationLock) {
774 return false; // Rotation forced to mDemoHdmiRotation.
775
776 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
777 && mUndockedHdmiRotation >= 0) {
778 return false; // Rotation forced to mUndockedHdmiRotation.
779
780 } else if (mDemoRotationLock) {
781 return false; // Rotation forced to mDemoRotation.
782
783 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
784 return false; // Rotation forced to mPortraitRotation.
785
786 } else if (!mSupportAutoRotation) {
787 return false;
788 }
789
790 // Ensure that some rotation choice is possible for the given orientation.
791 switch (orientation) {
792 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
793 case ActivityInfo.SCREEN_ORIENTATION_USER:
794 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
795 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
796 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
797 // NOSENSOR description is ambiguous, in reality WM ignores user choice.
798 return true;
799 }
800
801 // Rotation is forced, should be controlled by system.
802 return false;
Riddle Hsuad256a12018-07-18 16:11:30 +0800803 }
804
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800805 /** Notify the StatusBar that system rotation suggestion has changed. */
806 private void sendProposedRotationChangeToStatusBarInternal(int rotation, boolean isValid) {
807 if (mStatusBarManagerInternal == null) {
808 mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class);
809 }
810 if (mStatusBarManagerInternal != null) {
811 mStatusBarManagerInternal.onProposedRotationChanged(rotation, isValid);
812 }
813 }
814
815 private static String allowAllRotationsToString(int allowAll) {
816 switch (allowAll) {
817 case -1:
818 return "unknown";
819 case 0:
820 return "false";
821 case 1:
822 return "true";
823 default:
824 return Integer.toString(allowAll);
825 }
826 }
827
828 public void onUserSwitch() {
829 if (mSettingsObserver != null) {
830 mSettingsObserver.onChange(false);
831 }
832 }
833
834 /** Return whether the rotation settings has changed. */
835 private boolean updateSettings() {
836 final ContentResolver resolver = mContext.getContentResolver();
837 boolean shouldUpdateRotation = false;
838
839 synchronized (mLock) {
840 boolean shouldUpdateOrientationListener = false;
841
842 // Configure rotation suggestions.
Rajeev Kumarb2ff8e82018-08-06 11:45:05 -0700843 final int showRotationSuggestions =
844 ActivityManager.isLowRamDeviceStatic()
845 ? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED
846 : Settings.Secure.getIntForUser(resolver,
847 Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
848 Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
849 UserHandle.USER_CURRENT);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800850 if (mShowRotationSuggestions != showRotationSuggestions) {
851 mShowRotationSuggestions = showRotationSuggestions;
852 shouldUpdateOrientationListener = true;
853 }
854
855 // Configure rotation lock.
856 final int userRotation = Settings.System.getIntForUser(resolver,
857 Settings.System.USER_ROTATION, Surface.ROTATION_0,
858 UserHandle.USER_CURRENT);
859 if (mUserRotation != userRotation) {
860 mUserRotation = userRotation;
861 shouldUpdateRotation = true;
862 }
863
864 final int userRotationMode = Settings.System.getIntForUser(resolver,
865 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0
866 ? WindowManagerPolicy.USER_ROTATION_FREE
867 : WindowManagerPolicy.USER_ROTATION_LOCKED;
868 if (mUserRotationMode != userRotationMode) {
869 mUserRotationMode = userRotationMode;
870 shouldUpdateOrientationListener = true;
871 shouldUpdateRotation = true;
872 }
873
874 if (shouldUpdateOrientationListener) {
875 updateOrientationListenerLw(); // Enable or disable the orientation listener.
876 }
877 }
878
879 return shouldUpdateRotation;
Riddle Hsuad256a12018-07-18 16:11:30 +0800880 }
881
882 void dump(String prefix, PrintWriter pw) {
883 pw.println(prefix + "DisplayRotation");
884 pw.println(prefix + " mCurrentAppOrientation="
885 + ActivityInfo.screenOrientationToString(mCurrentAppOrientation));
886 pw.print(prefix + " mLandscapeRotation=" + Surface.rotationToString(mLandscapeRotation));
887 pw.println(" mSeascapeRotation=" + Surface.rotationToString(mSeascapeRotation));
888 pw.print(prefix + " mPortraitRotation=" + Surface.rotationToString(mPortraitRotation));
889 pw.println(" mUpsideDownRotation=" + Surface.rotationToString(mUpsideDownRotation));
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800890
Tiger Huang7c610aa2018-10-27 00:01:01 +0800891 pw.println(prefix + " mSupportAutoRotation=" + mSupportAutoRotation);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800892 if (mOrientationListener != null) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800893 mOrientationListener.dump(pw, prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800894 }
895 pw.println();
896
897 pw.print(prefix + " mCarDockRotation=" + Surface.rotationToString(mCarDockRotation));
898 pw.println(" mDeskDockRotation=" + Surface.rotationToString(mDeskDockRotation));
899 pw.print(prefix + " mUserRotationMode="
900 + WindowManagerPolicy.userRotationModeToString(mUserRotationMode));
901 pw.print(" mUserRotation=" + Surface.rotationToString(mUserRotation));
902 pw.println(" mAllowAllRotations=" + allowAllRotationsToString(mAllowAllRotations));
903
904 pw.print(prefix + " mDemoHdmiRotation=" + Surface.rotationToString(mDemoHdmiRotation));
905 pw.print(" mDemoHdmiRotationLock=" + mDemoHdmiRotationLock);
906 pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation));
907 pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation));
Garfield Tan7fbca052019-02-19 10:45:35 -0800908 pw.println(prefix + " mFixedToUserRotation=" + isFixedToUserRotation());
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800909 }
910
911 private class OrientationListener extends WindowOrientationListener {
912 final SparseArray<Runnable> mRunnableCache = new SparseArray<>(5);
913 boolean mEnabled;
914
915 OrientationListener(Context context, Handler handler) {
916 super(context, handler);
917 }
918
919 private class UpdateRunnable implements Runnable {
920 final int mRotation;
921
922 UpdateRunnable(int rotation) {
923 mRotation = rotation;
924 }
925
926 @Override
927 public void run() {
928 // Send interaction hint to improve redraw performance.
929 mService.mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
930 if (isRotationChoicePossible(mCurrentAppOrientation)) {
931 final boolean isValid = isValidRotationChoice(mRotation);
932 sendProposedRotationChangeToStatusBarInternal(mRotation, isValid);
933 } else {
934 mService.updateRotation(false /* alwaysSendConfiguration */,
935 false /* forceRelayout */);
936 }
937 }
938 }
939
940 @Override
941 public void onProposedRotationChanged(int rotation) {
942 if (DEBUG_ORIENTATION) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
943 Runnable r = mRunnableCache.get(rotation, null);
944 if (r == null) {
945 r = new UpdateRunnable(rotation);
946 mRunnableCache.put(rotation, r);
947 }
948 getHandler().post(r);
949 }
950
951 @Override
952 public void enable(boolean clearCurrentRotation) {
953 super.enable(clearCurrentRotation);
954 mEnabled = true;
955 if (DEBUG_ORIENTATION) Slog.v(TAG, "Enabling listeners");
956 }
957
958 @Override
959 public void disable() {
960 super.disable();
961 mEnabled = false;
962 if (DEBUG_ORIENTATION) Slog.v(TAG, "Disabling listeners");
963 }
964 }
965
966 private class SettingsObserver extends ContentObserver {
967 SettingsObserver(Handler handler) {
968 super(handler);
969 }
970
971 void observe() {
972 final ContentResolver resolver = mContext.getContentResolver();
973 resolver.registerContentObserver(Settings.Secure.getUriFor(
974 Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,
975 UserHandle.USER_ALL);
976 resolver.registerContentObserver(Settings.System.getUriFor(
977 Settings.System.ACCELEROMETER_ROTATION), false, this,
978 UserHandle.USER_ALL);
979 resolver.registerContentObserver(Settings.System.getUriFor(
980 Settings.System.USER_ROTATION), false, this,
981 UserHandle.USER_ALL);
982 updateSettings();
983 }
984
985 @Override
986 public void onChange(boolean selfChange) {
987 if (updateSettings()) {
988 mService.updateRotation(true /* alwaysSendConfiguration */,
989 false /* forceRelayout */);
990 }
991 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800992 }
Garfield Tanff362222018-11-14 17:52:32 -0800993
994 @VisibleForTesting
995 interface ContentObserverRegister {
996 void registerContentObserver(Uri uri, boolean notifyForDescendants,
997 ContentObserver observer, @UserIdInt int userHandle);
998 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800999}