From f5d1841c9d90fb72866a63d058ba5076478014a7 Mon Sep 17 00:00:00 2001 From: Yi Jiang Date: Thu, 10 Sep 2020 14:26:51 -0700 Subject: [PATCH] Merge Screen Attention and Screen timeout Settings. Bug: 155051311 Test: atest Change-Id: I6f6ee52618eab629a41b28982be32ead5f9ba08d --- res/xml/adaptive_sleep_detail.xml | 54 ---- res/xml/display_settings.xml | 14 +- res/xml/screen_timeout_settings.xml | 19 ++ src/com/android/settings/DisplaySettings.java | 4 - ...aptiveSleepDetailPreferenceController.java | 66 ----- ...veSleepPermissionPreferenceController.java | 67 ++--- .../AdaptiveSleepPreferenceController.java | 103 +++++--- .../display/AdaptiveSleepSettings.java | 77 ------ .../ScreenTimeoutPreferenceController.java | 81 ++++++ .../display/ScreenTimeoutSettings.java | 234 ++++++++++++++++++ .../slices/ContextualAdaptiveSleepSlice.java | 6 +- .../settings/slices/CustomSliceRegistry.java | 4 +- .../core/PreferenceXmlParserUtilsTest.java | 23 +- ...veSleepDetailPreferenceControllerTest.java | 127 ---------- ...eepPermissionPreferenceControllerTest.java | 58 ++--- ...AdaptiveSleepPreferenceControllerTest.java | 166 ++++++------- .../display/ScreenTimeoutSettingsTest.java | 99 ++++++++ 17 files changed, 661 insertions(+), 541 deletions(-) delete mode 100644 res/xml/adaptive_sleep_detail.xml create mode 100644 res/xml/screen_timeout_settings.xml delete mode 100644 src/com/android/settings/display/AdaptiveSleepDetailPreferenceController.java delete mode 100644 src/com/android/settings/display/AdaptiveSleepSettings.java create mode 100644 src/com/android/settings/display/ScreenTimeoutPreferenceController.java create mode 100644 src/com/android/settings/display/ScreenTimeoutSettings.java delete mode 100644 tests/robotests/src/com/android/settings/display/AdaptiveSleepDetailPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java diff --git a/res/xml/adaptive_sleep_detail.xml b/res/xml/adaptive_sleep_detail.xml deleted file mode 100644 index 0ea31ff7d36..00000000000 --- a/res/xml/adaptive_sleep_detail.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml index 9a51bdc9788..07564f0b1d1 100644 --- a/res/xml/display_settings.xml +++ b/res/xml/display_settings.xml @@ -63,20 +63,12 @@ - - - + android:fragment="com.android.settings.display.ScreenTimeoutSettings" + settings:controller="com.android.settings.display.ScreenTimeoutPreferenceController" /> + + + \ No newline at end of file diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java index 6b23b291902..cbfbe7aca4b 100644 --- a/src/com/android/settings/DisplaySettings.java +++ b/src/com/android/settings/DisplaySettings.java @@ -30,7 +30,6 @@ import com.android.settings.display.ScreenSaverPreferenceController; import com.android.settings.display.ShowOperatorNamePreferenceController; import com.android.settings.display.TapToWakePreferenceController; import com.android.settings.display.ThemePreferenceController; -import com.android.settings.display.TimeoutPreferenceController; import com.android.settings.display.VrDisplayPreferenceController; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; @@ -44,8 +43,6 @@ import java.util.List; public class DisplaySettings extends DashboardFragment { private static final String TAG = "DisplaySettings"; - private static final String KEY_SCREEN_TIMEOUT = "screen_timeout"; - @Override public int getMetricsCategory() { return SettingsEnums.DISPLAY; @@ -85,7 +82,6 @@ public class DisplaySettings extends DashboardFragment { controllers.add(new NightModePreferenceController(context)); controllers.add(new ScreenSaverPreferenceController(context)); controllers.add(new TapToWakePreferenceController(context)); - controllers.add(new TimeoutPreferenceController(context, KEY_SCREEN_TIMEOUT)); controllers.add(new VrDisplayPreferenceController(context)); controllers.add(new ShowOperatorNamePreferenceController(context)); controllers.add(new ThemePreferenceController(context)); diff --git a/src/com/android/settings/display/AdaptiveSleepDetailPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepDetailPreferenceController.java deleted file mode 100644 index d0fc5d75e69..00000000000 --- a/src/com/android/settings/display/AdaptiveSleepDetailPreferenceController.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2019 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.os.UserManager; - -import androidx.preference.Preference; - -import com.android.settings.bluetooth.RestrictionUtils; -import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; -import com.android.settingslib.RestrictedSwitchPreference; - -public class AdaptiveSleepDetailPreferenceController extends AdaptiveSleepPreferenceController { - private RestrictionUtils mRestrictionUtils; - - public AdaptiveSleepDetailPreferenceController(Context context, String key, - RestrictionUtils restrictionUtils) { - super(context, key); - mRestrictionUtils = restrictionUtils; - } - - public AdaptiveSleepDetailPreferenceController(Context context, String key) { - this(context, key, new RestrictionUtils()); - } - - @Override - @AvailabilityStatus - public int getAvailabilityStatus() { - return mContext.getResources().getBoolean( - com.android.internal.R.bool.config_adaptive_sleep_available) - ? AVAILABLE - : UNSUPPORTED_ON_DEVICE; - } - - @Override - public boolean isPublicSlice() { - return true; - } - - @Override - public void updateState(Preference preference) { - super.updateState(preference); - final EnforcedAdmin enforcedAdmin = mRestrictionUtils.checkIfRestrictionEnforced(mContext, - UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT); - if (enforcedAdmin != null) { - ((RestrictedSwitchPreference) preference).setDisabledByAdmin(enforcedAdmin); - } else { - preference.setEnabled(hasSufficientPermission(mContext.getPackageManager())); - } - } -} \ No newline at end of file diff --git a/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceController.java index 9e6bca453e4..1110ad2b9ca 100644 --- a/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceController.java +++ b/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceController.java @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.settings.display; @@ -20,44 +20,53 @@ import static com.android.settings.display.AdaptiveSleepPreferenceController.has import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.Uri; -import android.text.TextUtils; import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; -import com.android.settings.core.BasePreferenceController; +import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.R; -public class AdaptiveSleepPermissionPreferenceController extends BasePreferenceController { - final static String PREF_NAME = "adaptive_sleep_permission"; - private final Intent mIntent; +/** + * The controller of Screen attention's permission warning preference. The preference appears when + * the camera permission is missing for Screen Attention feature. + */ +public class AdaptiveSleepPermissionPreferenceController { + @VisibleForTesting + Preference mPreference; + private PackageManager mPackageManager; - public AdaptiveSleepPermissionPreferenceController(Context context, String key) { - super(context, key); + public AdaptiveSleepPermissionPreferenceController(Context context) { final String packageName = context.getPackageManager().getAttentionServicePackageName(); - mIntent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - mIntent.setData(Uri.parse("package:" + packageName)); - } - - @Override - @AvailabilityStatus - public int getAvailabilityStatus() { - return AVAILABLE_UNSEARCHABLE; - } - - @Override - public boolean handlePreferenceTreeClick(Preference preference) { - if (TextUtils.equals(getPreferenceKey(), preference.getKey())) { - mContext.startActivity(mIntent); + mPackageManager = context.getPackageManager(); + final Intent intent = new Intent( + android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + packageName)); + mPreference = new Preference(context); + mPreference.setTitle(R.string.adaptive_sleep_title_no_permission); + mPreference.setSummary(R.string.adaptive_sleep_summary_no_permission); + mPreference.setIcon(R.drawable.ic_info_outline_24); + mPreference.setOnPreferenceClickListener(p -> { + context.startActivity(intent); return true; - } - return super.handlePreferenceTreeClick(preference); + }); } - @Override - public void updateState(Preference preference) { - super.updateState(preference); - if (TextUtils.equals(getPreferenceKey(), preference.getKey())) { - preference.setVisible(!hasSufficientPermission(mContext.getPackageManager())); + /** + * Adds the controlled preference to the provided preference screen. + */ + public void addToScreen(PreferenceScreen screen) { + if (!hasSufficientPermission(mPackageManager)) { + screen.addPreference(mPreference); } } + + /** + * Refreshes the visibility of the preference. + */ + public void updateVisibility() { + mPreference.setVisible(!hasSufficientPermission(mPackageManager)); + } } diff --git a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java index 9f5b49e47af..dfe6826195e 100644 --- a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java +++ b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java @@ -1,66 +1,95 @@ /* * Copyright (C) 2019 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 + * 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. + * 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 android.provider.Settings.Secure.ADAPTIVE_SLEEP; +import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.UserManager; import android.provider.Settings; import android.service.attention.AttentionService; import android.text.TextUtils; +import androidx.preference.PreferenceScreen; + import com.android.settings.R; -import com.android.settings.core.TogglePreferenceController; +import com.android.settings.bluetooth.RestrictionUtils; +import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +import com.android.settingslib.RestrictedSwitchPreference; +import com.google.common.annotations.VisibleForTesting; -public class AdaptiveSleepPreferenceController extends TogglePreferenceController { - public static final String PREF_NAME = "adaptive_sleep"; - private static final String SYSTEM_KEY = ADAPTIVE_SLEEP; +/** The controller for Screen attention switch preference. */ +public class AdaptiveSleepPreferenceController { + public static final String PREFERENCE_KEY = "adaptive_sleep"; private static final int DEFAULT_VALUE = 0; + private RestrictionUtils mRestrictionUtils; + private PackageManager mPackageManager; + private Context mContext; - public AdaptiveSleepPreferenceController(Context context, String key) { - super(context, key); + @VisibleForTesting + RestrictedSwitchPreference mPreference; + + public AdaptiveSleepPreferenceController(Context context, RestrictionUtils restrictionUtils) { + mContext = context; + mRestrictionUtils = restrictionUtils; + mPreference = new RestrictedSwitchPreference(context); + mPreference.setTitle(R.string.adaptive_sleep_title); + mPreference.setSummary(R.string.adaptive_sleep_description); + mPreference.setIcon(R.drawable.empty_icon); + mPreference.setChecked(isChecked()); + mPreference.setKey(PREFERENCE_KEY); + mPreference.setOnPreferenceClickListener(preference -> { + final boolean isChecked = ((RestrictedSwitchPreference) preference).isChecked(); + Settings.Secure.putInt(context.getContentResolver(), + Settings.Secure.ADAPTIVE_SLEEP, isChecked ? 1 : DEFAULT_VALUE); + return true; + }); + mPackageManager = context.getPackageManager(); } - @Override - public boolean isChecked() { + public AdaptiveSleepPreferenceController(Context context) { + this(context, new RestrictionUtils()); + } + + /** + * Adds the controlled preference to the provided preference screen. + */ + public void addToScreen(PreferenceScreen screen) { + final EnforcedAdmin enforcedAdmin = mRestrictionUtils.checkIfRestrictionEnforced(mContext, + UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT); + if (enforcedAdmin != null) { + mPreference.setDisabledByAdmin(enforcedAdmin); + } else { + mPreference.setEnabled(hasSufficientPermission(mPackageManager)); + } + screen.addPreference(mPreference); + } + + @VisibleForTesting + boolean isChecked() { return hasSufficientPermission(mContext.getPackageManager()) && Settings.Secure.getInt( - mContext.getContentResolver(), SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE; - } - - @Override - public boolean setChecked(boolean isChecked) { - Settings.Secure.putInt(mContext.getContentResolver(), SYSTEM_KEY, - isChecked ? 1 : DEFAULT_VALUE); - return true; - } - - @Override - @AvailabilityStatus - public int getAvailabilityStatus() { - return isControllerAvailable(mContext); - } - - @Override - public CharSequence getSummary() { - return mContext.getText(isChecked() - ? R.string.adaptive_sleep_summary_on - : R.string.adaptive_sleep_summary_off); + mContext.getContentResolver(), Settings.Secure.ADAPTIVE_SLEEP, DEFAULT_VALUE) + != DEFAULT_VALUE; } public static int isControllerAvailable(Context context) { @@ -89,4 +118,4 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle return attentionPackage != null && packageManager.checkPermission( Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED; } -} +} \ No newline at end of file diff --git a/src/com/android/settings/display/AdaptiveSleepSettings.java b/src/com/android/settings/display/AdaptiveSleepSettings.java deleted file mode 100644 index 52ded6a2b75..00000000000 --- a/src/com/android/settings/display/AdaptiveSleepSettings.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2019 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.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF; -import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF_KEY_INTERACTED; - -import android.app.settings.SettingsEnums; -import android.content.Context; -import android.os.Bundle; - -import androidx.preference.Preference; - -import com.android.settings.R; -import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.search.SearchIndexable; - -@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) -public class AdaptiveSleepSettings extends DashboardFragment { - - private static final String TAG = "AdaptiveSleepSettings"; - private Context mContext; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - mContext = getContext(); - Preference permissionPreference = findPreference( - AdaptiveSleepPermissionPreferenceController.PREF_NAME); - if (permissionPreference != null) { - permissionPreference.setVisible(false); - } - - mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE) - .edit() - .putBoolean(PREF_KEY_INTERACTED, true) - .apply(); - } - - @Override - protected int getPreferenceScreenResId() { - return R.xml.adaptive_sleep_detail; - } - - @Override - protected String getLogTag() { - return TAG; - } - - @Override - public int getMetricsCategory() { - return SettingsEnums.SETTINGS_ADAPTIVE_SLEEP; - } - - @Override - public int getHelpResource() { - return R.string.help_url_adaptive_sleep; - } - - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.adaptive_sleep_detail); -} diff --git a/src/com/android/settings/display/ScreenTimeoutPreferenceController.java b/src/com/android/settings/display/ScreenTimeoutPreferenceController.java new file mode 100644 index 00000000000..2e39e8e665a --- /dev/null +++ b/src/com/android/settings/display/ScreenTimeoutPreferenceController.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 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 android.provider.Settings.System.SCREEN_OFF_TIMEOUT; + +import static com.android.settings.display.ScreenTimeoutSettings.FALLBACK_SCREEN_TIMEOUT_VALUE; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.RestrictedLockUtilsInternal; + +/** + * The controller of {@link ScreenTimeoutSettings}. + */ +public class ScreenTimeoutPreferenceController extends BasePreferenceController { + public static String PREF_NAME = "screen_timeout"; + + public ScreenTimeoutPreferenceController(Context context, String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + return isDisableByAdmin() ? UNSUPPORTED_ON_DEVICE : AVAILABLE; + } + + @Override + public CharSequence getSummary() { + if (isDisableByAdmin()) { + return mContext.getString(com.android.settings.R.string.disabled_by_policy_title); + } else { + final long currentTimeout = getCurrentScreenTimeout(); + final CharSequence[] timeoutEntries = mContext.getResources().getStringArray( + R.array.screen_timeout_entries); + final CharSequence[] timeoutValues = mContext.getResources().getStringArray( + R.array.screen_timeout_values); + final CharSequence description = TimeoutPreferenceController.getTimeoutDescription( + currentTimeout, timeoutEntries, timeoutValues); + return mContext.getString(R.string.screen_timeout_summary, description); + } + } + + private boolean isDisableByAdmin() { + final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class); + if (dpm != null) { + final RestrictedLockUtils.EnforcedAdmin admin = + RestrictedLockUtilsInternal.checkIfRestrictionEnforced( + mContext, UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT, + UserHandle.myUserId()); + return admin != null; + } + return false; + } + + private long getCurrentScreenTimeout() { + return Settings.System.getLong(mContext.getContentResolver(), + SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE); + } +} diff --git a/src/com/android/settings/display/ScreenTimeoutSettings.java b/src/com/android/settings/display/ScreenTimeoutSettings.java new file mode 100644 index 00000000000..35c2cc0cfe2 --- /dev/null +++ b/src/com/android/settings/display/ScreenTimeoutSettings.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2020 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 android.provider.Settings.System.SCREEN_OFF_TIMEOUT; + +import android.app.admin.DevicePolicyManager; +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Log; + +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.actionbar.SearchMenuController; +import com.android.settings.support.actionbar.HelpMenuController; +import com.android.settings.support.actionbar.HelpResourceProvider; +import com.android.settings.widget.RadioButtonPickerFragment; +import com.android.settings.widget.RadioButtonPreferenceWithExtraWidget; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.RestrictedLockUtilsInternal; +import com.android.settingslib.search.SearchIndexable; +import com.android.settingslib.search.SearchIndexableRaw; +import com.android.settingslib.widget.CandidateInfo; +import com.android.settingslib.widget.FooterPreference; + +import java.util.ArrayList; +import java.util.List; + +/** + * Fragment that is used to control screen timeout. + */ +@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) +public class ScreenTimeoutSettings extends RadioButtonPickerFragment implements + HelpResourceProvider { + private static final String TAG = "ScreenTimeout"; + /** If there is no setting in the provider, use this. */ + public static final int FALLBACK_SCREEN_TIMEOUT_VALUE = 30000; + + private CharSequence[] mInitialEntries; + private CharSequence[] mInitialValues; + private FooterPreference mPrivacyPreference; + private AdaptiveSleepPreferenceController mAdaptiveSleepController; + private AdaptiveSleepPermissionPreferenceController mAdaptiveSleepPermissionController; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + SearchMenuController.init(this /* host */); + HelpMenuController.init(this /* host */); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + mInitialEntries = getResources().getStringArray(R.array.screen_timeout_entries); + mInitialValues = getResources().getStringArray(R.array.screen_timeout_values); + mAdaptiveSleepController = new AdaptiveSleepPreferenceController(context); + mAdaptiveSleepPermissionController = new AdaptiveSleepPermissionPreferenceController( + context); + mPrivacyPreference = new FooterPreference(context); + mPrivacyPreference.setIcon(R.drawable.ic_privacy_shield_24dp); + mPrivacyPreference.setTitle(R.string.adaptive_sleep_privacy); + mPrivacyPreference.setSelectable(false); + mPrivacyPreference.setLayoutResource(R.layout.preference_footer); + } + + @Override + protected List getCandidates() { + final Context context = getContext(); + final List candidates = new ArrayList<>(); + final long maxTimeout = getMaxScreenTimeout(context); + for (int i = 0; i < mInitialValues.length; ++i) { + if (Long.parseLong(mInitialValues[i].toString()) <= maxTimeout) { + candidates.add( + new TimeoutCandidateInfo(mInitialEntries[i], mInitialValues[i].toString(), + true)); + } + } + return candidates; + } + + @Override + public void onStart() { + super.onStart(); + mAdaptiveSleepPermissionController.updateVisibility(); + } + + @Override + public void updateCandidates() { + final String defaultKey = getDefaultKey(); + final PreferenceScreen screen = getPreferenceScreen(); + screen.removeAll(); + + final List candidateList = getCandidates(); + if (candidateList == null) { + return; + } + + for (CandidateInfo info : candidateList) { + RadioButtonPreferenceWithExtraWidget pref = + new RadioButtonPreferenceWithExtraWidget(getPrefContext()); + bindPreference(pref, info.getKey(), info, defaultKey); + screen.addPreference(pref); + } + + mAdaptiveSleepPermissionController.addToScreen(screen); + mAdaptiveSleepController.addToScreen(screen); + screen.addPreference(mPrivacyPreference); + } + + @Override + protected String getDefaultKey() { + return getCurrentSystemScreenTimeout(getContext()); + } + + @Override + protected boolean setDefaultKey(String key) { + setCurrentSystemScreenTimeout(getContext(), key); + return true; + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.SCREEN_TIMEOUT; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.screen_timeout_settings; + } + + @Override + public int getHelpResource() { + return R.string.help_url_adaptive_sleep; + } + + private Long getMaxScreenTimeout(Context context) { + final DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class); + if (dpm == null) { + return Long.MAX_VALUE; + } + + final RestrictedLockUtils.EnforcedAdmin admin = + RestrictedLockUtilsInternal.checkIfMaximumTimeToLockIsSet(context); + if (admin != null) { + return dpm.getMaximumTimeToLock(null /* admin */, UserHandle.myUserId()); + } + return Long.MAX_VALUE; + } + + private String getCurrentSystemScreenTimeout(Context context) { + if (context == null) { + return Long.toString(FALLBACK_SCREEN_TIMEOUT_VALUE); + } else { + return Long.toString(Settings.System.getLong(context.getContentResolver(), + SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE)); + } + } + + private void setCurrentSystemScreenTimeout(Context context, String key) { + try { + if (context != null) { + final long value = Long.parseLong(key); + Settings.System.putLong(context.getContentResolver(), SCREEN_OFF_TIMEOUT, value); + } + } catch (NumberFormatException e) { + Log.e(TAG, "could not persist screen timeout setting", e); + } + } + + private static class TimeoutCandidateInfo extends CandidateInfo { + private final CharSequence mLabel; + private final String mKey; + + TimeoutCandidateInfo(CharSequence label, String key, boolean enabled) { + super(enabled); + mLabel = label; + mKey = key; + } + + @Override + public CharSequence loadLabel() { + return mLabel; + } + + @Override + public Drawable loadIcon() { + return null; + } + + @Override + public String getKey() { + return mKey; + } + } + + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.screen_timeout_settings) { + public List getRawDataToIndex(Context context, + boolean enabled) { + final Resources res = context.getResources(); + final SearchIndexableRaw data = new SearchIndexableRaw(context); + data.title = res.getString(R.string.adaptive_sleep_title); + data.key = AdaptiveSleepPreferenceController.PREFERENCE_KEY; + data.screenTitle = res.getString(R.string.screen_timeout_title); + data.keywords = res.getString(R.string.adaptive_sleep_title); + + final List result = new ArrayList<>(1); + result.add(data); + return result; + } + }; +} diff --git a/src/com/android/settings/homepage/contextualcards/slices/ContextualAdaptiveSleepSlice.java b/src/com/android/settings/homepage/contextualcards/slices/ContextualAdaptiveSleepSlice.java index 4068d7c419f..a6170d819cd 100644 --- a/src/com/android/settings/homepage/contextualcards/slices/ContextualAdaptiveSleepSlice.java +++ b/src/com/android/settings/homepage/contextualcards/slices/ContextualAdaptiveSleepSlice.java @@ -17,8 +17,8 @@ package com.android.settings.homepage.contextualcards.slices; import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; -import static com.android.settings.display.AdaptiveSleepPreferenceController.PREF_NAME; import static com.android.settings.display.AdaptiveSleepPreferenceController.isControllerAvailable; +import static com.android.settings.display.ScreenTimeoutPreferenceController.PREF_NAME; import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI; import android.app.PendingIntent; @@ -35,7 +35,7 @@ import androidx.slice.builders.SliceAction; import com.android.settings.R; import com.android.settings.SubSettings; -import com.android.settings.display.AdaptiveSleepSettings; +import com.android.settings.display.ScreenTimeoutSettings; import com.android.settings.slices.CustomSliceable; import com.android.settings.slices.SliceBuilderUtils; @@ -115,7 +115,7 @@ public class ContextualAdaptiveSleepSlice implements CustomSliceable { final CharSequence screenTitle = mContext.getText(R.string.adaptive_sleep_title); final Uri contentUri = new Uri.Builder().appendPath(PREF_NAME).build(); return SliceBuilderUtils.buildSearchResultPageIntent(mContext, - AdaptiveSleepSettings.class.getName(), PREF_NAME, screenTitle.toString(), + ScreenTimeoutSettings.class.getName(), PREF_NAME, screenTitle.toString(), SettingsEnums.SLICE).setClassName(mContext.getPackageName(), SubSettings.class.getName()).setData(contentUri); } diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java index bb7def6a887..7a4cd5b8698 100644 --- a/src/com/android/settings/slices/CustomSliceRegistry.java +++ b/src/com/android/settings/slices/CustomSliceRegistry.java @@ -26,8 +26,8 @@ import android.util.ArrayMap; import androidx.annotation.VisibleForTesting; -import com.android.settings.display.AdaptiveSleepPreferenceController; import com.android.settings.display.AlwaysOnDisplaySlice; +import com.android.settings.display.ScreenTimeoutPreferenceController; import com.android.settings.flashlight.FlashlightSlice; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice; @@ -63,7 +63,7 @@ public class CustomSliceRegistry { .scheme(ContentResolver.SCHEME_CONTENT) .authority(SettingsSliceProvider.SLICE_AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT) - .appendPath(AdaptiveSleepPreferenceController.PREF_NAME) + .appendPath(ScreenTimeoutPreferenceController.PREF_NAME) .build(); /** diff --git a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java index 41e1ab181e9..4cde04b94b4 100644 --- a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java +++ b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java @@ -16,6 +16,8 @@ package com.android.settings.core; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; + import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_APPEND; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEYWORDS; @@ -38,7 +40,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -52,7 +53,7 @@ import java.util.Objects; * uncommon (such as summaryOn). * * If changing a preference file breaks a test in this test file, please replace its reference - * with another preference with a matchin replacement attribute. + * with another preference with a matching replacement attribute. */ @RunWith(RobolectricTestRunner.class) public class PreferenceXmlParserUtilsTest { @@ -61,43 +62,43 @@ public class PreferenceXmlParserUtilsTest { @Before public void setUp() { - mContext = RuntimeEnvironment.application; + mContext = getApplicationContext(); } @Test public void testDataTitleValid_ReturnsPreferenceTitle() { XmlResourceParser parser = getChildByType(R.xml.display_settings, - "com.android.settings.display.TimeoutListPreference"); + "com.android.settings.display.darkmode.DarkModePreference"); final AttributeSet attrs = Xml.asAttributeSet(parser); String title = PreferenceXmlParserUtils.getDataTitle(mContext, attrs); - String expTitle = mContext.getString(R.string.screen_timeout); + String expTitle = mContext.getString(R.string.dark_ui_mode); assertThat(title).isEqualTo(expTitle); } @Test public void testDataKeywordsValid_ReturnsPreferenceKeywords() { XmlResourceParser parser = getChildByType(R.xml.display_settings, - "com.android.settings.display.TimeoutListPreference"); + "com.android.settings.display.darkmode.DarkModePreference"); final AttributeSet attrs = Xml.asAttributeSet(parser); String keywords = PreferenceXmlParserUtils.getDataKeywords(mContext, attrs); - String expKeywords = mContext.getString(R.string.keywords_screen_timeout); + String expKeywords = mContext.getString(R.string.keywords_dark_ui_mode); assertThat(keywords).isEqualTo(expKeywords); } @Test public void testDataKeyValid_ReturnsPreferenceKey() { XmlResourceParser parser = getChildByType(R.xml.display_settings, - "com.android.settings.display.TimeoutListPreference"); + "com.android.settings.display.darkmode.DarkModePreference"); final AttributeSet attrs = Xml.asAttributeSet(parser); String key = PreferenceXmlParserUtils.getDataKey(mContext, attrs); - String expKey = "screen_timeout"; + String expKey = "dark_ui_mode"; assertThat(key).isEqualTo(expKey); } @Test public void testDataSummaryValid_ReturnsPreferenceSummary() { - XmlResourceParser parser = getChildByType(R.xml.display_settings, - "com.android.settings.display.TimeoutListPreference"); + XmlResourceParser parser = getChildByType(R.xml.sound_settings, + "com.android.settings.DefaultRingtonePreference"); final AttributeSet attrs = Xml.asAttributeSet(parser); String summary = PreferenceXmlParserUtils.getDataSummary(mContext, attrs); String expSummary = mContext.getString(R.string.summary_placeholder); diff --git a/tests/robotests/src/com/android/settings/display/AdaptiveSleepDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AdaptiveSleepDetailPreferenceControllerTest.java deleted file mode 100644 index fe0e812f0fe..00000000000 --- a/tests/robotests/src/com/android/settings/display/AdaptiveSleepDetailPreferenceControllerTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2019 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 static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.UserHandle; -import android.os.UserManager; - -import com.android.internal.R; -import com.android.settings.bluetooth.RestrictionUtils; -import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settingslib.RestrictedLockUtils; -import com.android.settingslib.RestrictedSwitchPreference; - -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -@RunWith(RobolectricTestRunner.class) -@Config(shadows = {SettingsShadowResources.class}) -public class AdaptiveSleepDetailPreferenceControllerTest { - private static RestrictedLockUtils.EnforcedAdmin sFakeEnforcedAdmin; - - @BeforeClass - public static void beforeClass() { - sFakeEnforcedAdmin = new RestrictedLockUtils.EnforcedAdmin( - new ComponentName("test.package", "test.Class"), - UserHandle.of(10)); - } - - private AdaptiveSleepDetailPreferenceController mController; - @Mock - private PackageManager mPackageManager; - @Mock - private RestrictionUtils mRestrictionUtils; - @Mock - private RestrictedSwitchPreference mPreference; - - private Context mContext; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = Mockito.spy(RuntimeEnvironment.application); - doReturn(mPackageManager).when(mContext).getPackageManager(); - mController = new AdaptiveSleepDetailPreferenceController(mContext, "test_key", - mRestrictionUtils); - } - - @Test - public void isSliceable_returnTrue() { - mController.onPreferenceChange(null, true); - assertThat(mController.isSliceable()).isTrue(); - } - - @Test - public void isPublicSlice_returnTrue() { - assertThat(mController.isPublicSlice()).isTrue(); - } - - @Test - public void getAvailabilityStatus_configTrueSet_shouldReturnAvailable() { - SettingsShadowResources.overrideResource(R.bool.config_adaptive_sleep_available, true); - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); - } - - @Test - public void getAvailabilityStatus_configFalseSet_shouldReturnUnsupportedOnDevice() { - SettingsShadowResources.overrideResource(R.bool.config_adaptive_sleep_available, false); - assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); - } - - @Test - public void updateState_noRestriction_allowScreenAttentionSet() { - when(mRestrictionUtils.checkIfRestrictionEnforced(mContext, - UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT)).thenReturn(null); - - mController.updateState(mPreference); - - verify(mPreference, never()).setDisabledByAdmin( - any(RestrictedLockUtils.EnforcedAdmin.class)); - } - - @Test - public void updateState_enforceRestrictions_disallowScreenAttentionSet() { - when(mRestrictionUtils.checkIfRestrictionEnforced(mContext, - UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT)).thenReturn(sFakeEnforcedAdmin); - - mController.updateState(mPreference); - - verify(mPreference).setDisabledByAdmin(sFakeEnforcedAdmin); - } -} diff --git a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceControllerTest.java index f2edf980443..0ac600f153e 100644 --- a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceControllerTest.java @@ -11,73 +11,69 @@ * 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 + * limitations under the License. */ package com.android.settings.display; -import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; - -import static com.google.common.truth.Truth.assertThat; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; -import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; -import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class AdaptiveSleepPermissionPreferenceControllerTest { - private final static String PACKAGE_NAME = "package_name"; + private Context mContext; private AdaptiveSleepPermissionPreferenceController mController; + @Mock private PackageManager mPackageManager; @Mock - private Preference mPreference; + private PreferenceScreen mScreen; @Before public void setUp() { MockitoAnnotations.initMocks(this); - Context context = Mockito.spy(RuntimeEnvironment.application); - doReturn(mPackageManager).when(context).getPackageManager(); - doReturn(PACKAGE_NAME).when(mPackageManager).getAttentionServicePackageName(); - doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission( - Manifest.permission.CAMERA, PACKAGE_NAME); - mController = new AdaptiveSleepPermissionPreferenceController(context, "test_key"); - doReturn(mController.getPreferenceKey()).when(mPreference).getKey(); + mContext = spy(getApplicationContext()); + + doReturn(mPackageManager).when(mContext).getPackageManager(); + when(mPackageManager.getAttentionServicePackageName()).thenReturn("some.package"); + when(mPackageManager.checkPermission(any(), any())).thenReturn( + PackageManager.PERMISSION_GRANTED); + + mController = new AdaptiveSleepPermissionPreferenceController(mContext); } @Test - public void getAvailabilityStatus_returnAvailableUnsearchable() { - assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); + public void addToScreen_normalCase_hidePreference() { + mController.addToScreen(mScreen); + + verify(mScreen, never()).addPreference(mController.mPreference); } @Test - public void updateStates_permissionGranted_preferenceInvisible() { - mController.updateState(mPreference); + public void addToScreen_permissionNotGranted_showPreference() { + when(mPackageManager.checkPermission(any(), any())).thenReturn( + PackageManager.PERMISSION_DENIED); - verify(mPreference).setVisible(false); - } + mController.addToScreen(mScreen); - @Test - public void updateStates_permissionRevoked_preferenceVisible() { - doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( - Manifest.permission.CAMERA, PACKAGE_NAME); - - mController.updateState(mPreference); - - verify(mPreference).setVisible(true); + verify(mScreen).addPreference(mController.mPreference); } } diff --git a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java index 87f59f22f99..1db7873a92a 100644 --- a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPreferenceControllerTest.java @@ -18,27 +18,32 @@ package com.android.settings.display; import static android.provider.Settings.Secure.ADAPTIVE_SLEEP; +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; + import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.os.UserManager; import android.provider.Settings; -import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.settings.R; +import com.android.settings.bluetooth.RestrictionUtils; +import com.android.settingslib.RestrictedLockUtils; import org.junit.Before; import org.junit.Test; @@ -46,13 +51,9 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class AdaptiveSleepPreferenceControllerTest { - - private static final String PREFERENCE_KEY = "adaptive_sleep"; - private Context mContext; private AdaptiveSleepPreferenceController mController; private ContentResolver mContentResolver; @@ -62,114 +63,101 @@ public class AdaptiveSleepPreferenceControllerTest { @Mock private PreferenceScreen mScreen; @Mock - private Preference mPreference; + private RestrictionUtils mRestrictionUtils; + @Mock + private RestrictedLockUtils.EnforcedAdmin mEnforcedAdmin; @Before public void setUp() { MockitoAnnotations.initMocks(this); - - mContext = spy(RuntimeEnvironment.application); + mContext = spy(getApplicationContext()); mContentResolver = mContext.getContentResolver(); doReturn(mPackageManager).when(mContext).getPackageManager(); when(mPackageManager.getAttentionServicePackageName()).thenReturn("some.package"); when(mPackageManager.checkPermission(any(), any())).thenReturn( PackageManager.PERMISSION_GRANTED); + when(mRestrictionUtils.checkIfRestrictionEnforced(any(), + eq(UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT))).thenReturn(null); - mController = new AdaptiveSleepPreferenceController(mContext, PREFERENCE_KEY); - when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + mController = new AdaptiveSleepPreferenceController(mContext, mRestrictionUtils); } @Test - public void isControllerAvailable_ServiceUnavailable_returnUnsupported() { - doReturn(null).when(mPackageManager).resolveService(isA(Intent.class), anyInt()); + public void controlSetting_preferenceChecked_FeatureTurnOn() { + mController.mPreference.setChecked(false); + + mController.mPreference.performClick(); + + int mode = Settings.Secure.getInt(mContentResolver, ADAPTIVE_SLEEP, 0); + assertThat(mode).isEqualTo(1); + } + + @Test + public void controlSetting_preferenceNotChecked_FeatureTurnOff() { + mController.mPreference.setChecked(true); + + mController.mPreference.performClick(); + + int mode = Settings.Secure.getInt(mContentResolver, ADAPTIVE_SLEEP, 1); + assertThat(mode).isEqualTo(0); + } + + @Test + public void isControllerAvailable_serviceNotSupported_returnUnsupportedCode() { + when(mPackageManager.resolveService(isA(Intent.class), anyInt())).thenReturn(null); assertThat(AdaptiveSleepPreferenceController.isControllerAvailable(mContext)).isEqualTo( UNSUPPORTED_ON_DEVICE); } @Test - public void onPreferenceChange_turnOn_returnOn() { - mController.onPreferenceChange(null, true); - - final int mode = Settings.Secure.getInt(mContentResolver, ADAPTIVE_SLEEP, 0); - assertThat(mode).isEqualTo(1); + public void hasSufficientPermission_permissionGranted_returnTrue() { + assertThat(AdaptiveSleepPreferenceController.hasSufficientPermission( + mPackageManager)).isTrue(); } @Test - public void onPreferenceChange_turnOff_returnOff() { - mController.onPreferenceChange(null, false); - - final int mode = Settings.Secure.getInt(mContentResolver, ADAPTIVE_SLEEP, 1); - assertThat(mode).isEqualTo(0); - } - - @Test - public void setChecked_updatesCorrectly() { - mController.setChecked(true); - - assertThat(mController.isChecked()).isTrue(); - - mController.setChecked(false); - - assertThat(mController.isChecked()).isFalse(); - } - - @Test - public void isChecked_no() { - Settings.System.putInt(mContentResolver, ADAPTIVE_SLEEP, 0); - - assertThat(mController.isChecked()).isFalse(); - } - - @Test - public void isChecked_yes() { - Settings.Secure.putInt(mContentResolver, ADAPTIVE_SLEEP, 1); - - assertThat(mController.isChecked()).isTrue(); - } - - @Test - public void getSummary_settingOn_shouldReturnOnSummary() { - mController.setChecked(true); - - assertThat(mController.getSummary()) - .isEqualTo(mContext.getText(R.string.adaptive_sleep_summary_on)); - } - - @Test - public void getSummary_settingOff_shouldReturnOffSummary() { - mController.setChecked(false); - - assertThat(mController.getSummary()) - .isEqualTo(mContext.getText(R.string.adaptive_sleep_summary_off)); - } - - @Test - public void isSliceable_returnsTrue() { - final AdaptiveSleepPreferenceController controller = - new AdaptiveSleepPreferenceController(mContext, "any_key"); - assertThat(controller.isSliceable()).isTrue(); - } - - @Test - public void isChecked_returnsFalseWhenNotSufficientPermissions() { - when(mPackageManager.checkPermission(any(), any())).thenReturn( - PackageManager.PERMISSION_DENIED); - final AdaptiveSleepPreferenceController controller = new AdaptiveSleepPreferenceController( - mContext, PREFERENCE_KEY); - - controller.setChecked(true); - assertThat(controller.isChecked()).isFalse(); - } - - @Test - public void isEnabled_returnsFalseWhenNotSufficientPermissions() { + public void hasSufficientPermission_permissionNotGranted_returnFalse() { when(mPackageManager.checkPermission(any(), any())).thenReturn( PackageManager.PERMISSION_DENIED); - mController.setChecked(true); - mController.displayPreference(mScreen); - assertThat(mPreference.isEnabled()).isFalse(); + assertThat(AdaptiveSleepPreferenceController.hasSufficientPermission( + mPackageManager)).isFalse(); + } + + @Test + public void addToScreen_normalCase_enablePreference() { + mController.mPreference.setEnabled(false); + when(mPackageManager.checkPermission(any(), any())).thenReturn( + PackageManager.PERMISSION_GRANTED); + + mController.addToScreen(mScreen); + + assertThat(mController.mPreference.isEnabled()).isTrue(); + verify(mScreen).addPreference(mController.mPreference); + } + + @Test + public void addToScreen_permissionNotGranted_disablePreference() { + mController.mPreference.setEnabled(true); + when(mPackageManager.checkPermission(any(), any())).thenReturn( + PackageManager.PERMISSION_DENIED); + + mController.addToScreen(mScreen); + + assertThat(mController.mPreference.isEnabled()).isFalse(); + } + + @Test + public void addToScreen_enforcedAdmin_disablePreference() { + mController.mPreference.setEnabled(true); + + when(mRestrictionUtils.checkIfRestrictionEnforced(any(), + eq(UserManager.DISALLOW_CONFIG_SCREEN_TIMEOUT))).thenReturn(mEnforcedAdmin); + + mController.addToScreen(mScreen); + + assertThat(mController.mPreference.isEnabled()).isFalse(); } } diff --git a/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java b/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java new file mode 100644 index 00000000000..48912de62ca --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020 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 android.provider.Settings.System.SCREEN_OFF_TIMEOUT; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import android.provider.SearchIndexableResource; +import android.provider.Settings; + +import com.android.settings.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class ScreenTimeoutSettingsTest { + private static final String[] TIMEOUT_ENTRIES = new String[]{"15 secs", "30 secs"}; + private static final String[] TIMEOUT_VALUES = new String[]{"15000", "30000"}; + + private ScreenTimeoutSettings mSettings; + private Context mContext; + private ContentResolver mContentResolver; + + @Mock + private Resources mResources; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mContext = spy(getApplicationContext()); + mSettings = spy(new ScreenTimeoutSettings()); + mContentResolver = mContext.getContentResolver(); + + doReturn(TIMEOUT_ENTRIES).when(mResources).getStringArray(R.array.screen_timeout_entries); + doReturn(TIMEOUT_VALUES).when(mResources).getStringArray(R.array.screen_timeout_entries); + doReturn(mResources).when(mSettings).getResources(); + doReturn(mContext).when(mSettings).getContext(); + } + + @Test + public void searchIndexProvider_shouldIndexResource() { + final List indexRes = + ScreenTimeoutSettings.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex( + mContext, true /* enabled */); + + assertThat(indexRes).isNotNull(); + assertThat(indexRes.get(0).xmlResId).isEqualTo(mSettings.getPreferenceScreenResId()); + } + + @Test + public void getDefaultKey_returnCurrentTimeout() { + long timeout = Long.parseLong(TIMEOUT_VALUES[1]); + Settings.System.putLong(mContentResolver, SCREEN_OFF_TIMEOUT, timeout); + + String key = mSettings.getDefaultKey(); + + assertThat(key).isEqualTo(TIMEOUT_VALUES[1]); + } + + @Test + public void setDefaultKey_controlCurrentScreenTimeout() { + mSettings.setDefaultKey(TIMEOUT_VALUES[0]); + + long timeout = Settings.System.getLong(mContentResolver, SCREEN_OFF_TIMEOUT, + 30000 /* default */); + + assertThat(Long.toString(timeout)).isEqualTo(TIMEOUT_VALUES[0]); + } +}