diff --git a/res/values/strings.xml b/res/values/strings.xml
index ac239f61c96..2f9652ec998 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1311,16 +1311,16 @@
Choose screen lock
-
+
Choose a screen lock
-
+
Choose a new screen lock
-
+
Choose a lock for work apps
-
+
Choose a new work lock
diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java
index eede22ac868..97cda4b5118 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java
@@ -298,9 +298,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
private void launchChooseLock() {
Log.d(TAG, "launchChooseLock");
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
+ intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
@@ -350,8 +348,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
final Intent intent;
// If only device credential was specified, ask the user to only set that up.
intent = new Intent(this, ChooseLockGeneric.class);
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
launchEnrollActivity(intent);
}
diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
index b44c2c9da1a..c34b2843706 100644
--- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
+++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java
@@ -222,9 +222,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase
private void launchChooseLock() {
Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent());
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
+ intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
intent.putExtra(getExtraKeyForBiometric(), true);
if (mUserId != UserHandle.USER_NULL) {
diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
index c449ff4bfce..b5f6ef328a6 100644
--- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
+++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
@@ -19,7 +19,6 @@ import static android.app.Activity.RESULT_OK;
import static com.android.settings.password.ChooseLockPattern.RESULT_FINISHED;
-import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.hardware.face.FaceManager;
@@ -193,9 +192,8 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
if (!launched) {
Intent intent = BiometricUtils.getChooseLockIntent(getActivity(), getIntent());
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
+ intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS,
+ true);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index a328f21e578..dbac4150380 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -685,9 +685,7 @@ public class FingerprintSettings extends SubSettings {
// TODO: This should be cleaned up. ChooseLockGeneric should provide a way of
// specifying arguments/requests, instead of relying on callers setting extras.
intent.setClassName(SETTINGS_PACKAGE_NAME, ChooseLockGeneric.class.getName());
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
- intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS,
+ intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS,
true);
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index 67fc7efc67c..a1826ba0cbc 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -75,8 +75,6 @@ import com.android.settings.biometrics.BiometricEnrollBase;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.search.SearchFeatureProvider;
-import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedPreference;
import com.google.android.setupcompat.util.WizardManagerHelper;
@@ -112,8 +110,7 @@ public class ChooseLockGeneric extends SettingsActivity {
private static final String KEY_SKIP_BIOMETRICS = "unlock_skip_biometrics";
private static final String PASSWORD_CONFIRMED = "password_confirmed";
private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
- public static final String MINIMUM_QUALITY_KEY = "minimum_quality";
- public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs";
+ public static final String HIDE_INSECURE_OPTIONS = "hide_insecure_options";
public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
public static final String KEY_LOCK_SETTINGS_FOOTER ="lock_settings_footer";
@@ -277,21 +274,20 @@ public class ChooseLockGeneric extends SettingsActivity {
arguments,
intent.getExtras()).getIdentifier();
mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mUserId);
- mController = new ChooseLockGenericController(
- getContext(), mUserId, mRequestedMinComplexity,
- mOnlyEnforceDevicePasswordRequirement,
- mLockPatternUtils);
-
- final int aggregatedComplexity = mController.getAggregatedPasswordComplexity();
- final boolean isComplexityProvidedByAdmin =
- aggregatedComplexity > mRequestedMinComplexity
- && aggregatedComplexity > PASSWORD_COMPLEXITY_NONE;
+ mController = new ChooseLockGenericController.Builder(
+ getContext(), mUserId, mLockPatternUtils)
+ .setAppRequestedMinComplexity(mRequestedMinComplexity)
+ .setEnforceDevicePasswordRequirementOnly(mOnlyEnforceDevicePasswordRequirement)
+ .setProfileToUnify(mUnificationProfileId)
+ .setHideInsecureScreenLockTypes(alwaysHideInsecureScreenLockTypes()
+ || intent.getBooleanExtra(HIDE_INSECURE_OPTIONS, false))
+ .build();
// If the complexity is provided by the admin, do not get the caller app's name.
// If the app requires, for example, low complexity, and the admin requires high
// complexity, it does not make sense to show a footer telling the user it's the app
// requesting a particular complexity because the admin-set complexity will override it.
- mCallerAppName = isComplexityProvidedByAdmin ? null :
+ mCallerAppName = mController.isComplexityProvidedByAdmin() ? null :
intent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME);
mManagedPasswordProvider = ManagedLockPasswordProvider.get(activity, mUserId);
@@ -330,6 +326,10 @@ public class ChooseLockGeneric extends SettingsActivity {
return super.onCreateView(inflater, container, savedInstanceState);
}
+ protected boolean alwaysHideInsecureScreenLockTypes() {
+ return false;
+ }
+
private void updateActivityTitle() {
if (mLockPatternUtils == null) {
// mLockPatternUtils will be uninitialized if ChooseLockGenericFragment.onCreate()
@@ -606,16 +606,12 @@ public class ChooseLockGeneric extends SettingsActivity {
}
if (quality == -1) {
// If caller didn't specify password quality, show UI and allow the user to choose.
- quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
- quality = mController.upgradeQuality(quality);
- final boolean hideDisabledPrefs = intent.getBooleanExtra(
- HIDE_DISABLED_PREFS, false);
final PreferenceScreen prefScreen = getPreferenceScreen();
if (prefScreen != null) {
prefScreen.removeAll();
}
addPreferences();
- disableUnusablePreferences(quality, hideDisabledPrefs);
+ disableUnusablePreferences();
updatePreferenceText();
updateCurrentPreference();
updatePreferenceSummaryIfNeeded();
@@ -746,71 +742,23 @@ public class ChooseLockGeneric extends SettingsActivity {
return lock != null ? lock.preferenceKey : null;
}
- /***
- * Disables preferences that are less secure than required quality. The actual
- * implementation is in disableUnusablePreferenceImpl.
- *
- * @param quality the requested quality.
- * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise
- * they're not shown at all.
- */
- protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) {
- disableUnusablePreferencesImpl(quality, hideDisabledPrefs);
- }
-
/***
* Disables preferences that are less secure than required quality.
*
- * @param quality the requested quality.
- * @param hideDisabled whether to hide disable screen lock options.
*/
- protected void disableUnusablePreferencesImpl(final int quality,
- boolean hideDisabled) {
+ private void disableUnusablePreferences() {
final PreferenceScreen entries = getPreferenceScreen();
- int adminEnforcedQuality = LockPatternUtils.credentialTypeToPasswordQuality(
- mLockPatternUtils.getRequestedPasswordMetrics(
- mUserId, mOnlyEnforceDevicePasswordRequirement).credType);
- EnforcedAdmin enforcedAdmin =
- RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet(getActivity(),
- mUserId);
- // If we are to unify a work challenge at the end of the credential enrollment, manually
- // merge any password policy from that profile here, so we are enrolling a compliant
- // password. This is because once unified, the profile's password policy will
- // be enforced on the new credential.
- if (mUnificationProfileId != UserHandle.USER_NULL) {
- int profileEnforceQuality = mDpm.getPasswordQuality(null, mUnificationProfileId);
- if (profileEnforceQuality > adminEnforcedQuality) {
- adminEnforcedQuality = profileEnforceQuality;
- enforcedAdmin = EnforcedAdmin.combine(enforcedAdmin,
- RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet(
- getActivity(), mUnificationProfileId));
- }
- }
-
for (ScreenLockType lock : ScreenLockType.values()) {
String key = lock.preferenceKey;
Preference pref = findPreference(key);
if (pref instanceof RestrictedPreference) {
boolean visible = mController.isScreenLockVisible(lock);
- boolean enabled = mController.isScreenLockEnabled(lock, quality);
- boolean disabledByAdmin =
- mController.isScreenLockDisabledByAdmin(lock, adminEnforcedQuality);
- if (hideDisabled) {
- visible = visible && enabled;
- }
+ boolean enabled = mController.isScreenLockEnabled(lock);
if (!visible) {
entries.removePreference(pref);
- } else if (disabledByAdmin && enforcedAdmin != null) {
- ((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin);
} else if (!enabled) {
- // we need to setDisabledByAdmin to null first to disable the padlock
- // in case it was set earlier.
- ((RestrictedPreference) pref).setDisabledByAdmin(null);
- pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
pref.setEnabled(false);
- } else {
- ((RestrictedPreference) pref).setDisabledByAdmin(null);
}
}
}
diff --git a/src/com/android/settings/password/ChooseLockGenericController.java b/src/com/android/settings/password/ChooseLockGenericController.java
index 6900e3d0f60..1b951d4f968 100644
--- a/src/com/android/settings/password/ChooseLockGenericController.java
+++ b/src/com/android/settings/password/ChooseLockGenericController.java
@@ -17,6 +17,7 @@
package com.android.settings.password;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
@@ -24,6 +25,7 @@ import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.PasswordMetrics;
import android.content.Context;
import android.os.UserHandle;
+import android.os.UserManager;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -36,84 +38,140 @@ import java.util.List;
/**
* A controller for ChooseLockGeneric, and other similar classes which shows a list of possible
- * screen locks for the user to choose from.
+ * screen lock types for the user to choose from. This is the main place where different
+ * restrictions on allowed screen lock types are aggregated in Settings.
+ *
+ * Each screen lock type has two states: whether it is visible and whether it is enabled.
+ * Visibility is affected by things like resource configs, whether it's for a managed profile,
+ * or whether the caller allows it or not. This is determined by
+ * {@link #isScreenLockVisible(ScreenLockType)}. For visible screen lock types, they can be disabled
+ * by a combination of admin policies and request from the calling app, which is determined by
+ * {@link #isScreenLockEnabled(ScreenLockType}.
*/
+
public class ChooseLockGenericController {
private final Context mContext;
private final int mUserId;
- @PasswordComplexity private final int mRequestedMinComplexity;
+ private final boolean mHideInsecureScreenLockTypes;
+ @PasswordComplexity private final int mAppRequestedMinComplexity;
private final boolean mDevicePasswordRequirementOnly;
- private ManagedLockPasswordProvider mManagedPasswordProvider;
+ private final int mUnificationProfileId;
+ private final ManagedLockPasswordProvider mManagedPasswordProvider;
private final LockPatternUtils mLockPatternUtils;
- public ChooseLockGenericController(Context context, int userId) {
- this(
- context,
- userId,
- PASSWORD_COMPLEXITY_NONE,
- /* mOnlyEnforceDevicePasswordRequirement */ false,
- new LockPatternUtils(context));
- }
-
- /**
- * @param requestedMinComplexity specifies the min password complexity to be taken into account
- * when determining the available screen lock types
- */
public ChooseLockGenericController(Context context, int userId,
- @PasswordComplexity int requestedMinComplexity,
- boolean devicePasswordRequirementOnly,
- LockPatternUtils lockPatternUtils) {
- this(
- context,
- userId,
- requestedMinComplexity,
- devicePasswordRequirementOnly,
- ManagedLockPasswordProvider.get(context, userId),
- lockPatternUtils);
- }
-
- @VisibleForTesting
- ChooseLockGenericController(
- Context context,
- int userId,
- @PasswordComplexity int requestedMinComplexity,
- boolean devicePasswordRequirementOnly,
- ManagedLockPasswordProvider managedLockPasswordProvider,
- LockPatternUtils lockPatternUtils) {
+ ManagedLockPasswordProvider managedPasswordProvider, LockPatternUtils lockPatternUtils,
+ boolean hideInsecureScreenLockTypes, int appRequestedMinComplexity,
+ boolean devicePasswordRequirementOnly, int unificationProfileId) {
mContext = context;
mUserId = userId;
- mRequestedMinComplexity = requestedMinComplexity;
- mDevicePasswordRequirementOnly = devicePasswordRequirementOnly;
- mManagedPasswordProvider = managedLockPasswordProvider;
+ mManagedPasswordProvider = managedPasswordProvider;
mLockPatternUtils = lockPatternUtils;
+ mHideInsecureScreenLockTypes = hideInsecureScreenLockTypes;
+ mAppRequestedMinComplexity = appRequestedMinComplexity;
+ mDevicePasswordRequirementOnly = devicePasswordRequirementOnly;
+ mUnificationProfileId = unificationProfileId;
+ }
+
+ /** Builder class for {@link ChooseLockGenericController} */
+ public static class Builder {
+ private final Context mContext;
+ private final int mUserId;
+ private final ManagedLockPasswordProvider mManagedPasswordProvider;
+ private final LockPatternUtils mLockPatternUtils;
+
+ private boolean mHideInsecureScreenLockTypes = false;
+ @PasswordComplexity private int mAppRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE;
+ private boolean mDevicePasswordRequirementOnly = false;
+ private int mUnificationProfileId = UserHandle.USER_NULL;
+
+ public Builder(Context context, int userId) {
+ this(context, userId, new LockPatternUtils(context));
+ }
+
+ public Builder(Context context, int userId,
+ LockPatternUtils lockPatternUtils) {
+ this(
+ context,
+ userId,
+ ManagedLockPasswordProvider.get(context, userId),
+ lockPatternUtils);
+ }
+
+ @VisibleForTesting
+ Builder(
+ Context context,
+ int userId,
+ ManagedLockPasswordProvider managedLockPasswordProvider,
+ LockPatternUtils lockPatternUtils) {
+ mContext = context;
+ mUserId = userId;
+ mManagedPasswordProvider = managedLockPasswordProvider;
+ mLockPatternUtils = lockPatternUtils;
+ }
+ /**
+ * Sets the password complexity requested by the calling app via
+ * {@link android.app.admin.DevicePolicyManager#EXTRA_PASSWORD_COMPLEXITY}.
+ */
+ public Builder setAppRequestedMinComplexity(int complexity) {
+ mAppRequestedMinComplexity = complexity;
+ return this;
+ }
+
+ /**
+ * Sets whether the enrolment flow should discard any password policies originating from the
+ * work profile, even if the work profile currently has unified challenge. This can be
+ * requested by the calling app via
+ * {@link android.app.admin.DevicePolicyManager#EXTRA_DEVICE_PASSWORD_REQUIREMENT_ONLY}.
+ */
+ public Builder setEnforceDevicePasswordRequirementOnly(boolean deviceOnly) {
+ mDevicePasswordRequirementOnly = deviceOnly;
+ return this;
+ }
+
+ /**
+ * Sets the user ID of any profile whose work challenge should be unified at the end of this
+ * enrolment flow. This will lead to all password policies from that profile to be taken
+ * into consideration by this class, so that we are enrolling a compliant password. This is
+ * because once unified, the profile's password policy will be enforced on the new
+ * credential.
+ */
+ public Builder setProfileToUnify(int profileId) {
+ mUnificationProfileId = profileId;
+ return this;
+ }
+
+ /**
+ * Sets whether insecure screen lock types (NONE and SWIPE) should be hidden in the UI.
+ */
+ public Builder setHideInsecureScreenLockTypes(boolean hide) {
+ mHideInsecureScreenLockTypes = hide;
+ return this;
+ }
+
+ /** Creates {@link ChooseLockGenericController} instance. */
+ public ChooseLockGenericController build() {
+ return new ChooseLockGenericController(mContext, mUserId, mManagedPasswordProvider,
+ mLockPatternUtils, mHideInsecureScreenLockTypes, mAppRequestedMinComplexity,
+ mDevicePasswordRequirementOnly, mUnificationProfileId);
+ }
}
/**
- * Returns the highest quality among the specified {@code quality}, the password requirement
- * set by device admins (legacy password quality metrics and password complexity), and the
- * min password complexity requested by the calling app.
- */
- public int upgradeQuality(int quality) {
- // Compare specified quality and dpm quality
- // TODO(b/142781408): convert from quality to credential type once PIN is supported.
- int dpmUpgradedQuality = Math.max(quality, LockPatternUtils.credentialTypeToPasswordQuality(
- getAggregatedPasswordMetrics().credType));
- return Math.max(dpmUpgradedQuality,
- PasswordMetrics.complexityLevelToMinQuality(getAggregatedPasswordComplexity()));
- }
-
- /**
- * Whether the given screen lock type should be visible in the given context.
+ * Returns whether the given screen lock type should be visible in the given context.
*/
public boolean isScreenLockVisible(ScreenLockType type) {
- final boolean managedProfile = mUserId != UserHandle.myUserId();
+ final boolean managedProfile = mContext.getSystemService(UserManager.class)
+ .isManagedProfile(mUserId);
switch (type) {
case NONE:
- return !mContext.getResources().getBoolean(R.bool.config_hide_none_security_option)
+ return !mHideInsecureScreenLockTypes
+ && !mContext.getResources().getBoolean(R.bool.config_hide_none_security_option)
&& !managedProfile; // Profiles should use unified challenge instead.
case SWIPE:
- return !mContext.getResources().getBoolean(R.bool.config_hide_swipe_security_option)
+ return !mHideInsecureScreenLockTypes
+ && !mContext.getResources().getBoolean(R.bool.config_hide_swipe_security_option)
&& !managedProfile; // Swipe doesn't make sense for profiles.
case MANAGED:
return mManagedPasswordProvider.isManagedPasswordChoosable();
@@ -128,29 +186,27 @@ public class ChooseLockGenericController {
}
/**
- * Whether screen lock with {@code type} should be enabled.
- *
- * @param type The screen lock type.
- * @param quality The minimum required quality. This can either be requirement by device policy
- * manager or because some flow only makes sense with secure lock screens.
+ * Whether screen lock with {@code type} should be enabled assuming all relevant password
+ * requirements. The lock's visibility ({@link #isScreenLockVisible}) is not considered here.
*/
- public boolean isScreenLockEnabled(ScreenLockType type, int quality) {
- return type.maxQuality >= quality;
+ public boolean isScreenLockEnabled(ScreenLockType type) {
+ return type.maxQuality >= upgradeQuality(PASSWORD_QUALITY_UNSPECIFIED);
}
/**
- * Whether screen lock with {@code type} is disabled by device policy admin.
- *
- * @param type The screen lock type.
- * @param adminEnforcedQuality The minimum quality that the admin enforces.
+ * Increases the given quality to be as high as the combined quality from all relevant
+ * password requirements.
*/
- public boolean isScreenLockDisabledByAdmin(ScreenLockType type, int adminEnforcedQuality) {
- boolean disabledByAdmin = type.maxQuality < adminEnforcedQuality;
- if (type == ScreenLockType.MANAGED) {
- disabledByAdmin = disabledByAdmin
- || !mManagedPasswordProvider.isManagedPasswordChoosable();
- }
- return disabledByAdmin;
+ // TODO(b/142781408): convert from quality to credential type once PIN is supported.
+ public int upgradeQuality(int quality) {
+ return Math.max(quality,
+ Math.max(
+ LockPatternUtils.credentialTypeToPasswordQuality(
+ getAggregatedPasswordMetrics().credType),
+ PasswordMetrics.complexityLevelToMinQuality(
+ getAggregatedPasswordComplexity())
+ )
+ );
}
/**
@@ -175,43 +231,72 @@ public class ChooseLockGenericController {
}
/**
- * Gets a list of screen locks that should be visible for the given quality. The returned list
- * is ordered in the natural order of the enum (the order those enums were defined).
- *
- * @param quality The minimum quality required in the context of the current flow. This should
- * be one of the constants defined in
- * {@code DevicePolicyManager#PASSWORD_QUALITY_*}.
- * @param includeDisabled Whether to include screen locks disabled by {@code quality}
- * requirements in the returned list.
+ * Gets a list of screen lock types that should be visible for the given quality. The returned
+ * list is ordered in the natural order of the enum (the order those enums were defined). Screen
+ * locks disabled by password policy will not be returned.
*/
@NonNull
- public List getVisibleScreenLockTypes(int quality, boolean includeDisabled) {
- int upgradedQuality = upgradeQuality(quality);
+ public List getVisibleAndEnabledScreenLockTypes() {
List locks = new ArrayList<>();
// EnumSet's iterator guarantees the natural order of the enums
for (ScreenLockType lock : ScreenLockType.values()) {
- if (isScreenLockVisible(lock)) {
- if (includeDisabled || isScreenLockEnabled(lock, upgradedQuality)) {
- locks.add(lock);
- }
+ if (isScreenLockVisible(lock) && isScreenLockEnabled(lock)) {
+ locks.add(lock);
}
}
return locks;
}
+ /**
+ * Returns the combined password metrics from all relevant policies which affects the current
+ * user. Normally password policies set on the current user's work profile instance will be
+ * taken into consideration here iff the work profile doesn't have its own work challenge.
+ * By setting {@link #mUnificationProfileId}, the work profile's password policy will always
+ * be combined here. Alternatively, by setting {@link #mDevicePasswordRequirementOnly}, its
+ * password policy will always be disregarded here.
+ */
public PasswordMetrics getAggregatedPasswordMetrics() {
- return mLockPatternUtils.getRequestedPasswordMetrics(mUserId,
+ PasswordMetrics metrics = mLockPatternUtils.getRequestedPasswordMetrics(mUserId,
mDevicePasswordRequirementOnly);
+ if (mUnificationProfileId != UserHandle.USER_NULL) {
+ metrics.maxWith(mLockPatternUtils.getRequestedPasswordMetrics(mUnificationProfileId));
+ }
+ return metrics;
}
+ /**
+ * Returns the combined password complexity from all relevant policies which affects the current
+ * user. The same logic of handling work profile password policies as
+ * {@link #getAggregatedPasswordMetrics} applies here.
+ */
public int getAggregatedPasswordComplexity() {
- return Math.max(mRequestedMinComplexity,
+ int complexity = Math.max(mAppRequestedMinComplexity,
mLockPatternUtils.getRequestedPasswordComplexity(
mUserId, mDevicePasswordRequirementOnly));
+ if (mUnificationProfileId != UserHandle.USER_NULL) {
+ complexity = Math.max(complexity,
+ mLockPatternUtils.getRequestedPasswordComplexity(mUnificationProfileId));
+ }
+ return complexity;
}
+ /**
+ * Returns whether any screen lock type has been disabled only due to password policy
+ * from the admin. Will return {@code false} if the restriction is purely due to calling
+ * app's request.
+ */
public boolean isScreenLockRestrictedByAdmin() {
return getAggregatedPasswordMetrics().credType != CREDENTIAL_TYPE_NONE
- || getAggregatedPasswordComplexity() != PASSWORD_COMPLEXITY_NONE;
+ || isComplexityProvidedByAdmin();
+ }
+
+ /**
+ * Returns whether the aggregated password complexity is non-zero and comes from
+ * admin policy.
+ */
+ public boolean isComplexityProvidedByAdmin() {
+ final int aggregatedComplexity = getAggregatedPasswordComplexity();
+ return aggregatedComplexity > mAppRequestedMinComplexity
+ && aggregatedComplexity > PASSWORD_COMPLEXITY_NONE;
}
}
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index de377a73d67..6382abf9dbf 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -416,19 +416,6 @@ public class ChooseLockPassword extends SettingsActivity {
mMinComplexity = intent.getIntExtra(EXTRA_KEY_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
mMinMetrics = intent.getParcelableExtra(EXTRA_KEY_MIN_METRICS);
if (mMinMetrics == null) mMinMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
- // If we are to unify a work challenge at the end of the credential enrollment, manually
- // merge any password policy from that profile here, so we are enrolling a compliant
- // password. This is because once unified, the profile's password policy will
- // be enforced on the new credential.
- //TODO: Move this logic to ChooseLockGeneric; let ChooseLockGeneric be the only place
- //where password requirement mixing happens. ChooseLockPassword simply enforces what's
- //set via IntentBuilder.setPasswordRequirement()
- if (mUnificationProfileId != UserHandle.USER_NULL) {
- mMinMetrics.maxWith(
- mLockPatternUtils.getRequestedPasswordMetrics(mUnificationProfileId));
- mMinComplexity = Math.max(mMinComplexity,
- mLockPatternUtils.getRequestedPasswordComplexity(mUnificationProfileId));
- }
if (intent.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, false)) {
diff --git a/src/com/android/settings/password/ChooseLockTypeDialogFragment.java b/src/com/android/settings/password/ChooseLockTypeDialogFragment.java
index 8bc29763e2c..6ec70574b11 100644
--- a/src/com/android/settings/password/ChooseLockTypeDialogFragment.java
+++ b/src/com/android/settings/password/ChooseLockTypeDialogFragment.java
@@ -18,7 +18,6 @@ package com.android.settings.password;
import android.app.Activity;
import android.app.Dialog;
-import android.app.admin.DevicePolicyManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
@@ -100,7 +99,9 @@ public class ChooseLockTypeDialogFragment extends InstrumentedDialogFragment
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final int userId = getArguments().getInt(ARG_USER_ID);
- mController = new ChooseLockGenericController(getContext(), userId);
+ mController = new ChooseLockGenericController.Builder(getContext(), userId)
+ .setHideInsecureScreenLockTypes(true)
+ .build();
}
@Override
@@ -124,10 +125,7 @@ public class ChooseLockTypeDialogFragment extends InstrumentedDialogFragment
public Dialog onCreateDialog(Bundle savedInstanceState) {
Context context = getContext();
Builder builder = new Builder(context);
- List locks =
- mController.getVisibleScreenLockTypes(
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
- false /* includeDisabled */);
+ List locks = mController.getVisibleAndEnabledScreenLockTypes();
mAdapter = new ScreenLockAdapter(context, locks, mController);
builder.setAdapter(mAdapter, this);
builder.setTitle(R.string.setup_lock_settings_options_dialog_title);
diff --git a/src/com/android/settings/password/SetNewPasswordController.java b/src/com/android/settings/password/SetNewPasswordController.java
index 03efa605d53..ef4ff75497c 100644
--- a/src/com/android/settings/password/SetNewPasswordController.java
+++ b/src/com/android/settings/password/SetNewPasswordController.java
@@ -19,7 +19,6 @@ package com.android.settings.password;
import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FACE;
import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
-import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -145,10 +144,8 @@ final class SetNewPasswordController {
private Bundle getBiometricChooseLockExtras() {
Bundle chooseLockExtras = new Bundle();
- chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- PASSWORD_QUALITY_SOMETHING);
chooseLockExtras.putBoolean(
- ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
+ ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true);
return chooseLockExtras;
@@ -156,10 +153,8 @@ final class SetNewPasswordController {
private Bundle getFingerprintChooseLockExtras() {
Bundle chooseLockExtras = new Bundle();
- chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- PASSWORD_QUALITY_SOMETHING);
chooseLockExtras.putBoolean(
- ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
+ ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
return chooseLockExtras;
@@ -167,10 +162,8 @@ final class SetNewPasswordController {
private Bundle getFaceChooseLockExtras() {
Bundle chooseLockExtras = new Bundle();
- chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- PASSWORD_QUALITY_SOMETHING);
chooseLockExtras.putBoolean(
- ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
+ ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true);
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, true);
return chooseLockExtras;
diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java
index 7818f0d2fc9..15a90e3fdbf 100644
--- a/src/com/android/settings/password/SetupChooseLockGeneric.java
+++ b/src/com/android/settings/password/SetupChooseLockGeneric.java
@@ -21,7 +21,6 @@ import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
-import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -160,22 +159,12 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric {
return SetupChooseLockGeneric.InternalActivity.class;
}
- /***
- * Disables preferences that are less secure than required quality and shows only secure
- * screen lock options here.
- *
- * @param quality the requested quality.
- */
@Override
- protected void disableUnusablePreferences(final int quality, boolean hideDisabled) {
+ protected boolean alwaysHideInsecureScreenLockTypes() {
// At this part of the flow, the user has already indicated they want to add a pin,
- // pattern or password, so don't show "None" or "Slide". We disable them here and set
- // the HIDE_DISABLED flag to true to hide them. This only happens for setup wizard.
- // We do the following max check here since the device may already have a Device Admin
- // installed with a policy we need to honor.
- final int newQuality = Math.max(quality,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
- super.disableUnusablePreferencesImpl(newQuality, true /* hideDisabled */);
+ // pattern or password, so don't show "None" or "Slide". We disable them here.
+ // This only happens for setup wizard.
+ return true;
}
@Override
diff --git a/src/com/android/settings/password/SetupChooseLockPassword.java b/src/com/android/settings/password/SetupChooseLockPassword.java
index 25f5a348904..7cf90c09929 100644
--- a/src/com/android/settings/password/SetupChooseLockPassword.java
+++ b/src/com/android/settings/password/SetupChooseLockPassword.java
@@ -17,7 +17,6 @@
package com.android.settings.password;
import android.app.Activity;
-import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -81,9 +80,11 @@ public class SetupChooseLockPassword extends ChooseLockPassword {
super.onViewCreated(view, savedInstanceState);
final Activity activity = getActivity();
ChooseLockGenericController chooseLockGenericController =
- new ChooseLockGenericController(activity, mUserId);
- boolean anyOptionsShown = chooseLockGenericController.getVisibleScreenLockTypes(
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false).size() > 0;
+ new ChooseLockGenericController.Builder(activity, mUserId)
+ .setHideInsecureScreenLockTypes(true)
+ .build();
+ boolean anyOptionsShown = chooseLockGenericController
+ .getVisibleAndEnabledScreenLockTypes().size() > 0;
boolean showOptionsButton = activity.getIntent().getBooleanExtra(
ChooseLockGeneric.ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, false);
if (!anyOptionsShown) {
diff --git a/src/com/android/settings/security/ScreenPinningSettings.java b/src/com/android/settings/security/ScreenPinningSettings.java
index 3fa098b826a..e219b44084d 100644
--- a/src/com/android/settings/security/ScreenPinningSettings.java
+++ b/src/com/android/settings/security/ScreenPinningSettings.java
@@ -136,8 +136,8 @@ public class ScreenPinningSettings extends SettingsPreferenceFragment
if (passwordQuality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
chooseLockIntent.putExtra(
- ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS,
+ true);
startActivityForResult(chooseLockIntent, CHANGE_LOCK_METHOD_REQUEST);
return false;
}
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index d88d8b5c316..5f14399a26b 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -432,8 +432,8 @@ public class UserSettings extends SettingsPreferenceFragment
private void launchChooseLockscreen() {
Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
- chooseLockIntent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ chooseLockIntent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS,
+ true);
startActivityForResult(chooseLockIntent, REQUEST_CHOOSE_LOCK);
}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
index 02b89cba845..049a34969c1 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java
@@ -20,23 +20,31 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
import static org.robolectric.RuntimeEnvironment.application;
import android.app.admin.DevicePolicyManager;
-import android.app.admin.DevicePolicyManager.PasswordComplexity;
import android.app.admin.PasswordPolicy;
+import android.os.UserHandle;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.R;
import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.testutils.shadow.ShadowUserManager;
import org.junit.After;
import org.junit.Before;
@@ -48,10 +56,11 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.Arrays;
+import java.util.Set;
import java.util.regex.Pattern;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = SettingsShadowResources.class)
+@Config(shadows = {ShadowUserManager.class, SettingsShadowResources.class})
public class ChooseLockGenericControllerTest {
private ChooseLockGenericController mController;
@@ -68,7 +77,7 @@ public class ChooseLockGenericControllerTest {
when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(true);
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
- mController = createController(PASSWORD_COMPLEXITY_NONE);
+ mController = createBuilder().build();
SettingsShadowResources.overrideResource(R.bool.config_hide_none_security_option, false);
SettingsShadowResources.overrideResource(R.bool.config_hide_swipe_security_option, false);
}
@@ -95,8 +104,8 @@ public class ChooseLockGenericControllerTest {
}
@Test
- public void isScreenLockVisible_notCurrentUser_shouldHideInsecure() {
- mController = new ChooseLockGenericController(application, 1 /* userId */);
+ public void isScreenLockVisible_ManagedProfile_shouldHideInsecure() {
+ ShadowUserManager.getShadow().setManagedProfiles(Set.of(0));
assertWithMessage("SWIPE visible").that(
mController.isScreenLockVisible(ScreenLockType.SWIPE)).isFalse();
assertWithMessage("NONE visible").that(mController.isScreenLockVisible(ScreenLockType.NONE))
@@ -112,62 +121,116 @@ public class ChooseLockGenericControllerTest {
}
@Test
- public void isScreenLockEnabled_lowerQuality_shouldReturnFalse() {
- for (ScreenLockType lock : ScreenLockType.values()) {
- assertWithMessage(lock + " enabled").that(
- mController.isScreenLockEnabled(lock, lock.maxQuality + 1)).isFalse();
- }
+ public void isScreenLockEnabled_Default() {
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
}
@Test
- public void isScreenLockEnabled_equalQuality_shouldReturnTrue() {
- for (ScreenLockType lock : ScreenLockType.values()) {
- assertWithMessage(lock + " enabled").that(
- mController.isScreenLockEnabled(lock, lock.defaultQuality)).isTrue();
- }
+ public void isScreenLockEnabled_QualityUnspecified() {
+ setDevicePolicyPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
}
@Test
- public void isScreenLockEnabled_higherQuality_shouldReturnTrue() {
- for (ScreenLockType lock : ScreenLockType.values()) {
- assertWithMessage(lock + " enabled").that(
- mController.isScreenLockEnabled(lock, lock.maxQuality - 1)).isTrue();
- }
+ public void isScreenLockEnabled_QualitySomething() {
+ setDevicePolicyPasswordQuality(PASSWORD_QUALITY_SOMETHING);
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
}
@Test
- public void isScreenLockDisabledByAdmin_lowerQuality_shouldReturnTrue() {
- doReturn(true).when(mManagedLockPasswordProvider).isManagedPasswordChoosable();
- for (ScreenLockType lock : ScreenLockType.values()) {
- assertWithMessage(lock + " disabledByAdmin").that(
- mController.isScreenLockDisabledByAdmin(lock, lock.maxQuality + 1)).isTrue();
- }
+ public void isScreenLockEnabled_QualityNumeric() {
+ setDevicePolicyPasswordQuality(PASSWORD_QUALITY_NUMERIC);
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
}
@Test
- public void isScreenLockDisabledByAdmin_equalQuality_shouldReturnFalse() {
- doReturn(true).when(mManagedLockPasswordProvider).isManagedPasswordChoosable();
- for (ScreenLockType lock : ScreenLockType.values()) {
- assertWithMessage(lock + " disabledByAdmin").that(
- mController.isScreenLockDisabledByAdmin(lock, lock.maxQuality)).isFalse();
- }
+ public void isScreenLockEnabled_QualityNumericComplex() {
+ setDevicePolicyPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX);
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
}
@Test
- public void isScreenLockDisabledByAdmin_higherQuality_shouldReturnFalse() {
- doReturn(true).when(mManagedLockPasswordProvider).isManagedPasswordChoosable();
- for (ScreenLockType lock : ScreenLockType.values()) {
- assertWithMessage(lock + " disabledByAdmin").that(
- mController.isScreenLockDisabledByAdmin(lock, lock.maxQuality - 1)).isFalse();
- }
+ public void isScreenLockEnabled_QualityAlphabetic() {
+ setDevicePolicyPasswordQuality(PASSWORD_QUALITY_ALPHABETIC);
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
}
@Test
- public void isScreenLockDisabledByAdmin_managedNotChoosable_shouldReturnTrue() {
- doReturn(false).when(mManagedLockPasswordProvider).isManagedPasswordChoosable();
- assertWithMessage("MANANGED disabledByAdmin").that(mController.isScreenLockDisabledByAdmin(
- ScreenLockType.MANAGED, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
- .isTrue();
+ public void isScreenLockEnabled_QualityComplex() {
+ setDevicePolicyPasswordQuality(PASSWORD_QUALITY_COMPLEX);
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
+ }
+
+ @Test
+ public void isScreenLockEnabled_NoneComplexity() {
+ when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean()))
+ .thenReturn(PASSWORD_COMPLEXITY_NONE);
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
+ }
+
+ @Test
+ public void isScreenLockEnabled_lowComplexity() {
+ when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean()))
+ .thenReturn(PASSWORD_COMPLEXITY_LOW);
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
+ }
+
+ @Test
+ public void isScreenLockEnabled_mediumComplexity() {
+ when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean()))
+ .thenReturn(PASSWORD_COMPLEXITY_MEDIUM);
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
+ }
+
+ @Test
+ public void isScreenLockEnabled_highComplexity() {
+ when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean()))
+ .thenReturn(PASSWORD_COMPLEXITY_HIGH);
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue();
+ assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue();
}
@Test
@@ -181,8 +244,8 @@ public class ChooseLockGenericControllerTest {
@Test
public void getVisibleScreenLockTypes_qualitySomething_shouldReturnPatterPinPassword() {
- assertThat(mController.getVisibleScreenLockTypes(
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false))
+ mController = createBuilder().setHideInsecureScreenLockTypes(true).build();
+ assertThat(mController.getVisibleAndEnabledScreenLockTypes())
.isEqualTo(Arrays.asList(
ScreenLockType.PATTERN,
ScreenLockType.PIN,
@@ -191,8 +254,7 @@ public class ChooseLockGenericControllerTest {
@Test
public void getVisibleScreenLockTypes_showDisabled_shouldReturnAllButManaged() {
- assertThat(mController.getVisibleScreenLockTypes(
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, true))
+ assertThat(mController.getVisibleAndEnabledScreenLockTypes())
.isEqualTo(Arrays.asList(
ScreenLockType.NONE,
ScreenLockType.SWIPE,
@@ -223,31 +285,68 @@ public class ChooseLockGenericControllerTest {
@Test
public void upgradeQuality_complexityHigh_minQualityNumericComplex() {
+ mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_HIGH)
+ .build();
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
- ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_HIGH);
- assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
+ assertThat(mController.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
}
@Test
public void upgradeQuality_complexityMedium_minQualityNumericComplex() {
+ mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_MEDIUM)
+ .build();
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
- ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_MEDIUM);
- assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
+ assertThat(mController.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
}
@Test
public void upgradeQuality_complexityLow_minQualitySomething() {
+ mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_LOW)
+ .build();
setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
- ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_LOW);
- assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
+ assertThat(mController.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED))
.isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
}
+ @Test
+ public void getAggregatedPasswordComplexity_AppRequest() {
+ mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_HIGH)
+ .build();
+ assertThat(mController.getAggregatedPasswordComplexity())
+ .isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+ }
+
+ @Test
+ public void getAggregatedPasswordComplexity_DevicePolicy() {
+ mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_LOW)
+ .build();
+ when(mLockPatternUtils.getRequestedPasswordComplexity(eq(UserHandle.myUserId()), eq(false)))
+ .thenReturn(PASSWORD_COMPLEXITY_MEDIUM);
+
+ assertThat(mController.getAggregatedPasswordComplexity())
+ .isEqualTo(PASSWORD_COMPLEXITY_MEDIUM);
+ }
+
+ @Test
+ public void getAggregatedPasswordComplexity_ProfileUnification() {
+ mController = createBuilder()
+ .setProfileToUnify(123)
+ .setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_LOW)
+ .build();
+ when(mLockPatternUtils.getRequestedPasswordComplexity(eq(UserHandle.myUserId()), eq(false)))
+ .thenReturn(PASSWORD_COMPLEXITY_MEDIUM);
+ when(mLockPatternUtils.getRequestedPasswordComplexity(eq(123)))
+ .thenReturn(PASSWORD_COMPLEXITY_HIGH);
+
+ assertThat(mController.getAggregatedPasswordComplexity())
+ .isEqualTo(PASSWORD_COMPLEXITY_HIGH);
+ }
+
private void setDevicePolicyPasswordQuality(int quality) {
PasswordPolicy policy = new PasswordPolicy();
policy.quality = quality;
@@ -256,13 +355,10 @@ public class ChooseLockGenericControllerTest {
.thenReturn(policy.getMinMetrics());
}
- private ChooseLockGenericController createController(
- @PasswordComplexity int minPasswordComplexity) {
- return new ChooseLockGenericController(
+ private ChooseLockGenericController.Builder createBuilder() {
+ return new ChooseLockGenericController.Builder(
application,
0 /* userId */,
- minPasswordComplexity,
- false,
mManagedLockPasswordProvider,
mLockPatternUtils);
}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
index 2233f1d1d00..7da9c505b8e 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
@@ -30,7 +30,6 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
import static com.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY;
import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS;
-import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -429,18 +428,6 @@ public class ChooseLockPasswordTest {
"PIN must be at least 8 digits");
}
- @Test
- public void validateComplexityMergedFromUnificationUserOnCreate() {
- ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
- ShadowLockPatternUtils.setRequiredPasswordComplexity(123, PASSWORD_COMPLEXITY_HIGH);
-
- Intent intent = createIntentForPasswordValidation(null, PASSWORD_COMPLEXITY_NONE,
- PASSWORD_QUALITY_NUMERIC);
- intent.putExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID, 123);
- assertPasswordValidationResultForIntent(LockscreenCredential.createNone(), intent,
- "PIN must be at least 8 digits");
- }
-
private ChooseLockPassword buildChooseLockPasswordActivity(Intent intent) {
return Robolectric.buildActivity(ChooseLockPassword.class, intent).setup().get();
}
diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java
index 3034807baa6..f7b8d2d3f1b 100644
--- a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java
@@ -19,8 +19,7 @@ package com.android.settings.password;
import static android.content.pm.PackageManager.FEATURE_FACE;
import static android.content.pm.PackageManager.FEATURE_FINGERPRINT;
-import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS;
-import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY;
+import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE;
@@ -262,12 +261,9 @@ public final class SetNewPasswordControllerTest {
private void compareFingerprintExtras(Bundle actualBundle) {
assertEquals(
- "Password quality must be something in order to config fingerprint.",
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
- actualBundle.getInt(MINIMUM_QUALITY_KEY));
- assertTrue(
- "All disabled preference should be removed.",
- actualBundle.getBoolean(HIDE_DISABLED_PREFS));
+ "Insecure options must be disabled in order to config fingerprint.",
+ true,
+ actualBundle.getBoolean(HIDE_INSECURE_OPTIONS));
assertTrue(
"Fingerprint enroll must request Gatekeeper Password.",
actualBundle.getBoolean(EXTRA_KEY_REQUEST_GK_PW_HANDLE));
@@ -282,12 +278,9 @@ public final class SetNewPasswordControllerTest {
private void compareFaceExtras(Bundle actualBundle) {
assertEquals(
- "Password quality must be something in order to config face.",
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
- actualBundle.getInt(MINIMUM_QUALITY_KEY));
- assertTrue(
- "All disabled preference should be removed.",
- actualBundle.getBoolean(HIDE_DISABLED_PREFS));
+ "Insecure options must be disabled in order to config face.",
+ true,
+ actualBundle.getBoolean(HIDE_INSECURE_OPTIONS));
assertTrue(
"Face enroll must request Gatekeeper Password",
actualBundle.getBoolean(EXTRA_KEY_REQUEST_GK_PW_HANDLE));
diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
index 5242e11a6e7..af4ae0b8a30 100644
--- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java
@@ -198,8 +198,7 @@ public class SetupChooseLockPasswordTest {
@Implements(ChooseLockGenericController.class)
public static class ShadowChooseLockGenericController {
@Implementation
- protected List getVisibleScreenLockTypes(int quality,
- boolean includeDisabled) {
+ protected List getVisibleScreenLockTypes() {
return Collections.emptyList();
}
}