Merge "Implement new rotation policy." into jb-dev
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8630204..a90dd8c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1750,6 +1750,20 @@
public static final String USER_ROTATION = "user_rotation";
/**
+ * Control whether the rotation lock toggle in the System UI should be hidden.
+ * Typically this is done for accessibility purposes to make it harder for
+ * the user to accidentally toggle the rotation lock while the display rotation
+ * has been locked for accessibility.
+ *
+ * If 0, then rotation lock toggle is not hidden for accessibility (although it may be
+ * unavailable for other reasons). If 1, then the rotation lock toggle is hidden.
+ *
+ * @hide
+ */
+ public static final String HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY =
+ "hide_rotation_lock_toggle_for_accessibility";
+
+ /**
* Whether the phone vibrates when it is ringing due to an incoming call. This will
* be used by Phone and Setting apps; it shouldn't affect other apps.
* The value is boolean (1 or 0).
@@ -2029,6 +2043,7 @@
DATE_FORMAT,
ACCELEROMETER_ROTATION,
USER_ROTATION,
+ HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
DTMF_TONE_WHEN_DIALING,
DTMF_TONE_TYPE_WHEN_DIALING,
EMERGENCY_TONE,
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
new file mode 100644
index 0000000..af512a3
--- /dev/null
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.Surface;
+
+/**
+ * Provides helper functions for configuring the display rotation policy.
+ */
+public final class RotationPolicy {
+ private static final String TAG = "RotationPolicy";
+
+ private RotationPolicy() {
+ }
+
+ /**
+ * Returns true if the device supports the rotation-lock toggle feature
+ * in the system UI or system bar.
+ *
+ * When the rotation-lock toggle is supported, the "auto-rotate screen" option in
+ * Display settings should be hidden, but it should remain available in Accessibility
+ * settings.
+ */
+ public static boolean isRotationLockToggleSupported(Context context) {
+ return context.getResources().getConfiguration().smallestScreenWidthDp >= 600;
+ }
+
+ /**
+ * Returns true if the rotation-lock toggle should be shown in the UI.
+ */
+ public static boolean isRotationLockToggleVisible(Context context) {
+ return isRotationLockToggleSupported(context) &&
+ Settings.System.getInt(context.getContentResolver(),
+ Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0) == 0;
+ }
+
+ /**
+ * Returns true if rotation lock is enabled.
+ */
+ public static boolean isRotationLocked(Context context) {
+ return Settings.System.getInt(context.getContentResolver(),
+ Settings.System.ACCELEROMETER_ROTATION, 0) == 0;
+ }
+
+ /**
+ * Enables or disables rotation lock.
+ *
+ * Should be used by the rotation lock toggle.
+ */
+ public static void setRotationLock(Context context, final boolean enabled) {
+ Settings.System.putInt(context.getContentResolver(),
+ Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0);
+
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ IWindowManager wm = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ if (enabled) {
+ wm.freezeRotation(-1);
+ } else {
+ wm.thawRotation();
+ }
+ } catch (RemoteException exc) {
+ Log.w(TAG, "Unable to save auto-rotate setting");
+ }
+ }
+ });
+ }
+
+ /**
+ * Enables or disables rotation lock and adjusts whether the rotation lock toggle
+ * should be hidden for accessibility purposes.
+ *
+ * Should be used by Display settings and Accessibility settings.
+ */
+ public static void setRotationLockForAccessibility(Context context, final boolean enabled) {
+ Settings.System.putInt(context.getContentResolver(),
+ Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, enabled ? 1 : 0);
+
+ AsyncTask.execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ IWindowManager wm = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ if (enabled) {
+ wm.freezeRotation(Surface.ROTATION_0);
+ } else {
+ wm.thawRotation();
+ }
+ } catch (RemoteException exc) {
+ Log.w(TAG, "Unable to save auto-rotate setting");
+ }
+ }
+ });
+ }
+
+ /**
+ * Registers a listener for rotation policy changes.
+ */
+ public static void registerRotationPolicyListener(Context context,
+ RotationPolicyListener listener) {
+ context.getContentResolver().registerContentObserver(Settings.System.getUriFor(
+ Settings.System.ACCELEROMETER_ROTATION),
+ false, listener.mObserver);
+ context.getContentResolver().registerContentObserver(Settings.System.getUriFor(
+ Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY),
+ false, listener.mObserver);
+ }
+
+ /**
+ * Unregisters a listener for rotation policy changes.
+ */
+ public static void unregisterRotationPolicyListener(Context context,
+ RotationPolicyListener listener) {
+ context.getContentResolver().unregisterContentObserver(listener.mObserver);
+ }
+
+ /**
+ * Listener that is invoked whenever a change occurs that might affect the rotation policy.
+ */
+ public static abstract class RotationPolicyListener {
+ final ContentObserver mObserver = new ContentObserver(new Handler()) {
+ public void onChange(boolean selfChange, Uri uri) {
+ RotationPolicyListener.this.onChange();
+ }
+ };
+
+ public abstract void onChange();
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_expanded_header.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_expanded_header.xml
deleted file mode 100644
index 9b834d2..0000000
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_expanded_header.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="@dimen/notification_panel_header_padding_top"
- android:background="@drawable/notification_header_bg"
- android:orientation="horizontal"
- android:gravity="center_vertical"
- android:baselineAligned="false"
- >
- <com.android.systemui.statusbar.policy.Clock
- android:id="@+id/clock"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:singleLine="true"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
- />
-
- <com.android.systemui.statusbar.policy.DateView android:id="@+id/date"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
- />
-
- <com.android.systemui.statusbar.RotationToggle android:id="@+id/rotation_lock_button"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_margin="8dp"
- android:button="@drawable/ic_notify_rotation"
- android:contentDescription="@string/accessibility_rotation_lock_off"
- />
-
- <ImageView android:id="@+id/settings_button"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:scaleType="center"
- android:src="@drawable/ic_notify_quicksettings"
- android:contentDescription="@string/accessibility_settings_button"
- />
-
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"
- />
-
- <ImageView android:id="@+id/clear_all_button"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:scaleType="center"
- android:src="@drawable/ic_notify_clear"
- android:contentDescription="@string/accessibility_clear_all"
- />
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 893d422..cb4e6a9 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -43,6 +43,15 @@
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
/>
+ <com.android.systemui.statusbar.RotationToggle android:id="@+id/rotation_lock_button"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_margin="8dp"
+ android:button="@drawable/ic_notify_rotation"
+ android:contentDescription="@string/accessibility_rotation_lock_off"
+ android:clickable="true"
+ />
+
<ImageView android:id="@+id/settings_button"
android:layout_width="48dp"
android:layout_height="48dp"
diff --git a/packages/SystemUI/res/layout/system_bar_settings_view.xml b/packages/SystemUI/res/layout/system_bar_settings_view.xml
index 677988d..e1b2a54 100644
--- a/packages/SystemUI/res/layout/system_bar_settings_view.xml
+++ b/packages/SystemUI/res/layout/system_bar_settings_view.xml
@@ -89,7 +89,9 @@
android:layout_marginRight="5dp"
/>
</LinearLayout>
- <View style="@style/StatusBarPanelSettingsPanelSeparator" />
+ <View
+ android:id="@+id/rotate_separator"
+ style="@style/StatusBarPanelSettingsPanelSeparator" />
<!-- Brightness -->
<LinearLayout style="@style/StatusBarPanelSettingsRow" >
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RotationToggle.java b/packages/SystemUI/src/com/android/systemui/statusbar/RotationToggle.java
index c5a7354..5dd45a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RotationToggle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RotationToggle.java
@@ -6,25 +6,39 @@
import com.android.systemui.statusbar.policy.AutoRotateController;
-public class RotationToggle extends CompoundButton {
- AutoRotateController mRotater;
+public class RotationToggle extends CompoundButton
+ implements AutoRotateController.RotationLockCallbacks {
+ private AutoRotateController mRotater;
public RotationToggle(Context context) {
super(context);
- mRotater = new AutoRotateController(context, this);
- setClickable(true);
}
public RotationToggle(Context context, AttributeSet attrs) {
super(context, attrs);
- mRotater = new AutoRotateController(context, this);
- setClickable(true);
}
public RotationToggle(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mRotater = new AutoRotateController(context, this);
- setClickable(true);
}
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mRotater = new AutoRotateController(getContext(), this, this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mRotater != null) {
+ mRotater.release();
+ mRotater = null;
+ }
+ }
+
+ @Override
+ public void setRotationLockControlVisibility(boolean show) {
+ setVisibility(show ? VISIBLE : GONE);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
index 3d63781..109395c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
@@ -16,80 +16,60 @@
package com.android.systemui.statusbar.policy;
-import android.content.ContentResolver;
+import com.android.internal.view.RotationPolicy;
+
import android.content.Context;
-import android.database.ContentObserver;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.IWindowManager;
import android.widget.CompoundButton;
-public class AutoRotateController implements CompoundButton.OnCheckedChangeListener {
- private static final String TAG = "StatusBar.AutoRotateController";
-
+public final class AutoRotateController implements CompoundButton.OnCheckedChangeListener {
private final Context mContext;
private final CompoundButton mCheckbox;
+ private final RotationLockCallbacks mCallbacks;
private boolean mAutoRotation;
- private ContentObserver mAccelerometerRotationObserver = new ContentObserver(new Handler()) {
+ private final RotationPolicy.RotationPolicyListener mRotationPolicyListener =
+ new RotationPolicy.RotationPolicyListener() {
@Override
- public void onChange(boolean selfChange) {
- updateCheckbox();
+ public void onChange() {
+ updateState();
}
};
- public AutoRotateController(Context context, CompoundButton checkbox) {
+ public AutoRotateController(Context context, CompoundButton checkbox,
+ RotationLockCallbacks callbacks) {
mContext = context;
mCheckbox = checkbox;
- updateCheckbox();
+ mCallbacks = callbacks;
+
mCheckbox.setOnCheckedChangeListener(this);
- mContext.getContentResolver().registerContentObserver(
- Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), true,
- mAccelerometerRotationObserver);
+ RotationPolicy.registerRotationPolicyListener(context, mRotationPolicyListener);
+ updateState();
}
public void onCheckedChanged(CompoundButton view, boolean checked) {
if (checked != mAutoRotation) {
- setAutoRotation(checked);
+ mAutoRotation = checked;
+ RotationPolicy.setRotationLock(mContext, !checked);
}
}
public void release() {
- mContext.getContentResolver().unregisterContentObserver(mAccelerometerRotationObserver);
+ RotationPolicy.unregisterRotationPolicyListener(mContext,
+ mRotationPolicyListener);
}
- private void updateCheckbox() {
- mAutoRotation = getAutoRotation();
+ private void updateState() {
+ mAutoRotation = !RotationPolicy.isRotationLocked(mContext);
mCheckbox.setChecked(mAutoRotation);
+
+ boolean visible = RotationPolicy.isRotationLockToggleVisible(mContext);
+ mCallbacks.setRotationLockControlVisibility(visible);
+ mCheckbox.setEnabled(visible);
}
- private boolean getAutoRotation() {
- ContentResolver cr = mContext.getContentResolver();
- return 0 != Settings.System.getInt(cr, Settings.System.ACCELEROMETER_ROTATION, 0);
- }
-
- private void setAutoRotation(final boolean autorotate) {
- mAutoRotation = autorotate;
- AsyncTask.execute(new Runnable() {
- public void run() {
- try {
- IWindowManager wm = IWindowManager.Stub.asInterface(
- ServiceManager.getService(Context.WINDOW_SERVICE));
- if (autorotate) {
- wm.thawRotation();
- } else {
- wm.freezeRotation(-1);
- }
- } catch (RemoteException exc) {
- Log.w(TAG, "Unable to save auto-rotate setting");
- }
- }
- });
+ public interface RotationLockCallbacks {
+ void setRotationLockControlVisibility(boolean show);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
index 46ea940..537ff66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
@@ -43,6 +43,8 @@
AutoRotateController mRotate;
BrightnessController mBrightness;
DoNotDisturbController mDoNotDisturb;
+ View mRotationLockContainer;
+ View mRotationLockSeparator;
public SettingsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -61,8 +63,19 @@
mAirplane = new AirplaneModeController(context,
(CompoundButton)findViewById(R.id.airplane_checkbox));
findViewById(R.id.network).setOnClickListener(this);
+
+ mRotationLockContainer = findViewById(R.id.rotate);
+ mRotationLockSeparator = findViewById(R.id.rotate_separator);
mRotate = new AutoRotateController(context,
- (CompoundButton)findViewById(R.id.rotate_checkbox));
+ (CompoundButton)findViewById(R.id.rotate_checkbox),
+ new AutoRotateController.RotationLockCallbacks() {
+ @Override
+ public void setRotationLockControlVisibility(boolean show) {
+ mRotationLockContainer.setVisibility(show ? View.VISIBLE : View.GONE);
+ mRotationLockSeparator.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+ });
+
mBrightness = new BrightnessController(context,
(ToggleSlider)findViewById(R.id.brightness));
mDoNotDisturb = new DoNotDisturbController(context,
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1033296..9ef8d6b 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -346,6 +346,7 @@
int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
int mUserRotation = Surface.ROTATION_0;
+ boolean mAccelerometerDefault;
int mAllowAllRotations = -1;
boolean mCarDockEnablesAccelerometer;
@@ -358,8 +359,6 @@
boolean mScreenOnFully = false;
boolean mOrientationSensorEnabled = false;
int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
- static final int DEFAULT_ACCELEROMETER_ROTATION = 0;
- int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION;
boolean mHasSoftInput = false;
int mPointerLocationMode = 0; // guarded by mLock
@@ -617,7 +616,7 @@
// orientation management,
return true;
}
- if (mAccelerometerDefault == 0) {
+ if (mUserRotationMode == USER_ROTATION_LOCKED) {
// If the setting for using the sensor by default is enabled, then
// we will always leave it on. Note that the user could go to
// a window that forces an orientation that does not use the
@@ -1076,19 +1075,21 @@
mIncallPowerBehavior = Settings.Secure.getInt(resolver,
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT);
- int accelerometerDefault = Settings.System.getInt(resolver,
- Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION);
-
- // set up rotation lock state
- mUserRotationMode = (accelerometerDefault == 0)
- ? WindowManagerPolicy.USER_ROTATION_LOCKED
- : WindowManagerPolicy.USER_ROTATION_FREE;
- mUserRotation = Settings.System.getInt(resolver,
- Settings.System.USER_ROTATION,
- Surface.ROTATION_0);
- if (mAccelerometerDefault != accelerometerDefault) {
- mAccelerometerDefault = accelerometerDefault;
+ // Configure rotation lock.
+ int userRotation = Settings.System.getInt(resolver,
+ Settings.System.USER_ROTATION, Surface.ROTATION_0);
+ if (mUserRotation != userRotation) {
+ mUserRotation = userRotation;
+ updateRotation = true;
+ }
+ int userRotationMode = Settings.System.getInt(resolver,
+ Settings.System.ACCELEROMETER_ROTATION, 0) != 0 ?
+ WindowManagerPolicy.USER_ROTATION_FREE :
+ WindowManagerPolicy.USER_ROTATION_LOCKED;
+ if (mUserRotationMode != userRotationMode) {
+ mUserRotationMode = userRotationMode;
+ updateRotation = true;
updateOrientationListenerLp();
}
@@ -3670,7 +3671,7 @@
// Ignore sensor when plugged into HDMI.
// Note that the dock orientation overrides the HDMI orientation.
preferredRotation = mHdmiRotation;
- } else if ((mAccelerometerDefault != 0 /* implies not rotation locked */
+ } else if ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_FREE
&& (orientation == ActivityInfo.SCREEN_ORIENTATION_USER
|| orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED))
|| orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
@@ -3693,8 +3694,12 @@
} else {
preferredRotation = lastRotation;
}
- } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) {
- // Apply rotation lock.
+ } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
+ && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+ // Apply rotation lock. Does not apply to NOSENSOR.
+ // The idea is that the user rotation expresses a weak preference for the direction
+ // of gravity and as NOSENSOR is never affected by gravity, then neither should
+ // NOSENSOR be affected by rotation lock (although it will be affected by docks).
preferredRotation = mUserRotation;
} else {
// No overriding preference.
@@ -4325,8 +4330,7 @@
pw.print(prefix); pw.print("mUserRotationMode="); pw.print(mUserRotationMode);
pw.print(" mUserRotation="); pw.print(mUserRotation);
pw.print(" mAllowAllRotations="); pw.println(mAllowAllRotations);
- pw.print(prefix); pw.print("mAccelerometerDefault="); pw.print(mAccelerometerDefault);
- pw.print(" mCurrentAppOrientation="); pw.println(mCurrentAppOrientation);
+ pw.print(prefix); pw.print(" mCurrentAppOrientation="); pw.println(mCurrentAppOrientation);
pw.print(prefix); pw.print("mCarDockEnablesAccelerometer=");
pw.print(mCarDockEnablesAccelerometer);
pw.print(" mDeskDockEnablesAccelerometer=");