From ff9065ac95fab01eadf2e8e67e9764128fc1c5a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6llner?= Date: Thu, 17 Feb 2022 11:32:54 +0000 Subject: [PATCH] Add support for device state based auto-rotation preferences in Settings. - Creates new preferences that are shown when device-state rotation is supported. - Hides standard preferences when device-state rotation is supported. - Controllers/Preferences for individual folded/unfolded rotation settings are created and added programatically based on the settable device states available. Test: Manually + Unit tests Bug: 195757480 Change-Id: I16f50fd3664756b363c7eb79e5c35eb0d3b6df17 --- res/values/config.xml | 15 +- res/xml/accessibility_system_controls.xml | 13 ++ res/xml/device_state_auto_rotate_settings.xml | 24 +++ res/xml/display_settings.xml | 15 ++ ...ockScreenRotationPreferenceController.java | 5 +- .../settings/dashboard/DashboardFragment.java | 6 + .../AutoRotatePreferenceController.java | 1 + .../DeviceStateAutoRotateDetailsFragment.java | 76 ++++++++ ...viceStateAutoRotateOverviewController.java | 52 ++++++ ...eviceStateAutoRotateSettingController.java | 141 ++++++++++++++ .../DeviceStateAutoRotationHelper.java | 113 +++++++++++ .../display/SmartAutoRotateController.java | 16 +- .../SmartAutoRotatePreferenceController.java | 1 + .../SmartAutoRotatePreferenceFragment.java | 26 ++- ...creenRotationPreferenceControllerTest.java | 25 ++- .../dashboard/DashboardFragmentTest.java | 22 +++ .../AutoRotatePreferenceControllerTest.java | 33 ++++ ...iceStateAutoRotateDetailsFragmentTest.java | 105 +++++++++++ ...StateAutoRotateOverviewControllerTest.java | 70 +++++++ ...eStateAutoRotateSettingControllerTest.java | 175 ++++++++++++++++++ .../SmartAutoRotateControllerTest.java | 52 ++++++ ...artAutoRotatePreferenceControllerTest.java | 17 +- ...SmartAutoRotatePreferenceFragmentTest.java | 78 +++++++- ...eviceStateRotationLockSettingsManager.java | 39 ++++ 24 files changed, 1106 insertions(+), 14 deletions(-) create mode 100644 res/xml/device_state_auto_rotate_settings.xml create mode 100644 src/com/android/settings/display/DeviceStateAutoRotateDetailsFragment.java create mode 100644 src/com/android/settings/display/DeviceStateAutoRotateOverviewController.java create mode 100644 src/com/android/settings/display/DeviceStateAutoRotateSettingController.java create mode 100644 src/com/android/settings/display/DeviceStateAutoRotationHelper.java create mode 100644 tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java create mode 100644 tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateOverviewControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/testutils/shadow/ShadowDeviceStateRotationLockSettingsManager.java diff --git a/res/values/config.xml b/res/values/config.xml index 50eddb528f7..bf78fd7fc98 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -570,7 +570,19 @@ 2 3 - + + + + + + false @@ -596,4 +608,5 @@ false + diff --git a/res/xml/accessibility_system_controls.xml b/res/xml/accessibility_system_controls.xml index 71e11436445..37c4d679022 100644 --- a/res/xml/accessibility_system_controls.xml +++ b/res/xml/accessibility_system_controls.xml @@ -42,9 +42,22 @@ android:title="@string/accessibility_power_button_ends_call_prerefence_title" settings:controller="com.android.settings.accessibility.PowerButtonEndsCallPreferenceController"/> + + + + + diff --git a/res/xml/device_state_auto_rotate_settings.xml b/res/xml/device_state_auto_rotate_settings.xml new file mode 100644 index 00000000000..2ddb4c7d9d5 --- /dev/null +++ b/res/xml/device_state_auto_rotate_settings.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml index 0724eea8255..ba52a301666 100644 --- a/res/xml/display_settings.xml +++ b/res/xml/display_settings.xml @@ -96,12 +96,27 @@ + + + + List useAll(Class clazz) { + return (List) mPreferenceControllers.getOrDefault(clazz, Collections.emptyList()); + } + protected void addPreferenceController(AbstractPreferenceController controller) { if (mPreferenceControllers.get(controller.getClass()) == null) { mPreferenceControllers.put(controller.getClass(), new ArrayList<>()); diff --git a/src/com/android/settings/display/AutoRotatePreferenceController.java b/src/com/android/settings/display/AutoRotatePreferenceController.java index 5dc228644a9..90423fbea7c 100644 --- a/src/com/android/settings/display/AutoRotatePreferenceController.java +++ b/src/com/android/settings/display/AutoRotatePreferenceController.java @@ -74,6 +74,7 @@ public class AutoRotatePreferenceController extends TogglePreferenceController i @Override public int getAvailabilityStatus() { return RotationPolicy.isRotationLockToggleVisible(mContext) + && !DeviceStateAutoRotationHelper.isDeviceStateRotationEnabled(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragment.java b/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragment.java new file mode 100644 index 00000000000..fb6d9f4cab0 --- /dev/null +++ b/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragment.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 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.app.settings.SettingsEnums; +import android.content.Context; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.search.Indexable; +import com.android.settingslib.search.SearchIndexable; +import com.android.settingslib.search.SearchIndexableRaw; + +import java.util.List; + +/** Fragment that shows all the available device state based auto-rotation preferences. */ +@SearchIndexable +public class DeviceStateAutoRotateDetailsFragment extends DashboardFragment { + + private static final String TAG = "DeviceStateAutoRotateDetailsFragment"; + + @Override + public int getMetricsCategory() { + return SettingsEnums.DISPLAY_AUTO_ROTATE_SETTINGS; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.device_state_auto_rotate_settings; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + DeviceStateAutoRotationHelper.initControllers( + getLifecycle(), + useAll(DeviceStateAutoRotateSettingController.class) + ); + } + + @Override + protected List createPreferenceControllers(Context context) { + return DeviceStateAutoRotationHelper.createPreferenceControllers(context); + } + + @Override + protected String getLogTag() { + return TAG; + } + + public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.device_state_auto_rotate_settings) { + + @Override + public List getRawDataToIndex(Context context, + boolean enabled) { + return DeviceStateAutoRotationHelper.getRawDataToIndex(context, enabled); + } + }; +} diff --git a/src/com/android/settings/display/DeviceStateAutoRotateOverviewController.java b/src/com/android/settings/display/DeviceStateAutoRotateOverviewController.java new file mode 100644 index 00000000000..5e49bf3e149 --- /dev/null +++ b/src/com/android/settings/display/DeviceStateAutoRotateOverviewController.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 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.Context; +import android.text.TextUtils; + +import com.android.settings.core.BasePreferenceController; + +/** + * The top-level preference controller for device state based auto-rotation settings. + * + * It doesn't do anything on its own besides showing/hiding. The toggling of the settings will + * always be done in the details screen when device state based auto-rotation is enabled. + */ +public class DeviceStateAutoRotateOverviewController extends BasePreferenceController { + + /** Preference key for when it is used in "accessibility_system_controls.xml". */ + private static final String ACCESSIBILITY_PREF_KEY = "device_state_auto_rotate_accessibility"; + + public DeviceStateAutoRotateOverviewController(Context context, String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + return isAvailableInternal() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + + private boolean isAvailableInternal() { + return isA11yPage() + ? DeviceStateAutoRotationHelper.isDeviceStateRotationEnabledForA11y(mContext) + : DeviceStateAutoRotationHelper.isDeviceStateRotationEnabled(mContext); + } + + private boolean isA11yPage() { + return TextUtils.equals(getPreferenceKey(), ACCESSIBILITY_PREF_KEY); + } +} diff --git a/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java b/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java new file mode 100644 index 00000000000..c8f6280fe3b --- /dev/null +++ b/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2022 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 static androidx.lifecycle.Lifecycle.Event.ON_START; +import static androidx.lifecycle.Lifecycle.Event.ON_STOP; + +import android.app.settings.SettingsEnums; +import android.content.Context; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +import com.android.settings.R; +import com.android.settings.core.TogglePreferenceController; +import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; +import com.android.settingslib.search.SearchIndexableRaw; + +import java.util.List; + +/** Controller for device state based auto rotation preferences. */ +public class DeviceStateAutoRotateSettingController extends TogglePreferenceController implements + LifecycleObserver { + + private SwitchPreference mPreference; + + private final DeviceStateRotationLockSettingsManager mAutoRotateSettingsManager; + private final int mOrder; + private final DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener + mDeviceStateRotationLockSettingsListener = () -> updateState(mPreference); + private final int mDeviceState; + private final String mDeviceStateDescription; + private final MetricsFeatureProvider mMetricsFeatureProvider; + + public DeviceStateAutoRotateSettingController(Context context, int deviceState, + String deviceStateDescription, int order) { + super(context, getPreferenceKeyForDeviceState(deviceState)); + mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); + mDeviceState = deviceState; + mDeviceStateDescription = deviceStateDescription; + mAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance(context); + mOrder = order; + } + + void init(Lifecycle lifecycle) { + lifecycle.addObserver(this); + } + + @OnLifecycleEvent(ON_START) + void onStart() { + mAutoRotateSettingsManager.registerListener(mDeviceStateRotationLockSettingsListener); + } + + @OnLifecycleEvent(ON_STOP) + void onStop() { + mAutoRotateSettingsManager.unregisterListener(mDeviceStateRotationLockSettingsListener); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + mPreference = new SwitchPreference(mContext); + mPreference.setTitle(mDeviceStateDescription); + mPreference.setKey(getPreferenceKey()); + mPreference.setOrder(mOrder); + screen.addPreference(mPreference); + super.displayPreference(screen); + } + + @Override + public int getAvailabilityStatus() { + return DeviceStateAutoRotationHelper.isDeviceStateRotationEnabled(mContext) + ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + + @Override + public String getPreferenceKey() { + return getPreferenceKeyForDeviceState(mDeviceState); + } + + private static String getPreferenceKeyForDeviceState(int deviceState) { + return "auto_rotate_device_state_" + deviceState; + } + + @Override + public boolean isChecked() { + return !mAutoRotateSettingsManager.isRotationLocked(mDeviceState); + } + + @Override + public boolean setChecked(boolean isChecked) { + boolean isRotationLocked = !isChecked; + mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_ROTATION_LOCK, + isRotationLocked); + mAutoRotateSettingsManager.updateSetting(mDeviceState, isRotationLocked); + return true; + } + + @Override + public void updateRawDataToIndex(List rawData) { + SearchIndexableRaw indexable = new SearchIndexableRaw(mContext); + indexable.key = getPreferenceKey(); + indexable.title = mDeviceStateDescription; + // Maybe pass screen title as param? + indexable.screenTitle = mContext.getString(R.string.accelerometer_title); + rawData.add(indexable); + } + + @Override + public int getSliceHighlightMenuRes() { + return R.string.menu_key_display; + } + + @Override + public boolean isSliceable() { + return true; // Maybe set to false if in accessibility settings screen + } + + @Override + public boolean isPublicSlice() { + return true; + } +} diff --git a/src/com/android/settings/display/DeviceStateAutoRotationHelper.java b/src/com/android/settings/display/DeviceStateAutoRotationHelper.java new file mode 100644 index 00000000000..223ef1aa4fa --- /dev/null +++ b/src/com/android/settings/display/DeviceStateAutoRotationHelper.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2022 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.Context; +import android.util.Log; + +import androidx.lifecycle.Lifecycle; + +import com.android.internal.view.RotationPolicy; +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; +import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState; +import com.android.settingslib.search.SearchIndexableRaw; + +import com.google.common.collect.ImmutableList; + +import java.util.ArrayList; +import java.util.List; + +/** + * Helper class with utility methods related to device state auto-rotation that can be used in + * auto-rotation settings fragments and controllers. + */ +public class DeviceStateAutoRotationHelper { + + private static final String TAG = "DeviceStateAutoRotHelpr"; + + static void initControllers(Lifecycle lifecycle, + List controllers) { + for (DeviceStateAutoRotateSettingController controller : controllers) { + controller.init(lifecycle); + } + } + + static ImmutableList createPreferenceControllers( + Context context) { + List settableDeviceStates = DeviceStateRotationLockSettingsManager + .getInstance(context).getSettableDeviceStates(); + int numDeviceStates = settableDeviceStates.size(); + if (numDeviceStates == 0) { + return ImmutableList.of(); + } + String[] deviceStateSettingDescriptions = context.getResources().getStringArray( + R.array.config_settableAutoRotationDeviceStatesDescriptions); + if (numDeviceStates != deviceStateSettingDescriptions.length) { + Log.wtf(TAG, + "Mismatch between number of device states and device states descriptions."); + return ImmutableList.of(); + } + + ImmutableList.Builder controllers = + ImmutableList.builderWithExpectedSize(numDeviceStates); + for (int i = 0; i < numDeviceStates; i++) { + SettableDeviceState settableDeviceState = settableDeviceStates.get(i); + if (!settableDeviceState.isSettable()) { + continue; + } + // Preferences with a lower order will be showed first. Here we go below 0 to make sure + // we are shown before statically declared preferences in XML. + int order = -numDeviceStates + i; + controllers.add(new DeviceStateAutoRotateSettingController( + context, + settableDeviceState.getDeviceState(), + deviceStateSettingDescriptions[i], + order + )); + } + return controllers.build(); + } + + static List getRawDataToIndex( + Context context, boolean enabled) { + // Check what the "enabled" param is for + List controllers = createPreferenceControllers(context); + List rawData = new ArrayList<>(); + for (AbstractPreferenceController controller : controllers) { + ((BasePreferenceController) controller).updateRawDataToIndex(rawData); + } + return rawData; + } + + /** Returns whether the device state based auto-rotation settings are enabled. */ + public static boolean isDeviceStateRotationEnabled(Context context) { + return RotationPolicy.isRotationLockToggleVisible(context) + && DeviceStateRotationLockSettingsManager.isDeviceStateRotationLockEnabled(context); + } + + /** + * Returns whether the device state based auto-rotation settings are enabled for the + * accessibility settings page. + */ + public static boolean isDeviceStateRotationEnabledForA11y(Context context) { + return RotationPolicy.isRotationSupported(context) + && DeviceStateRotationLockSettingsManager.isDeviceStateRotationLockEnabled(context); + } +} diff --git a/src/com/android/settings/display/SmartAutoRotateController.java b/src/com/android/settings/display/SmartAutoRotateController.java index 76a222aac75..d29a64e7d88 100644 --- a/src/com/android/settings/display/SmartAutoRotateController.java +++ b/src/com/android/settings/display/SmartAutoRotateController.java @@ -47,6 +47,7 @@ import com.android.settings.R; import com.android.settings.core.TogglePreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; /** * SmartAutoRotateController controls whether auto rotation is enabled @@ -54,6 +55,8 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public class SmartAutoRotateController extends TogglePreferenceController implements Preference.OnPreferenceChangeListener, LifecycleObserver { + protected Preference mPreference; + private final MetricsFeatureProvider mMetricsFeatureProvider; private final SensorPrivacyManager mPrivacyManager; private final PowerManager mPowerManager; @@ -63,7 +66,9 @@ public class SmartAutoRotateController extends TogglePreferenceController implem updateState(mPreference); } }; - protected Preference mPreference; + private final DeviceStateRotationLockSettingsManager mDeviceStateAutoRotateSettingsManager; + private final DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener + mDeviceStateRotationLockSettingsListener = () -> updateState(mPreference); private RotationPolicy.RotationPolicyListener mRotationPolicyListener; public SmartAutoRotateController(Context context, String preferenceKey) { @@ -73,6 +78,8 @@ public class SmartAutoRotateController extends TogglePreferenceController implem mPrivacyManager .addSensorPrivacyListener(CAMERA, (sensor, enabled) -> updateState(mPreference)); mPowerManager = context.getSystemService(PowerManager.class); + mDeviceStateAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance( + context); } public void init(Lifecycle lifecycle) { @@ -89,6 +96,9 @@ public class SmartAutoRotateController extends TogglePreferenceController implem } protected boolean isRotationLocked() { + if (DeviceStateAutoRotationHelper.isDeviceStateRotationEnabled(mContext)) { + return mDeviceStateAutoRotateSettingsManager.isRotationLockedForAllStates(); + } return RotationPolicy.isRotationLocked(mContext); } @@ -127,6 +137,8 @@ public class SmartAutoRotateController extends TogglePreferenceController implem }; } RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener); + mDeviceStateAutoRotateSettingsManager.registerListener( + mDeviceStateRotationLockSettingsListener); } @OnLifecycleEvent(ON_STOP) @@ -136,6 +148,8 @@ public class SmartAutoRotateController extends TogglePreferenceController implem RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener); mRotationPolicyListener = null; } + mDeviceStateAutoRotateSettingsManager.unregisterListener( + mDeviceStateRotationLockSettingsListener); } @Override diff --git a/src/com/android/settings/display/SmartAutoRotatePreferenceController.java b/src/com/android/settings/display/SmartAutoRotatePreferenceController.java index bd8ee84a2d3..d02e3367692 100644 --- a/src/com/android/settings/display/SmartAutoRotatePreferenceController.java +++ b/src/com/android/settings/display/SmartAutoRotatePreferenceController.java @@ -77,6 +77,7 @@ public class SmartAutoRotatePreferenceController extends TogglePreferenceControl @Override public int getAvailabilityStatus() { return RotationPolicy.isRotationLockToggleVisible(mContext) + && !DeviceStateAutoRotationHelper.isDeviceStateRotationEnabled(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java b/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java index 47373366ebe..9fda03c4d5f 100644 --- a/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java +++ b/src/com/android/settings/display/SmartAutoRotatePreferenceFragment.java @@ -34,10 +34,14 @@ import com.android.settings.SettingsActivity; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.widget.SettingsMainSwitchBar; +import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.search.Indexable; import com.android.settingslib.search.SearchIndexable; +import com.android.settingslib.search.SearchIndexableRaw; import com.android.settingslib.widget.FooterPreference; +import java.util.List; + /** * Preference fragment used for auto rotation */ @@ -60,6 +64,15 @@ public class SmartAutoRotatePreferenceFragment extends DashboardFragment { public void onAttach(Context context) { super.onAttach(context); use(SmartAutoRotateController.class).init(getLifecycle()); + DeviceStateAutoRotationHelper.initControllers( + getLifecycle(), + useAll(DeviceStateAutoRotateSettingController.class) + ); + } + + @Override + protected List createPreferenceControllers(Context context) { + return DeviceStateAutoRotationHelper.createPreferenceControllers(context); } @Override @@ -79,7 +92,9 @@ public class SmartAutoRotatePreferenceFragment extends DashboardFragment { @VisibleForTesting void createHeader(SettingsActivity activity) { - if (isRotationResolverServiceAvailable(activity)) { + boolean deviceStateRotationEnabled = + DeviceStateAutoRotationHelper.isDeviceStateRotationEnabled(activity); + if (isRotationResolverServiceAvailable(activity) && !deviceStateRotationEnabled) { final SettingsMainSwitchBar switchBar = activity.getSwitchBar(); switchBar.setTitle( getContext().getString(R.string.auto_rotate_settings_primary_switch_title)); @@ -127,5 +142,12 @@ public class SmartAutoRotatePreferenceFragment extends DashboardFragment { } public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.auto_rotate_settings); + new BaseSearchIndexProvider(R.xml.auto_rotate_settings) { + + @Override + public List getRawDataToIndex( + Context context, boolean enabled) { + return DeviceStateAutoRotationHelper.getRawDataToIndex(context, enabled); + } + }; } diff --git a/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java index ef8f569e4fd..f908b8aee61 100644 --- a/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/LockScreenRotationPreferenceControllerTest.java @@ -26,6 +26,7 @@ import androidx.preference.SwitchPreference; import com.android.internal.view.RotationPolicy; import com.android.settings.core.BasePreferenceController; +import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager; import com.android.settings.testutils.shadow.ShadowRotationPolicy; import org.junit.Before; @@ -50,7 +51,10 @@ public class LockScreenRotationPreferenceControllerTest { } @Test - @Config(shadows = {ShadowRotationPolicy.class}) + @Config(shadows = { + ShadowRotationPolicy.class, + ShadowDeviceStateRotationLockSettingsManager.class + }) public void getAvailabilityStatus_supportedRotation_shouldReturnAvailable() { ShadowRotationPolicy.setRotationSupported(true /* supported */); @@ -59,8 +63,23 @@ public class LockScreenRotationPreferenceControllerTest { } @Test - @Config(shadows = {ShadowRotationPolicy.class}) - public void getAvailabilityStatus_unsupportedRotation_shouldReturnUnsupportedOnDevice() { + @Config(shadows = { + ShadowRotationPolicy.class, + ShadowDeviceStateRotationLockSettingsManager.class + }) + public void getAvailabilityStatus_deviceStateRotationEnabled_returnsUnsupported() { + ShadowRotationPolicy.setRotationSupported(true /* supported */); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); + + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.UNSUPPORTED_ON_DEVICE); + } + + @Test + @Config(shadows = { + ShadowRotationPolicy.class, + ShadowDeviceStateRotationLockSettingsManager.class + }) public void getAvailabilityStatus_unsupportedRotation_shouldReturnUnsupportedOnDevice() { ShadowRotationPolicy.setRotationSupported(false /* supported */); assertThat(mController.getAvailabilityStatus()).isEqualTo( diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java index fd1c8ff528b..aa5f980f8d0 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java @@ -143,6 +143,21 @@ public class DashboardFragmentTest { assertThat(controller1).isSameInstanceAs(retrievedController); } + @Test + public void useAll_returnsAllControllersOfType() { + final TestPreferenceController controller1 = new TestPreferenceController(mContext); + final TestPreferenceController controller2 = new TestPreferenceController(mContext); + final SubTestPreferenceController controller3 = new SubTestPreferenceController(mContext); + mTestFragment.addPreferenceController(controller1); + mTestFragment.addPreferenceController(controller2); + mTestFragment.addPreferenceController(controller3); + + final List retrievedControllers = mTestFragment.useAll( + TestPreferenceController.class); + + assertThat(retrievedControllers).containsExactly(controller1, controller2); + } + @Test public void displayTilesAsPreference_shouldAddTilesWithIntent() { when(mFakeFeatureFactory.dashboardFeatureProvider @@ -360,6 +375,13 @@ public class DashboardFragmentTest { } } + public static class SubTestPreferenceController extends TestPreferenceController { + + private SubTestPreferenceController(Context context) { + super(context); + } + } + private static class TestFragment extends DashboardFragment { private final PreferenceManager mPreferenceManager; diff --git a/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java index 1d175def202..54e6b991108 100644 --- a/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/AutoRotatePreferenceControllerTest.java @@ -30,6 +30,7 @@ import android.provider.Settings; import androidx.preference.SwitchPreference; +import com.android.internal.R; import com.android.internal.view.RotationPolicy; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.FakeFeatureFactory; @@ -64,6 +65,7 @@ public class AutoRotatePreferenceControllerTest { mPreference = new SwitchPreference(RuntimeEnvironment.application); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getContentResolver()).thenReturn(mContentResolver); + disableDeviceStateRotation(); mController = new AutoRotatePreferenceController(mContext, "auto_rotate"); } @@ -111,6 +113,26 @@ public class AutoRotatePreferenceControllerTest { .UNSUPPORTED_ON_DEVICE); } + @Test + public void getAvailabilityStatus_deviceRotationDisabled_returnsAvailable() { + enableAutoRotationPreference(); + disableDeviceStateRotation(); + + int availability = mController.getAvailabilityStatus(); + + assertThat(availability).isEqualTo(BasePreferenceController.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_deviceRotationEnabled_returnsUnsupported() { + enableAutoRotationPreference(); + enableDeviceStateRotation(); + + int availability = mController.getAvailabilityStatus(); + + assertThat(availability).isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE); + } + @Test public void testIsCheck() { assertThat(mController.isChecked()).isFalse(); @@ -180,4 +202,15 @@ public class AutoRotatePreferenceControllerTest { Settings.System.putIntForUser(mContentResolver, Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT); } + + private void enableDeviceStateRotation() { + when(mContext.getResources().getStringArray( + R.array.config_perDeviceStateRotationLockDefaults)).thenReturn( + new String[]{"0:0", "1:1", "2:2"}); + } + + private void disableDeviceStateRotation() { + when(mContext.getResources().getStringArray( + R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(new String[]{}); + } } diff --git a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java new file mode 100644 index 00000000000..b773657e686 --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2022 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 static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.res.Resources; + +import com.android.settings.R; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class DeviceStateAutoRotateDetailsFragmentTest { + + private final DeviceStateAutoRotateDetailsFragment mFragment = + spy(new DeviceStateAutoRotateDetailsFragment()); + private final Context mContext = spy(RuntimeEnvironment.application); + private final Resources mResources = spy(mContext.getResources()); + + @Before + public void setUp() throws Exception { + when(mContext.getResources()).thenReturn(mResources); + when(mContext.getApplicationContext()).thenReturn(mContext); + when(mFragment.getContext()).thenReturn(mContext); + when(mFragment.getResources()).thenReturn(mResources); + } + + @Test + public void getMetricsCategory_returnsAutoRotateSettings() { + assertThat(mFragment.getMetricsCategory()).isEqualTo( + SettingsEnums.DISPLAY_AUTO_ROTATE_SETTINGS); + } + + @Test + public void getPreferenceScreenResId_returnsDeviceStateAutoRotationSettings() { + assertThat(mFragment.getPreferenceScreenResId()).isEqualTo( + R.xml.device_state_auto_rotate_settings); + } + + @Test + public void createPreferenceControllers_settableDeviceStates_returnsDeviceStateControllers() { + enableDeviceStateSettableRotationStates(new String[]{"0:1", "1:1"}, + new String[]{"Folded", "Unfolded"}); + + List preferenceControllers = + mFragment.createPreferenceControllers(mContext); + + assertThat(preferenceControllers).hasSize(2); + assertThat(preferenceControllers.get(0)).isInstanceOf( + DeviceStateAutoRotateSettingController.class); + assertThat(preferenceControllers.get(1)).isInstanceOf( + DeviceStateAutoRotateSettingController.class); + } + + @Test + public void createPreferenceControllers_noSettableDeviceStates_returnsEmptyList() { + enableDeviceStateSettableRotationStates(new String[]{}, new String[]{}); + + List preferenceControllers = + mFragment.createPreferenceControllers(mContext); + + assertThat(preferenceControllers).isEmpty(); + } + + private void enableDeviceStateSettableRotationStates(String[] settableStates, + String[] settableStatesDescriptions) { + when(mResources.getStringArray( + com.android.internal.R.array.config_perDeviceStateRotationLockDefaults)).thenReturn( + settableStates); + when(mResources.getStringArray( + R.array.config_settableAutoRotationDeviceStatesDescriptions)).thenReturn( + settableStatesDescriptions); + DeviceStateRotationLockSettingsManager.resetInstance(); + DeviceStateRotationLockSettingsManager.getInstance(mContext) + .resetStateForTesting(mResources); + } +} diff --git a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateOverviewControllerTest.java b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateOverviewControllerTest.java new file mode 100644 index 00000000000..a5416e70413 --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateOverviewControllerTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2022 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 static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + +import static com.google.common.truth.Truth.assertThat; + +import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager; +import com.android.settings.testutils.shadow.ShadowRotationPolicy; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowRotationPolicy.class, ShadowDeviceStateRotationLockSettingsManager.class}) +public class DeviceStateAutoRotateOverviewControllerTest { + + private final DeviceStateAutoRotateOverviewController mController = + new DeviceStateAutoRotateOverviewController( + RuntimeEnvironment.application, "device_state_auto_rotate"); + + @Test + public void getAvailabilityStatus_rotationAndDeviceStateRotationEnabled_returnsAvailable() { + ShadowRotationPolicy.setRotationSupported(true); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); + + int availability = mController.getAvailabilityStatus(); + + assertThat(availability).isEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_rotationNotSupported_returnsUnsupportedOnDevice() { + ShadowRotationPolicy.setRotationSupported(false); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); + + int availability = mController.getAvailabilityStatus(); + + assertThat(availability).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void getAvailabilityStatus_deviceStateRotationNotSupported_returnsUnsupportedOnDevice() { + ShadowRotationPolicy.setRotationSupported(true); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false); + + int availability = mController.getAvailabilityStatus(); + + assertThat(availability).isEqualTo(UNSUPPORTED_ON_DEVICE); + } +} diff --git a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java new file mode 100644 index 00000000000..28a071aca02 --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2022 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 static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import androidx.preference.Preference; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager; +import com.android.settings.testutils.shadow.ShadowRotationPolicy; +import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; +import com.android.settingslib.search.SearchIndexableRaw; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = { + ShadowRotationPolicy.class, + ShadowDeviceStateRotationLockSettingsManager.class +}) +public class DeviceStateAutoRotateSettingControllerTest { + + private static final int DEFAULT_DEVICE_STATE = 1; + private static final String DEFAULT_DEVICE_STATE_DESCRIPTION = "Device state description"; + private static final int DEFAULT_ORDER = -10; + + private final Context mContext = RuntimeEnvironment.application; + private final DeviceStateAutoRotateSettingController mController = + new DeviceStateAutoRotateSettingController(mContext, DEFAULT_DEVICE_STATE, + DEFAULT_DEVICE_STATE_DESCRIPTION, DEFAULT_ORDER); + private final DeviceStateRotationLockSettingsManager mAutoRotateSettingsManager = + DeviceStateRotationLockSettingsManager.getInstance(mContext); + + @Test + public void displayPreference_addsPreferenceToPreferenceScreen() { + PreferenceScreen screen = new PreferenceManager(mContext).createPreferenceScreen(mContext); + + mController.displayPreference(screen); + + assertThat(screen.getPreferenceCount()).isEqualTo(1); + Preference preference = screen.getPreference(0); + assertThat(preference.getTitle().toString()).isEqualTo(DEFAULT_DEVICE_STATE_DESCRIPTION); + assertThat(preference.getOrder()).isEqualTo(DEFAULT_ORDER); + assertThat(preference.getKey()).isEqualTo(mController.getPreferenceKey()); + } + + @Test + public void getAvailabilityStatus_rotationAndDeviceStateRotationEnabled_returnsAvailable() { + ShadowRotationPolicy.setRotationSupported(true); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); + + int availability = mController.getAvailabilityStatus(); + + assertThat(availability).isEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_deviceStateRotationDisabled_returnsUnsupported() { + ShadowRotationPolicy.setRotationSupported(true); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false); + + int availability = mController.getAvailabilityStatus(); + + assertThat(availability).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void getAvailabilityStatus_rotationDisabled_returnsUnsupported() { + ShadowRotationPolicy.setRotationSupported(false); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); + + int availability = mController.getAvailabilityStatus(); + + assertThat(availability).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void getPreferenceKey_returnsKeyBasedOnDeviceState() { + String key = mController.getPreferenceKey(); + + String expectedKey = "auto_rotate_device_state_" + DEFAULT_DEVICE_STATE; + assertThat(key).isEqualTo(expectedKey); + } + + @Test + public void isChecked_settingForStateIsUnlocked_returnsTrue() { + mAutoRotateSettingsManager.updateSetting(DEFAULT_DEVICE_STATE, /* rotationLocked= */ false); + + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void isChecked_settingForStateIsLocked_returnsFalse() { + mAutoRotateSettingsManager.updateSetting(DEFAULT_DEVICE_STATE, /* rotationLocked= */ true); + + assertThat(mController.isChecked()).isFalse(); + } + + @Test + public void setChecked_true_deviceStateSettingIsUnlocked() { + mController.setChecked(true); + + boolean rotationLocked = mAutoRotateSettingsManager.isRotationLocked(DEFAULT_DEVICE_STATE); + + assertThat(rotationLocked).isFalse(); + } + + @Test + public void setChecked_false_deviceStateSettingIsLocked() { + mController.setChecked(false); + + boolean rotationLocked = mAutoRotateSettingsManager.isRotationLocked(DEFAULT_DEVICE_STATE); + + assertThat(rotationLocked).isTrue(); + } + + @Test + public void updateRawDataToIndex_addsItemToList() { + List rawData = new ArrayList<>(); + + mController.updateRawDataToIndex(rawData); + + assertThat(rawData).hasSize(1); + SearchIndexableRaw item = rawData.get(0); + assertThat(item.key).isEqualTo(mController.getPreferenceKey()); + assertThat(item.title).isEqualTo(DEFAULT_DEVICE_STATE_DESCRIPTION); + assertThat(item.screenTitle).isEqualTo(mContext.getString(R.string.accelerometer_title)); + } + + @Test + public void getSliceHighlightMenuRes_returnsMenuKeyDisplay() { + int sliceHighlightMenuRes = mController.getSliceHighlightMenuRes(); + + assertThat(sliceHighlightMenuRes).isEqualTo(R.string.menu_key_display); + } + + @Test + public void isSliceable_returnsTrue() { + assertThat(mController.isSliceable()).isTrue(); + } + + @Test + public void isPublicSlice_returnsTrue() { + assertThat(mController.isPublicSlice()).isTrue(); + } +} diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java index 778721a163c..4fec38b762d 100644 --- a/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java @@ -39,7 +39,10 @@ import android.provider.Settings; import androidx.preference.Preference; import com.android.settings.testutils.ResolveInfoBuilder; +import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager; +import com.android.settings.testutils.shadow.ShadowRotationPolicy; import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager; +import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import org.junit.Before; import org.junit.Test; @@ -63,6 +66,8 @@ public class SmartAutoRotateControllerTest { @Mock private Preference mPreference; private ContentResolver mContentResolver; + private final DeviceStateRotationLockSettingsManager mDeviceStateAutoRotateSettingsManager = + DeviceStateRotationLockSettingsManager.getInstance(RuntimeEnvironment.application); @Before public void setUp() { @@ -122,6 +127,34 @@ public class SmartAutoRotateControllerTest { assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); } + @Test + @Config(shadows = { + ShadowDeviceStateRotationLockSettingsManager.class, + ShadowRotationPolicy.class + }) + public void getAvailabilityStatus_deviceStateRotationLocked_returnDisableDependentSetting() { + enableDeviceStateRotation(); + lockDeviceStateRotation(); + + int availabilityStatus = mController.getAvailabilityStatus(); + + assertThat(availabilityStatus).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + @Config(shadows = { + ShadowDeviceStateRotationLockSettingsManager.class, + ShadowRotationPolicy.class + }) + public void getAvailabilityStatus_deviceStateRotationUnlocked_returnAvailable() { + enableDeviceStateRotation(); + unlockDeviceStateRotation(); + + int availabilityStatus = mController.getAvailabilityStatus(); + + assertThat(availabilityStatus).isEqualTo(AVAILABLE); + } + private void enableAutoRotation() { Settings.System.putIntForUser(mContentResolver, Settings.System.ACCELEROMETER_ROTATION, 1, UserHandle.USER_CURRENT); @@ -131,4 +164,23 @@ public class SmartAutoRotateControllerTest { Settings.System.putIntForUser(mContentResolver, Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT); } + + private void enableDeviceStateRotation() { + ShadowRotationPolicy.setRotationSupported(true); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); + } + + private void lockDeviceStateRotation() { + mDeviceStateAutoRotateSettingsManager.updateSetting( + /* deviceState= */0, /* rotationLocked= */ true); + mDeviceStateAutoRotateSettingsManager.updateSetting( + /* deviceState= */1, /* rotationLocked= */ true); + } + + private void unlockDeviceStateRotation() { + mDeviceStateAutoRotateSettingsManager.updateSetting( + /* deviceState= */0, /* rotationLocked= */ false); + mDeviceStateAutoRotateSettingsManager.updateSetting( + /* deviceState= */1, /* rotationLocked= */ true); + } } diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java index 068de3472b5..39fdb049228 100644 --- a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceControllerTest.java @@ -40,6 +40,7 @@ import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.ResolveInfoBuilder; +import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager; import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager; import org.junit.Before; @@ -53,7 +54,10 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) -@Config(shadows = ShadowSensorPrivacyManager.class) +@Config(shadows = { + ShadowSensorPrivacyManager.class, + ShadowDeviceStateRotationLockSettingsManager.class +}) public class SmartAutoRotatePreferenceControllerTest { private static final String PACKAGE_NAME = "package_name"; @@ -95,6 +99,7 @@ public class SmartAutoRotatePreferenceControllerTest { new SmartAutoRotatePreferenceController(mContext, "smart_auto_rotate")); when(mController.isCameraLocked()).thenReturn(false); when(mController.isPowerSaveMode()).thenReturn(false); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false); } @Test @@ -199,6 +204,16 @@ public class SmartAutoRotatePreferenceControllerTest { .UNSUPPORTED_ON_DEVICE); } + + @Test + public void getAvailabilityStatus_deviceStateRotationEnabled_returnsUnsupported() { + enableAutoRotationPreference(); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); + + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.UNSUPPORTED_ON_DEVICE); + } + @Test public void isSliceableCorrectKey_returnsTrue() { final AutoRotatePreferenceController controller = diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java index 877d2c11e77..942fed6f619 100644 --- a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java @@ -18,6 +18,8 @@ package com.android.settings.display; import static com.android.settings.display.SmartAutoRotatePreferenceFragment.AUTO_ROTATE_SWITCH_PREFERENCE_ID; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; @@ -33,6 +35,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.res.Resources; import android.view.View; import androidx.preference.Preference; @@ -40,7 +43,11 @@ import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.testutils.ResolveInfoBuilder; +import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager; +import com.android.settings.testutils.shadow.ShadowRotationPolicy; import com.android.settings.widget.SettingsMainSwitchBar; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import org.junit.Before; import org.junit.Test; @@ -49,8 +56,15 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.List; @RunWith(RobolectricTestRunner.class) +@Config(shadows = { + ShadowDeviceStateRotationLockSettingsManager.class, + ShadowRotationPolicy.class +}) public class SmartAutoRotatePreferenceFragmentTest { private static final String PACKAGE_NAME = "package_name"; @@ -70,19 +84,24 @@ public class SmartAutoRotatePreferenceFragmentTest { @Mock private Preference mRotateSwitchPreference; + private Resources mResources; + private Context mContext; @Before public void setUp() { MockitoAnnotations.initMocks(this); - final Context context = spy(RuntimeEnvironment.application); + mContext = spy(RuntimeEnvironment.application); ContentResolver mContentResolver = RuntimeEnvironment.application.getContentResolver(); - when(context.getPackageManager()).thenReturn(mPackageManager); - when(context.getContentResolver()).thenReturn(mContentResolver); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mContext.getContentResolver()).thenReturn(mContentResolver); doReturn(PACKAGE_NAME).when(mPackageManager).getRotationResolverPackageName(); doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission( Manifest.permission.CAMERA, PACKAGE_NAME); + mResources = spy(mContext.getResources()); + when(mContext.getResources()).thenReturn(mResources); + final ResolveInfo resolveInfo = new ResolveInfoBuilder(PACKAGE_NAME).build(); resolveInfo.serviceInfo = new ServiceInfo(); when(mPackageManager.resolveService(any(), anyInt())).thenReturn(resolveInfo); @@ -90,15 +109,16 @@ public class SmartAutoRotatePreferenceFragmentTest { mFragment = spy(new SmartAutoRotatePreferenceFragment()); when(mActivity.getPackageManager()).thenReturn(mPackageManager); when(mFragment.getActivity()).thenReturn(mActivity); - when(mFragment.getContext()).thenReturn(context); + when(mFragment.getContext()).thenReturn(mContext); doReturn(mView).when(mFragment).getView(); when(mFragment.findPreference(AUTO_ROTATE_SWITCH_PREFERENCE_ID)).thenReturn( mRotateSwitchPreference); - mSwitchBar = spy(new SettingsMainSwitchBar(context)); + mSwitchBar = spy(new SettingsMainSwitchBar(mContext)); when(mActivity.getSwitchBar()).thenReturn(mSwitchBar); doReturn(mSwitchBar).when(mView).findViewById(R.id.switch_bar); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(false); } @@ -110,6 +130,17 @@ public class SmartAutoRotatePreferenceFragmentTest { verify(mRotateSwitchPreference, times(1)).setVisible(false); } + @Test + public void createHeader_deviceStateRotationSupported_switchBarIsDisabled() { + ShadowRotationPolicy.setRotationSupported(true); + ShadowDeviceStateRotationLockSettingsManager.setDeviceStateRotationLockEnabled(true); + + mFragment.createHeader(mActivity); + + verify(mSwitchBar, never()).show(); + verify(mRotateSwitchPreference, never()).setVisible(false); + } + @Test public void createHeader_faceDetectionUnSupported_switchBarIsDisabled() { doReturn(null).when(mPackageManager).getRotationResolverPackageName(); @@ -120,4 +151,41 @@ public class SmartAutoRotatePreferenceFragmentTest { verify(mRotateSwitchPreference, never()).setVisible(false); } + @Test + public void createPreferenceControllers_noSettableDeviceStates_returnsEmptyList() { + enableDeviceStateSettableRotationStates(new String[]{}, new String[]{}); + + List preferenceControllers = + mFragment.createPreferenceControllers(mContext); + + assertThat(preferenceControllers).isEmpty(); + } + + @Test + public void createPreferenceControllers_settableDeviceStates_returnsDeviceStateControllers() { + enableDeviceStateSettableRotationStates(new String[]{"0:1", "1:1"}, + new String[]{"Folded", "Unfolded"}); + + List preferenceControllers = + mFragment.createPreferenceControllers(mContext); + + assertThat(preferenceControllers).hasSize(2); + assertThat(preferenceControllers.get(0)).isInstanceOf( + DeviceStateAutoRotateSettingController.class); + assertThat(preferenceControllers.get(1)).isInstanceOf( + DeviceStateAutoRotateSettingController.class); + } + + private void enableDeviceStateSettableRotationStates(String[] settableStates, + String[] settableStatesDescriptions) { + when(mResources.getStringArray( + com.android.internal.R.array.config_perDeviceStateRotationLockDefaults)).thenReturn( + settableStates); + when(mResources.getStringArray( + R.array.config_settableAutoRotationDeviceStatesDescriptions)).thenReturn( + settableStatesDescriptions); + DeviceStateRotationLockSettingsManager.resetInstance(); + DeviceStateRotationLockSettingsManager.getInstance(mContext) + .resetStateForTesting(mResources); + } } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDeviceStateRotationLockSettingsManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDeviceStateRotationLockSettingsManager.java new file mode 100644 index 00000000000..72df3cc94b3 --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDeviceStateRotationLockSettingsManager.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 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.Context; + +import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(DeviceStateRotationLockSettingsManager.class) +public class ShadowDeviceStateRotationLockSettingsManager { + + private static boolean sDeviceStateRotationLockEnabled; + + @Implementation + public static boolean isDeviceStateRotationLockEnabled(Context context) { + return sDeviceStateRotationLockEnabled; + } + + public static void setDeviceStateRotationLockEnabled(boolean enabled) { + sDeviceStateRotationLockEnabled = enabled; + } +}