From c10c16bb39d82178315f20bc61d3135b2111047c Mon Sep 17 00:00:00 2001 From: Yuri Ufimtsev Date: Tue, 8 Feb 2022 14:21:20 +0000 Subject: [PATCH] Move all the shared Screen Lock details into a reusable utility class Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.security.ChangeScreenLockPreferenceControllerTest Test: atest SettingsUnitTests:ScreenLockPreferenceDetailsUtilsTest Bug: 215515298 Change-Id: I46543d35ce4dc2fee85ad1c55886b272de113768 --- .../ChangeScreenLockPreferenceController.java | 70 +--- .../ScreenLockPreferenceDetailsUtils.java | 156 +++++++++ ...ngeScreenLockPreferenceControllerTest.java | 8 +- .../ScreenLockPreferenceDetailsUtilsTest.java | 310 ++++++++++++++++++ 4 files changed, 482 insertions(+), 62 deletions(-) create mode 100644 src/com/android/settings/security/ScreenLockPreferenceDetailsUtils.java create mode 100644 tests/unit/src/com/android/settings/security/ScreenLockPreferenceDetailsUtilsTest.java diff --git a/src/com/android/settings/security/ChangeScreenLockPreferenceController.java b/src/com/android/settings/security/ChangeScreenLockPreferenceController.java index 5439fef2238..4e542386c7f 100644 --- a/src/com/android/settings/security/ChangeScreenLockPreferenceController.java +++ b/src/com/android/settings/security/ChangeScreenLockPreferenceController.java @@ -16,40 +16,32 @@ package com.android.settings.security; -import android.app.admin.DevicePolicyManager; import android.content.Context; import android.os.UserHandle; import android.os.UserManager; -import android.os.storage.StorageManager; import android.text.TextUtils; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.internal.widget.LockPatternUtils; -import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; import com.android.settings.core.PreferenceControllerMixin; -import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.overlay.FeatureFactory; -import com.android.settings.password.ChooseLockGeneric; -import com.android.settings.security.screenlock.ScreenLockSettings; import com.android.settings.widget.GearPreference; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedPreference; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; -import com.android.settingslib.transition.SettingsTransitionHelper; public class ChangeScreenLockPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin, GearPreference.OnGearClickListener { private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; - protected final DevicePolicyManager mDPM; protected final SettingsPreferenceFragment mHost; protected final UserManager mUm; protected final LockPatternUtils mLockPatternUtils; @@ -57,24 +49,26 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont protected final int mUserId = UserHandle.myUserId(); protected final int mProfileChallengeUserId; private final MetricsFeatureProvider mMetricsFeatureProvider; + private final ScreenLockPreferenceDetailsUtils mScreenLockPreferenceDetailUtils; protected RestrictedPreference mPreference; public ChangeScreenLockPreferenceController(Context context, SettingsPreferenceFragment host) { super(context); mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); - mDPM = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); mLockPatternUtils = FeatureFactory.getFactory(context) .getSecurityFeatureProvider() .getLockPatternUtils(context); mHost = host; mProfileChallengeUserId = Utils.getManagedProfileId(mUm, mUserId); mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); + mScreenLockPreferenceDetailUtils = + new ScreenLockPreferenceDetailsUtils(context, host.getMetricsCategory()); } @Override public boolean isAvailable() { - return mContext.getResources().getBoolean(R.bool.config_show_unlock_set_or_change); + return mScreenLockPreferenceDetailUtils.isAvailable(); } @Override @@ -91,7 +85,7 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont @Override public void updateState(Preference preference) { if (mPreference != null && mPreference instanceof GearPreference) { - if (mLockPatternUtils.isSecure(mUserId)) { + if (mScreenLockPreferenceDetailUtils.shouldShowGearMenu()) { ((GearPreference) mPreference).setOnGearClickListener(this); } else { ((GearPreference) mPreference).setOnGearClickListener(null); @@ -112,10 +106,7 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont if (TextUtils.equals(p.getKey(), getPreferenceKey())) { mMetricsFeatureProvider.logClickedPreference(p, p.getExtras().getInt(DashboardFragment.CATEGORY)); - new SubSettingLauncher(mContext) - .setDestination(ScreenLockSettings.class.getName()) - .setSourceMetricsCategory(mHost.getMetricsCategory()) - .launch(); + mScreenLockPreferenceDetailUtils.openScreenLockSettings(); } } @@ -124,51 +115,11 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { return super.handlePreferenceTreeClick(preference); } - // TODO(b/35930129): Remove once existing password can be passed into vold directly. - // Currently we need this logic to ensure that the QUIET_MODE is off for any work - // profile with unified challenge on FBE-enabled devices. Otherwise, vold would not be - // able to complete the operation due to the lack of (old) encryption key. - if (mProfileChallengeUserId != UserHandle.USER_NULL - && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId) - && StorageManager.isFileEncryptedNativeOnly()) { - if (Utils.startQuietModeDialogIfNecessary(mContext, mUm, mProfileChallengeUserId)) { - return false; - } - } - - new SubSettingLauncher(mContext) - .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()) - .setSourceMetricsCategory(mHost.getMetricsCategory()) - .setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE) - .launch(); - return true; + return mScreenLockPreferenceDetailUtils.openChooseLockGenericFragment(); } protected void updateSummary(Preference preference, int userId) { - if (!mLockPatternUtils.isSecure(userId)) { - if (userId == mProfileChallengeUserId - || mLockPatternUtils.isLockScreenDisabled(userId)) { - preference.setSummary(R.string.unlock_set_unlock_mode_off); - } else { - preference.setSummary(R.string.unlock_set_unlock_mode_none); - } - } else { - switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(userId)) { - case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: - preference.setSummary(R.string.unlock_set_unlock_mode_pattern); - break; - case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: - preference.setSummary(R.string.unlock_set_unlock_mode_pin); - break; - case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: - case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: - case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: - case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: - preference.setSummary(R.string.unlock_set_unlock_mode_password); - break; - } - } + preference.setSummary(mScreenLockPreferenceDetailUtils.getSummary(userId)); mPreference.setEnabled(true); } @@ -181,10 +132,7 @@ public class ChangeScreenLockPreferenceController extends AbstractPreferenceCont void disableIfPasswordQualityManaged(int userId) { final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtilsInternal .checkIfPasswordQualityIsSet(mContext, userId); - final DevicePolicyManager dpm = (DevicePolicyManager) mContext - .getSystemService(Context.DEVICE_POLICY_SERVICE); - if (admin != null && dpm.getPasswordQuality(admin.component, userId) - == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) { + if (mScreenLockPreferenceDetailUtils.isPasswordQualityManaged(userId, admin)) { mPreference.setDisabledByAdmin(admin); } } diff --git a/src/com/android/settings/security/ScreenLockPreferenceDetailsUtils.java b/src/com/android/settings/security/ScreenLockPreferenceDetailsUtils.java new file mode 100644 index 00000000000..abcacf021b9 --- /dev/null +++ b/src/com/android/settings/security/ScreenLockPreferenceDetailsUtils.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.security; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.os.UserHandle; +import android.os.UserManager; +import android.os.storage.StorageManager; + +import androidx.annotation.StringRes; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.core.SubSettingLauncher; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment; +import com.android.settings.security.screenlock.ScreenLockSettings; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.transition.SettingsTransitionHelper; + +/** + * Utilities for screen lock details shared between Security Settings and Safety Center. + */ +public class ScreenLockPreferenceDetailsUtils { + + private final int mUserId = UserHandle.myUserId(); + private final Context mContext; + private final LockPatternUtils mLockPatternUtils; + private final int mProfileChallengeUserId; + private final UserManager mUm; + private final int mSourceMetricsCategory; + + public ScreenLockPreferenceDetailsUtils(Context context, int sourceMetricsCategory) { + mContext = context; + mUm = context.getSystemService(UserManager.class); + mLockPatternUtils = FeatureFactory.getFactory(context) + .getSecurityFeatureProvider() + .getLockPatternUtils(context); + mProfileChallengeUserId = Utils.getManagedProfileId(mUm, mUserId); + mSourceMetricsCategory = sourceMetricsCategory; + } + + /** + * Returns whether the screen lock settings entity should be shown. + */ + public boolean isAvailable() { + return mContext.getResources().getBoolean(R.bool.config_show_unlock_set_or_change); + } + + /** + * Returns the summary of screen lock settings entity. + */ + public String getSummary(int userId) { + final Integer summaryResId = getSummaryResId(userId); + return summaryResId != null ? mContext.getResources().getString(summaryResId) : null; + } + + /** + * Returns whether the password quality is managed by device admin. + */ + public boolean isPasswordQualityManaged(int userId, RestrictedLockUtils.EnforcedAdmin admin) { + final DevicePolicyManager dpm = (DevicePolicyManager) mContext + .getSystemService(Context.DEVICE_POLICY_SERVICE); + return admin != null && dpm.getPasswordQuality(admin.component, userId) + == DevicePolicyManager.PASSWORD_QUALITY_MANAGED; + } + + /** + * Returns whether the Gear Menu should be shown. + */ + public boolean shouldShowGearMenu() { + return mLockPatternUtils.isSecure(mUserId); + } + + /** + * Launches the {@link ScreenLockSettings}. + */ + public void openScreenLockSettings() { + new SubSettingLauncher(mContext) + .setDestination(ScreenLockSettings.class.getName()) + .setSourceMetricsCategory(mSourceMetricsCategory) + .launch(); + } + + /** + * Tries to launch the {@link ChooseLockGenericFragment} if Quiet Mode is not enabled + * for managed profile, otherwise shows a dialog to disable the Quiet Mode. + * + * @return true if the {@link ChooseLockGenericFragment} is launching. + */ + public boolean openChooseLockGenericFragment() { + // TODO(b/35930129): Remove once existing password can be passed into vold directly. + // Currently we need this logic to ensure that the QUIET_MODE is off for any work + // profile with unified challenge on FBE-enabled devices. Otherwise, vold would not be + // able to complete the operation due to the lack of (old) encryption key. + if (mProfileChallengeUserId != UserHandle.USER_NULL + && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId) + && StorageManager.isFileEncryptedNativeOnly()) { + if (Utils.startQuietModeDialogIfNecessary(mContext, mUm, mProfileChallengeUserId)) { + return false; + } + } + + new SubSettingLauncher(mContext) + .setDestination(ChooseLockGenericFragment.class.getName()) + .setSourceMetricsCategory(mSourceMetricsCategory) + .setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE) + .launch(); + return true; + } + + @StringRes + private Integer getSummaryResId(int userId) { + if (!mLockPatternUtils.isSecure(userId)) { + if (userId == mProfileChallengeUserId + || mLockPatternUtils.isLockScreenDisabled(userId)) { + return R.string.unlock_set_unlock_mode_off; + } else { + return R.string.unlock_set_unlock_mode_none; + } + } else { + int keyguardStoredPasswordQuality = + mLockPatternUtils.getKeyguardStoredPasswordQuality(userId); + switch (keyguardStoredPasswordQuality) { + case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: + return R.string.unlock_set_unlock_mode_pattern; + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: + return R.string.unlock_set_unlock_mode_pin; + case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: + case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: + case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: + case DevicePolicyManager.PASSWORD_QUALITY_MANAGED: + return R.string.unlock_set_unlock_mode_password; + default: + return null; + } + } + } +} diff --git a/tests/robotests/src/com/android/settings/security/ChangeScreenLockPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/ChangeScreenLockPreferenceControllerTest.java index 9913e554b4d..35431696acb 100644 --- a/tests/robotests/src/com/android/settings/security/ChangeScreenLockPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/security/ChangeScreenLockPreferenceControllerTest.java @@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -35,6 +36,7 @@ import androidx.preference.PreferenceViewHolder; import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settings.widget.GearPreference; @@ -52,6 +54,8 @@ import org.robolectric.annotation.Config; @Config(shadows = ShadowUtils.class) public class ChangeScreenLockPreferenceControllerTest { + private static final int METRICS_CATEGORY = 1; + @Mock private LockPatternUtils mLockPatternUtils; @Mock @@ -78,7 +82,9 @@ public class ChangeScreenLockPreferenceControllerTest { when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)) .thenReturn(mDevicePolicyManager); - mController = new ChangeScreenLockPreferenceController(mContext, null /* Host */ ); + final SettingsPreferenceFragment host = mock(SettingsPreferenceFragment.class); + when(host.getMetricsCategory()).thenReturn(METRICS_CATEGORY); + mController = new ChangeScreenLockPreferenceController(mContext, host); } @Test diff --git a/tests/unit/src/com/android/settings/security/ScreenLockPreferenceDetailsUtilsTest.java b/tests/unit/src/com/android/settings/security/ScreenLockPreferenceDetailsUtilsTest.java new file mode 100644 index 00000000000..3d13b480d66 --- /dev/null +++ b/tests/unit/src/com/android/settings/security/ScreenLockPreferenceDetailsUtilsTest.java @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.security; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.os.UserManager; +import android.os.storage.StorageManager; + +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.internal.widget.LockPatternUtils; +import com.android.settings.SettingsActivity; +import com.android.settings.password.ChooseLockGeneric; +import com.android.settings.security.screenlock.ScreenLockSettings; +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.ResourcesUtils; +import com.android.settingslib.RestrictedLockUtils; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +public class ScreenLockPreferenceDetailsUtilsTest { + + private static final int SOURCE_METRICS_CATEGORY = 10; + private static final int USER_ID = 11; + + @Mock + private LockPatternUtils mLockPatternUtils; + @Mock + private UserManager mUserManager; + @Mock + private DevicePolicyManager mDevicePolicyManager; + @Mock + private Resources mResources; + @Mock + private StorageManager mStorageManager; + + private Context mContext; + + private ScreenLockPreferenceDetailsUtils mScreenLockPreferenceDetailsUtils; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(ApplicationProvider.getApplicationContext()); + when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); + when(mContext.getResources()).thenReturn(mResources); + when(mContext.getSystemService(StorageManager.class)).thenReturn(mStorageManager); + when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)) + .thenReturn(mDevicePolicyManager); + when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + doNothing().when(mContext).startActivity(any()); + when(mUserManager.getProfileIdsWithDisabled(anyInt())).thenReturn(new int[] {}); + + final FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest(); + when(featureFactory.securityFeatureProvider.getLockPatternUtils(mContext)) + .thenReturn(mLockPatternUtils); + + mScreenLockPreferenceDetailsUtils = + new ScreenLockPreferenceDetailsUtils(mContext, SOURCE_METRICS_CATEGORY); + } + + @Test + public void isAvailable_whenEnabled_shouldReturnTrue() { + whenConfigShowUnlockSetOrChangeIsEnabled(true); + + assertThat(mScreenLockPreferenceDetailsUtils.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_whenDisabled_shouldReturnFalse() { + whenConfigShowUnlockSetOrChangeIsEnabled(false); + + assertThat(mScreenLockPreferenceDetailsUtils.isAvailable()).isFalse(); + } + + @Test + public void getSummary_unsecureAndDisabledPattern_shouldReturnUnlockModeOff() { + final String summary = prepareString("unlock_set_unlock_mode_off", "unlockModeOff"); + + when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(false); + when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(true); + + assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary); + } + + @Test + public void getSummary_unsecurePattern_shouldReturnUnlockModeNone() { + final String summary = + prepareString("unlock_set_unlock_mode_none", "unlockModeNone"); + + when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(false); + when(mLockPatternUtils.isLockScreenDisabled(anyInt())).thenReturn(false); + + assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary); + } + + @Test + public void getSummary_passwordQualitySomething_shouldUnlockModePattern() { + final String summary = + prepareString("unlock_set_unlock_mode_pattern", "unlockModePattern"); + + when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + + assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary); + } + + @Test + public void getSummary_passwordQualityNumeric_shouldUnlockModePin() { + final String summary = + prepareString("unlock_set_unlock_mode_pin", "unlockModePin"); + + when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); + + assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary); + } + + @Test + public void getSummary_passwordQualityNumericComplex_shouldUnlockModePin() { + final String summary = prepareString("unlock_set_unlock_mode_pin", "unlockModePin"); + + when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX); + + assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary); + } + + @Test + public void getSummary_passwordQualityAlphabetic_shouldUnlockModePassword() { + final String summary = + prepareString("unlock_set_unlock_mode_password", "unlockModePassword"); + + when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC); + + assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary); + } + + @Test + public void getSummary_passwordQualityAlphanumeric_shouldUnlockModePassword() { + final String summary = + prepareString("unlock_set_unlock_mode_password", "unlockModePassword"); + + when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC); + + assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary); + } + + @Test + public void getSummary_passwordQualityComplex_shouldUnlockModePassword() { + final String summary = + prepareString("unlock_set_unlock_mode_password", "unlockModePassword"); + + when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX); + + assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary); + } + + @Test + public void getSummary_passwordQualityManaged_shouldUnlockModePassword() { + final String summary = + prepareString("unlock_set_unlock_mode_password", "unlockModePassword"); + + when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_MANAGED); + + assertThat(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)).isEqualTo(summary); + } + + + @Test + public void getSummary_unsupportedPasswordQuality_shouldReturnNull() { + when(mLockPatternUtils.isSecure(USER_ID)).thenReturn(true); + when(mLockPatternUtils.getKeyguardStoredPasswordQuality(USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); + + assertNull(mScreenLockPreferenceDetailsUtils.getSummary(USER_ID)); + } + + @Test + public void isPasswordQualityManaged_withoutAdmin_shouldReturnFalse() { + final RestrictedLockUtils.EnforcedAdmin admin = null; + + assertThat(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(USER_ID, admin)) + .isFalse(); + } + + @Test + public void isPasswordQualityManaged_passwordQualityIsManaged_shouldReturnTrue() { + final RestrictedLockUtils.EnforcedAdmin admin = new RestrictedLockUtils.EnforcedAdmin(); + + when(mDevicePolicyManager.getPasswordQuality(admin.component, USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_MANAGED); + + assertThat(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(USER_ID, admin)) + .isTrue(); + } + + @Test + public void isPasswordQualityManaged_passwordQualityIsNotManaged_shouldReturnFalse() { + final RestrictedLockUtils.EnforcedAdmin admin = new RestrictedLockUtils.EnforcedAdmin(); + + when(mDevicePolicyManager.getPasswordQuality(admin.component, USER_ID)) + .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); + + assertThat(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(USER_ID, admin)) + .isFalse(); + } + + @Test + public void shouldShowGearMenu_patternIsSecure_shouldReturnTrue() { + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); + + assertThat(mScreenLockPreferenceDetailsUtils.shouldShowGearMenu()).isTrue(); + } + + @Test + public void shouldShowGearMenu_patternIsNotSecure_shouldReturnFalse() { + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(false); + + assertThat(mScreenLockPreferenceDetailsUtils.shouldShowGearMenu()).isFalse(); + } + + @Test + public void openScreenLockSettings_shouldSendIntent() { + mScreenLockPreferenceDetailsUtils.openScreenLockSettings(); + + assertFragmentLaunchRequested(ScreenLockSettings.class.getName()); + } + + @Test + public void openChooseLockGenericFragment_noQuietMode_shouldSendIntent_shouldReturnTrue() { + when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); + + assertThat(mScreenLockPreferenceDetailsUtils.openChooseLockGenericFragment()).isTrue(); + assertFragmentLaunchRequested(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()); + } + + private void whenConfigShowUnlockSetOrChangeIsEnabled(boolean enabled) { + final int resId = ResourcesUtils.getResourcesId( + ApplicationProvider.getApplicationContext(), "bool", + "config_show_unlock_set_or_change"); + when(mResources.getBoolean(resId)).thenReturn(enabled); + } + + private String prepareString(String stringResName, String string) { + final int stringResId = ResourcesUtils.getResourcesId( + ApplicationProvider.getApplicationContext(), "string", stringResName); + when(mResources.getString(stringResId)).thenReturn(string); + return string; + } + + private void assertFragmentLaunchRequested(String fragmentClassName) { + ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mContext).startActivity(intentCaptor.capture()); + + Intent intent = intentCaptor.getValue(); + assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) + .isEqualTo(fragmentClassName); + assertThat(intent.getIntExtra( + MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, -1 /* defaultValue */)) + .isEqualTo(SOURCE_METRICS_CATEGORY); + } +}