am 615fd3df: Merge "Implement new rotation policy." into jb-dev

* commit '615fd3dff2e369d8b786abcfe41b6da988e41001':
  Implement new rotation policy.
This commit is contained in:
Jeff Brown
2012-06-05 19:14:17 -07:00
committed by Android Git Automerger
9 changed files with 270 additions and 151 deletions

View File

@@ -1749,6 +1749,20 @@ public final class Settings {
*/
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.
@@ -2029,6 +2043,7 @@ public final class Settings {
DATE_FORMAT,
ACCELEROMETER_ROTATION,
USER_ROTATION,
HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
DTMF_TONE_WHEN_DIALING,
DTMF_TONE_TYPE_WHEN_DIALING,
EMERGENCY_TONE,

View File

@@ -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();
}
}

View File

@@ -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>

View File

@@ -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"

View File

@@ -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" >

View File

@@ -6,25 +6,39 @@ import android.widget.CompoundButton;
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);
}
}

View File

@@ -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);
}
}

View File

@@ -43,6 +43,8 @@ public class SettingsView extends LinearLayout implements View.OnClickListener {
AutoRotateController mRotate;
BrightnessController mBrightness;
DoNotDisturbController mDoNotDisturb;
View mRotationLockContainer;
View mRotationLockSeparator;
public SettingsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -61,8 +63,19 @@ public class SettingsView extends LinearLayout implements View.OnClickListener {
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,

View File

@@ -346,6 +346,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
int mUserRotation = Surface.ROTATION_0;
boolean mAccelerometerDefault;
int mAllowAllRotations = -1;
boolean mCarDockEnablesAccelerometer;
@@ -358,8 +359,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// 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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// 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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} 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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
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=");