blob: 282ed42468ddfe98e25b3d199fe1a9eeb281be81 [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
Garfield Tan90c90052018-10-08 12:29:41 -0700298 private void setUserRotation(int userRotationMode, int userRotation) {
299 if (isDefaultDisplay) {
300 // We'll be notified via settings listener, so we don't need to update internal values.
301 final ContentResolver res = mContext.getContentResolver();
302 final int accelerometerRotation =
303 userRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED ? 0 : 1;
304 Settings.System.putIntForUser(res, Settings.System.ACCELEROMETER_ROTATION,
305 accelerometerRotation, UserHandle.USER_CURRENT);
306 Settings.System.putIntForUser(res, Settings.System.USER_ROTATION, userRotation,
307 UserHandle.USER_CURRENT);
308 return;
309 }
310
311 boolean changed = false;
312 if (mUserRotationMode != userRotationMode) {
313 mUserRotationMode = userRotationMode;
314 changed = true;
315 }
316 if (mUserRotation != userRotation) {
317 mUserRotation = userRotation;
318 changed = true;
319 }
Garfield Tanff362222018-11-14 17:52:32 -0800320 mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode,
Chilun8753ad32018-10-09 15:56:45 +0800321 userRotation);
Garfield Tan90c90052018-10-08 12:29:41 -0700322 if (changed) {
323 mService.updateRotation(true /* alwaysSendConfiguration */,
324 false /* forceRelayout */);
Garfield Tan90c90052018-10-08 12:29:41 -0700325 }
326 }
327
328 void freezeRotation(int rotation) {
329 rotation = (rotation == -1) ? mDisplayContent.getRotation() : rotation;
330 setUserRotation(WindowManagerPolicy.USER_ROTATION_LOCKED, rotation);
331 }
332
333 void thawRotation() {
334 setUserRotation(WindowManagerPolicy.USER_ROTATION_FREE, mUserRotation);
335 }
336
337 boolean isRotationFrozen() {
338 if (!isDefaultDisplay) {
339 return mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED;
340 }
341
342 return Settings.System.getIntForUser(mContext.getContentResolver(),
343 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0;
344 }
345
Garfield Tanff362222018-11-14 17:52:32 -0800346 boolean isFixedToUserRotation() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800347 switch (mFixedToUserRotation) {
348 case FIXED_TO_USER_ROTATION_DISABLED:
349 return false;
350 case FIXED_TO_USER_ROTATION_ENABLED:
351 return true;
352 default:
353 return mDefaultFixedToUserRotation;
354 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800355 }
356
Garfield Tan49dae102019-02-04 09:51:59 -0800357 /**
358 * Returns {@code true} if this display rotation takes app requested orientation into
359 * consideration; {@code false} otherwise. For the time being the only case where this is {@code
360 * false} is when {@link #isFixedToUserRotation()} is {@code true}.
361 */
362 boolean respectAppRequestedOrientation() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800363 return !isFixedToUserRotation();
Garfield Tan49dae102019-02-04 09:51:59 -0800364 }
365
Riddle Hsuad256a12018-07-18 16:11:30 +0800366 public int getLandscapeRotation() {
367 return mLandscapeRotation;
368 }
369
370 public int getSeascapeRotation() {
371 return mSeascapeRotation;
372 }
373
374 public int getPortraitRotation() {
375 return mPortraitRotation;
376 }
377
378 public int getUpsideDownRotation() {
379 return mUpsideDownRotation;
380 }
381
382 public int getCurrentAppOrientation() {
383 return mCurrentAppOrientation;
384 }
385
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800386 public DisplayPolicy getDisplayPolicy() {
387 return mDisplayPolicy;
Riddle Hsuad256a12018-07-18 16:11:30 +0800388 }
389
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800390 public WindowOrientationListener getOrientationListener() {
391 return mOrientationListener;
Riddle Hsuad256a12018-07-18 16:11:30 +0800392 }
393
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800394 public int getUserRotation() {
395 return mUserRotation;
396 }
397
398 public int getUserRotationMode() {
399 return mUserRotationMode;
400 }
401
402 public void updateOrientationListener() {
403 synchronized (mLock) {
404 updateOrientationListenerLw();
Riddle Hsuad256a12018-07-18 16:11:30 +0800405 }
406 }
407
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800408 /**
409 * Various use cases for invoking this function:
410 * <li>Screen turning off, should always disable listeners if already enabled.</li>
411 * <li>Screen turned on and current app has sensor based orientation, enable listeners
412 * if not already enabled.</li>
413 * <li>Screen turned on and current app does not have sensor orientation, disable listeners
414 * if already enabled.</li>
415 * <li>Screen turning on and current app has sensor based orientation, enable listeners
416 * if needed.</li>
417 * <li>screen turning on and current app has nosensor based orientation, do nothing.</li>
418 */
419 private void updateOrientationListenerLw() {
420 if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {
421 // If sensor is turned off or nonexistent for some reason.
422 return;
423 }
424
425 final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();
426 final boolean awake = mDisplayPolicy.isAwake();
427 final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();
428 final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();
429
430 // Could have been invoked due to screen turning on or off or
431 // change of the currently visible window's orientation.
432 if (DEBUG_ORIENTATION) Slog.v(TAG, "screenOnEarly=" + screenOnEarly
433 + ", awake=" + awake + ", currentAppOrientation=" + mCurrentAppOrientation
434 + ", orientationSensorEnabled=" + mOrientationListener.mEnabled
435 + ", keyguardDrawComplete=" + keyguardDrawComplete
436 + ", windowManagerDrawComplete=" + windowManagerDrawComplete);
437
438 boolean disable = true;
439 // Note: We postpone the rotating of the screen until the keyguard as well as the
440 // window manager have reported a draw complete or the keyguard is going away in dismiss
441 // mode.
442 if (screenOnEarly && awake && ((keyguardDrawComplete && windowManagerDrawComplete))) {
443 if (needSensorRunning()) {
444 disable = false;
445 // Enable listener if not already enabled.
446 if (!mOrientationListener.mEnabled) {
447 // Don't clear the current sensor orientation if the keyguard is going away in
448 // dismiss mode. This allows window manager to use the last sensor reading to
449 // determine the orientation vs. falling back to the last known orientation if
450 // the sensor reading was cleared which can cause it to relaunch the app that
451 // will show in the wrong orientation first before correcting leading to app
452 // launch delays.
453 mOrientationListener.enable(true /* clearCurrentRotation */);
454 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800455 }
456 }
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800457 // Check if sensors need to be disabled.
458 if (disable && mOrientationListener.mEnabled) {
459 mOrientationListener.disable();
460 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800461 }
462
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800463 /**
464 * We always let the sensor be switched on by default except when
465 * the user has explicitly disabled sensor based rotation or when the
466 * screen is switched off.
467 */
468 private boolean needSensorRunning() {
Garfield Tan7fbca052019-02-19 10:45:35 -0800469 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800470 // We are sure we only respect user rotation settings, so we are sure we will not
471 // support sensor rotation.
472 return false;
473 }
474
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800475 if (mSupportAutoRotation) {
476 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
477 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
478 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
479 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) {
480 // If the application has explicitly requested to follow the
481 // orientation, then we need to turn the sensor on.
482 return true;
483 }
484 }
485
486 final int dockMode = mDisplayPolicy.getDockMode();
487 if ((mDisplayPolicy.isCarDockEnablesAccelerometer()
488 && dockMode == Intent.EXTRA_DOCK_STATE_CAR)
489 || (mDisplayPolicy.isDeskDockEnablesAccelerometer()
490 && (dockMode == Intent.EXTRA_DOCK_STATE_DESK
491 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
492 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) {
493 // Enable accelerometer if we are docked in a dock that enables accelerometer
494 // orientation management.
495 return true;
496 }
497
498 if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
499 // If the setting for using the sensor by default is enabled, then
500 // we will always leave it on. Note that the user could go to
501 // a window that forces an orientation that does not use the
502 // sensor and in theory we could turn it off... however, when next
503 // turning it on we won't have a good value for the current
504 // orientation for a little bit, which can cause orientation
505 // changes to lag, so we'd like to keep it always on. (It will
506 // still be turned off when the screen is off.)
507
508 // When locked we can provide rotation suggestions users can approve to change the
509 // current screen rotation. To do this the sensor needs to be running.
510 return mSupportAutoRotation &&
511 mShowRotationSuggestions == Settings.Secure.SHOW_ROTATION_SUGGESTIONS_ENABLED;
512 }
513 return mSupportAutoRotation;
514 }
515
516 /**
517 * Given an orientation constant, returns the appropriate surface rotation,
518 * taking into account sensors, docking mode, rotation lock, and other factors.
519 *
520 * @param orientation An orientation constant, such as
521 * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
522 * @param lastRotation The most recently used rotation.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800523 * @return The surface rotation to use.
524 */
525 int rotationForOrientation(int orientation, int lastRotation) {
526 if (DEBUG_ORIENTATION) {
527 Slog.v(TAG, "rotationForOrientation(orient="
528 + orientation + ", last=" + lastRotation
529 + "); user=" + mUserRotation + " "
530 + (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
531 ? "USER_ROTATION_LOCKED" : "")
532 );
533 }
534
Garfield Tan7fbca052019-02-19 10:45:35 -0800535 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800536 return mUserRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800537 }
538
539 int sensorRotation = mOrientationListener != null
540 ? mOrientationListener.getProposedRotation() // may be -1
541 : -1;
542 if (sensorRotation < 0) {
543 sensorRotation = lastRotation;
544 }
545
546 final int lidState = mDisplayPolicy.getLidState();
547 final int dockMode = mDisplayPolicy.getDockMode();
548 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
549 final boolean carDockEnablesAccelerometer =
550 mDisplayPolicy.isCarDockEnablesAccelerometer();
551 final boolean deskDockEnablesAccelerometer =
552 mDisplayPolicy.isDeskDockEnablesAccelerometer();
553
554 final int preferredRotation;
555 if (!isDefaultDisplay) {
556 // For secondary displays we ignore things like displays sensors, docking mode and
Garfield Tan90c90052018-10-08 12:29:41 -0700557 // rotation lock, and always prefer user rotation.
558 preferredRotation = mUserRotation;
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800559 } else if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
560 // Ignore sensor when lid switch is open and rotation is forced.
561 preferredRotation = mLidOpenRotation;
562 } else if (dockMode == Intent.EXTRA_DOCK_STATE_CAR
563 && (carDockEnablesAccelerometer || mCarDockRotation >= 0)) {
564 // Ignore sensor when in car dock unless explicitly enabled.
565 // This case can override the behavior of NOSENSOR, and can also
566 // enable 180 degree rotation while docked.
567 preferredRotation = carDockEnablesAccelerometer ? sensorRotation : mCarDockRotation;
568 } else if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
569 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
570 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
571 && (deskDockEnablesAccelerometer || mDeskDockRotation >= 0)) {
572 // Ignore sensor when in desk dock unless explicitly enabled.
573 // This case can override the behavior of NOSENSOR, and can also
574 // enable 180 degree rotation while docked.
575 preferredRotation = deskDockEnablesAccelerometer ? sensorRotation : mDeskDockRotation;
576 } else if (hdmiPlugged && mDemoHdmiRotationLock) {
577 // Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
578 // Note that the dock orientation overrides the HDMI orientation.
579 preferredRotation = mDemoHdmiRotation;
580 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
581 && mUndockedHdmiRotation >= 0) {
582 // Ignore sensor when plugged into HDMI and an undocked orientation has
583 // been specified in the configuration (only for legacy devices without
584 // full multi-display support).
585 // Note that the dock orientation overrides the HDMI orientation.
586 preferredRotation = mUndockedHdmiRotation;
587 } else if (mDemoRotationLock) {
588 // Ignore sensor when demo rotation lock is enabled.
589 // Note that the dock orientation and HDMI rotation lock override this.
590 preferredRotation = mDemoRotation;
591 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
592 // While in VR, apps always prefer a portrait rotation. This does not change
593 // any apps that explicitly set landscape, but does cause sensors be ignored,
594 // and ignored any orientation lock that the user has set (this conditional
595 // should remain above the ORIENTATION_LOCKED conditional below).
596 preferredRotation = mPortraitRotation;
597 } else if (orientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
598 // Application just wants to remain locked in the last rotation.
599 preferredRotation = lastRotation;
600 } else if (!mSupportAutoRotation) {
601 // If we don't support auto-rotation then bail out here and ignore
602 // the sensor and any rotation lock settings.
603 preferredRotation = -1;
604 } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
605 && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
606 || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
607 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
608 || orientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
609 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER))
610 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
611 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
612 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
613 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) {
614 // Otherwise, use sensor only if requested by the application or enabled
615 // by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR.
616 if (mAllowAllRotations < 0) {
617 // Can't read this during init() because the context doesn't
618 // have display metrics at that time so we cannot determine
619 // tablet vs. phone then.
620 mAllowAllRotations = mContext.getResources().getBoolean(
621 com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;
622 }
623 if (sensorRotation != Surface.ROTATION_180
624 || mAllowAllRotations == 1
625 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
626 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
627 preferredRotation = sensorRotation;
628 } else {
629 preferredRotation = lastRotation;
630 }
631 } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
632 && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
633 // Apply rotation lock. Does not apply to NOSENSOR.
634 // The idea is that the user rotation expresses a weak preference for the direction
635 // of gravity and as NOSENSOR is never affected by gravity, then neither should
636 // NOSENSOR be affected by rotation lock (although it will be affected by docks).
637 preferredRotation = mUserRotation;
638 } else {
639 // No overriding preference.
640 // We will do exactly what the application asked us to do.
641 preferredRotation = -1;
642 }
643
Riddle Hsuad256a12018-07-18 16:11:30 +0800644 switch (orientation) {
645 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
646 // Return portrait unless overridden.
647 if (isAnyPortrait(preferredRotation)) {
648 return preferredRotation;
649 }
650 return mPortraitRotation;
651
652 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
653 // Return landscape unless overridden.
654 if (isLandscapeOrSeascape(preferredRotation)) {
655 return preferredRotation;
656 }
657 return mLandscapeRotation;
658
659 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
660 // Return reverse portrait unless overridden.
661 if (isAnyPortrait(preferredRotation)) {
662 return preferredRotation;
663 }
664 return mUpsideDownRotation;
665
666 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
667 // Return seascape unless overridden.
668 if (isLandscapeOrSeascape(preferredRotation)) {
669 return preferredRotation;
670 }
671 return mSeascapeRotation;
672
673 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
674 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
675 // Return either landscape rotation.
676 if (isLandscapeOrSeascape(preferredRotation)) {
677 return preferredRotation;
678 }
679 if (isLandscapeOrSeascape(lastRotation)) {
680 return lastRotation;
681 }
682 return mLandscapeRotation;
683
684 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
685 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
686 // Return either portrait rotation.
687 if (isAnyPortrait(preferredRotation)) {
688 return preferredRotation;
689 }
690 if (isAnyPortrait(lastRotation)) {
691 return lastRotation;
692 }
693 return mPortraitRotation;
694
695 default:
696 // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR,
697 // just return the preferred orientation we already calculated.
698 if (preferredRotation >= 0) {
699 return preferredRotation;
700 }
701 return Surface.ROTATION_0;
702 }
703 }
704
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800705 private boolean isLandscapeOrSeascape(int rotation) {
706 return rotation == mLandscapeRotation || rotation == mSeascapeRotation;
707 }
708
709 private boolean isAnyPortrait(int rotation) {
710 return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
711 }
712
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800713 private boolean isValidRotationChoice(final int preferredRotation) {
Riddle Hsuad256a12018-07-18 16:11:30 +0800714 // Determine if the given app orientation is compatible with the provided rotation choice.
715 switch (mCurrentAppOrientation) {
716 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
717 // Works with any of the 4 rotations.
718 return preferredRotation >= 0;
719
720 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
721 // It's possible for the user pref to be set at 180 because of FULL_USER. This would
722 // make switching to USER_PORTRAIT appear at 180. Provide choice to back to portrait
723 // but never to go to 180.
724 return preferredRotation == mPortraitRotation;
725
726 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
727 // Works landscape or seascape.
728 return isLandscapeOrSeascape(preferredRotation);
729
730 case ActivityInfo.SCREEN_ORIENTATION_USER:
731 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
732 // Works with any rotation except upside down.
733 return (preferredRotation >= 0) && (preferredRotation != mUpsideDownRotation);
734 }
735
736 return false;
737 }
738
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800739 private boolean isRotationChoicePossible(int orientation) {
740 // Rotation choice is only shown when the user is in locked mode.
741 if (mUserRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) return false;
742
743 // We should only enable rotation choice if the rotation isn't forced by the lid, dock,
744 // demo, hdmi, vr, etc mode.
745
746 // Determine if the rotation is currently forced.
Garfield Tan7fbca052019-02-19 10:45:35 -0800747 if (isFixedToUserRotation()) {
Garfield Tanff362222018-11-14 17:52:32 -0800748 return false; // Rotation is forced to user settings.
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800749 }
750
751 final int lidState = mDisplayPolicy.getLidState();
752 if (lidState == LID_OPEN && mLidOpenRotation >= 0) {
753 return false; // Rotation is forced mLidOpenRotation.
754 }
755
756 final int dockMode = mDisplayPolicy.getDockMode();
757 final boolean carDockEnablesAccelerometer = false;
758 if (dockMode == Intent.EXTRA_DOCK_STATE_CAR && !carDockEnablesAccelerometer) {
759 return false; // Rotation forced to mCarDockRotation.
760 }
761
762 final boolean deskDockEnablesAccelerometer =
763 mDisplayPolicy.isDeskDockEnablesAccelerometer();
764 if ((dockMode == Intent.EXTRA_DOCK_STATE_DESK
765 || dockMode == Intent.EXTRA_DOCK_STATE_LE_DESK
766 || dockMode == Intent.EXTRA_DOCK_STATE_HE_DESK)
767 && !deskDockEnablesAccelerometer) {
768 return false; // Rotation forced to mDeskDockRotation.
769 }
770
771 final boolean hdmiPlugged = mDisplayPolicy.isHdmiPlugged();
772 if (hdmiPlugged && mDemoHdmiRotationLock) {
773 return false; // Rotation forced to mDemoHdmiRotation.
774
775 } else if (hdmiPlugged && dockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
776 && mUndockedHdmiRotation >= 0) {
777 return false; // Rotation forced to mUndockedHdmiRotation.
778
779 } else if (mDemoRotationLock) {
780 return false; // Rotation forced to mDemoRotation.
781
782 } else if (mDisplayPolicy.isPersistentVrModeEnabled()) {
783 return false; // Rotation forced to mPortraitRotation.
784
785 } else if (!mSupportAutoRotation) {
786 return false;
787 }
788
789 // Ensure that some rotation choice is possible for the given orientation.
790 switch (orientation) {
791 case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:
792 case ActivityInfo.SCREEN_ORIENTATION_USER:
793 case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:
794 case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:
795 case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:
796 // NOSENSOR description is ambiguous, in reality WM ignores user choice.
797 return true;
798 }
799
800 // Rotation is forced, should be controlled by system.
801 return false;
Riddle Hsuad256a12018-07-18 16:11:30 +0800802 }
803
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800804 /** Notify the StatusBar that system rotation suggestion has changed. */
805 private void sendProposedRotationChangeToStatusBarInternal(int rotation, boolean isValid) {
806 if (mStatusBarManagerInternal == null) {
807 mStatusBarManagerInternal = LocalServices.getService(StatusBarManagerInternal.class);
808 }
809 if (mStatusBarManagerInternal != null) {
810 mStatusBarManagerInternal.onProposedRotationChanged(rotation, isValid);
811 }
812 }
813
814 private static String allowAllRotationsToString(int allowAll) {
815 switch (allowAll) {
816 case -1:
817 return "unknown";
818 case 0:
819 return "false";
820 case 1:
821 return "true";
822 default:
823 return Integer.toString(allowAll);
824 }
825 }
826
827 public void onUserSwitch() {
828 if (mSettingsObserver != null) {
829 mSettingsObserver.onChange(false);
830 }
831 }
832
833 /** Return whether the rotation settings has changed. */
834 private boolean updateSettings() {
835 final ContentResolver resolver = mContext.getContentResolver();
836 boolean shouldUpdateRotation = false;
837
838 synchronized (mLock) {
839 boolean shouldUpdateOrientationListener = false;
840
841 // Configure rotation suggestions.
Rajeev Kumarb2ff8e82018-08-06 11:45:05 -0700842 final int showRotationSuggestions =
843 ActivityManager.isLowRamDeviceStatic()
844 ? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED
845 : Settings.Secure.getIntForUser(resolver,
846 Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
847 Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,
848 UserHandle.USER_CURRENT);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800849 if (mShowRotationSuggestions != showRotationSuggestions) {
850 mShowRotationSuggestions = showRotationSuggestions;
851 shouldUpdateOrientationListener = true;
852 }
853
854 // Configure rotation lock.
855 final int userRotation = Settings.System.getIntForUser(resolver,
856 Settings.System.USER_ROTATION, Surface.ROTATION_0,
857 UserHandle.USER_CURRENT);
858 if (mUserRotation != userRotation) {
859 mUserRotation = userRotation;
860 shouldUpdateRotation = true;
861 }
862
863 final int userRotationMode = Settings.System.getIntForUser(resolver,
864 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0
865 ? WindowManagerPolicy.USER_ROTATION_FREE
866 : WindowManagerPolicy.USER_ROTATION_LOCKED;
867 if (mUserRotationMode != userRotationMode) {
868 mUserRotationMode = userRotationMode;
869 shouldUpdateOrientationListener = true;
870 shouldUpdateRotation = true;
871 }
872
873 if (shouldUpdateOrientationListener) {
874 updateOrientationListenerLw(); // Enable or disable the orientation listener.
875 }
876 }
877
878 return shouldUpdateRotation;
Riddle Hsuad256a12018-07-18 16:11:30 +0800879 }
880
881 void dump(String prefix, PrintWriter pw) {
882 pw.println(prefix + "DisplayRotation");
883 pw.println(prefix + " mCurrentAppOrientation="
884 + ActivityInfo.screenOrientationToString(mCurrentAppOrientation));
885 pw.print(prefix + " mLandscapeRotation=" + Surface.rotationToString(mLandscapeRotation));
886 pw.println(" mSeascapeRotation=" + Surface.rotationToString(mSeascapeRotation));
887 pw.print(prefix + " mPortraitRotation=" + Surface.rotationToString(mPortraitRotation));
888 pw.println(" mUpsideDownRotation=" + Surface.rotationToString(mUpsideDownRotation));
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800889
Tiger Huang7c610aa2018-10-27 00:01:01 +0800890 pw.println(prefix + " mSupportAutoRotation=" + mSupportAutoRotation);
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800891 if (mOrientationListener != null) {
Tiger Huang7c610aa2018-10-27 00:01:01 +0800892 mOrientationListener.dump(pw, prefix + " ");
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800893 }
894 pw.println();
895
896 pw.print(prefix + " mCarDockRotation=" + Surface.rotationToString(mCarDockRotation));
897 pw.println(" mDeskDockRotation=" + Surface.rotationToString(mDeskDockRotation));
898 pw.print(prefix + " mUserRotationMode="
899 + WindowManagerPolicy.userRotationModeToString(mUserRotationMode));
900 pw.print(" mUserRotation=" + Surface.rotationToString(mUserRotation));
901 pw.println(" mAllowAllRotations=" + allowAllRotationsToString(mAllowAllRotations));
902
903 pw.print(prefix + " mDemoHdmiRotation=" + Surface.rotationToString(mDemoHdmiRotation));
904 pw.print(" mDemoHdmiRotationLock=" + mDemoHdmiRotationLock);
905 pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation));
906 pw.println(prefix + " mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation));
Garfield Tan7fbca052019-02-19 10:45:35 -0800907 pw.println(prefix + " mFixedToUserRotation=" + isFixedToUserRotation());
Riddle Hsu5ce4bb32018-07-18 16:11:30 +0800908 }
909
910 private class OrientationListener extends WindowOrientationListener {
911 final SparseArray<Runnable> mRunnableCache = new SparseArray<>(5);
912 boolean mEnabled;
913
914 OrientationListener(Context context, Handler handler) {
915 super(context, handler);
916 }
917
918 private class UpdateRunnable implements Runnable {
919 final int mRotation;
920
921 UpdateRunnable(int rotation) {
922 mRotation = rotation;
923 }
924
925 @Override
926 public void run() {
927 // Send interaction hint to improve redraw performance.
928 mService.mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
929 if (isRotationChoicePossible(mCurrentAppOrientation)) {
930 final boolean isValid = isValidRotationChoice(mRotation);
931 sendProposedRotationChangeToStatusBarInternal(mRotation, isValid);
932 } else {
933 mService.updateRotation(false /* alwaysSendConfiguration */,
934 false /* forceRelayout */);
935 }
936 }
937 }
938
939 @Override
940 public void onProposedRotationChanged(int rotation) {
941 if (DEBUG_ORIENTATION) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
942 Runnable r = mRunnableCache.get(rotation, null);
943 if (r == null) {
944 r = new UpdateRunnable(rotation);
945 mRunnableCache.put(rotation, r);
946 }
947 getHandler().post(r);
948 }
949
950 @Override
951 public void enable(boolean clearCurrentRotation) {
952 super.enable(clearCurrentRotation);
953 mEnabled = true;
954 if (DEBUG_ORIENTATION) Slog.v(TAG, "Enabling listeners");
955 }
956
957 @Override
958 public void disable() {
959 super.disable();
960 mEnabled = false;
961 if (DEBUG_ORIENTATION) Slog.v(TAG, "Disabling listeners");
962 }
963 }
964
965 private class SettingsObserver extends ContentObserver {
966 SettingsObserver(Handler handler) {
967 super(handler);
968 }
969
970 void observe() {
971 final ContentResolver resolver = mContext.getContentResolver();
972 resolver.registerContentObserver(Settings.Secure.getUriFor(
973 Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,
974 UserHandle.USER_ALL);
975 resolver.registerContentObserver(Settings.System.getUriFor(
976 Settings.System.ACCELEROMETER_ROTATION), false, this,
977 UserHandle.USER_ALL);
978 resolver.registerContentObserver(Settings.System.getUriFor(
979 Settings.System.USER_ROTATION), false, this,
980 UserHandle.USER_ALL);
981 updateSettings();
982 }
983
984 @Override
985 public void onChange(boolean selfChange) {
986 if (updateSettings()) {
987 mService.updateRotation(true /* alwaysSendConfiguration */,
988 false /* forceRelayout */);
989 }
990 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800991 }
Garfield Tanff362222018-11-14 17:52:32 -0800992
993 @VisibleForTesting
994 interface ContentObserverRegister {
995 void registerContentObserver(Uri uri, boolean notifyForDescendants,
996 ContentObserver observer, @UserIdInt int userHandle);
997 }
Riddle Hsuad256a12018-07-18 16:11:30 +0800998}