Home | History | Annotate | Download | only in view
      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 
     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      */
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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 
    141     private static boolean areAllRotationsAllowed(Context context) {
    142         return context.getResources().getBoolean(R.bool.config_allowAllRotations);
    143     }
    144 
    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      */
    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      */
    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      */
    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 
    204         public abstract void onChange();
    205     }
    206 }