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
17package com.android.internal.view;
18
19import android.content.Context;
20import android.database.ContentObserver;
21import android.net.Uri;
22import android.os.AsyncTask;
23import android.os.Handler;
24import android.os.RemoteException;
25import android.os.ServiceManager;
26import android.provider.Settings;
27import android.util.Log;
28import android.view.IWindowManager;
29import android.view.Surface;
30
31/**
32 * Provides helper functions for configuring the display rotation policy.
33 */
34public final class RotationPolicy {
35    private static final String TAG = "RotationPolicy";
36
37    private RotationPolicy() {
38    }
39
40    /**
41     * Returns true if the device supports the rotation-lock toggle feature
42     * in the system UI or system bar.
43     *
44     * When the rotation-lock toggle is supported, the "auto-rotate screen" option in
45     * Display settings should be hidden, but it should remain available in Accessibility
46     * settings.
47     */
48    public static boolean isRotationLockToggleSupported(Context context) {
49        return context.getResources().getConfiguration().smallestScreenWidthDp >= 600;
50    }
51
52    /**
53     * Returns true if the rotation-lock toggle should be shown in the UI.
54     */
55    public static boolean isRotationLockToggleVisible(Context context) {
56        return isRotationLockToggleSupported(context) &&
57                Settings.System.getInt(context.getContentResolver(),
58                        Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0) == 0;
59    }
60
61    /**
62     * Returns true if rotation lock is enabled.
63     */
64    public static boolean isRotationLocked(Context context) {
65        return Settings.System.getInt(context.getContentResolver(),
66                Settings.System.ACCELEROMETER_ROTATION, 0) == 0;
67    }
68
69    /**
70     * Enables or disables rotation lock.
71     *
72     * Should be used by the rotation lock toggle.
73     */
74    public static void setRotationLock(Context context, final boolean enabled) {
75        Settings.System.putInt(context.getContentResolver(),
76                Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0);
77
78        AsyncTask.execute(new Runnable() {
79            @Override
80            public void run() {
81                try {
82                    IWindowManager wm = IWindowManager.Stub.asInterface(
83                            ServiceManager.getService(Context.WINDOW_SERVICE));
84                    if (enabled) {
85                        wm.freezeRotation(-1);
86                    } else {
87                        wm.thawRotation();
88                    }
89                } catch (RemoteException exc) {
90                    Log.w(TAG, "Unable to save auto-rotate setting");
91                }
92            }
93        });
94    }
95
96    /**
97     * Enables or disables rotation lock and adjusts whether the rotation lock toggle
98     * should be hidden for accessibility purposes.
99     *
100     * Should be used by Display settings and Accessibility settings.
101     */
102    public static void setRotationLockForAccessibility(Context context, final boolean enabled) {
103        Settings.System.putInt(context.getContentResolver(),
104                Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, enabled ? 1 : 0);
105
106        AsyncTask.execute(new Runnable() {
107            @Override
108            public void run() {
109                try {
110                    IWindowManager wm = IWindowManager.Stub.asInterface(
111                            ServiceManager.getService(Context.WINDOW_SERVICE));
112                    if (enabled) {
113                        wm.freezeRotation(Surface.ROTATION_0);
114                    } else {
115                        wm.thawRotation();
116                    }
117                } catch (RemoteException exc) {
118                    Log.w(TAG, "Unable to save auto-rotate setting");
119                }
120            }
121        });
122    }
123
124    /**
125     * Registers a listener for rotation policy changes.
126     */
127    public static void registerRotationPolicyListener(Context context,
128            RotationPolicyListener listener) {
129        context.getContentResolver().registerContentObserver(Settings.System.getUriFor(
130                Settings.System.ACCELEROMETER_ROTATION),
131                false, listener.mObserver);
132        context.getContentResolver().registerContentObserver(Settings.System.getUriFor(
133                Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY),
134                false, listener.mObserver);
135    }
136
137    /**
138     * Unregisters a listener for rotation policy changes.
139     */
140    public static void unregisterRotationPolicyListener(Context context,
141            RotationPolicyListener listener) {
142        context.getContentResolver().unregisterContentObserver(listener.mObserver);
143    }
144
145    /**
146     * Listener that is invoked whenever a change occurs that might affect the rotation policy.
147     */
148    public static abstract class RotationPolicyListener {
149        final ContentObserver mObserver = new ContentObserver(new Handler()) {
150            public void onChange(boolean selfChange, Uri uri) {
151                RotationPolicyListener.this.onChange();
152            }
153        };
154
155        public abstract void onChange();
156    }
157}