From 670410c04ebc5910d3306559c97e3b92f9ac3821 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Fri, 5 May 2017 17:38:50 -0700 Subject: [PATCH] Use a SwitchPreference for auto-rotate instead - Change the UI to SwitchPreference - Remove old string used by DropDownPreference - Attach listener to monitor setting change Change-Id: If42cceb74296814311eb0eff8e26b4a48a1c4d29 Fix: 35959797 Test: robotests --- res/values/strings.xml | 11 -- res/xml/display_settings.xml | 5 +- src/com/android/settings/DisplaySettings.java | 2 +- .../AutoRotatePreferenceController.java | 76 ++++++------ .../AutoRotatePreferenceControllerTest.java | 111 ++++++++++++++++++ .../shadow/ShadowSystemSettings.java | 76 ++++++++++++ 6 files changed, 233 insertions(+), 48 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/testutils/shadow/ShadowSystemSettings.java diff --git a/res/values/strings.xml b/res/values/strings.xml index bb4e2a4d413..6fe3512a6b7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7075,17 +7075,6 @@ (Experimental) - - Device rotation - - Rotate the contents of the screen - - Stay in portrait view - - Stay in landscape view - - Stay in current orientation - Secure start-up diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml index 8815665ac09..d270fb894aa 100644 --- a/res/xml/display_settings.xml +++ b/res/xml/display_settings.xml @@ -57,10 +57,9 @@ android:entries="@array/screen_timeout_entries" android:entryValues="@array/screen_timeout_values" /> - + android:title="@string/accelerometer_title" /> controllers = new ArrayList<>(); controllers.add(new AutoBrightnessPreferenceController(context, KEY_AUTO_BRIGHTNESS)); - controllers.add(new AutoRotatePreferenceController(context)); + controllers.add(new AutoRotatePreferenceController(context, lifecycle)); controllers.add(new CameraGesturePreferenceController(context)); controllers.add(new DozePreferenceController(context)); controllers.add(new FontSizePreferenceController(context)); diff --git a/src/com/android/settings/display/AutoRotatePreferenceController.java b/src/com/android/settings/display/AutoRotatePreferenceController.java index 11c933371aa..af2cd8593c3 100644 --- a/src/com/android/settings/display/AutoRotatePreferenceController.java +++ b/src/com/android/settings/display/AutoRotatePreferenceController.java @@ -14,26 +14,33 @@ package com.android.settings.display; import android.content.Context; -import android.content.res.Configuration; -import android.support.v7.preference.DropDownPreference; import android.support.v7.preference.Preference; +import android.support.v7.preference.TwoStatePreference; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.view.RotationPolicy; -import com.android.settings.R; import com.android.settings.core.PreferenceController; import com.android.settings.core.instrumentation.MetricsFeatureProvider; +import com.android.settings.core.lifecycle.Lifecycle; +import com.android.settings.core.lifecycle.LifecycleObserver; +import com.android.settings.core.lifecycle.events.OnPause; +import com.android.settings.core.lifecycle.events.OnResume; import com.android.settings.overlay.FeatureFactory; public class AutoRotatePreferenceController extends PreferenceController implements - Preference.OnPreferenceChangeListener { + Preference.OnPreferenceChangeListener, LifecycleObserver, OnResume, OnPause { private static final String KEY_AUTO_ROTATE = "auto_rotate"; private final MetricsFeatureProvider mMetricsFeatureProvider; + private TwoStatePreference mPreference; + private RotationPolicy.RotationPolicyListener mRotationPolicyListener; - public AutoRotatePreferenceController(Context context) { + public AutoRotatePreferenceController(Context context, Lifecycle lifecycle) { super(context); mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); + if (lifecycle != null) { + lifecycle.addObserver(this); + } } @Override @@ -43,28 +50,8 @@ public class AutoRotatePreferenceController extends PreferenceController impleme @Override public void updateState(Preference preference) { - final DropDownPreference rotatePreference = (DropDownPreference) preference; - final int rotateLockedResourceId; - // The following block sets the string used when rotation is locked. - // If the device locks specifically to portrait or landscape (rather than current - // rotation), then we use a different string to include this information. - if (allowAllRotations()) { - rotateLockedResourceId = R.string.display_auto_rotate_stay_in_current; - } else { - if (RotationPolicy.getRotationLockOrientation(mContext) - == Configuration.ORIENTATION_PORTRAIT) { - rotateLockedResourceId = R.string.display_auto_rotate_stay_in_portrait; - } else { - rotateLockedResourceId = R.string.display_auto_rotate_stay_in_landscape; - } - } - rotatePreference.setEntries(new CharSequence[]{ - mContext.getString(R.string.display_auto_rotate_rotate), - mContext.getString(rotateLockedResourceId), - }); - rotatePreference.setEntryValues(new CharSequence[]{"0", "1"}); - rotatePreference.setValueIndex(RotationPolicy.isRotationLocked(mContext) ? - 1 : 0); + mPreference = (TwoStatePreference) preference; + updatePreference(); } @Override @@ -72,17 +59,40 @@ public class AutoRotatePreferenceController extends PreferenceController impleme return RotationPolicy.isRotationLockToggleVisible(mContext); } - private boolean allowAllRotations() { - return mContext.getResources().getBoolean( - com.android.internal.R.bool.config_allowAllRotations); - } - @Override public boolean onPreferenceChange(Preference preference, Object newValue) { - final boolean locked = Integer.parseInt((String) newValue) != 0; + final boolean locked = !(boolean) newValue; mMetricsFeatureProvider.action(mContext, MetricsProto.MetricsEvent.ACTION_ROTATION_LOCK, locked); RotationPolicy.setRotationLock(mContext, locked); return true; } + + @Override + public void onResume() { + if (mRotationPolicyListener == null) { + mRotationPolicyListener = new RotationPolicy.RotationPolicyListener() { + @Override + public void onChange() { + updatePreference(); + } + }; + } + RotationPolicy.registerRotationPolicyListener(mContext, + mRotationPolicyListener); + } + + @Override + public void onPause() { + if (mRotationPolicyListener != null) { + RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener); + } + } + + private void updatePreference() { + if (mPreference == null) { + return; + } + mPreference.setChecked(!RotationPolicy.isRotationLocked(mContext)); + } } diff --git a/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java new file mode 100644 index 00000000000..823e4c8cebb --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2017 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.settings.display; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.UserHandle; +import android.provider.Settings; +import android.support.v14.preference.SwitchPreference; + +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settings.core.lifecycle.Lifecycle; +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.shadow.ShadowSystemSettings; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.when; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class AutoRotatePreferenceControllerTest { + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private PackageManager mPackageManager; + private Lifecycle mLifecycle; + private SwitchPreference mPreference; + private ContentResolver mContentResolver; + private AutoRotatePreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + FakeFeatureFactory.setupForTest(mContext); + mContentResolver = RuntimeEnvironment.application.getContentResolver(); + mLifecycle = new Lifecycle(); + mPreference = new SwitchPreference(RuntimeEnvironment.application); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mContext.getContentResolver()).thenReturn(mContentResolver); + + mController = new AutoRotatePreferenceController(mContext, mLifecycle); + } + + @After + public void tearDown() { + ShadowSystemSettings.reset(); + } + + @Test + public void isAvailableWhenPolicyAllows() { + assertThat(mController.isAvailable()).isFalse(); + + when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true); + when(mContext.getResources().getBoolean(anyInt())).thenReturn(true); + Settings.System.putInt(mContentResolver, + Settings.System.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY, 0); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + @Config(shadows = ShadowSystemSettings.class) + public void updatePreference_settingsIsOff_shouldTurnOffToggle() { + Settings.System.putIntForUser(mContentResolver, + Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT); + + mController.updateState(mPreference); + + assertThat(mPreference.isChecked()).isFalse(); + } + + @Test + @Config(shadows = ShadowSystemSettings.class) + public void updatePreference_settingsIsOn_shouldTurnOnToggle() { + Settings.System.putIntForUser(mContentResolver, + Settings.System.ACCELEROMETER_ROTATION, 1, UserHandle.USER_CURRENT); + + mController.updateState(mPreference); + + assertThat(mPreference.isChecked()).isTrue(); + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSystemSettings.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSystemSettings.java new file mode 100644 index 00000000000..e50a7692f47 --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowSystemSettings.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2017 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.settings.testutils.shadow; + + +import android.content.ContentResolver; +import android.provider.Settings; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +import java.util.HashMap; +import java.util.Map; + +@Implements(Settings.System.class) +public class ShadowSystemSettings { + + private static final Map sValueMap = new HashMap<>(); + + @Implementation + public static boolean putInt(ContentResolver resolver, String name, int value) { + sValueMap.put(name, value); + return true; + } + + @Implementation + public static boolean putString(ContentResolver resolver, String name, String value) { + sValueMap.put(name, value); + return true; + } + + @Implementation + public static String getString(ContentResolver resolver, String name) { + return (String) sValueMap.get(name); + } + + @Implementation + public static String getStringForUser(ContentResolver resolver, String name, int userHandle) { + return getString(resolver, name); + } + + @Implementation + public static boolean putIntForUser(ContentResolver cr, String name, int value, + int userHandle) { + return putInt(cr, name, value); + } + + @Implementation + public static int getIntForUser(ContentResolver cr, String name, int def, int userHandle) { + return getInt(cr, name, def); + } + + @Implementation + public static int getInt(ContentResolver resolver, String name, int defaultValue) { + Integer value = (Integer) sValueMap.get(name); + return value == null ? defaultValue : value; + } + + public static void reset() { + sValueMap.clear(); + } +}