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 1/9] 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; + } +} From ce321f0dd0672317301f04ba1329bb1a1f3a2e17 Mon Sep 17 00:00:00 2001 From: Marie Matheson Date: Fri, 18 Feb 2022 22:57:17 +0000 Subject: [PATCH 2/9] Merge SafetyCenterStatusHolder into SafetyCenterManagerWrapper Test: SettingsUnitTests Bug: 220384387 Change-Id: I3886d3cf4717b5c7efd99ebd8ffb6a039e3565a4 --- src/com/android/settings/Settings.java | 6 +- .../privacy/PrivacyDashboardFragment.java | 4 +- ...LevelPrivacyEntryPreferenceController.java | 4 +- .../safetycenter/BiometricsSafetySource.java | 2 +- .../safetycenter/LockScreenSafetySource.java | 2 +- .../SafetyCenterManagerWrapper.java | 20 ++++++ .../SafetyCenterStatusHolder.java | 62 ------------------- .../SafetySourceBroadcastReceiver.java | 2 +- ...SafetyCenterEntryPreferenceController.java | 2 +- .../security/SecurityAdvancedSettings.java | 4 +- .../settings/security/SecuritySettings.java | 4 +- ...evelSecurityEntryPreferenceController.java | 4 +- .../privacy/PrivacyDashboardActivityTest.java | 10 +-- ...lPrivacyEntryPreferenceControllerTest.java | 10 +-- .../BiometricsSafetySourceTest.java | 9 +-- .../LockScreenSafetySourceTest.java | 11 +--- ...va => SafetyCenterManagerWrapperTest.java} | 6 +- .../SafetySourceBroadcastReceiverTest.java | 19 +++--- ...tyCenterEntryPreferenceControllerTest.java | 14 +++-- .../SecurityAdvancedSettingsTest.java | 12 ++-- .../SecurityDashboardActivityTest.java | 10 +-- ...SecurityEntryPreferenceControllerTest.java | 10 +-- 22 files changed, 88 insertions(+), 139 deletions(-) delete mode 100644 src/com/android/settings/safetycenter/SafetyCenterStatusHolder.java rename tests/unit/src/com/android/settings/safetycenter/{SafetyCenterStatusHolderTest.java => SafetyCenterManagerWrapperTest.java} (87%) diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index e276484a1aa..57d7d105188 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -33,7 +33,7 @@ import com.android.settings.enterprise.EnterprisePrivacySettings; import com.android.settings.network.SubscriptionUtil; import com.android.settings.network.telephony.MobileNetworkUtils; import com.android.settings.overlay.FeatureFactory; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import com.android.settings.security.SecuritySettingsFeatureProvider; import com.google.android.setupdesign.util.ThemeHelper; @@ -152,7 +152,7 @@ public class Settings extends SettingsActivity { /** Redirects to SafetyCenter if enabled. */ @VisibleForTesting public void handleSafetyCenterRedirection() { - if (SafetyCenterStatusHolder.get().isEnabled(this)) { + if (SafetyCenterManagerWrapper.get().isEnabled(this)) { try { startActivity(new Intent(Intent.ACTION_SAFETY_CENTER)); finish(); @@ -213,7 +213,7 @@ public class Settings extends SettingsActivity { /** Redirects to SafetyCenter if enabled. */ @VisibleForTesting public void handleSafetyCenterRedirection() { - if (SafetyCenterStatusHolder.get().isEnabled(this)) { + if (SafetyCenterManagerWrapper.get().isEnabled(this)) { try { startActivity(new Intent(Intent.ACTION_SAFETY_CENTER)); finish(); diff --git a/src/com/android/settings/privacy/PrivacyDashboardFragment.java b/src/com/android/settings/privacy/PrivacyDashboardFragment.java index 0638c60c94c..df59bd5f119 100644 --- a/src/com/android/settings/privacy/PrivacyDashboardFragment.java +++ b/src/com/android/settings/privacy/PrivacyDashboardFragment.java @@ -29,7 +29,7 @@ import android.os.Bundle; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.notification.LockScreenNotificationPreferenceController; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -118,7 +118,7 @@ public class PrivacyDashboardFragment extends DashboardFragment { @Override protected boolean isPageSearchEnabled(Context context) { - return !SafetyCenterStatusHolder.get().isEnabled(context); + return !SafetyCenterManagerWrapper.get().isEnabled(context); } }; } diff --git a/src/com/android/settings/privacy/TopLevelPrivacyEntryPreferenceController.java b/src/com/android/settings/privacy/TopLevelPrivacyEntryPreferenceController.java index 87daf7fe7ba..b5532394aa2 100644 --- a/src/com/android/settings/privacy/TopLevelPrivacyEntryPreferenceController.java +++ b/src/com/android/settings/privacy/TopLevelPrivacyEntryPreferenceController.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.content.Context; import com.android.settings.core.BasePreferenceController; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; /** The preference controller for the top level privacy tile. */ public class TopLevelPrivacyEntryPreferenceController extends BasePreferenceController { @@ -31,7 +31,7 @@ public class TopLevelPrivacyEntryPreferenceController extends BasePreferenceCon @Override public int getAvailabilityStatus() { - if (!SafetyCenterStatusHolder.get().isEnabled(mContext)) { + if (!SafetyCenterManagerWrapper.get().isEnabled(mContext)) { return AVAILABLE; } return CONDITIONALLY_UNAVAILABLE; diff --git a/src/com/android/settings/safetycenter/BiometricsSafetySource.java b/src/com/android/settings/safetycenter/BiometricsSafetySource.java index f37ea0361ae..296ca73daa8 100644 --- a/src/com/android/settings/safetycenter/BiometricsSafetySource.java +++ b/src/com/android/settings/safetycenter/BiometricsSafetySource.java @@ -27,7 +27,7 @@ public final class BiometricsSafetySource { /** Sends biometric safety data to Safety Center. */ public static void sendSafetyData(Context context) { - if (!SafetyCenterStatusHolder.get().isEnabled(context)) { + if (!SafetyCenterManagerWrapper.get().isEnabled(context)) { return; } diff --git a/src/com/android/settings/safetycenter/LockScreenSafetySource.java b/src/com/android/settings/safetycenter/LockScreenSafetySource.java index c9c1cd49a43..5ebe12aca95 100644 --- a/src/com/android/settings/safetycenter/LockScreenSafetySource.java +++ b/src/com/android/settings/safetycenter/LockScreenSafetySource.java @@ -40,7 +40,7 @@ public final class LockScreenSafetySource { /** Sends lock screen safety data to Safety Center. */ public static void sendSafetyData(Context context, ScreenLockPreferenceDetailsUtils screenLockPreferenceDetailsUtils) { - if (!SafetyCenterStatusHolder.get().isEnabled(context)) { + if (!SafetyCenterManagerWrapper.get().isEnabled(context)) { return; } diff --git a/src/com/android/settings/safetycenter/SafetyCenterManagerWrapper.java b/src/com/android/settings/safetycenter/SafetyCenterManagerWrapper.java index 7e47f239f93..e4a1d673c4d 100644 --- a/src/com/android/settings/safetycenter/SafetyCenterManagerWrapper.java +++ b/src/com/android/settings/safetycenter/SafetyCenterManagerWrapper.java @@ -58,4 +58,24 @@ public class SafetyCenterManagerWrapper { return; } } + + /** Returns true is SafetyCenter page is enabled, false otherwise. */ + public boolean isEnabled(Context context) { + if (context == null) { + Log.e(TAG, "Context is null at SafetyCenterManagerWrapper#isEnabled"); + return false; + } + SafetyCenterManager safetyCenterManager = + context.getSystemService(SafetyCenterManager.class); + if (safetyCenterManager == null) { + Log.w(TAG, "System service SAFETY_CENTER_SERVICE (SafetyCenterManager) is null"); + return false; + } + try { + return safetyCenterManager.isSafetyCenterEnabled(); + } catch (RuntimeException e) { + Log.e(TAG, "Calling isSafetyCenterEnabled failed.", e); + return false; + } + } } diff --git a/src/com/android/settings/safetycenter/SafetyCenterStatusHolder.java b/src/com/android/settings/safetycenter/SafetyCenterStatusHolder.java deleted file mode 100644 index 014c600d487..00000000000 --- a/src/com/android/settings/safetycenter/SafetyCenterStatusHolder.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.safetycenter; - -import android.content.Context; -import android.safetycenter.SafetyCenterManager; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -/** Knows whether safety center is enabled or disabled. */ -public class SafetyCenterStatusHolder { - - private static final String TAG = "SafetyCenterStatusHolder"; - - @VisibleForTesting - public static SafetyCenterStatusHolder sInstance; - - private SafetyCenterStatusHolder() {} - - /** Returns an instance of {@link SafetyCenterStatusHolder}. */ - public static SafetyCenterStatusHolder get() { - if (sInstance == null) { - sInstance = new SafetyCenterStatusHolder(); - } - return sInstance; - } - - /** Returns true is SafetyCenter page is enabled, false otherwise. */ - public boolean isEnabled(Context context) { - if (context == null) { - Log.e(TAG, "Context is null at SafetyCenterStatusHolder#isEnabled"); - return false; - } - SafetyCenterManager safetyCenterManager = - context.getSystemService(SafetyCenterManager.class); - if (safetyCenterManager == null) { - Log.w(TAG, "System service SAFETY_CENTER_SERVICE (SafetyCenterManager) is null"); - return false; - } - try { - return safetyCenterManager.isSafetyCenterEnabled(); - } catch (RuntimeException e) { - Log.e(TAG, "Calling isSafetyCenterEnabled failed.", e); - return false; - } - } -} diff --git a/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiver.java b/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiver.java index 558a8b9f519..a0d18c7d09f 100644 --- a/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiver.java +++ b/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiver.java @@ -36,7 +36,7 @@ public class SafetySourceBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (!SafetyCenterStatusHolder.get().isEnabled(context)) { + if (!SafetyCenterManagerWrapper.get().isEnabled(context)) { return; } diff --git a/src/com/android/settings/safetycenter/TopLevelSafetyCenterEntryPreferenceController.java b/src/com/android/settings/safetycenter/TopLevelSafetyCenterEntryPreferenceController.java index b00c084e6cb..af9509bf7cc 100644 --- a/src/com/android/settings/safetycenter/TopLevelSafetyCenterEntryPreferenceController.java +++ b/src/com/android/settings/safetycenter/TopLevelSafetyCenterEntryPreferenceController.java @@ -37,7 +37,7 @@ public class TopLevelSafetyCenterEntryPreferenceController extends BasePreferenc @Override public int getAvailabilityStatus() { - if (SafetyCenterStatusHolder.get().isEnabled(mContext)) { + if (SafetyCenterManagerWrapper.get().isEnabled(mContext)) { return AVAILABLE; } return CONDITIONALLY_UNAVAILABLE; diff --git a/src/com/android/settings/security/SecurityAdvancedSettings.java b/src/com/android/settings/security/SecurityAdvancedSettings.java index e5f494507a0..f716064a6ae 100644 --- a/src/com/android/settings/security/SecurityAdvancedSettings.java +++ b/src/com/android/settings/security/SecurityAdvancedSettings.java @@ -34,7 +34,7 @@ import com.android.settings.biometrics.face.FaceProfileStatusPreferenceControlle import com.android.settings.biometrics.fingerprint.FingerprintProfileStatusPreferenceController; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.overlay.FeatureFactory; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.security.trustagent.TrustAgentListPreferenceController; import com.android.settings.widget.PreferenceCategoryController; @@ -92,7 +92,7 @@ public class SecurityAdvancedSettings extends DashboardFragment { final Context context = getContext(); if (context == null) { return CATEGORY_SECURITY_LEGACY_ADVANCED_SETTINGS; - } else if (SafetyCenterStatusHolder.get().isEnabled(context)) { + } else if (SafetyCenterManagerWrapper.get().isEnabled(context)) { return CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS; } else { final SecuritySettingsFeatureProvider securitySettingsFeatureProvider = diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java index 6bfbf6cc3f3..6aadee6aad5 100644 --- a/src/com/android/settings/security/SecuritySettings.java +++ b/src/com/android/settings/security/SecuritySettings.java @@ -25,7 +25,7 @@ import com.android.settings.biometrics.face.FaceStatusPreferenceController; import com.android.settings.biometrics.fingerprint.FingerprintStatusPreferenceController; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.overlay.FeatureFactory; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.security.trustagent.TrustAgentListPreferenceController; import com.android.settings.widget.PreferenceCategoryController; @@ -129,7 +129,7 @@ public class SecuritySettings extends DashboardFragment { protected boolean isPageSearchEnabled(Context context) { return !FeatureFactory.getFactory(context).getSecuritySettingsFeatureProvider() .hasAlternativeSecuritySettingsFragment() - && !SafetyCenterStatusHolder.get().isEnabled(context); + && !SafetyCenterManagerWrapper.get().isEnabled(context); } }; } diff --git a/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java b/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java index 11d1dc32da7..3cf40a0e907 100644 --- a/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java +++ b/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java @@ -24,7 +24,7 @@ import androidx.preference.Preference; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.SubSettingLauncher; import com.android.settings.overlay.FeatureFactory; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; public class TopLevelSecurityEntryPreferenceController extends BasePreferenceController { @@ -38,7 +38,7 @@ public class TopLevelSecurityEntryPreferenceController extends BasePreferenceCon @Override public int getAvailabilityStatus() { - if (!SafetyCenterStatusHolder.get().isEnabled(mContext)) { + if (!SafetyCenterManagerWrapper.get().isEnabled(mContext)) { return AVAILABLE; } return CONDITIONALLY_UNAVAILABLE; diff --git a/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java b/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java index d4df97ff77e..1cfee0f377a 100644 --- a/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java +++ b/tests/unit/src/com/android/settings/privacy/PrivacyDashboardActivityTest.java @@ -33,7 +33,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.settings.Settings; import com.android.settings.SettingsActivity; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import org.junit.Before; import org.junit.Test; @@ -48,14 +48,14 @@ public class PrivacyDashboardActivityTest { private static final String DEFAULT_FRAGMENT_CLASSNAME = "DefaultFragmentClassname"; @Mock - private SafetyCenterStatusHolder mSafetyCenterStatusHolder; + private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; private Settings.PrivacyDashboardActivity mActivity; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - SafetyCenterStatusHolder.sInstance = mSafetyCenterStatusHolder; + SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; final Intent intent = new Intent(); intent.setAction(android.provider.Settings.ACTION_PRIVACY_SETTINGS); intent.setClass(InstrumentationRegistry.getInstrumentation().getTargetContext(), @@ -78,7 +78,7 @@ public class PrivacyDashboardActivityTest { @Test public void onCreate_whenSafetyCenterEnabled_redirectsToSafetyCenter() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true); final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); mActivity.handleSafetyCenterRedirection(); @@ -89,7 +89,7 @@ public class PrivacyDashboardActivityTest { @Test public void onCreate_whenSafetyCenterDisabled_doesntRedirectToSafetyCenter() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(false); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(false); mActivity.handleSafetyCenterRedirection(); verify(mActivity, times(0)).startActivity(any()); diff --git a/tests/unit/src/com/android/settings/privacy/TopLevelPrivacyEntryPreferenceControllerTest.java b/tests/unit/src/com/android/settings/privacy/TopLevelPrivacyEntryPreferenceControllerTest.java index 495700a10dd..bc6be2eaf80 100644 --- a/tests/unit/src/com/android/settings/privacy/TopLevelPrivacyEntryPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/privacy/TopLevelPrivacyEntryPreferenceControllerTest.java @@ -26,7 +26,7 @@ import android.content.Context; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import com.android.settings.security.TopLevelSecurityEntryPreferenceController; import org.junit.Before; @@ -43,12 +43,12 @@ public class TopLevelPrivacyEntryPreferenceControllerTest { private TopLevelPrivacyEntryPreferenceController mTopLevelPrivacyEntryPreferenceController; @Mock - private SafetyCenterStatusHolder mSafetyCenterStatusHolder; + private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; @Before public void setUp() { MockitoAnnotations.initMocks(this); - SafetyCenterStatusHolder.sInstance = mSafetyCenterStatusHolder; + SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; mTopLevelPrivacyEntryPreferenceController = new TopLevelPrivacyEntryPreferenceController( @@ -57,7 +57,7 @@ public class TopLevelPrivacyEntryPreferenceControllerTest { @Test public void getAvailabilityStatus_whenSafetyCenterEnabled_returnsUnavailable() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true); assertThat(mTopLevelPrivacyEntryPreferenceController.getAvailabilityStatus()) .isEqualTo(TopLevelSecurityEntryPreferenceController.CONDITIONALLY_UNAVAILABLE); @@ -65,7 +65,7 @@ public class TopLevelPrivacyEntryPreferenceControllerTest { @Test public void getAvailabilityStatus_whenSafetyCenterDisabled_returnsAvailable() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(false); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(false); assertThat(mTopLevelPrivacyEntryPreferenceController.getAvailabilityStatus()) .isEqualTo(TopLevelSecurityEntryPreferenceController.AVAILABLE); diff --git a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java index f53d3366474..2627d245d96 100644 --- a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java +++ b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java @@ -41,26 +41,21 @@ public class BiometricsSafetySourceTest { @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; - @Mock - private SafetyCenterStatusHolder mSafetyCenterStatusHolder; - @Before public void setUp() { MockitoAnnotations.initMocks(this); mApplicationContext = ApplicationProvider.getApplicationContext(); SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; - SafetyCenterStatusHolder.sInstance = mSafetyCenterStatusHolder; } @After public void tearDown() { SafetyCenterManagerWrapper.sInstance = null; - SafetyCenterStatusHolder.sInstance = null; } @Test public void sendSafetyData_whenSafetyCenterIsDisabled_sendsNoData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(false); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false); BiometricsSafetySource.sendSafetyData(mApplicationContext); @@ -70,7 +65,7 @@ public class BiometricsSafetySourceTest { @Test // TODO(b/215517420): Adapt this test when method is implemented. public void sendSafetyData_whenSafetyCenterIsEnabled_sendsNoData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); BiometricsSafetySource.sendSafetyData(mApplicationContext); diff --git a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java index 4a58b4c2f04..4b214083e5b 100644 --- a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java +++ b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java @@ -56,9 +56,6 @@ public class LockScreenSafetySourceTest { @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; - @Mock - private SafetyCenterStatusHolder mSafetyCenterStatusHolder; - @Mock private ScreenLockPreferenceDetailsUtils mScreenLockPreferenceDetailsUtils; @@ -67,18 +64,16 @@ public class LockScreenSafetySourceTest { MockitoAnnotations.initMocks(this); mApplicationContext = ApplicationProvider.getApplicationContext(); SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; - SafetyCenterStatusHolder.sInstance = mSafetyCenterStatusHolder; } @After public void tearDown() { SafetyCenterManagerWrapper.sInstance = null; - SafetyCenterStatusHolder.sInstance = null; } @Test public void sendSafetyData_whenSafetyCenterIsDisabled_sendsNoData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(false); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false); LockScreenSafetySource.sendSafetyData(mApplicationContext, mScreenLockPreferenceDetailsUtils); @@ -88,7 +83,7 @@ public class LockScreenSafetySourceTest { @Test public void sendSafetyData_whenScreenLockIsDisabled_sendsNoData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); when(mScreenLockPreferenceDetailsUtils.isAvailable()).thenReturn(false); LockScreenSafetySource.sendSafetyData(mApplicationContext, @@ -227,7 +222,7 @@ public class LockScreenSafetySourceTest { } private void whenScreenLockIsEnabled() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); when(mScreenLockPreferenceDetailsUtils.isAvailable()).thenReturn(true); when(mScreenLockPreferenceDetailsUtils.getSummary(anyInt())).thenReturn(SUMMARY); diff --git a/tests/unit/src/com/android/settings/safetycenter/SafetyCenterStatusHolderTest.java b/tests/unit/src/com/android/settings/safetycenter/SafetyCenterManagerWrapperTest.java similarity index 87% rename from tests/unit/src/com/android/settings/safetycenter/SafetyCenterStatusHolderTest.java rename to tests/unit/src/com/android/settings/safetycenter/SafetyCenterManagerWrapperTest.java index 2a31eb8e14a..432a5d67e98 100644 --- a/tests/unit/src/com/android/settings/safetycenter/SafetyCenterStatusHolderTest.java +++ b/tests/unit/src/com/android/settings/safetycenter/SafetyCenterManagerWrapperTest.java @@ -32,7 +32,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) -public class SafetyCenterStatusHolderTest { +public class SafetyCenterManagerWrapperTest { @Mock private Context mContext; @@ -44,13 +44,13 @@ public class SafetyCenterStatusHolderTest { @Test public void isEnabled_whenContextNull_returnsFalse() { - assertThat(SafetyCenterStatusHolder.get().isEnabled(null)).isFalse(); + assertThat(SafetyCenterManagerWrapper.get().isEnabled(null)).isFalse(); } @Test public void isEnabled_whenSystemServiceNull_returnsFalse() { when(mContext.getSystemService(SafetyCenterManager.class)).thenReturn(null); - assertThat(SafetyCenterStatusHolder.get().isEnabled(mContext)).isFalse(); + assertThat(SafetyCenterManagerWrapper.get().isEnabled(mContext)).isFalse(); } } diff --git a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java index 6c9addd6a3e..d81e8afed3a 100644 --- a/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java +++ b/tests/unit/src/com/android/settings/safetycenter/SafetySourceBroadcastReceiverTest.java @@ -50,26 +50,21 @@ public class SafetySourceBroadcastReceiverTest { @Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; - @Mock - private SafetyCenterStatusHolder mSafetyCenterStatusHolder; - @Before public void setUp() { MockitoAnnotations.initMocks(this); mApplicationContext = ApplicationProvider.getApplicationContext(); SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; - SafetyCenterStatusHolder.sInstance = mSafetyCenterStatusHolder; } @After public void tearDown() { SafetyCenterManagerWrapper.sInstance = null; - SafetyCenterStatusHolder.sInstance = null; } @Test public void sendSafetyData_whenSafetyCenterIsEnabled_withNoIntentAction_sendsNoData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); Intent intent = new Intent().putExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS, new String[]{}); new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent); @@ -79,7 +74,7 @@ public class SafetySourceBroadcastReceiverTest { @Test public void sendSafetyData_whenSafetyCenterIsDisabled_sendsNoData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(false); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false); Intent intent = new Intent() .setAction(ACTION_REFRESH_SAFETY_SOURCES) @@ -94,7 +89,7 @@ public class SafetySourceBroadcastReceiverTest { @Test public void sendSafetyData_whenSafetyCenterIsEnabled_withNullSourceIds_sendsNoData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); Intent intent = new Intent().setAction(ACTION_REFRESH_SAFETY_SOURCES); new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent); @@ -104,7 +99,7 @@ public class SafetySourceBroadcastReceiverTest { @Test public void sendSafetyData_whenSafetyCenterIsEnabled_withNoSourceIds_sendsNoData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); Intent intent = new Intent() .setAction(ACTION_REFRESH_SAFETY_SOURCES) @@ -117,7 +112,7 @@ public class SafetySourceBroadcastReceiverTest { @Test public void sendSafetyData_withLockscreenSourceId_sendsLockscreenData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); Intent intent = new Intent() .setAction(ACTION_REFRESH_SAFETY_SOURCES) @@ -136,7 +131,7 @@ public class SafetySourceBroadcastReceiverTest { @Test public void sendSafetyData_withBiometricsSourceId_sendsBiometricData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); Intent intent = new Intent() .setAction(ACTION_REFRESH_SAFETY_SOURCES) @@ -152,7 +147,7 @@ public class SafetySourceBroadcastReceiverTest { @Test public void sendSafetyData_onBootCompleted_sendsBiometricAndLockscreenData() { - when(mSafetyCenterStatusHolder.isEnabled(mApplicationContext)).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true); Intent intent = new Intent().setAction(Intent.ACTION_BOOT_COMPLETED); // TODO(b/215517420): Update this test when BiometricSafetySource is implemented to test diff --git a/tests/unit/src/com/android/settings/safetycenter/TopLevelSafetyCenterEntryPreferenceControllerTest.java b/tests/unit/src/com/android/settings/safetycenter/TopLevelSafetyCenterEntryPreferenceControllerTest.java index e9c451e4c31..25cd774ea05 100644 --- a/tests/unit/src/com/android/settings/safetycenter/TopLevelSafetyCenterEntryPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/safetycenter/TopLevelSafetyCenterEntryPreferenceControllerTest.java @@ -32,6 +32,7 @@ import androidx.preference.Preference; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,7 +50,7 @@ public class TopLevelSafetyCenterEntryPreferenceControllerTest { private Preference mPreference; @Mock - private SafetyCenterStatusHolder mSafetyCenterStatusHolder; + private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; @Mock private Context mContext; @@ -57,7 +58,7 @@ public class TopLevelSafetyCenterEntryPreferenceControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - SafetyCenterStatusHolder.sInstance = mSafetyCenterStatusHolder; + SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; mPreference = new Preference(ApplicationProvider.getApplicationContext()); mPreference.setKey(PREFERENCE_KEY); @@ -67,6 +68,11 @@ public class TopLevelSafetyCenterEntryPreferenceControllerTest { new TopLevelSafetyCenterEntryPreferenceController(mContext, PREFERENCE_KEY); } + @After + public void tearDown() { + SafetyCenterManagerWrapper.sInstance = null; + } + @Test public void handlePreferenceTreeClick_forDifferentPreferenceKey_isNotHandled() { Preference preference = new Preference(ApplicationProvider.getApplicationContext()); @@ -104,7 +110,7 @@ public class TopLevelSafetyCenterEntryPreferenceControllerTest { @Test public void getAvailabilityStatus_whenSafetyCenterDisabled_returnsUnavailable() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(false); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(false); assertThat(mTopLevelSafetyCenterEntryPreferenceController.getAvailabilityStatus()) .isEqualTo(TopLevelSafetyCenterEntryPreferenceController.CONDITIONALLY_UNAVAILABLE); @@ -112,7 +118,7 @@ public class TopLevelSafetyCenterEntryPreferenceControllerTest { @Test public void getAvailabilityStatus_whenSafetyCenterEnabled_returnsAvailable() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true); assertThat(mTopLevelSafetyCenterEntryPreferenceController.getAvailabilityStatus()) .isEqualTo(TopLevelSafetyCenterEntryPreferenceController.AVAILABLE); diff --git a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java index ac91abba547..2efb357b869 100644 --- a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java +++ b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java @@ -29,7 +29,7 @@ import androidx.test.annotation.UiThreadTest; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.ResourcesUtils; import com.android.settingslib.drawer.CategoryKey; @@ -51,7 +51,7 @@ public class SecurityAdvancedSettingsTest { private SecurityAdvancedSettings mSecurityAdvancedSettings; @Mock - private SafetyCenterStatusHolder mSafetyCenterStatusHolder; + private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; @Before @UiThreadTest @@ -61,7 +61,7 @@ public class SecurityAdvancedSettingsTest { Looper.prepare(); } - SafetyCenterStatusHolder.sInstance = mSafetyCenterStatusHolder; + SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; mContext = ApplicationProvider.getApplicationContext(); mSecurityAdvancedSettings = spy(new SecurityAdvancedSettings()); @@ -76,7 +76,7 @@ public class SecurityAdvancedSettingsTest { @Test public void getCategoryKey_whenSafetyCenterIsEnabled_returnsSecurity() { - when(mSafetyCenterStatusHolder.isEnabled(any())).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(true); assertThat(mSecurityAdvancedSettings.getCategoryKey()) .isEqualTo(CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS); @@ -84,7 +84,7 @@ public class SecurityAdvancedSettingsTest { @Test public void getCategoryKey_whenAlternativeFragmentPresented_returnsAlternative() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(false); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(false); setupAlternativeFragment(true, ALTERNATIVE_CATEGORY_KEY); assertThat(mSecurityAdvancedSettings.getCategoryKey()) @@ -93,7 +93,7 @@ public class SecurityAdvancedSettingsTest { @Test public void getCategoryKey_whenNoAlternativeFragmentPresented_returnsLegacy() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(false); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(false); setupAlternativeFragment(false, null); assertThat(mSecurityAdvancedSettings.getCategoryKey()) diff --git a/tests/unit/src/com/android/settings/security/SecurityDashboardActivityTest.java b/tests/unit/src/com/android/settings/security/SecurityDashboardActivityTest.java index 33486638bd9..82112c96807 100644 --- a/tests/unit/src/com/android/settings/security/SecurityDashboardActivityTest.java +++ b/tests/unit/src/com/android/settings/security/SecurityDashboardActivityTest.java @@ -33,7 +33,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.settings.Settings; import com.android.settings.SettingsActivity; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Before; @@ -53,14 +53,14 @@ public class SecurityDashboardActivityTest { private Intent mDefaultIntent; @Mock - private SafetyCenterStatusHolder mSafetyCenterStatusHolder; + private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; @Before public void setUp() { MockitoAnnotations.initMocks(this); FakeFeatureFactory mFeatureFactory = FakeFeatureFactory.setupForTest(); mSecuritySettingsFeatureProvider = mFeatureFactory.getSecuritySettingsFeatureProvider(); - SafetyCenterStatusHolder.sInstance = mSafetyCenterStatusHolder; + SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; mDefaultIntent = new Intent(); mDefaultIntent.setAction(android.provider.Settings.ACTION_SECURITY_SETTINGS); @@ -122,7 +122,7 @@ public class SecurityDashboardActivityTest { @Test public void onCreate_whenSafetyCenterEnabled_redirectsToSafetyCenter() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true); final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); mActivity.handleSafetyCenterRedirection(); @@ -133,7 +133,7 @@ public class SecurityDashboardActivityTest { @Test public void onCreate_whenSafetyCenterDisabled_doesntRedirectToSafetyCenter() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(false); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(false); mActivity.handleSafetyCenterRedirection(); diff --git a/tests/unit/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java b/tests/unit/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java index 81ebda6f4ac..eb8fa17807b 100644 --- a/tests/unit/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java @@ -31,7 +31,7 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.settings.SettingsActivity; -import com.android.settings.safetycenter.SafetyCenterStatusHolder; +import com.android.settings.safetycenter.SafetyCenterManagerWrapper; import com.android.settings.testutils.FakeFeatureFactory; import org.junit.Before; @@ -55,14 +55,14 @@ public class TopLevelSecurityEntryPreferenceControllerTest { @Mock private Context mContext; @Mock - private SafetyCenterStatusHolder mSafetyCenterStatusHolder; + private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper; @Before public void setUp() { MockitoAnnotations.initMocks(this); mFeatureFactory = FakeFeatureFactory.setupForTest(); mSecuritySettingsFeatureProvider = mFeatureFactory.getSecuritySettingsFeatureProvider(); - SafetyCenterStatusHolder.sInstance = mSafetyCenterStatusHolder; + SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper; mPreference = new Preference(ApplicationProvider.getApplicationContext()); mPreference.setKey(PREFERENCE_KEY); @@ -128,7 +128,7 @@ public class TopLevelSecurityEntryPreferenceControllerTest { @Test public void getAvailabilityStatus_whenSafetyCenterEnabled_returnsUnavailable() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(true); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true); assertThat(mTopLevelSecurityEntryPreferenceController.getAvailabilityStatus()) .isEqualTo(TopLevelSecurityEntryPreferenceController.CONDITIONALLY_UNAVAILABLE); @@ -136,7 +136,7 @@ public class TopLevelSecurityEntryPreferenceControllerTest { @Test public void getAvailabilityStatus_whenSafetyCenterDisabled_returnsAvailable() { - when(mSafetyCenterStatusHolder.isEnabled(any(Context.class))).thenReturn(false); + when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(false); assertThat(mTopLevelSecurityEntryPreferenceController.getAvailabilityStatus()) .isEqualTo(TopLevelSecurityEntryPreferenceController.AVAILABLE); From c23be3fa162e11760a9cf41e35bae3e7efba4456 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Tue, 8 Feb 2022 15:37:53 +0800 Subject: [PATCH 3/9] Cache mechanism for Storage page - Use SharedPreference to cache the size info - Improve the flicker problem on Documents & other preference - The jobs are destroied on onPause to prevent the jobs being restarting when back to Storage page - Enable progress bar animation for each storage item Bug: 191117970 Test: manual test 1) The loading spinner will be shown when entering Storage page at first time. 2) Back to Settings homepage and switch back to Storage page, the loading spinner shouldn't be shown. 3) Click each preference in the Storage page and switch between these pages, the size info should be updated if something removed and the order of preference shouldn't be changed. Change-Id: I75533742a025dc61116207285a894ee728d0af68 Merged-In: I75533742a025dc61116207285a894ee728d0af68 (cherry picked from commit 77775a66f2004afcc8c93ac39b84d048f5dc04e9) --- .../deviceinfo/StorageDashboardFragment.java | 56 +++++++-- .../deviceinfo/StorageItemPreference.java | 2 +- .../storage/SecondaryUserController.java | 3 + .../storage/StorageCacheHelper.java | 115 ++++++++++++++++++ .../StorageItemPreferenceController.java | 112 +++++++++++------ ...eUsageProgressBarPreferenceController.java | 12 ++ .../storage/StorageCacheHelperTest.java | 97 +++++++++++++++ 7 files changed, 351 insertions(+), 46 deletions(-) create mode 100644 src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java create mode 100644 tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java index 746d2341696..cf31724ad69 100644 --- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java +++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java @@ -47,6 +47,7 @@ import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchP import com.android.settings.deviceinfo.storage.DiskInitFragment; import com.android.settings.deviceinfo.storage.SecondaryUserController; import com.android.settings.deviceinfo.storage.StorageAsyncLoader; +import com.android.settings.deviceinfo.storage.StorageCacheHelper; import com.android.settings.deviceinfo.storage.StorageEntry; import com.android.settings.deviceinfo.storage.StorageItemPreferenceController; import com.android.settings.deviceinfo.storage.StorageSelectionPreferenceController; @@ -109,6 +110,8 @@ public class StorageDashboardFragment extends DashboardFragment private boolean mIsWorkProfile; private int mUserId; private Preference mFreeUpSpacePreference; + private boolean mIsLoadedFromCache; + private StorageCacheHelper mStorageCacheHelper; private final StorageEventListener mStorageEventListener = new StorageEventListener() { @Override @@ -239,15 +242,27 @@ public class StorageDashboardFragment extends DashboardFragment mPreferenceController.setVolume(null); return; } + + if (mStorageCacheHelper.hasCachedSizeInfo() && mSelectedStorageEntry.isPrivate()) { + StorageCacheHelper.StorageCache cachedData = mStorageCacheHelper.retrieveCachedSize(); + mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo()); + mPreferenceController.setUsedSize(cachedData.usedSize); + mPreferenceController.setTotalSize(cachedData.totalSize); + } + if (mSelectedStorageEntry.isPrivate()) { mStorageInfo = null; mAppsResult = null; - maybeSetLoading(isQuotaSupported()); - - // To prevent flicker, sets null volume to hide category preferences. - // onReceivedSizes will setVolume with the volume of selected storage. - mPreferenceController.setVolume(null); - + // Hide the loading spinner if there is cached data. + if (mStorageCacheHelper.hasCachedSizeInfo()) { + //TODO(b/220259287): apply cache mechanism to secondary user + mPreferenceController.onLoadFinished(mAppsResult, mUserId); + } else { + maybeSetLoading(isQuotaSupported()); + // To prevent flicker, sets null volume to hide category preferences. + // onReceivedSizes will setVolume with the volume of selected storage. + mPreferenceController.setVolume(null); + } // Stats data is only available on private volumes. getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this); getLoaderManager() @@ -277,6 +292,16 @@ public class StorageDashboardFragment extends DashboardFragment initializePreference(); initializeOptionsMenu(activity); + + if (mStorageCacheHelper.hasCachedSizeInfo()) { + mIsLoadedFromCache = true; + mStorageEntries.clear(); + mStorageEntries.addAll( + StorageUtils.getAllStorageEntries(getContext(), mStorageManager)); + refreshUi(); + updateSecondaryUserControllers(mSecondaryUsers, mAppsResult); + setSecondaryUsersVisible(true); + } } private void initializePreference() { @@ -291,6 +316,7 @@ public class StorageDashboardFragment extends DashboardFragment mUserManager = context.getSystemService(UserManager.class); mIsWorkProfile = false; mUserId = UserHandle.myUserId(); + mStorageCacheHelper = new StorageCacheHelper(getContext(), mUserId); super.onAttach(context); use(AutomaticStorageManagementSwitchPreferenceController.class).setFragmentManager( @@ -323,9 +349,14 @@ public class StorageDashboardFragment extends DashboardFragment public void onResume() { super.onResume(); - mStorageEntries.clear(); - mStorageEntries.addAll(StorageUtils.getAllStorageEntries(getContext(), mStorageManager)); - refreshUi(); + if (mIsLoadedFromCache) { + mIsLoadedFromCache = false; + } else { + mStorageEntries.clear(); + mStorageEntries.addAll( + StorageUtils.getAllStorageEntries(getContext(), mStorageManager)); + refreshUi(); + } mStorageManager.registerListener(mStorageEventListener); } @@ -333,6 +364,11 @@ public class StorageDashboardFragment extends DashboardFragment public void onPause() { super.onPause(); mStorageManager.unregisterListener(mStorageEventListener); + // Destroy the data loaders to prevent unnecessary data loading when switching back to the + // page. + getLoaderManager().destroyLoader(STORAGE_JOB_ID); + getLoaderManager().destroyLoader(ICON_JOB_ID); + getLoaderManager().destroyLoader(VOLUME_SIZE_JOB_ID); } @Override @@ -359,6 +395,8 @@ public class StorageDashboardFragment extends DashboardFragment mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo()); mPreferenceController.setUsedSize(privateUsedBytes); mPreferenceController.setTotalSize(mStorageInfo.totalBytes); + // Cache total size and used size + mStorageCacheHelper.cacheTotalSizeAndUsedSize(mStorageInfo.totalBytes, privateUsedBytes); for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) { final AbstractPreferenceController controller = mSecondaryUsers.get(i); if (controller instanceof SecondaryUserController) { diff --git a/src/com/android/settings/deviceinfo/StorageItemPreference.java b/src/com/android/settings/deviceinfo/StorageItemPreference.java index 934ff3f603b..d3549d45061 100644 --- a/src/com/android/settings/deviceinfo/StorageItemPreference.java +++ b/src/com/android/settings/deviceinfo/StorageItemPreference.java @@ -66,7 +66,7 @@ public class StorageItemPreference extends Preference { return; mProgressBar.setMax(PROGRESS_MAX); - mProgressBar.setProgress(mProgressPercent); + mProgressBar.setProgress(mProgressPercent, true /* animate */); } @Override diff --git a/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java b/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java index f87a06a76f0..84cafd40797 100644 --- a/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java +++ b/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java @@ -183,6 +183,9 @@ public class SecondaryUserController extends AbstractPreferenceController implem @Override public void handleResult(SparseArray stats) { + if (stats == null) { + return; + } final StorageAsyncLoader.StorageResult result = stats.get(getUser().id); if (result != null) { setSize(result.externalStats.totalBytes); diff --git a/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java b/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java new file mode 100644 index 00000000000..a868c9f3f6e --- /dev/null +++ b/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java @@ -0,0 +1,115 @@ +/* + * 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.deviceinfo.storage; + +import android.content.Context; +import android.content.SharedPreferences; + +/** + * A utility class to cache and restore the storage size information. + */ +public class StorageCacheHelper { + + private static final String SHARED_PREFERENCE_NAME = "StorageCache"; + private static final String TOTAL_SIZE_KEY = "total_size_key"; + private static final String USED_SIZE_KEY = "used_size_key"; + private static final String IMAGES_SIZE_KEY = "images_size_key"; + private static final String VIDEOS_SIZE_KEY = "videos_size_key"; + private static final String AUDIO_SIZE_KEY = "audio_size_key"; + private static final String APPS_SIZE_KEY = "apps_size_key"; + private static final String GAMES_SIZE_KEY = "games_size_key"; + private static final String DOCUMENTS_AND_OTHER_SIZE_KEY = "documents_and_other_size_key"; + private static final String TRASH_SIZE_KEY = "trash_size_key"; + private static final String SYSTEM_SIZE_KEY = "system_size_key"; + + private final SharedPreferences mSharedPreferences; + + public StorageCacheHelper(Context context, int userId) { + String sharedPrefName = SHARED_PREFERENCE_NAME + userId; + mSharedPreferences = context.getSharedPreferences(sharedPrefName, Context.MODE_PRIVATE); + } + + /** + * Returns true if there's a cached size info. + */ + public boolean hasCachedSizeInfo() { + return mSharedPreferences.getAll().size() > 0; + } + + /** + * Cache the size info + * @param data a data about the file size info. + */ + public void cacheSizeInfo(StorageCache data) { + mSharedPreferences + .edit() + .putLong(IMAGES_SIZE_KEY, data.imagesSize) + .putLong(VIDEOS_SIZE_KEY, data.videosSize) + .putLong(AUDIO_SIZE_KEY, data.audioSize) + .putLong(APPS_SIZE_KEY, data.allAppsExceptGamesSize) + .putLong(GAMES_SIZE_KEY, data.gamesSize) + .putLong(DOCUMENTS_AND_OTHER_SIZE_KEY, data.documentsAndOtherSize) + .putLong(TRASH_SIZE_KEY, data.trashSize) + .putLong(SYSTEM_SIZE_KEY, data.systemSize) + .apply(); + } + + /** + * Cache total size and used size + */ + public void cacheTotalSizeAndUsedSize(long totalSize, long usedSize) { + mSharedPreferences + .edit() + .putLong(TOTAL_SIZE_KEY, totalSize) + .putLong(USED_SIZE_KEY, usedSize) + .apply(); + } + + /** + * Returns a cached data about all file size information. + */ + public StorageCache retrieveCachedSize() { + StorageCache result = new StorageCache(); + result.totalSize = mSharedPreferences.getLong(TOTAL_SIZE_KEY, 0); + result.usedSize = mSharedPreferences.getLong(USED_SIZE_KEY, 0); + result.imagesSize = mSharedPreferences.getLong(IMAGES_SIZE_KEY, 0); + result.videosSize = mSharedPreferences.getLong(VIDEOS_SIZE_KEY, 0); + result.audioSize = mSharedPreferences.getLong(AUDIO_SIZE_KEY, 0); + result.allAppsExceptGamesSize = mSharedPreferences.getLong(APPS_SIZE_KEY, 0); + result.gamesSize = mSharedPreferences.getLong(GAMES_SIZE_KEY, 0); + result.documentsAndOtherSize = mSharedPreferences.getLong(DOCUMENTS_AND_OTHER_SIZE_KEY, 0); + result.trashSize = mSharedPreferences.getLong(TRASH_SIZE_KEY, 0); + result.systemSize = mSharedPreferences.getLong(SYSTEM_SIZE_KEY, 0); + return result; + } + + /** + * All the cached data about the file size information. + */ + public static class StorageCache { + public long totalSize; + public long usedSize; + public long gamesSize; + public long allAppsExceptGamesSize; + public long audioSize; + public long imagesSize; + public long videosSize; + public long documentsAndOtherSize; + public long trashSize; + public long systemSize; + } +} diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index ee0c9e75435..9813439b235 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -34,6 +34,7 @@ import android.util.Log; import android.util.SparseArray; import android.widget.Toast; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.preference.Preference; @@ -135,7 +136,11 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle private boolean mIsWorkProfile; - private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents"; + private StorageCacheHelper mStorageCacheHelper; + // The mIsDocumentsPrefShown being used here is to prevent a flicker problem from displaying + // the Document entry. + private boolean mIsDocumentsPrefShown; + private boolean mIsPreferenceOrderedBySize; public StorageItemPreferenceController(Context context, Fragment hostFragment, VolumeInfo volume, StorageVolumeProvider svp, boolean isWorkProfile) { @@ -148,6 +153,8 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mIsWorkProfile = isWorkProfile; mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); mUserId = getCurrentUserId(); + mIsDocumentsPrefShown = isDocumentsPrefShown(); + mStorageCacheHelper = new StorageCacheHelper(mContext, mUserId); mImagesUri = Uri.parse(context.getResources() .getString(R.string.config_images_storage_category_uri)); @@ -267,14 +274,17 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle // If we don't have a shared volume for our internal storage (or the shared volume isn't // mounted as readable for whatever reason), we should hide the File preference. if (visible) { - final VolumeInfo sharedVolume = mSvp.findEmulatedForPrivate(mVolume); - mDocumentsAndOtherPreference.setVisible(sharedVolume != null - && sharedVolume.isMountedReadable()); + mDocumentsAndOtherPreference.setVisible(mIsDocumentsPrefShown); } else { mDocumentsAndOtherPreference.setVisible(false); } } + private boolean isDocumentsPrefShown() { + VolumeInfo sharedVolume = mSvp.findEmulatedForPrivate(mVolume); + return sharedVolume != null && sharedVolume.isMountedReadable(); + } + private void updatePrivateStorageCategoryPreferencesOrder() { if (mScreen == null || !isValidPrivateVolume()) { return; @@ -360,44 +370,74 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mTrashPreference = screen.findPreference(TRASH_KEY); } - /** Fragments use it to set storage result and update UI of this controller. */ - public void onLoadFinished(SparseArray result, int userId) { - final StorageAsyncLoader.StorageResult data = result.get(userId); - - mImagesPreference.setStorageSize(data.imagesSize, mTotalSize); - mVideosPreference.setStorageSize(data.videosSize, mTotalSize); - mAudioPreference.setStorageSize(data.audioSize, mTotalSize); - mAppsPreference.setStorageSize(data.allAppsExceptGamesSize, mTotalSize); - mGamesPreference.setStorageSize(data.gamesSize, mTotalSize); - mDocumentsAndOtherPreference.setStorageSize(data.documentsAndOtherSize, mTotalSize); - mTrashPreference.setStorageSize(data.trashSize, mTotalSize); - + /** + * Fragments use it to set storage result and update UI of this controller. + * @param result The StorageResult from StorageAsyncLoader. This allows a nullable result. + * When it's null, the cached storage size info will be used instead. + * @param userId User ID to get the storage size info + */ + public void onLoadFinished(@Nullable SparseArray result, + int userId) { + // Calculate the size info for each category + StorageCacheHelper.StorageCache storageCache = getSizeInfo(result, userId); + // Set size info to each preference + mImagesPreference.setStorageSize(storageCache.imagesSize, mTotalSize); + mVideosPreference.setStorageSize(storageCache.videosSize, mTotalSize); + mAudioPreference.setStorageSize(storageCache.audioSize, mTotalSize); + mAppsPreference.setStorageSize(storageCache.allAppsExceptGamesSize, mTotalSize); + mGamesPreference.setStorageSize(storageCache.gamesSize, mTotalSize); + mDocumentsAndOtherPreference.setStorageSize(storageCache.documentsAndOtherSize, mTotalSize); + mTrashPreference.setStorageSize(storageCache.trashSize, mTotalSize); if (mSystemPreference != null) { - // Everything else that hasn't already been attributed is tracked as - // belonging to system. - long attributedSize = 0; - for (int i = 0; i < result.size(); i++) { - final StorageAsyncLoader.StorageResult otherData = result.valueAt(i); - attributedSize += - otherData.gamesSize - + otherData.audioSize - + otherData.videosSize - + otherData.imagesSize - + otherData.documentsAndOtherSize - + otherData.trashSize - + otherData.allAppsExceptGamesSize; - attributedSize -= otherData.duplicateCodeSize; - } - - final long systemSize = Math.max(DataUnit.GIBIBYTES.toBytes(1), - mUsedBytes - attributedSize); - mSystemPreference.setStorageSize(systemSize, mTotalSize); + mSystemPreference.setStorageSize(storageCache.systemSize, mTotalSize); + } + // Cache the size info + if (result != null) { + mStorageCacheHelper.cacheSizeInfo(storageCache); } - updatePrivateStorageCategoryPreferencesOrder(); + // Sort the preference according to size info in descending order + if (!mIsPreferenceOrderedBySize) { + updatePrivateStorageCategoryPreferencesOrder(); + mIsPreferenceOrderedBySize = true; + } setPrivateStorageCategoryPreferencesVisibility(true); } + private StorageCacheHelper.StorageCache getSizeInfo( + SparseArray result, int userId) { + if (result == null) { + return mStorageCacheHelper.retrieveCachedSize(); + } + StorageAsyncLoader.StorageResult data = result.get(userId); + StorageCacheHelper.StorageCache storageCache = new StorageCacheHelper.StorageCache(); + storageCache.imagesSize = data.imagesSize; + storageCache.videosSize = data.videosSize; + storageCache.audioSize = data.audioSize; + storageCache.allAppsExceptGamesSize = data.allAppsExceptGamesSize; + storageCache.gamesSize = data.gamesSize; + storageCache.documentsAndOtherSize = data.documentsAndOtherSize; + storageCache.trashSize = data.trashSize; + // Everything else that hasn't already been attributed is tracked as + // belonging to system. + long attributedSize = 0; + for (int i = 0; i < result.size(); i++) { + final StorageAsyncLoader.StorageResult otherData = result.valueAt(i); + attributedSize += + otherData.gamesSize + + otherData.audioSize + + otherData.videosSize + + otherData.imagesSize + + otherData.documentsAndOtherSize + + otherData.trashSize + + otherData.allAppsExceptGamesSize; + attributedSize -= otherData.duplicateCodeSize; + } + storageCache.systemSize = Math.max(DataUnit.GIBIBYTES.toBytes(1), + mUsedBytes - attributedSize); + return storageCache; + } + public void setUsedSize(long usedSizeBytes) { mUsedBytes = usedSizeBytes; } diff --git a/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java index 766035307e9..872fa8a462b 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java @@ -18,6 +18,7 @@ package com.android.settings.deviceinfo.storage; import android.app.usage.StorageStatsManager; import android.content.Context; +import android.os.UserHandle; import android.util.Log; import androidx.annotation.VisibleForTesting; @@ -47,11 +48,13 @@ public class StorageUsageProgressBarPreferenceController extends BasePreferenceC private UsageProgressBarPreference mUsageProgressBarPreference; private StorageEntry mStorageEntry; boolean mIsUpdateStateFromSelectedStorageEntry; + private StorageCacheHelper mStorageCacheHelper; public StorageUsageProgressBarPreferenceController(Context context, String key) { super(context, key); mStorageStatsManager = context.getSystemService(StorageStatsManager.class); + mStorageCacheHelper = new StorageCacheHelper(context, UserHandle.myUserId()); } /** Set StorageEntry to display. */ @@ -71,6 +74,15 @@ public class StorageUsageProgressBarPreferenceController extends BasePreferenceC } private void getStorageStatsAndUpdateUi() { + // Use cached data for both total size and used size. + if (mStorageEntry != null && mStorageEntry.isMounted() && mStorageEntry.isPrivate()) { + StorageCacheHelper.StorageCache cachedData = mStorageCacheHelper.retrieveCachedSize(); + mTotalBytes = cachedData.totalSize; + mUsedBytes = cachedData.usedSize; + mIsUpdateStateFromSelectedStorageEntry = true; + updateState(mUsageProgressBarPreference); + } + // Get the latest data from StorageStatsManager. ThreadUtils.postOnBackgroundThread(() -> { try { if (mStorageEntry == null || !mStorageEntry.isMounted()) { diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java new file mode 100644 index 00000000000..1956b09a95d --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java @@ -0,0 +1,97 @@ +/* + * 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.deviceinfo.storage; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.os.UserHandle; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class StorageCacheHelperTest { + private static final long FAKE_IMAGES_SIZE = 7000L; + private static final long FAKE_VIDEOS_SIZE = 8900L; + private static final long FAKE_AUDIO_SIZE = 3500L; + private static final long FAKE_APPS_SIZE = 4000L; + private static final long FAKE_GAMES_SIZE = 5000L; + private static final long FAKE_DOCS_SIZE = 1500L; + private static final long FAKE_TRASH_SIZE = 500L; + private static final long FAKE_SYSTEM_SIZE = 2300L; + private static final long FAKE_TOTAL_SIZE = 256000L; + private static final long FAKE_USED_SIZE = 50000L; + + private Context mContext; + private StorageCacheHelper mHelper; + + @Before + public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); + mHelper = new StorageCacheHelper(mContext, UserHandle.myUserId()); + } + + @Test + public void hasCachedSizeInfo_noCacheData_shouldReturnFalse() { + assertThat(mHelper.hasCachedSizeInfo()).isFalse(); + } + + @Test + public void hasCachedSizeInfo_hasCacheData_shouldReturnTrue() { + mHelper.cacheSizeInfo(getFakeStorageCache()); + + assertThat(mHelper.hasCachedSizeInfo()).isTrue(); + } + + @Test + public void cacheSizeInfo_shouldSaveToSharedPreference() { + mHelper.cacheSizeInfo(getFakeStorageCache()); + + StorageCacheHelper.StorageCache storageCache = mHelper.retrieveCachedSize(); + + assertThat(storageCache.imagesSize).isEqualTo(FAKE_IMAGES_SIZE); + assertThat(storageCache.totalSize).isEqualTo(0); + } + + @Test + public void cacheTotalSizeAndUsedSize_shouldSaveToSharedPreference() { + mHelper.cacheTotalSizeAndUsedSize(FAKE_TOTAL_SIZE, FAKE_USED_SIZE); + + StorageCacheHelper.StorageCache storageCache = mHelper.retrieveCachedSize(); + + assertThat(storageCache.totalSize).isEqualTo(FAKE_TOTAL_SIZE); + assertThat(storageCache.usedSize).isEqualTo(FAKE_USED_SIZE); + } + + private StorageCacheHelper.StorageCache getFakeStorageCache() { + StorageCacheHelper.StorageCache result = new StorageCacheHelper.StorageCache(); + result.trashSize = FAKE_TRASH_SIZE; + result.systemSize = FAKE_SYSTEM_SIZE; + result.imagesSize = FAKE_IMAGES_SIZE; + result.documentsAndOtherSize = FAKE_DOCS_SIZE; + result.audioSize = FAKE_AUDIO_SIZE; + result.gamesSize = FAKE_GAMES_SIZE; + result.videosSize = FAKE_VIDEOS_SIZE; + result.allAppsExceptGamesSize = FAKE_APPS_SIZE; + return result; + } +} From 39c8905f4cd7fe774da9943909775de6d2388049 Mon Sep 17 00:00:00 2001 From: Tsung-Mao Fang Date: Tue, 22 Feb 2022 16:37:48 +0800 Subject: [PATCH 4/9] Fix incorrect colored bar when task bar is hidden Set backgorund color on content id view instead of homepage view. Also setup edge to edge for the homepage. Fix: 215440529 Test: See correct ui on the two pane mode and regular phone. Change-Id: I2d5988a489410e9620137bd6cf9607768787d4fc --- res/layout/settings_homepage_container.xml | 1 - .../homepage/SettingsHomepageActivity.java | 29 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/res/layout/settings_homepage_container.xml b/res/layout/settings_homepage_container.xml index 4f0d8049c6c..f0aafe12dc0 100644 --- a/res/layout/settings_homepage_container.xml +++ b/res/layout/settings_homepage_container.xml @@ -19,7 +19,6 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/settings_homepage_container" - android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent"> diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index c56d89b1a3a..051a54ad9cc 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -32,12 +32,17 @@ import android.util.ArraySet; import android.util.FeatureFlagUtils; import android.util.Log; import android.view.View; +import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.Toolbar; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; @@ -96,7 +101,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements void onHomepageLoaded(); } - private interface FragmentBuilder { + private interface FragmentBuilder { T build(); } @@ -149,7 +154,9 @@ public class SettingsHomepageActivity extends FragmentActivity implements @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setupEdgeToEdge(); setContentView(R.layout.settings_homepage_container); + mIsEmbeddingActivityEnabled = ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this); mSplitController = SplitController.getInstance(); mIsTwoPane = mSplitController.isActivityEmbedded(this); @@ -224,6 +231,24 @@ public class SettingsHomepageActivity extends FragmentActivity implements } } + private void setupEdgeToEdge() { + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); + ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content), + (v, windowInsets) -> { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); + // Apply the insets as a margin to the view. Here the system is setting + // only the top dimensions. + ViewGroup.MarginLayoutParams mlp = + (ViewGroup.MarginLayoutParams) v.getLayoutParams(); + mlp.topMargin = insets.top; + v.setLayoutParams(mlp); + + // Return CONSUMED if you don't want the window insets to keep being + // passed down to descendant views. + return WindowInsetsCompat.CONSUMED; + }); + } + private void initSearchBarView() { final Toolbar toolbar = findViewById(R.id.search_action_bar); FeatureFactory.getFactory(this).getSearchFeatureProvider() @@ -265,7 +290,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements // Update status bar color window.setStatusBarColor(color); // Update content background. - findViewById(R.id.settings_homepage_container).setBackgroundColor(color); + findViewById(android.R.id.content).setBackgroundColor(color); } private void showSuggestionFragment(boolean scrollNeeded) { From d4822fe6b47fde0bb445ce932aa7968a9c88a056 Mon Sep 17 00:00:00 2001 From: Marie Matheson Date: Tue, 22 Feb 2022 20:14:50 +0000 Subject: [PATCH 5/9] Use primary profile lock settings string in Safety Source, not work profile Test: atest CtsSafetyCenterTestCases Bug: 215518847 Change-Id: I1c7ddbeb05be81fa902fcb4e42868ddd770d2dc0 --- .../android/settings/safetycenter/LockScreenSafetySource.java | 2 +- .../settings/safetycenter/LockScreenSafetySourceTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/safetycenter/LockScreenSafetySource.java b/src/com/android/settings/safetycenter/LockScreenSafetySource.java index 5ebe12aca95..f059920aa73 100644 --- a/src/com/android/settings/safetycenter/LockScreenSafetySource.java +++ b/src/com/android/settings/safetycenter/LockScreenSafetySource.java @@ -57,7 +57,7 @@ public final class LockScreenSafetySource { screenLockPreferenceDetailsUtils); final SafetySourceStatus status = new SafetySourceStatus.Builder( - context.getString(R.string.unlock_set_unlock_launch_picker_title_profile), + context.getString(R.string.unlock_set_unlock_launch_picker_title), screenLockPreferenceDetailsUtils.getSummary(UserHandle.myUserId()), screenLockPreferenceDetailsUtils.isLockPatternSecure() ? SafetySourceStatus.STATUS_LEVEL_OK diff --git a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java index 4b214083e5b..64b96928de9 100644 --- a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java +++ b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java @@ -108,7 +108,7 @@ public class LockScreenSafetySourceTest { assertThat(safetySourceStatus.getTitle().toString()) .isEqualTo(ResourcesUtils.getResourcesString( mApplicationContext, - "unlock_set_unlock_launch_picker_title_profile")); + "unlock_set_unlock_launch_picker_title")); assertThat(safetySourceStatus.getSummary().toString()) .isEqualTo(SUMMARY); assertThat(safetySourceStatus.getPendingIntent().getIntent()).isNotNull(); From a6693df48dd3c25c90bba53d15be643b8083cb3e Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Wed, 23 Feb 2022 16:03:10 +0000 Subject: [PATCH 6/9] Reset all TARE constants. Reset all TARE constants, not just the enabled status, when a user clicks on "Reset to defaults." Bug: 158300259 Test: manual Change-Id: I5328c7790729e3358751e703271a6ffd386bb33f --- src/com/android/settings/development/tare/TareHomePage.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/development/tare/TareHomePage.java b/src/com/android/settings/development/tare/TareHomePage.java index 38e7ed8d519..cea09540d60 100644 --- a/src/com/android/settings/development/tare/TareHomePage.java +++ b/src/com/android/settings/development/tare/TareHomePage.java @@ -69,11 +69,14 @@ public class TareHomePage extends Activity { } /** Reverts the TARE settings to the original default settings */ - // TODO: Establish default TARE values and make this method revert all settings back to default. public void revertSettings(View v) { Toast.makeText(this, R.string.tare_settings_reverted_toast, Toast.LENGTH_LONG).show(); Settings.Global.putString(getApplicationContext().getContentResolver(), Settings.Global.ENABLE_TARE, null); + Settings.Global.putString(getApplicationContext().getContentResolver(), + Settings.Global.TARE_ALARM_MANAGER_CONSTANTS, null); + Settings.Global.putString(getApplicationContext().getContentResolver(), + Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS, null); setEnabled(Settings.Global.DEFAULT_ENABLE_TARE == SETTING_VALUE_ON); } From ba685c0be07aafc93b302e3bdee311ddf1e8784a Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Wed, 23 Feb 2022 16:04:45 +0000 Subject: [PATCH 7/9] Switch from androidx to android. The rest of the TARE classes use pure Android Fragments and will have an issue trying to create an androidx Fragment, so switch from using an androidx Fragment to an android Fragment. Bug: 158300259 Test: manual Change-Id: I4c27198a66bd51b3822421116b46ae3d80d589ff --- .../development/tare/TareFactorDialogFragment.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/com/android/settings/development/tare/TareFactorDialogFragment.java b/src/com/android/settings/development/tare/TareFactorDialogFragment.java index ff7f5f9d0a8..8d2f3415651 100644 --- a/src/com/android/settings/development/tare/TareFactorDialogFragment.java +++ b/src/com/android/settings/development/tare/TareFactorDialogFragment.java @@ -16,7 +16,10 @@ package com.android.settings.development.tare; +import android.annotation.NonNull; +import android.app.AlertDialog; import android.app.Dialog; +import android.app.DialogFragment; import android.content.Context; import android.os.Bundle; import android.text.InputType; @@ -25,10 +28,6 @@ import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; -import androidx.fragment.app.DialogFragment; - import com.android.settings.R; import com.android.settings.Utils; From bc3304b6a22608f1076efa91d3ce67ab759f562a Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Wed, 23 Feb 2022 16:30:08 +0000 Subject: [PATCH 8/9] Clean up code. 1. Create a method for duplicate code. 2. Address style/lint issues. 3. Properly parse settings constant string. The original iteration wouldn't reset values to their default if the constant string didn't have a value set. Bug: 158300259 Test: manual Change-Id: I994b872ba16f12c8e06ce85aedc526b84e5fa31b --- .../tare/TareFactorController.java | 128 +++++++----------- 1 file changed, 48 insertions(+), 80 deletions(-) diff --git a/src/com/android/settings/development/tare/TareFactorController.java b/src/com/android/settings/development/tare/TareFactorController.java index 7e9f3149335..3cabd8d05a4 100644 --- a/src/com/android/settings/development/tare/TareFactorController.java +++ b/src/com/android/settings/development/tare/TareFactorController.java @@ -16,6 +16,10 @@ package com.android.settings.development.tare; +import static android.provider.Settings.Global.TARE_ALARM_MANAGER_CONSTANTS; +import static android.provider.Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS; + +import android.annotation.NonNull; import android.app.tare.EconomyManager; import android.content.ContentResolver; import android.content.Context; @@ -49,11 +53,10 @@ public class TareFactorController { mContentResolver = context.getContentResolver(); mResources = context.getResources(); - mAlarmManagerConstants = Settings.Global - .getString(mContentResolver, Settings.Global.TARE_ALARM_MANAGER_CONSTANTS); - - mJobSchedulerConstants = Settings.Global - .getString(mContentResolver, Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS); + mAlarmManagerConstants = + Settings.Global.getString(mContentResolver, TARE_ALARM_MANAGER_CONSTANTS); + mJobSchedulerConstants = + Settings.Global.getString(mContentResolver, TARE_JOB_SCHEDULER_CONSTANTS); initAlarmManagerMap(); parseAlarmManagerGlobalSettings(); @@ -408,8 +411,7 @@ public class TareFactorController { mJobSchedulerMap.put( EconomyManager.KEY_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE, new TareFactorData(mResources.getString(R.string.tare_job_low_running), - EconomyManager - .DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE, + EconomyManager.DEFAULT_JS_ACTION_JOB_LOW_RUNNING_BASE_PRICE, POLICY_JOB_SCHEDULER)); mJobSchedulerMap.put(EconomyManager.KEY_JS_ACTION_JOB_MIN_START_BASE_PRICE, new TareFactorData(mResources.getString(R.string.tare_job_min_start), @@ -425,68 +427,50 @@ public class TareFactorController { POLICY_JOB_SCHEDULER)); } - - /** - * Takes a key and factor policy as input and grabs the default value linked to it. - * - * @param key the key of the factor you want to get the default value of - * @param factorPolicy the policy you want the default value of - */ - private int getDefaultValue(String key, int factorPolicy) { - ArrayMap currentMap; - switch (factorPolicy) { - case POLICY_ALARM_MANAGER: - currentMap = mAlarmManagerMap; - break; - case POLICY_JOB_SCHEDULER: - currentMap = mJobSchedulerMap; - break; - default: - throw new IllegalArgumentException("Invalid factor policy given"); - } - return currentMap.get(key).defaultValue; - } - /** * Parses the AM constant from Settings.Global to get to the current value. */ private void parseAlarmManagerGlobalSettings() { - try { - mParser.setString(mAlarmManagerConstants); - } catch (Exception e) { - Slog.e(TAG, "Bad value string constants", e); - } - int size = mParser.size(); - - for (int i = 0; i < size - 1; i++) { - String key = mParser.keyAt(i); - TareFactorData data = mAlarmManagerMap.get(key); - data.currentValue = mParser.getInt(key, getDefaultValue(key, getFactorType(key))); - } + parseSettingsIntoMap(mAlarmManagerConstants, mAlarmManagerMap); } /** * Parses the JS constant from Settings.Global to get to the current value. */ private void parseJobSchedulerGlobalSettings() { - try { - mParser.setString(mJobSchedulerConstants); - } catch (Exception e) { - Slog.e(TAG, "Bad value string constants", e); - } - int size = mParser.size(); + parseSettingsIntoMap(mJobSchedulerConstants, mJobSchedulerMap); + } - for (int i = 0; i < size - 1; i++) { - String key = mParser.keyAt(i); - TareFactorData data = mJobSchedulerMap.get(key); - data.currentValue = mParser.getInt(key, getDefaultValue(key, getFactorType(key))); + private void parseSettingsIntoMap(String constants, ArrayMap map) { + try { + mParser.setString(constants); + } catch (Exception e) { + Slog.e(TAG, "Bad string constants value", e); + } + + for (int i = map.size() - 1; i >= 0; --i) { + final String key = map.keyAt(i); + final TareFactorData data = map.valueAt(i); + data.currentValue = mParser.getInt(key, data.defaultValue); + } + } + + @NonNull + private ArrayMap getMap(int factorPolicy) { + switch (factorPolicy) { + case POLICY_ALARM_MANAGER: + return mAlarmManagerMap; + case POLICY_JOB_SCHEDULER: + return mJobSchedulerMap; + default: + throw new IllegalArgumentException("Invalid factor policy given"); } } /** * Takes a key and factor policy as input and grabs the title linked to it. * - * @param key the key of the factor you want to get the title of + * @param key the key of the factor you want to get the title of * @param factorPolicy the policy you want the title of */ private String getTitle(String key, int factorPolicy) { @@ -507,21 +491,11 @@ public class TareFactorController { /** * Takes a key and factor policy as input and grabs the current value linked to it. * - * @param key the key of the factor you want to get the default value of + * @param key the key of the factor you want to get the default value of * @param factorPolicy the policy you want the current value of */ private int getCurrentValue(String key, int factorPolicy) { - ArrayMap currentMap; - switch (factorPolicy) { - case POLICY_ALARM_MANAGER: - currentMap = mAlarmManagerMap; - break; - case POLICY_JOB_SCHEDULER: - currentMap = mJobSchedulerMap; - break; - default: - throw new IllegalArgumentException("Invalid factor policy given"); - } + final ArrayMap currentMap = getMap(factorPolicy); return currentMap.get(key).currentValue; } @@ -551,18 +525,14 @@ public class TareFactorController { * @param factorPolicy policy being updated */ public void updateValue(String key, int editedValue, int factorPolicy) { - switch (factorPolicy) { - case POLICY_ALARM_MANAGER: - mAlarmManagerMap.get(key).currentValue = editedValue; - rebuildPolicyConstants(factorPolicy); - break; - case POLICY_JOB_SCHEDULER: - mJobSchedulerMap.get(key).currentValue = editedValue; - rebuildPolicyConstants(factorPolicy); - break; - default: - throw new IllegalArgumentException("Invalid factor policy given"); + final ArrayMap map = getMap(factorPolicy); + + final TareFactorData data = map.get(key); + if (data.currentValue == editedValue) { + return; } + data.currentValue = editedValue; + rebuildPolicyConstants(factorPolicy); } /** @@ -574,16 +544,14 @@ public class TareFactorController { private void rebuildPolicyConstants(int factorPolicy) { switch (factorPolicy) { case POLICY_ALARM_MANAGER: - writeConstantsToSettings(mAlarmManagerMap, - Settings.Global.TARE_ALARM_MANAGER_CONSTANTS); + writeConstantsToSettings(mAlarmManagerMap, TARE_ALARM_MANAGER_CONSTANTS); mAlarmManagerConstants = Settings.Global .getString(mContentResolver, Settings.Global .TARE_ALARM_MANAGER_CONSTANTS); break; case POLICY_JOB_SCHEDULER: - writeConstantsToSettings(mJobSchedulerMap, - Settings.Global.TARE_JOB_SCHEDULER_CONSTANTS); + writeConstantsToSettings(mJobSchedulerMap, TARE_JOB_SCHEDULER_CONSTANTS); mJobSchedulerConstants = Settings.Global .getString(mContentResolver, Settings.Global @@ -623,7 +591,7 @@ public class TareFactorController { public TareFactorDialogFragment createDialog(String key) { int policy = getFactorType(key); return new TareFactorDialogFragment(getTitle(key, policy), key, - getCurrentValue(key, policy), policy , this); + getCurrentValue(key, policy), policy, this); } /** From de08d984efb7d29c1c00d4fbf55177ece308fd10 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 23 Feb 2022 12:25:49 -0500 Subject: [PATCH 9/9] Ensure icons on app filtering page Test: BridgedAppsPreferenceControllerTest.java, manually look at screen Fixes: 218724983 Change-Id: I6ee4bb6c39efacecff5c4219dbe9fdb066c49368 --- .../notificationaccess/BridgedAppsPreferenceController.java | 3 ++- .../BridgedAppsPreferenceControllerTest.java | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java b/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java index c56f6309148..8e2d3d4fd2f 100644 --- a/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java +++ b/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceController.java @@ -25,6 +25,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.applications.AppStateBaseBridge; import com.android.settings.core.BasePreferenceController; import com.android.settings.notification.NotificationBackend; +import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.AppFilter; @@ -128,7 +129,7 @@ public class BridgedAppsPreferenceController extends BasePreferenceController im CheckBoxPreference preference = mScreen.findPreference(prefKey); if (preference == null) { preference = new CheckBoxPreference(mScreen.getContext()); - preference.setIcon(entry.icon); + preference.setIcon(AppUtils.getIcon(mContext, entry)); preference.setTitle(entry.label); preference.setKey(prefKey); mScreen.addPreference(preference); diff --git a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java index 90b89278762..38c605c930d 100644 --- a/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/applications/specialaccess/notificationaccess/BridgedAppsPreferenceControllerTest.java @@ -30,7 +30,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.VersionedPackage; -import android.graphics.drawable.Drawable; import android.os.Looper; import android.service.notification.NotificationListenerFilter; import android.util.ArraySet; @@ -65,6 +64,7 @@ public class BridgedAppsPreferenceControllerTest { PreferenceScreen mScreen; @Mock ApplicationsState mAppState; + private ApplicationsState.AppEntry mAppEntry; private ApplicationsState.AppEntry mAppEntry2; @@ -92,8 +92,6 @@ public class BridgedAppsPreferenceControllerTest { mAppEntry.info = ai; mAppEntry.label = "hi"; - Drawable icon = mock(Drawable.class); - mAppEntry.icon = icon; mController = new BridgedAppsPreferenceController(mContext, "key"); mController.setCn(mCn); @@ -167,7 +165,7 @@ public class BridgedAppsPreferenceControllerTest { assertThat(actual.isChecked()).isTrue(); assertThat(actual.getTitle()).isEqualTo("hi"); - assertThat(actual.getIcon()).isEqualTo(mAppEntry.icon); + assertThat(actual.getIcon()).isNotNull(); } @Test