1 /* 2 * Copyright (C) 2012 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 17 package com.android.internal.view; 18 19 import android.content.Context; 20 import android.content.pm.PackageManager; 21 import android.content.res.Configuration; 22 import android.database.ContentObserver; 23 import android.graphics.Point; 24 import android.net.Uri; 25 import android.os.AsyncTask; 26 import android.os.Handler; 27 import android.os.RemoteException; 28 import android.os.UserHandle; 29 import android.provider.Settings; 30 import android.util.Log; 31 import android.view.Display; 32 import android.view.IWindowManager; 33 import android.view.Surface; 34 import android.view.WindowManagerGlobal; 35 36 import com.android.internal.R; 37 38 /** 39 * Provides helper functions for configuring the display rotation policy. 40 */ 41 public final class RotationPolicy { 42 private static final String TAG = "RotationPolicy"; 43 private static final int CURRENT_ROTATION = -1; 44 45 public static final int NATURAL_ROTATION = Surface.ROTATION_0; 46 RotationPolicy()47 private RotationPolicy() { 48 } 49 50 /** 51 * Gets whether the device supports rotation. In general such a 52 * device has an accelerometer and has the portrait and landscape 53 * features. 54 * 55 * @param context Context for accessing system resources. 56 * @return Whether the device supports rotation. 57 */ isRotationSupported(Context context)58 public static boolean isRotationSupported(Context context) { 59 PackageManager pm = context.getPackageManager(); 60 return pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER) 61 && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_PORTRAIT) 62 && pm.hasSystemFeature(PackageManager.FEATURE_SCREEN_LANDSCAPE) 63 && context.getResources().getBoolean( 64 com.android.internal.R.bool.config_supportAutoRotation); 65 } 66 67 /** 68 * Returns the orientation that will be used when locking the orientation from system UI 69 * with {@link #setRotationLock}. 70 * 71 * If the device only supports locking to its natural orientation, this will be either 72 * Configuration.ORIENTATION_PORTRAIT or Configuration.ORIENTATION_LANDSCAPE, 73 * otherwise Configuration.ORIENTATION_UNDEFINED if any orientation is lockable. 74 */ getRotationLockOrientation(Context context)75 public static int getRotationLockOrientation(Context context) { 76 if (!areAllRotationsAllowed(context)) { 77 final Point size = new Point(); 78 final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); 79 try { 80 final Display display = context.getDisplay(); 81 final int displayId = display != null 82 ? display.getDisplayId() 83 : Display.DEFAULT_DISPLAY; 84 wm.getInitialDisplaySize(displayId, size); 85 return size.x < size.y ? 86 Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; 87 } catch (RemoteException e) { 88 Log.w(TAG, "Unable to get the display size"); 89 } 90 } 91 return Configuration.ORIENTATION_UNDEFINED; 92 } 93 94 /** 95 * Returns true if the rotation-lock toggle should be shown in system UI. 96 */ isRotationLockToggleVisible(Context context)97 public static boolean isRotationLockToggleVisible(Context context) { 98 return isRotationSupported(context) && 99 Settings.System.getIntForUser(context.getContentResolver(), 100 Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0, 101 UserHandle.USER_CURRENT) == 0; 102 } 103 104 /** 105 * Returns true if rotation lock is enabled. 106 */ isRotationLocked(Context context)107 public static boolean isRotationLocked(Context context) { 108 return Settings.System.getIntForUser(context.getContentResolver(), 109 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0; 110 } 111 112 /** 113 * Enables or disables rotation lock from the system UI toggle. 114 */ setRotationLock(Context context, final boolean enabled)115 public static void setRotationLock(Context context, final boolean enabled) { 116 final int rotation = areAllRotationsAllowed(context) ? CURRENT_ROTATION : NATURAL_ROTATION; 117 setRotationLockAtAngle(context, enabled, rotation); 118 } 119 120 /** 121 * Enables or disables rotation lock at a specific rotation from system UI. 122 */ setRotationLockAtAngle(Context context, final boolean enabled, final int rotation)123 public static void setRotationLockAtAngle(Context context, final boolean enabled, 124 final int rotation) { 125 Settings.System.putIntForUser(context.getContentResolver(), 126 Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0, 127 UserHandle.USER_CURRENT); 128 129 setRotationLock(enabled, rotation); 130 } 131 132 /** 133 * Enables or disables natural rotation lock from Accessibility settings. 134 * 135 * If rotation is locked for accessibility, the system UI toggle is hidden to avoid confusion. 136 */ setRotationLockForAccessibility(Context context, final boolean enabled)137 public static void setRotationLockForAccessibility(Context context, final boolean enabled) { 138 Settings.System.putIntForUser(context.getContentResolver(), 139 Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, enabled ? 1 : 0, 140 UserHandle.USER_CURRENT); 141 142 setRotationLock(enabled, NATURAL_ROTATION); 143 } 144 areAllRotationsAllowed(Context context)145 private static boolean areAllRotationsAllowed(Context context) { 146 return context.getResources().getBoolean(R.bool.config_allowAllRotations); 147 } 148 setRotationLock(final boolean enabled, final int rotation)149 private static void setRotationLock(final boolean enabled, final int rotation) { 150 AsyncTask.execute(new Runnable() { 151 @Override 152 public void run() { 153 try { 154 IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); 155 if (enabled) { 156 wm.freezeRotation(rotation); 157 } else { 158 wm.thawRotation(); 159 } 160 } catch (RemoteException exc) { 161 Log.w(TAG, "Unable to save auto-rotate setting"); 162 } 163 } 164 }); 165 } 166 167 /** 168 * Registers a listener for rotation policy changes affecting the caller's user 169 */ registerRotationPolicyListener(Context context, RotationPolicyListener listener)170 public static void registerRotationPolicyListener(Context context, 171 RotationPolicyListener listener) { 172 registerRotationPolicyListener(context, listener, UserHandle.getCallingUserId()); 173 } 174 175 /** 176 * Registers a listener for rotation policy changes affecting a specific user, 177 * or USER_ALL for all users. 178 */ registerRotationPolicyListener(Context context, RotationPolicyListener listener, int userHandle)179 public static void registerRotationPolicyListener(Context context, 180 RotationPolicyListener listener, int userHandle) { 181 context.getContentResolver().registerContentObserver(Settings.System.getUriFor( 182 Settings.System.ACCELEROMETER_ROTATION), 183 false, listener.mObserver, userHandle); 184 context.getContentResolver().registerContentObserver(Settings.System.getUriFor( 185 Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY), 186 false, listener.mObserver, userHandle); 187 } 188 189 /** 190 * Unregisters a listener for rotation policy changes. 191 */ unregisterRotationPolicyListener(Context context, RotationPolicyListener listener)192 public static void unregisterRotationPolicyListener(Context context, 193 RotationPolicyListener listener) { 194 context.getContentResolver().unregisterContentObserver(listener.mObserver); 195 } 196 197 /** 198 * Listener that is invoked whenever a change occurs that might affect the rotation policy. 199 */ 200 public static abstract class RotationPolicyListener { 201 final ContentObserver mObserver = new ContentObserver(new Handler()) { 202 @Override 203 public void onChange(boolean selfChange, Uri uri) { 204 RotationPolicyListener.this.onChange(); 205 } 206 }; 207 onChange()208 public abstract void onChange(); 209 } 210 }