From a681094e8a30e42e34e261d9e928709256bb8f61 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Fri, 3 Nov 2017 15:43:53 -0700 Subject: [PATCH] Convert SecuritySubSetting into DashboardFragment Bug: 32953042 Test: robotests Change-Id: Iecdb0a42695644ff8aa095bcd49b5ccb16aa46d4 --- ...ttern_sub.xml => screen_lock_settings.xml} | 36 +-- res/xml/security_settings_password_sub.xml | 38 --- res/xml/security_settings_pin_sub.xml | 38 --- res/xml/security_settings_slide_sub.xml | 28 -- .../password/ManagedLockPasswordProvider.java | 9 - .../search/SearchIndexableResources.java | 2 + .../OwnerInfoPreferenceController.java | 5 +- .../settings/security/SecuritySettings.java | 11 +- .../security/SecuritySubSettings.java | 252 ------------------ .../LockAfterTimeoutPreferenceController.java | 155 +++++++++++ .../PatternVisiblePreferenceController.java | 70 +++++ ...ButtonInstantLockPreferenceController.java | 94 +++++++ .../screenlock/ScreenLockSettings.java | 106 ++++++++ .../{ => users}/OwnerInfoSettings.java | 3 +- .../android/settings/users/UserSettings.java | 1 - .../grandfather_not_implementing_indexable | 1 - .../security/ConfigureKeyGuardDialogTest.java | 10 +- .../OwnerInfoPreferenceControllerTest.java | 35 ++- ...kAfterTimeoutPreferenceControllerTest.java | 104 ++++++++ ...atternVisiblePreferenceControllerTest.java | 102 +++++++ ...onInstantLockPreferenceControllerTest.java | 133 +++++++++ .../screenlock/ScreenLockSettingsTest.java | 67 +++++ .../testutils/FakeFeatureFactory.java | 21 +- 23 files changed, 899 insertions(+), 422 deletions(-) rename res/xml/{security_settings_pattern_sub.xml => screen_lock_settings.xml} (50%) delete mode 100644 res/xml/security_settings_password_sub.xml delete mode 100644 res/xml/security_settings_pin_sub.xml delete mode 100644 res/xml/security_settings_slide_sub.xml delete mode 100644 src/com/android/settings/security/SecuritySubSettings.java create mode 100644 src/com/android/settings/security/screenlock/LockAfterTimeoutPreferenceController.java create mode 100644 src/com/android/settings/security/screenlock/PatternVisiblePreferenceController.java create mode 100644 src/com/android/settings/security/screenlock/PowerButtonInstantLockPreferenceController.java create mode 100644 src/com/android/settings/security/screenlock/ScreenLockSettings.java rename src/com/android/settings/{ => users}/OwnerInfoSettings.java (98%) create mode 100644 tests/robotests/src/com/android/settings/security/screenlock/LockAfterTimeoutPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/security/screenlock/PatternVisiblePreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/security/screenlock/PowerButtonInstantLockPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java diff --git a/res/xml/security_settings_pattern_sub.xml b/res/xml/screen_lock_settings.xml similarity index 50% rename from res/xml/security_settings_pattern_sub.xml rename to res/xml/screen_lock_settings.xml index c898d6f4185..3bd82554ba7 100644 --- a/res/xml/security_settings_pattern_sub.xml +++ b/res/xml/screen_lock_settings.xml @@ -1,29 +1,31 @@ + android:key="security_settings_password_sub_screen" + android:title="@string/security_settings_title"> + + + + - + \ No newline at end of file diff --git a/res/xml/security_settings_password_sub.xml b/res/xml/security_settings_password_sub.xml deleted file mode 100644 index d9e6111c46e..00000000000 --- a/res/xml/security_settings_password_sub.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - diff --git a/res/xml/security_settings_pin_sub.xml b/res/xml/security_settings_pin_sub.xml deleted file mode 100644 index f98ccbc2b8f..00000000000 --- a/res/xml/security_settings_pin_sub.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - diff --git a/res/xml/security_settings_slide_sub.xml b/res/xml/security_settings_slide_sub.xml deleted file mode 100644 index 126b8af3398..00000000000 --- a/res/xml/security_settings_slide_sub.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - diff --git a/src/com/android/settings/password/ManagedLockPasswordProvider.java b/src/com/android/settings/password/ManagedLockPasswordProvider.java index 09fe1049863..82135cf817d 100644 --- a/src/com/android/settings/password/ManagedLockPasswordProvider.java +++ b/src/com/android/settings/password/ManagedLockPasswordProvider.java @@ -65,15 +65,6 @@ public class ManagedLockPasswordProvider { : R.xml.security_settings_password; } - /** - * Gets resource id of the subscreen that should be shown after clicking gear icon for lock - * screen preference in security settings if the current password quality is set to - * {@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_MANAGED}. - */ - public int getResIdForLockUnlockSubScreen() { - return R.xml.security_settings_password_sub; - } - /** * Creates intent that should be launched when user chooses managed password in the lock * settings picker. diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index ebba99a63e5..47d17b63c48 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -76,6 +76,7 @@ import com.android.settings.print.PrintSettingsFragment; import com.android.settings.security.EncryptionAndCredential; import com.android.settings.security.LockscreenDashboardFragment; import com.android.settings.security.SecuritySettings; +import com.android.settings.security.screenlock.ScreenLockSettings; import com.android.settings.sim.SimSettings; import com.android.settings.support.SupportDashboardActivity; import com.android.settings.system.ResetDashboardFragment; @@ -138,6 +139,7 @@ public final class SearchIndexableResources { addIndex(LocationSettings.class); addIndex(ScanningSettings.class); addIndex(SecuritySettings.class); + addIndex(ScreenLockSettings.class); addIndex(EncryptionAndCredential.class); addIndex(ScreenPinningSettings.class); addIndex(UserAndAccountDashboardFragment.class); diff --git a/src/com/android/settings/security/OwnerInfoPreferenceController.java b/src/com/android/settings/security/OwnerInfoPreferenceController.java index cae4d1099bc..395e5320eb5 100644 --- a/src/com/android/settings/security/OwnerInfoPreferenceController.java +++ b/src/com/android/settings/security/OwnerInfoPreferenceController.java @@ -22,9 +22,10 @@ import android.support.annotation.VisibleForTesting; import android.support.v7.preference.Preference; import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.support.v7.preference.PreferenceScreen; + import com.android.internal.widget.LockPatternUtils; -import com.android.settings.OwnerInfoSettings; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.users.OwnerInfoSettings; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedPreference; @@ -45,7 +46,7 @@ public class OwnerInfoPreferenceController extends AbstractPreferenceController // Container fragment should implement this in order to show the correct summary public interface OwnerInfoCallback { - public void onOwnerInfoUpdated(); + void onOwnerInfoUpdated(); } public OwnerInfoPreferenceController(Context context, Fragment parent, Lifecycle lifecycle ) { diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java index 16ab1fc7d06..02beaaad172 100644 --- a/src/com/android/settings/security/SecuritySettings.java +++ b/src/com/android/settings/security/SecuritySettings.java @@ -67,6 +67,7 @@ import com.android.settings.password.ManagedLockPasswordProvider; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.search.SearchIndexableRaw; +import com.android.settings.security.screenlock.ScreenLockSettings; import com.android.settings.security.trustagent.TrustAgentManager; import com.android.settings.security.trustagent.TrustAgentManager.TrustAgentComponentInfo; import com.android.settings.widget.GearPreference; @@ -522,7 +523,7 @@ public class SecuritySettings extends SettingsPreferenceFragment @Override public void onGearClick(GearPreference p) { if (KEY_UNLOCK_SET_OR_CHANGE.equals(p.getKey())) { - startFragment(this, SecuritySubSettings.class.getName(), 0, 0, null); + startFragment(this, ScreenLockSettings.class.getName(), 0, 0, null); } } @@ -763,7 +764,7 @@ public class SecuritySettings extends SettingsPreferenceFragment @Override public List getXmlResourcesToIndex( Context context, boolean enabled) { - final List index = new ArrayList(); + final List index = new ArrayList<>(); final LockPatternUtils lockPatternUtils = new LockPatternUtils(context); final ManagedLockPasswordProvider managedPasswordProvider = @@ -792,12 +793,6 @@ public class SecuritySettings extends SettingsPreferenceFragment lockPatternUtils, managedPasswordProvider, profileUserId))); } - final SearchIndexableResource sir = getSearchResource(context, - SecuritySubSettings.getResIdForLockUnlockSubScreen(lockPatternUtils, - managedPasswordProvider)); - sir.className = SecuritySubSettings.class.getName(); - index.add(sir); - // Append the rest of the settings index.add(getSearchResource(context, R.xml.security_settings_misc)); diff --git a/src/com/android/settings/security/SecuritySubSettings.java b/src/com/android/settings/security/SecuritySubSettings.java deleted file mode 100644 index 5c5052bf3d4..00000000000 --- a/src/com/android/settings/security/SecuritySubSettings.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.security; - -import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; - -import android.app.admin.DevicePolicyManager; -import android.content.Intent; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; -import android.support.v14.preference.SwitchPreference; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceScreen; -import android.text.TextUtils; -import android.util.Log; - -import com.android.internal.logging.nano.MetricsProto; -import com.android.internal.widget.LockPatternUtils; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.TimeoutListPreference; -import com.android.settings.overlay.FeatureFactory; -import com.android.settings.password.ManagedLockPasswordProvider; -import com.android.settings.security.trustagent.TrustAgentManager; -import com.android.settingslib.RestrictedLockUtils; - -public class SecuritySubSettings extends SettingsPreferenceFragment - implements Preference.OnPreferenceChangeListener, - OwnerInfoPreferenceController.OwnerInfoCallback { - - private static final String TAG = "SecuritySubSettings"; - - private static final String KEY_VISIBLE_PATTERN = "visiblepattern"; - private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout"; - private static final String KEY_POWER_INSTANTLY_LOCKS = "power_button_instantly_locks"; - - // These switch preferences need special handling since they're not all stored in Settings. - private static final String SWITCH_PREFERENCE_KEYS[] = { - KEY_LOCK_AFTER_TIMEOUT, KEY_VISIBLE_PATTERN, KEY_POWER_INSTANTLY_LOCKS}; - private static final int MY_USER_ID = UserHandle.myUserId(); - - private TimeoutListPreference mLockAfter; - private SwitchPreference mVisiblePattern; - private SwitchPreference mPowerButtonInstantlyLocks; - - private TrustAgentManager mTrustAgentManager; - private LockPatternUtils mLockPatternUtils; - private DevicePolicyManager mDPM; - private OwnerInfoPreferenceController mOwnerInfoPreferenceController; - - @Override - public int getMetricsCategory() { - return MetricsProto.MetricsEvent.SECURITY; - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - mTrustAgentManager = - FeatureFactory.getFactory( - getActivity()).getSecurityFeatureProvider().getTrustAgentManager(); - mLockPatternUtils = new LockPatternUtils(getContext()); - mDPM = getContext().getSystemService(DevicePolicyManager.class); - mOwnerInfoPreferenceController = - new OwnerInfoPreferenceController(getContext(), this, null /* lifecycle */); - createPreferenceHierarchy(); - } - - @Override - public void onResume() { - super.onResume(); - - createPreferenceHierarchy(); - - if (mVisiblePattern != null) { - mVisiblePattern.setChecked(mLockPatternUtils.isVisiblePatternEnabled(MY_USER_ID)); - } - if (mPowerButtonInstantlyLocks != null) { - mPowerButtonInstantlyLocks.setChecked( - mLockPatternUtils.getPowerButtonInstantlyLocks(MY_USER_ID)); - } - - mOwnerInfoPreferenceController.updateSummary(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - createPreferenceHierarchy(); - } - - private void createPreferenceHierarchy() { - PreferenceScreen root = getPreferenceScreen(); - if (root != null) { - root.removeAll(); - } - - final int resid = getResIdForLockUnlockSubScreen(new LockPatternUtils(getContext()), - ManagedLockPasswordProvider.get(getContext(), MY_USER_ID)); - addPreferencesFromResource(resid); - - // lock after preference - mLockAfter = (TimeoutListPreference) findPreference(KEY_LOCK_AFTER_TIMEOUT); - if (mLockAfter != null) { - setupLockAfterPreference(); - updateLockAfterPreferenceSummary(); - } - - // visible pattern - mVisiblePattern = (SwitchPreference) findPreference(KEY_VISIBLE_PATTERN); - - // lock instantly on power key press - mPowerButtonInstantlyLocks = (SwitchPreference) findPreference( - KEY_POWER_INSTANTLY_LOCKS); - final CharSequence trustAgentLabel = mTrustAgentManager.getActiveTrustAgentLabel( - getContext(), mLockPatternUtils); - if (mPowerButtonInstantlyLocks != null && !TextUtils.isEmpty(trustAgentLabel)) { - mPowerButtonInstantlyLocks.setSummary(getString( - R.string.lockpattern_settings_power_button_instantly_locks_summary, - trustAgentLabel)); - } - - mOwnerInfoPreferenceController.displayPreference(getPreferenceScreen()); - mOwnerInfoPreferenceController.updateEnableState(); - - for (int i = 0; i < SWITCH_PREFERENCE_KEYS.length; i++) { - final Preference pref = findPreference(SWITCH_PREFERENCE_KEYS[i]); - if (pref != null) pref.setOnPreferenceChangeListener(this); - } - } - - private void setupLockAfterPreference() { - // Compatible with pre-Froyo - long currentTimeout = Settings.Secure.getLong(getContentResolver(), - Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000); - mLockAfter.setValue(String.valueOf(currentTimeout)); - mLockAfter.setOnPreferenceChangeListener(this); - if (mDPM != null) { - final RestrictedLockUtils.EnforcedAdmin admin = - RestrictedLockUtils.checkIfMaximumTimeToLockIsSet( - getActivity()); - final long adminTimeout = mDPM - .getMaximumTimeToLockForUserAndProfiles(UserHandle.myUserId()); - final long displayTimeout = Math.max(0, - Settings.System.getInt(getContentResolver(), SCREEN_OFF_TIMEOUT, 0)); - // This setting is a slave to display timeout when a device policy is enforced. - // As such, maxLockTimeout = adminTimeout - displayTimeout. - // If there isn't enough time, shows "immediately" setting. - final long maxTimeout = Math.max(0, adminTimeout - displayTimeout); - mLockAfter.removeUnusableTimeouts(maxTimeout, admin); - } - } - - private void updateLockAfterPreferenceSummary() { - final String summary; - if (mLockAfter.isDisabledByAdmin()) { - summary = getString(R.string.disabled_by_policy_title); - } else { - // Update summary message with current value - long currentTimeout = Settings.Secure.getLong(getContentResolver(), - Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000); - final CharSequence[] entries = mLockAfter.getEntries(); - final CharSequence[] values = mLockAfter.getEntryValues(); - int best = 0; - for (int i = 0; i < values.length; i++) { - long timeout = Long.valueOf(values[i].toString()); - if (currentTimeout >= timeout) { - best = i; - } - } - - final CharSequence trustAgentLabel = mTrustAgentManager - .getActiveTrustAgentLabel(getContext(), mLockPatternUtils); - if (!TextUtils.isEmpty(trustAgentLabel)) { - if (Long.valueOf(values[best].toString()) == 0) { - summary = getString(R.string.lock_immediately_summary_with_exception, - trustAgentLabel); - } else { - summary = getString(R.string.lock_after_timeout_summary_with_exception, - entries[best], trustAgentLabel); - } - } else { - summary = getString(R.string.lock_after_timeout_summary, entries[best]); - } - } - mLockAfter.setSummary(summary); - } - - @Override - public void onOwnerInfoUpdated() { - mOwnerInfoPreferenceController.updateSummary(); - } - - static int getResIdForLockUnlockSubScreen(LockPatternUtils lockPatternUtils, - ManagedLockPasswordProvider managedPasswordProvider) { - if (lockPatternUtils.isSecure(MY_USER_ID)) { - switch (lockPatternUtils.getKeyguardStoredPasswordQuality(MY_USER_ID)) { - case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: - return R.xml.security_settings_pattern_sub; - case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: - return R.xml.security_settings_pin_sub; - case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: - case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: - return R.xml.security_settings_password_sub; - case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: - return managedPasswordProvider.getResIdForLockUnlockSubScreen(); - } - } else if (!lockPatternUtils.isLockScreenDisabled(MY_USER_ID)) { - return R.xml.security_settings_slide_sub; - } - return 0; - } - - @Override - public boolean onPreferenceChange(Preference preference, Object value) { - String key = preference.getKey(); - if (KEY_POWER_INSTANTLY_LOCKS.equals(key)) { - mLockPatternUtils.setPowerButtonInstantlyLocks((Boolean) value, MY_USER_ID); - } else if (KEY_LOCK_AFTER_TIMEOUT.equals(key)) { - int timeout = Integer.parseInt((String) value); - try { - Settings.Secure.putInt(getContentResolver(), - Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, timeout); - } catch (NumberFormatException e) { - Log.e(TAG, "could not persist lockAfter timeout setting", e); - } - setupLockAfterPreference(); - updateLockAfterPreferenceSummary(); - } else if (KEY_VISIBLE_PATTERN.equals(key)) { - mLockPatternUtils.setVisiblePatternEnabled((Boolean) value, MY_USER_ID); - } - return true; - } -} diff --git a/src/com/android/settings/security/screenlock/LockAfterTimeoutPreferenceController.java b/src/com/android/settings/security/screenlock/LockAfterTimeoutPreferenceController.java new file mode 100644 index 00000000000..3cbde584e13 --- /dev/null +++ b/src/com/android/settings/security/screenlock/LockAfterTimeoutPreferenceController.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.security.screenlock; + +import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; +import android.support.v7.preference.Preference; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.R; +import com.android.settings.TimeoutListPreference; +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.security.trustagent.TrustAgentManager; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.core.AbstractPreferenceController; + +public class LockAfterTimeoutPreferenceController extends AbstractPreferenceController + implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { + + private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout"; + + private final int mUserId; + private final LockPatternUtils mLockPatternUtils; + private final TrustAgentManager mTrustAgentManager; + private final DevicePolicyManager mDPM; + + public LockAfterTimeoutPreferenceController(Context context, int userId, + LockPatternUtils lockPatternUtils) { + super(context); + mUserId = userId; + mLockPatternUtils = lockPatternUtils; + mDPM = context.getSystemService(DevicePolicyManager.class); + mTrustAgentManager = FeatureFactory.getFactory(context) + .getSecurityFeatureProvider().getTrustAgentManager(); + } + + @Override + public boolean isAvailable() { + if (!mLockPatternUtils.isSecure(mUserId)) { + return false; + } + switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) { + case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: + case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: + case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: + case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: + return true; + default: + return false; + } + } + + @Override + public String getPreferenceKey() { + return KEY_LOCK_AFTER_TIMEOUT; + } + + @Override + public void updateState(Preference preference) { + setupLockAfterPreference((TimeoutListPreference) preference); + updateLockAfterPreferenceSummary((TimeoutListPreference) preference); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + try { + final int timeout = Integer.parseInt((String) newValue); + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, timeout); + updateState(preference); + } catch (NumberFormatException e) { + Log.e(TAG, "could not persist lockAfter timeout setting", e); + } + return true; + } + + private void setupLockAfterPreference(TimeoutListPreference preference) { + // Compatible with pre-Froyo + long currentTimeout = Settings.Secure.getLong(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000); + preference.setValue(String.valueOf(currentTimeout)); + if (mDPM != null) { + final RestrictedLockUtils.EnforcedAdmin admin = + RestrictedLockUtils.checkIfMaximumTimeToLockIsSet(mContext); + final long adminTimeout = mDPM + .getMaximumTimeToLockForUserAndProfiles(UserHandle.myUserId()); + final long displayTimeout = Math.max(0, + Settings.System.getInt(mContext.getContentResolver(), SCREEN_OFF_TIMEOUT, 0)); + // This setting is a slave to display timeout when a device policy is enforced. + // As such, maxLockTimeout = adminTimeout - displayTimeout. + // If there isn't enough time, shows "immediately" setting. + final long maxTimeout = Math.max(0, adminTimeout - displayTimeout); + preference.removeUnusableTimeouts(maxTimeout, admin); + } + } + + private void updateLockAfterPreferenceSummary(TimeoutListPreference preference) { + final CharSequence summary; + if (preference.isDisabledByAdmin()) { + summary = mContext.getText(R.string.disabled_by_policy_title); + } else { + // Update summary message with current value + long currentTimeout = Settings.Secure.getLong(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000); + final CharSequence[] entries = preference.getEntries(); + final CharSequence[] values = preference.getEntryValues(); + int best = 0; + for (int i = 0; i < values.length; i++) { + long timeout = Long.valueOf(values[i].toString()); + if (currentTimeout >= timeout) { + best = i; + } + } + + final CharSequence trustAgentLabel = mTrustAgentManager + .getActiveTrustAgentLabel(mContext, mLockPatternUtils); + if (!TextUtils.isEmpty(trustAgentLabel)) { + if (Long.valueOf(values[best].toString()) == 0) { + summary = mContext.getString(R.string.lock_immediately_summary_with_exception, + trustAgentLabel); + } else { + summary = mContext.getString(R.string.lock_after_timeout_summary_with_exception, + entries[best], trustAgentLabel); + } + } else { + summary = mContext.getString(R.string.lock_after_timeout_summary, entries[best]); + } + } + preference.setSummary(summary); + } +} diff --git a/src/com/android/settings/security/screenlock/PatternVisiblePreferenceController.java b/src/com/android/settings/security/screenlock/PatternVisiblePreferenceController.java new file mode 100644 index 00000000000..beddd4b69f4 --- /dev/null +++ b/src/com/android/settings/security/screenlock/PatternVisiblePreferenceController.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.security.screenlock; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.support.v7.preference.Preference; +import android.support.v7.preference.TwoStatePreference; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settingslib.core.AbstractPreferenceController; + +public class PatternVisiblePreferenceController extends AbstractPreferenceController + implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { + + private static final String PREF_KEY = "visiblepattern"; + + private final int mUserId; + private final LockPatternUtils mLockPatternUtils; + + public PatternVisiblePreferenceController(Context context, int userId, + LockPatternUtils lockPatternUtils) { + super(context); + mUserId = userId; + mLockPatternUtils = lockPatternUtils; + } + + @Override + public boolean isAvailable() { + return isPatternLock(); + } + + @Override + public String getPreferenceKey() { + return PREF_KEY; + } + + @Override + public void updateState(Preference preference) { + ((TwoStatePreference) preference).setChecked( + mLockPatternUtils.isVisiblePatternEnabled(mUserId)); + } + + private boolean isPatternLock() { + return mLockPatternUtils.isSecure(mUserId) + && mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId) + == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + mLockPatternUtils.setVisiblePatternEnabled((Boolean) newValue, mUserId); + return true; + } +} diff --git a/src/com/android/settings/security/screenlock/PowerButtonInstantLockPreferenceController.java b/src/com/android/settings/security/screenlock/PowerButtonInstantLockPreferenceController.java new file mode 100644 index 00000000000..1a32a0e382f --- /dev/null +++ b/src/com/android/settings/security/screenlock/PowerButtonInstantLockPreferenceController.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.security.screenlock; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.support.v7.preference.Preference; +import android.support.v7.preference.TwoStatePreference; +import android.text.TextUtils; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.R; +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.security.trustagent.TrustAgentManager; +import com.android.settingslib.core.AbstractPreferenceController; + +public class PowerButtonInstantLockPreferenceController extends AbstractPreferenceController + implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { + + private static final String KEY_POWER_INSTANTLY_LOCKS = "power_button_instantly_locks"; + + private final int mUserId; + private final LockPatternUtils mLockPatternUtils; + private final TrustAgentManager mTrustAgentManager; + + public PowerButtonInstantLockPreferenceController(Context context, int userId, + LockPatternUtils lockPatternUtils) { + super(context); + mUserId = userId; + mLockPatternUtils = lockPatternUtils; + mTrustAgentManager = FeatureFactory.getFactory(context) + .getSecurityFeatureProvider().getTrustAgentManager(); + } + + @Override + public boolean isAvailable() { + if (!mLockPatternUtils.isSecure(mUserId)) { + return false; + } + switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) { + case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: + case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: + case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: + case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: + return true; + default: + return false; + } + } + + @Override + public void updateState(Preference preference) { + ((TwoStatePreference) preference).setChecked( + mLockPatternUtils.getPowerButtonInstantlyLocks(mUserId)); + final CharSequence trustAgentLabel = mTrustAgentManager.getActiveTrustAgentLabel( + mContext, mLockPatternUtils); + if (!TextUtils.isEmpty(trustAgentLabel)) { + preference.setSummary(mContext.getString( + R.string.lockpattern_settings_power_button_instantly_locks_summary, + trustAgentLabel)); + } else { + preference.setSummary(R.string.summary_placeholder); + } + } + + @Override + public String getPreferenceKey() { + return KEY_POWER_INSTANTLY_LOCKS; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + mLockPatternUtils.setPowerButtonInstantlyLocks((Boolean) newValue, mUserId); + return true; + } +} diff --git a/src/com/android/settings/security/screenlock/ScreenLockSettings.java b/src/com/android/settings/security/screenlock/ScreenLockSettings.java new file mode 100644 index 00000000000..8d4832579ea --- /dev/null +++ b/src/com/android/settings/security/screenlock/ScreenLockSettings.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.security.screenlock; + +import android.app.Fragment; +import android.content.Context; +import android.os.UserHandle; +import android.provider.SearchIndexableResource; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settings.security.OwnerInfoPreferenceController; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import java.util.ArrayList; +import java.util.List; + +public class ScreenLockSettings extends DashboardFragment + implements OwnerInfoPreferenceController.OwnerInfoCallback { + + private static final String TAG = "ScreenLockSettings"; + + private static final int MY_USER_ID = UserHandle.myUserId(); + private LockPatternUtils mLockPatternUtils; + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.SECURITY; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.screen_lock_settings; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected List getPreferenceControllers(Context context) { + mLockPatternUtils = new LockPatternUtils(context); + return buildPreferenceControllers(context, this /* parent */, getLifecycle(), + mLockPatternUtils); + } + + @Override + public void onOwnerInfoUpdated() { + getPreferenceController(OwnerInfoPreferenceController.class).updateSummary(); + } + + private static List buildPreferenceControllers(Context context, + Fragment parent, Lifecycle lifecycle, LockPatternUtils lockPatternUtils) { + final List controllers = new ArrayList<>(); + controllers.add(new PatternVisiblePreferenceController( + context, MY_USER_ID, lockPatternUtils)); + controllers.add(new PowerButtonInstantLockPreferenceController( + context, MY_USER_ID, lockPatternUtils)); + controllers.add(new LockAfterTimeoutPreferenceController( + context, MY_USER_ID, lockPatternUtils)); + controllers.add(new OwnerInfoPreferenceController(context, parent, lifecycle)); + return controllers; + } + + + public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final ArrayList result = new ArrayList<>(); + + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.screen_lock_settings; + result.add(sir); + return result; + } + + @Override + public List getPreferenceControllers( + Context context) { + return buildPreferenceControllers(context, null /* parent */, + null /* lifecycle */, new LockPatternUtils(context)); + } + }; +} diff --git a/src/com/android/settings/OwnerInfoSettings.java b/src/com/android/settings/users/OwnerInfoSettings.java similarity index 98% rename from src/com/android/settings/OwnerInfoSettings.java rename to src/com/android/settings/users/OwnerInfoSettings.java index 3128dfe6ab8..582431f3439 100644 --- a/src/com/android/settings/OwnerInfoSettings.java +++ b/src/com/android/settings/users/OwnerInfoSettings.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings; +package com.android.settings.users; import android.app.AlertDialog; import android.app.Dialog; @@ -30,6 +30,7 @@ import android.widget.EditText; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.widget.LockPatternUtils; +import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.security.OwnerInfoPreferenceController.OwnerInfoCallback; diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index e6122b9ce57..642f289f9cd 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -54,7 +54,6 @@ import android.widget.SimpleAdapter; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; -import com.android.settings.OwnerInfoSettings; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragment; diff --git a/tests/robotests/assets/grandfather_not_implementing_indexable b/tests/robotests/assets/grandfather_not_implementing_indexable index 31b8f43d81f..4ea533872e4 100644 --- a/tests/robotests/assets/grandfather_not_implementing_indexable +++ b/tests/robotests/assets/grandfather_not_implementing_indexable @@ -71,7 +71,6 @@ com.android.settings.applications.ExternalSourcesDetails com.android.settings.applications.PictureInPictureSettings com.android.settings.applications.PictureInPictureDetails com.android.settings.ApnSettings -com.android.settings.security.SecuritySubSettings com.android.settings.PrivacySettings com.android.settings.WifiCallingSettings com.android.settings.WifiCallingSettingsForSub diff --git a/tests/robotests/src/com/android/settings/security/ConfigureKeyGuardDialogTest.java b/tests/robotests/src/com/android/settings/security/ConfigureKeyGuardDialogTest.java index 38a6b422f20..ab7512fd580 100644 --- a/tests/robotests/src/com/android/settings/security/ConfigureKeyGuardDialogTest.java +++ b/tests/robotests/src/com/android/settings/security/ConfigureKeyGuardDialogTest.java @@ -17,10 +17,14 @@ package com.android.settings.security; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + import android.content.DialogInterface; -import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import org.junit.Test; @@ -29,10 +33,6 @@ import org.robolectric.Robolectric; import org.robolectric.android.controller.FragmentController; import org.robolectric.annotation.Config; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - @RunWith(SettingsRobolectricTestRunner.class) @Config( manifest = TestConfig.MANIFEST_PATH, diff --git a/tests/robotests/src/com/android/settings/security/OwnerInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/OwnerInfoPreferenceControllerTest.java index 8406d9089b1..71e2d8b352f 100644 --- a/tests/robotests/src/com/android/settings/security/OwnerInfoPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/security/OwnerInfoPreferenceControllerTest.java @@ -15,16 +15,27 @@ */ package com.android.settings.security; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Answers.RETURNS_DEEP_STUBS; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Context; -import android.support.v7.preference.PreferenceScreen; import android.support.v14.preference.PreferenceFragment; +import android.support.v7.preference.PreferenceScreen; import com.android.internal.widget.LockPatternUtils; -import com.android.settings.OwnerInfoSettings; -import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.users.OwnerInfoSettings; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedPreference; @@ -37,18 +48,6 @@ import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowApplication; import org.robolectric.util.ReflectionHelpers; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Answers.RETURNS_DEEP_STUBS; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class OwnerInfoPreferenceControllerTest { @@ -139,7 +138,7 @@ public class OwnerInfoPreferenceControllerTest { mController.updateSummary(); verify(mPreference).setSummary(mContext.getString( - com.android.settings.R.string.owner_info_settings_summary)); + com.android.settings.R.string.owner_info_settings_summary)); } @Test @@ -179,7 +178,7 @@ public class OwnerInfoPreferenceControllerTest { public void performClick_shouldLaunchOwnerInfoSettings() { final ShadowApplication application = ShadowApplication.getInstance(); final RestrictedPreference preference = - new RestrictedPreference(application.getApplicationContext()); + new RestrictedPreference(application.getApplicationContext()); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(preference); doReturn(false).when(mController).isDeviceOwnerInfoEnabled(); doReturn(false).when(mLockPatternUtils).isLockScreenDisabled(anyInt()); @@ -190,7 +189,7 @@ public class OwnerInfoPreferenceControllerTest { verify(mFragment).getFragmentManager(); verify(mFragment.getFragmentManager().beginTransaction()) - .add(any(OwnerInfoSettings.class), anyString()); + .add(any(OwnerInfoSettings.class), anyString()); } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/security/screenlock/LockAfterTimeoutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/screenlock/LockAfterTimeoutPreferenceControllerTest.java new file mode 100644 index 00000000000..a1d7b4edc72 --- /dev/null +++ b/tests/robotests/src/com/android/settings/security/screenlock/LockAfterTimeoutPreferenceControllerTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.security.screenlock; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.support.v14.preference.SwitchPreference; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.TestConfig; +import com.android.settings.security.trustagent.TrustAgentManager; +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O) +public class LockAfterTimeoutPreferenceControllerTest { + + private static final int TEST_USER_ID = 0; + + @Mock + private LockPatternUtils mLockPatternUtils; + @Mock + private TrustAgentManager mTrustAgentManager; + + private Context mContext; + private LockAfterTimeoutPreferenceController mController; + private SwitchPreference mPreference; + private FakeFeatureFactory mFeatureFactory; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mFeatureFactory = FakeFeatureFactory.setupForTest(); + when(mFeatureFactory.securityFeatureProvider.getTrustAgentManager()) + .thenReturn(mTrustAgentManager); + + mPreference = new SwitchPreference(mContext); + mController = new LockAfterTimeoutPreferenceController( + mContext, TEST_USER_ID, mLockPatternUtils); + } + + @Test + public void isAvailable_lockSetToPattern_shouldReturnTrue() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_lockSetToPin_shouldReturnTrue() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_lockSetToPassword_shouldReturnTrue() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_lockSetToNone_shouldReturnFalse() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(false); + + assertThat(mController.isAvailable()).isFalse(); + } + + +} diff --git a/tests/robotests/src/com/android/settings/security/screenlock/PatternVisiblePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/screenlock/PatternVisiblePreferenceControllerTest.java new file mode 100644 index 00000000000..a947fca84bc --- /dev/null +++ b/tests/robotests/src/com/android/settings/security/screenlock/PatternVisiblePreferenceControllerTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.security.screenlock; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.support.v14.preference.SwitchPreference; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O) +public class PatternVisiblePreferenceControllerTest { + + private static final int TEST_USER_ID = 0; + + @Mock + private LockPatternUtils mLockPatternUtils; + private Context mContext; + private PatternVisiblePreferenceController mController; + private SwitchPreference mPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = new PatternVisiblePreferenceController( + mContext, TEST_USER_ID, mLockPatternUtils); + mPreference = new SwitchPreference(mContext); + } + + @Test + public void isAvailable_lockSetToPattern_shouldReturnTrue() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_lockSetToPin_shouldReturnFalse() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void isAvailable_lockSetToNone_shouldReturnFalse() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(false); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void updateState_shouldSetPref() { + when(mLockPatternUtils.isVisiblePatternEnabled(TEST_USER_ID)).thenReturn(true); + mController.updateState(mPreference); + assertThat(mPreference.isChecked()).isTrue(); + + when(mLockPatternUtils.isVisiblePatternEnabled(TEST_USER_ID)).thenReturn(false); + mController.updateState(mPreference); + assertThat(mPreference.isChecked()).isFalse(); + } + + @Test + public void onPreferenceChange_shouldUpdateLockPatternUtils() { + mController.onPreferenceChange(mPreference, true /* newValue */); + + verify(mLockPatternUtils).setVisiblePatternEnabled(true, TEST_USER_ID); + } +} diff --git a/tests/robotests/src/com/android/settings/security/screenlock/PowerButtonInstantLockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/screenlock/PowerButtonInstantLockPreferenceControllerTest.java new file mode 100644 index 00000000000..2d2e92f0a1a --- /dev/null +++ b/tests/robotests/src/com/android/settings/security/screenlock/PowerButtonInstantLockPreferenceControllerTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.security.screenlock; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.support.v14.preference.SwitchPreference; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.security.trustagent.TrustAgentManager; +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O) +public class PowerButtonInstantLockPreferenceControllerTest { + + private static final int TEST_USER_ID = 0; + + @Mock + private LockPatternUtils mLockPatternUtils; + @Mock + private TrustAgentManager mTrustAgentManager; + + private Context mContext; + private PowerButtonInstantLockPreferenceController mController; + private SwitchPreference mPreference; + private FakeFeatureFactory mFeatureFactory; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mFeatureFactory = FakeFeatureFactory.setupForTest(); + when(mFeatureFactory.securityFeatureProvider.getTrustAgentManager()) + .thenReturn(mTrustAgentManager); + + mPreference = new SwitchPreference(mContext); + mController = new PowerButtonInstantLockPreferenceController( + mContext, TEST_USER_ID, mLockPatternUtils); + } + + @Test + public void isAvailable_lockSetToPattern_shouldReturnTrue() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_lockSetToPin_shouldReturnTrue() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_lockSetToPassword_shouldReturnTrue() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(TEST_USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_lockSetToNone_shouldReturnFalse() { + when(mLockPatternUtils.isSecure(TEST_USER_ID)).thenReturn(false); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void updateState_shouldSetPref() { + final String fakeTrustAgent = "trust_agent"; + when(mTrustAgentManager.getActiveTrustAgentLabel(mContext, mLockPatternUtils)) + .thenReturn(fakeTrustAgent); + when(mLockPatternUtils.getPowerButtonInstantlyLocks(TEST_USER_ID)).thenReturn(true); + mController.updateState(mPreference); + assertThat(mPreference.isChecked()).isTrue(); + assertThat(mPreference.getSummary()).isEqualTo(mContext.getString( + R.string.lockpattern_settings_power_button_instantly_locks_summary, + fakeTrustAgent)); + + when(mTrustAgentManager.getActiveTrustAgentLabel(mContext, mLockPatternUtils)) + .thenReturn(null); + when(mLockPatternUtils.getPowerButtonInstantlyLocks(TEST_USER_ID)).thenReturn(false); + mController.updateState(mPreference); + assertThat(mPreference.isChecked()).isFalse(); + assertThat(mPreference.getSummary()).isEqualTo(mContext.getString( + R.string.summary_placeholder)); + } + + @Test + public void onPreferenceChange_shouldUpdateLockPatternUtils() { + mController.onPreferenceChange(mPreference, true /* newValue */); + + verify(mLockPatternUtils).setPowerButtonInstantlyLocks(true, TEST_USER_ID); + } + +} diff --git a/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java b/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java new file mode 100644 index 00000000000..e8416eef8ec --- /dev/null +++ b/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.security.screenlock; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.security.OwnerInfoPreferenceController; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.AbstractPreferenceController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +import java.util.Map; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O) +public class ScreenLockSettingsTest { + + private ScreenLockSettings mSettings; + + @Before + public void setUp() { + mSettings = new ScreenLockSettings(); + } + + @Test + public void verifyConstants() { + assertThat(mSettings.getMetricsCategory()).isEqualTo(MetricsProto.MetricsEvent.SECURITY); + assertThat(mSettings.getPreferenceScreenResId()).isEqualTo(R.xml.screen_lock_settings); + } + + @Test + public void onOwnerInfoUpdated_shouldUpdateOwnerInfoController() { + final Map preferenceControllers = + ReflectionHelpers.getField(mSettings, "mPreferenceControllers"); + final OwnerInfoPreferenceController controller = mock(OwnerInfoPreferenceController.class); + preferenceControllers.put(OwnerInfoPreferenceController.class, controller); + + mSettings.onOwnerInfoUpdated(); + + verify(controller).updateSummary(); + } + +} diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java index 6da7a6655c5..dd5c76a6e3b 100644 --- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java +++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java @@ -15,6 +15,10 @@ */ package com.android.settings.testutils; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.content.Context; import com.android.settings.applications.ApplicationFeatureProvider; @@ -30,14 +34,12 @@ import com.android.settings.gestures.AssistGestureFeatureProvider; import com.android.settings.localepicker.LocaleFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.SupportFeatureProvider; -import com.android.settings.security.SecurityFeatureProvider; -import com.android.settings.search.SearchFeatureProvider; import com.android.settings.overlay.SurveyFeatureProvider; +import com.android.settings.search.SearchFeatureProvider; +import com.android.settings.security.SecurityFeatureProvider; import com.android.settings.users.UserFeatureProvider; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import org.mockito.Answers; /** * Test util to provide fake FeatureFactory. To use this factory, call {@code setupForTest} in @@ -67,6 +69,7 @@ public class FakeFeatureFactory extends FeatureFactory { * * @param context The context must be a deep mock. */ + @Deprecated public static FakeFeatureFactory setupForTest(Context context) { sFactory = null; when(context.getString(com.android.settings.R.string.config_featureFactory)) @@ -80,6 +83,14 @@ public class FakeFeatureFactory extends FeatureFactory { return (FakeFeatureFactory) FakeFeatureFactory.getFactory(context); } + /** + * Call this in {@code @Before} method of the test class to use fake factory. + */ + public static FakeFeatureFactory setupForTest() { + final Context context = mock(Context.class, Answers.RETURNS_DEEP_STUBS); + return setupForTest(context); + } + /** * Used by reflection. Do not call directly. */