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 int displayId = context.getDisplayId(); 81 wm.getInitialDisplaySize(displayId, size); 82 return size.x < size.y ? 83 Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; 84 } catch (RemoteException e) { 85 Log.w(TAG, "Unable to get the display size"); 86 } 87 } 88 return Configuration.ORIENTATION_UNDEFINED; 89 } 90 91 /** 92 * Returns true if the rotation-lock toggle should be shown in system UI. 93 */ isRotationLockToggleVisible(Context context)94 public static boolean isRotationLockToggleVisible(Context context) { 95 return isRotationSupported(context) && 96 Settings.System.getIntForUser(context.getContentResolver(), 97 Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0, 98 UserHandle.USER_CURRENT) == 0; 99 } 100 101 /** 102 * Returns true if rotation lock is enabled. 103 */ isRotationLocked(Context context)104 public static boolean isRotationLocked(Context context) { 105 return Settings.System.getIntForUser(context.getContentResolver(), 106 Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0; 107 } 108 109 /** 110 * Enables or disables rotation lock from the system UI toggle. 111 */ setRotationLock(Context context, final boolean enabled)112 public static void setRotationLock(Context context, final boolean enabled) { 113 final int rotation = areAllRotationsAllowed(context) ? CURRENT_ROTATION : NATURAL_ROTATION; 114 setRotationLockAtAngle(context, enabled, rotation); 115 } 116 117 /** 118 * Enables or disables rotation lock at a specific rotation from system UI. 119 */ setRotationLockAtAngle(Context context, final boolean enabled, final int rotation)120 public static void setRotationLockAtAngle(Context context, final boolean enabled, 121 final int rotation) { 122 Settings.System.putIntForUser(context.getContentResolver(), 123 Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0, 124 UserHandle.USER_CURRENT); 125 126 setRotationLock(enabled, rotation); 127 } 128 129 /** 130 * Enables or disables natural rotation lock from Accessibility settings. 131 * 132 * If rotation is locked for accessibility, the system UI toggle is hidden to avoid confusion. 133 */ setRotationLockForAccessibility(Context context, final boolean enabled)134 public static void setRotationLockForAccessibility(Context context, final boolean enabled) { 135 Settings.System.putIntForUser(context.getContentResolver(), 136 Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, enabled ? 1 : 0, 137 UserHandle.USER_CURRENT); 138 139 setRotationLock(enabled, NATURAL_ROTATION); 140 } 141 areAllRotationsAllowed(Context context)142 private static boolean areAllRotationsAllowed(Context context) { 143 return context.getResources().getBoolean(R.bool.config_allowAllRotations); 144 } 145 setRotationLock(final boolean enabled, final int rotation)146 private static void setRotationLock(final boolean enabled, final int rotation) { 147 AsyncTask.execute(new Runnable() { 148 @Override 149 public void run() { 150 try { 151 IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); 152 if (enabled) { 153 wm.freezeRotation(rotation); 154 } else { 155 wm.thawRotation(); 156 } 157 } catch (RemoteException exc) { 158 Log.w(TAG, "Unable to save auto-rotate setting"); 159 } 160 } 161 }); 162 } 163 164 /** 165 * Registers a listener for rotation policy changes affecting the caller's user 166 */ registerRotationPolicyListener(Context context, RotationPolicyListener listener)167 public static void registerRotationPolicyListener(Context context, 168 RotationPolicyListener listener) { 169 registerRotationPolicyListener(context, listener, UserHandle.getCallingUserId()); 170 } 171 172 /** 173 * Registers a listener for rotation policy changes affecting a specific user, 174 * or USER_ALL for all users. 175 */ registerRotationPolicyListener(Context context, RotationPolicyListener listener, int userHandle)176 public static void registerRotationPolicyListener(Context context, 177 RotationPolicyListener listener, int userHandle) { 178 context.getContentResolver().registerContentObserver(Settings.System.getUriFor( 179 Settings.System.ACCELEROMETER_ROTATION), 180 false, listener.mObserver, userHandle); 181 context.getContentResolver().registerContentObserver(Settings.System.getUriFor( 182 Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY), 183 false, listener.mObserver, userHandle); 184 } 185 186 /** 187 * Unregisters a listener for rotation policy changes. 188 */ unregisterRotationPolicyListener(Context context, RotationPolicyListener listener)189 public static void unregisterRotationPolicyListener(Context context, 190 RotationPolicyListener listener) { 191 context.getContentResolver().unregisterContentObserver(listener.mObserver); 192 } 193 194 /** 195 * Listener that is invoked whenever a change occurs that might affect the rotation policy. 196 */ 197 public static abstract class RotationPolicyListener { 198 final ContentObserver mObserver = new ContentObserver(new Handler()) { 199 @Override 200 public void onChange(boolean selfChange, Uri uri) { 201 RotationPolicyListener.this.onChange(); 202 } 203 }; 204 onChange()205 public abstract void onChange(); 206 } 207 }