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