diff options
9 files changed, 269 insertions, 150 deletions
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 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. * The value is boolean (1 or 0). @@ -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, 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 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); + } } 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); - } - private boolean getAutoRotation() { - ContentResolver cr = mContext.getContentResolver(); - return 0 != Settings.System.getInt(cr, Settings.System.ACCELEROMETER_ROTATION, 0); + boolean visible = RotationPolicy.isRotationLockToggleVisible(mContext); + mCallbacks.setRotationLockControlVisibility(visible); + mCheckbox.setEnabled(visible); } - 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 @@ 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, 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 @@ 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="); |