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