mValidationErrors;
+
+ @PasswordComplexity private int mMinComplexity = PASSWORD_COMPLEXITY_NONE;
protected int mUserId;
private byte[] mPasswordHistoryHashFactor;
@@ -228,28 +231,6 @@ public class ChooseLockPassword extends SettingsActivity {
private static final int CONFIRM_EXISTING_REQUEST = 58;
static final int RESULT_FINISHED = RESULT_FIRST_USER;
- private static final int MIN_LETTER_IN_PASSWORD = 0;
- private static final int MIN_UPPER_LETTERS_IN_PASSWORD = 1;
- private static final int MIN_LOWER_LETTERS_IN_PASSWORD = 2;
- private static final int MIN_SYMBOLS_IN_PASSWORD = 3;
- private static final int MIN_NUMBER_IN_PASSWORD = 4;
- private static final int MIN_NON_LETTER_IN_PASSWORD = 5;
-
- // Error code returned from {@link #validatePassword(byte[])}.
- static final int NO_ERROR = 0;
- static final int CONTAIN_INVALID_CHARACTERS = 1 << 0;
- static final int TOO_SHORT = 1 << 1;
- static final int TOO_LONG = 1 << 2;
- static final int CONTAIN_NON_DIGITS = 1 << 3;
- static final int CONTAIN_SEQUENTIAL_DIGITS = 1 << 4;
- static final int RECENTLY_USED = 1 << 5;
- static final int NOT_ENOUGH_LETTER = 1 << 6;
- static final int NOT_ENOUGH_UPPER_CASE = 1 << 7;
- static final int NOT_ENOUGH_LOWER_CASE = 1 << 8;
- static final int NOT_ENOUGH_DIGITS = 1 << 9;
- static final int NOT_ENOUGH_SYMBOLS = 1 << 10;
- static final int NOT_ENOUGH_NON_LETTER = 1 << 11;
-
/**
* Keep track internally of where the user is in choosing a pattern.
*/
@@ -381,13 +362,13 @@ public class ChooseLockPassword extends SettingsActivity {
mForFingerprint = intent.getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
mForFace = intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
- mRequestedMinComplexity = intent.getIntExtra(
+ mMinComplexity = intent.getIntExtra(
EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
- mRequestedQuality = Math.max(
- intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, mRequestedQuality),
- mLockPatternUtils.getRequestedPasswordQuality(mUserId));
- loadDpmPasswordRequirements();
+ mRequestedQuality = intent.getIntExtra(
+ LockPatternUtils.PASSWORD_TYPE_KEY, PASSWORD_QUALITY_NUMERIC);
+
+ mMinMetrics = mLockPatternUtils.getRequestedPasswordMetrics(mUserId);
mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
if (intent.getBooleanExtra(
@@ -602,209 +583,23 @@ public class ChooseLockPassword extends SettingsActivity {
}
/**
- * Read the requirements from {@link DevicePolicyManager} and intent and aggregate them.
- */
- private void loadDpmPasswordRequirements() {
- final int dpmPasswordQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
- if (dpmPasswordQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
- mPasswordNumSequenceAllowed = false;
- }
- mPasswordMinLength = Math.max(LockPatternUtils.MIN_LOCK_PASSWORD_SIZE,
- mLockPatternUtils.getRequestedMinimumPasswordLength(mUserId));
- mPasswordMaxLength = mLockPatternUtils.getMaximumPasswordLength(mRequestedQuality);
- mPasswordMinLetters = mLockPatternUtils.getRequestedPasswordMinimumLetters(mUserId);
- mPasswordMinUpperCase = mLockPatternUtils.getRequestedPasswordMinimumUpperCase(mUserId);
- mPasswordMinLowerCase = mLockPatternUtils.getRequestedPasswordMinimumLowerCase(mUserId);
- mPasswordMinNumeric = mLockPatternUtils.getRequestedPasswordMinimumNumeric(mUserId);
- mPasswordMinSymbols = mLockPatternUtils.getRequestedPasswordMinimumSymbols(mUserId);
- mPasswordMinNonLetter = mLockPatternUtils.getRequestedPasswordMinimumNonLetter(mUserId);
-
- // Modify the value based on dpm policy
- switch (dpmPasswordQuality) {
- case PASSWORD_QUALITY_ALPHABETIC:
- if (mPasswordMinLetters == 0) {
- mPasswordMinLetters = 1;
- }
- break;
- case PASSWORD_QUALITY_ALPHANUMERIC:
- if (mPasswordMinLetters == 0) {
- mPasswordMinLetters = 1;
- }
- if (mPasswordMinNumeric == 0) {
- mPasswordMinNumeric = 1;
- }
- break;
- case PASSWORD_QUALITY_COMPLEX:
- // Reserve all the requirements.
- break;
- default:
- mPasswordMinNumeric = 0;
- mPasswordMinLetters = 0;
- mPasswordMinUpperCase = 0;
- mPasswordMinLowerCase = 0;
- mPasswordMinSymbols = 0;
- mPasswordMinNonLetter = 0;
- }
-
- mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
- }
-
- /**
- * Merges the dpm requirements and the min complexity requirements.
+ * Validates PIN/Password and returns the validation result and updates mValidationErrors
+ * and mPasswordReused to reflect validation results.
*
- * Since there are more than one set of metrics to meet the min complexity requirement,
- * and we are not hard-coding any one of them to be the requirements the user must fulfil,
- * we are taking what the user has already entered into account when compiling the list of
- * requirements from min complexity. Then we merge this list with the DPM requirements, and
- * present the merged set as validation results to the user on the UI.
- *
- *
For example, suppose min complexity requires either ALPHABETIC(8+), or
- * ALPHANUMERIC(6+). If the user has entered "a", the length requirement displayed on the UI
- * would be 8. Then the user appends "1" to make it "a1". We now know the user is entering
- * an alphanumeric password so we would update the min complexity required min length to 6.
- * This might result in a little confusion for the user but the UI does not support showing
- * multiple sets of requirements / validation results as options to users, this is the best
- * we can do now.
- */
- private void mergeMinComplexityAndDpmRequirements(int userEnteredPasswordQuality) {
- if (mRequestedMinComplexity == PASSWORD_COMPLEXITY_NONE) {
- // dpm requirements are dominant if min complexity is none
- return;
- }
-
- // reset dpm requirements
- loadDpmPasswordRequirements();
-
- PasswordMetrics minMetrics = PasswordMetrics.getMinimumMetrics(
- mRequestedMinComplexity, userEnteredPasswordQuality, mRequestedQuality,
- requiresNumeric(), requiresLettersOrSymbols());
- mPasswordNumSequenceAllowed = mPasswordNumSequenceAllowed
- && minMetrics.quality != PASSWORD_QUALITY_NUMERIC_COMPLEX;
- mPasswordMinLength = Math.max(mPasswordMinLength, minMetrics.length);
- mPasswordMinLetters = Math.max(mPasswordMinLetters, minMetrics.letters);
- mPasswordMinUpperCase = Math.max(mPasswordMinUpperCase, minMetrics.upperCase);
- mPasswordMinLowerCase = Math.max(mPasswordMinLowerCase, minMetrics.lowerCase);
- mPasswordMinNumeric = Math.max(mPasswordMinNumeric, minMetrics.numeric);
- mPasswordMinSymbols = Math.max(mPasswordMinSymbols, minMetrics.symbols);
- mPasswordMinNonLetter = Math.max(mPasswordMinNonLetter, minMetrics.nonLetter);
-
- if (minMetrics.quality == PASSWORD_QUALITY_ALPHABETIC) {
- if (!requiresLettersOrSymbols()) {
- mPasswordMinLetters = 1;
- }
- }
- if (minMetrics.quality == PASSWORD_QUALITY_ALPHANUMERIC) {
- if (!requiresLettersOrSymbols()) {
- mPasswordMinLetters = 1;
- }
- if (!requiresNumeric()) {
- mPasswordMinNumeric = 1;
- }
- }
-
- mPasswordMinLengthToFulfillAllPolicies = getMinLengthToFulfillAllPolicies();
- }
-
- private boolean requiresLettersOrSymbols() {
- // This is the condition for the password to be considered ALPHABETIC according to
- // PasswordMetrics.computeForPassword()
- return mPasswordMinLetters + mPasswordMinUpperCase
- + mPasswordMinLowerCase + mPasswordMinSymbols + mPasswordMinNonLetter > 0;
- }
-
- private boolean requiresNumeric() {
- return mPasswordMinNumeric > 0;
- }
-
- /**
- * Validates PIN/Password and returns the validation result.
- *
- * @param password the raw password the user typed in
- * @return the validation result.
+ * @param credential credential the user typed in.
+ * @return whether password satisfies all the requirements.
*/
@VisibleForTesting
- int validatePassword(LockscreenCredential credential) {
+ boolean validatePassword(LockscreenCredential credential) {
final byte[] password = credential.getCredential();
- int errorCode = NO_ERROR;
- final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
- mergeMinComplexityAndDpmRequirements(metrics.quality);
-
- if (password == null || password.length < mPasswordMinLength) {
- if (mPasswordMinLength > mPasswordMinLengthToFulfillAllPolicies) {
- errorCode |= TOO_SHORT;
- }
- } else if (password.length > mPasswordMaxLength) {
- errorCode |= TOO_LONG;
- } else {
- // The length requirements are fulfilled.
- if (!mPasswordNumSequenceAllowed
- && !requiresLettersOrSymbols()
- && metrics.numeric == password.length) {
- // Check for repeated characters or sequences (e.g. '1234', '0000', '2468')
- // if DevicePolicyManager or min password complexity requires a complex numeric
- // password. There can be two cases in the UI: 1. User chooses to enroll a
- // PIN, 2. User chooses to enroll a password but enters a numeric-only pin. We
- // should carry out the sequence check in both cases.
- //
- // Conditions for the !requiresLettersOrSymbols() to be necessary:
- // - DPM requires NUMERIC_COMPLEX
- // - min complexity not NONE, user picks PASSWORD type so ALPHABETIC or
- // ALPHANUMERIC is required
- // Imagine user has entered "12345678", if we don't skip the sequence check, the
- // validation result would show both "requires a letter" and "sequence not
- // allowed", while the only requirement the user needs to know is "requires a
- // letter" because once the user has fulfilled the alphabetic requirement, the
- // password would not be containing only digits so this check would not be
- // performed anyway.
- final int sequence = PasswordMetrics.maxLengthSequence(password);
- if (sequence > PasswordMetrics.MAX_ALLOWED_SEQUENCE) {
- errorCode |= CONTAIN_SEQUENTIAL_DIGITS;
- }
- }
- // Is the password recently used?
- if (mLockPatternUtils.checkPasswordHistory(password, getPasswordHistoryHashFactor(),
- mUserId)) {
- errorCode |= RECENTLY_USED;
- }
+ mValidationErrors = PasswordMetrics.validatePassword(
+ mMinMetrics, mMinComplexity, !mIsAlphaMode, password);
+ if (mValidationErrors.isEmpty() && mLockPatternUtils.checkPasswordHistory(
+ password, getPasswordHistoryHashFactor(), mUserId)) {
+ mValidationErrors =
+ Collections.singletonList(new PasswordValidationError(RECENTLY_USED));
}
-
- // Allow non-control Latin-1 characters only.
- for (int i = 0; i < password.length; i++) {
- char c = (char) password[i];
- if (c < 32 || c > 127) {
- errorCode |= CONTAIN_INVALID_CHARACTERS;
- break;
- }
- }
-
- // Ensure no non-digits if we are requesting numbers. This shouldn't be possible unless
- // user finds some way to bring up soft keyboard.
- if (mRequestedQuality == PASSWORD_QUALITY_NUMERIC
- || mRequestedQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
- if (metrics.letters > 0 || metrics.symbols > 0) {
- errorCode |= CONTAIN_NON_DIGITS;
- }
- }
-
- if (metrics.letters < mPasswordMinLetters) {
- errorCode |= NOT_ENOUGH_LETTER;
- }
- if (metrics.upperCase < mPasswordMinUpperCase) {
- errorCode |= NOT_ENOUGH_UPPER_CASE;
- }
- if (metrics.lowerCase < mPasswordMinLowerCase) {
- errorCode |= NOT_ENOUGH_LOWER_CASE;
- }
- if (metrics.symbols < mPasswordMinSymbols) {
- errorCode |= NOT_ENOUGH_SYMBOLS;
- }
- if (metrics.numeric < mPasswordMinNumeric) {
- errorCode |= NOT_ENOUGH_DIGITS;
- }
- if (metrics.nonLetter < mPasswordMinNonLetter) {
- errorCode |= NOT_ENOUGH_NON_LETTER;
- }
- return errorCode;
+ return mValidationErrors.isEmpty();
}
/**
@@ -830,7 +625,7 @@ public class ChooseLockPassword extends SettingsActivity {
mChosenPassword = mIsAlphaMode ? LockscreenCredential.createPassword(passwordText)
: LockscreenCredential.createPin(passwordText);
if (mUiStage == Stage.Introduction) {
- if (validatePassword(mChosenPassword) == NO_ERROR) {
+ if (validatePassword(mChosenPassword)) {
mFirstPassword = mChosenPassword;
mPasswordEntry.setText("");
updateStage(Stage.NeedToConfirm);
@@ -879,79 +674,79 @@ public class ChooseLockPassword extends SettingsActivity {
}
/**
- * @param errorCode error code returned from {@link #validatePassword(String)}.
+ * @param errorCode error code returned from password validation.
* @return an array of messages describing the error, important messages come first.
*/
- String[] convertErrorCodeToMessages(int errorCode) {
+ String[] convertErrorCodeToMessages() {
List messages = new ArrayList<>();
- if ((errorCode & CONTAIN_INVALID_CHARACTERS) > 0) {
- messages.add(getString(R.string.lockpassword_illegal_character));
+ for (PasswordValidationError error : mValidationErrors) {
+ switch (error.errorCode) {
+ case CONTAINS_INVALID_CHARACTERS:
+ messages.add(getString(R.string.lockpassword_illegal_character));
+ break;
+ case NOT_ENOUGH_UPPER_CASE:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_uppercase,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_LOWER_CASE:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_lowercase,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_LETTERS:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_letters,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_DIGITS:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_numeric,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_SYMBOLS:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_symbols,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_NON_LETTER:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_nonletter,
+ error.requirement, error.requirement));
+ break;
+ case NOT_ENOUGH_NON_DIGITS:
+ messages.add(getResources().getQuantityString(
+ R.plurals.lockpassword_password_requires_nonnumerical,
+ error.requirement, error.requirement));
+ break;
+ case TOO_SHORT:
+ messages.add(getResources().getQuantityString(
+ mIsAlphaMode
+ ? R.plurals.lockpassword_password_too_short
+ : R.plurals.lockpassword_pin_too_short,
+ error.requirement, error.requirement));
+ break;
+ case TOO_LONG:
+ messages.add(getResources().getQuantityString(
+ mIsAlphaMode
+ ? R.plurals.lockpassword_password_too_long
+ : R.plurals.lockpassword_pin_too_long,
+ error.requirement + 1, error.requirement + 1));
+ break;
+ case CONTAINS_SEQUENCE:
+ messages.add(getString(R.string.lockpassword_pin_no_sequential_digits));
+ break;
+ case RECENTLY_USED:
+ messages.add(getString(mIsAlphaMode
+ ? R.string.lockpassword_password_recently_used
+ : R.string.lockpassword_pin_recently_used));
+ break;
+ default:
+ Log.wtf(TAG, "unknown error validating password: " + error);
+ }
}
- if ((errorCode & CONTAIN_NON_DIGITS) > 0) {
- messages.add(getString(R.string.lockpassword_pin_contains_non_digits));
- }
- if ((errorCode & NOT_ENOUGH_UPPER_CASE) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_uppercase, mPasswordMinUpperCase,
- mPasswordMinUpperCase));
- }
- if ((errorCode & NOT_ENOUGH_LOWER_CASE) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_lowercase, mPasswordMinLowerCase,
- mPasswordMinLowerCase));
- }
- if ((errorCode & NOT_ENOUGH_LETTER) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_letters, mPasswordMinLetters,
- mPasswordMinLetters));
- }
- if ((errorCode & NOT_ENOUGH_DIGITS) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_numeric, mPasswordMinNumeric,
- mPasswordMinNumeric));
- }
- if ((errorCode & NOT_ENOUGH_SYMBOLS) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_symbols, mPasswordMinSymbols,
- mPasswordMinSymbols));
- }
- if ((errorCode & NOT_ENOUGH_NON_LETTER) > 0) {
- messages.add(getResources().getQuantityString(
- R.plurals.lockpassword_password_requires_nonletter, mPasswordMinNonLetter,
- mPasswordMinNonLetter));
- }
- if ((errorCode & TOO_SHORT) > 0) {
- messages.add(getResources().getQuantityString(
- mIsAlphaMode
- ? R.plurals.lockpassword_password_too_short
- : R.plurals.lockpassword_pin_too_short,
- mPasswordMinLength,
- mPasswordMinLength));
- }
- if ((errorCode & TOO_LONG) > 0) {
- messages.add(getResources().getQuantityString(
- mIsAlphaMode
- ? R.plurals.lockpassword_password_too_long
- : R.plurals.lockpassword_pin_too_long,
- mPasswordMaxLength + 1,
- mPasswordMaxLength + 1));
- }
- if ((errorCode & CONTAIN_SEQUENTIAL_DIGITS) > 0) {
- messages.add(getString(R.string.lockpassword_pin_no_sequential_digits));
- }
- if ((errorCode & RECENTLY_USED) > 0) {
- messages.add(getString((mIsAlphaMode) ? R.string.lockpassword_password_recently_used
- : R.string.lockpassword_pin_recently_used));
- }
- return messages.toArray(new String[0]);
- }
- private int getMinLengthToFulfillAllPolicies() {
- final int minLengthForLetters = Math.max(mPasswordMinLetters,
- mPasswordMinUpperCase + mPasswordMinLowerCase);
- final int minLengthForNonLetters = Math.max(mPasswordMinNonLetter,
- mPasswordMinSymbols + mPasswordMinNumeric);
- return minLengthForLetters + minLengthForNonLetters;
+ return messages.toArray(new String[0]);
}
/**
@@ -966,17 +761,17 @@ public class ChooseLockPassword extends SettingsActivity {
final int length = password.size();
if (mUiStage == Stage.Introduction) {
mPasswordRestrictionView.setVisibility(View.VISIBLE);
- final int errorCode = validatePassword(password);
- String[] messages = convertErrorCodeToMessages(errorCode);
+ final boolean passwordCompliant = validatePassword(password);
+ String[] messages = convertErrorCodeToMessages();
// Update the fulfillment of requirements.
mPasswordRequirementAdapter.setRequirements(messages);
// Enable/Disable the next button accordingly.
- setNextEnabled(errorCode == NO_ERROR);
+ setNextEnabled(passwordCompliant);
} else {
// Hide password requirement view when we are just asking user to confirm the pw.
mPasswordRestrictionView.setVisibility(View.GONE);
setHeaderText(getString(mUiStage.getHint(mIsAlphaMode, getStageType())));
- setNextEnabled(canInput && length >= mPasswordMinLength);
+ setNextEnabled(canInput && length >= LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
mSkipOrClearButton.setVisibility(toVisibility(canInput && length > 0));
}
int message = mUiStage.getMessage(mIsAlphaMode, getStageType());
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
index 084d710ee98..4bbf51d981f 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
@@ -77,7 +77,6 @@ public class ChooseLockPasswordTest {
SettingsShadowResources.overrideResource(
com.android.internal.R.string.config_headlineFontFamily, "");
mShadowDpm = ShadowDevicePolicyManager.getShadow();
- mShadowDpm.setPasswordMaximumLength(16);
}
@After
@@ -157,7 +156,7 @@ public class ChooseLockPasswordTest {
/* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
/* userEnteredPassword= */ LockscreenCredential.createNone(),
- "Must contain at least 1 letter",
+ "Must contain at least 1 non-numerical character",
"Must be at least 10 characters");
}
@@ -180,7 +179,7 @@ public class ChooseLockPasswordTest {
/* minComplexity= */ PASSWORD_COMPLEXITY_MEDIUM,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
/* userEnteredPassword= */ LockscreenCredential.createNone(),
- "Must contain at least 1 letter",
+ "Must contain at least 1 non-numerical character",
"Must be at least 4 characters");
}
@@ -193,7 +192,7 @@ public class ChooseLockPasswordTest {
/* minComplexity= */ PASSWORD_COMPLEXITY_LOW,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
/* userEnteredPassword= */ LockscreenCredential.createNone(),
- "Must contain at least 1 letter",
+ "Must contain at least 1 non-numerical character",
"Must contain at least 1 numerical digit",
"Must be at least 9 characters");
}
@@ -220,7 +219,9 @@ public class ChooseLockPasswordTest {
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
/* userEnteredPassword= */ LockscreenCredential.createNone(),
"Must contain at least 2 special symbols",
- "Must be at least 6 characters");
+ "Must be at least 6 characters",
+ "Must contain at least 1 letter",
+ "Must contain at least 1 numerical digit");
}
@Test
@@ -280,7 +281,7 @@ public class ChooseLockPasswordTest {
/* minComplexity= */ PASSWORD_COMPLEXITY_LOW,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
/* userEnteredPassword= */ LockscreenCredential.createPassword("12345678"),
- "Must contain at least 1 letter");
+ "Ascending, descending, or repeated sequence of digits isn't allowed");
}
@Test
@@ -291,8 +292,8 @@ public class ChooseLockPasswordTest {
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
/* userEnteredPassword= */ LockscreenCredential.createNone(),
- "Must contain at least 1 letter",
- "Must be at least 6 characters");
+ "Must be at least 6 characters",
+ "Must contain at least 1 non-numerical character");
}
@Test
@@ -303,8 +304,8 @@ public class ChooseLockPasswordTest {
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
/* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
/* userEnteredPassword= */ LockscreenCredential.createPassword("1"),
- "Must contain at least 1 letter",
- "Must be at least 6 characters");
+ "Must be at least 6 characters",
+ "Must contain at least 1 non-numerical character");
}
@Test
@@ -329,6 +330,28 @@ public class ChooseLockPasswordTest {
"Must be at least 6 characters");
}
+ @Test
+ public void processAndValidatePasswordRequirements_defaultPinMinimumLength() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+ /* passwordType= */ PASSWORD_QUALITY_NUMERIC,
+ /* userEnteredPassword= */ LockscreenCredential.createPassword("11"),
+ "PIN must be at least 4 digits");
+ }
+
+ @Test
+ public void processAndValidatePasswordRequirements_maximumLength() {
+ mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED);
+
+ assertPasswordValidationResult(
+ /* minComplexity= */ PASSWORD_COMPLEXITY_NONE,
+ /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC,
+ LockscreenCredential.createPassword("01234567890123456789"),
+ "Must be fewer than 17 characters");
+ }
+
@Test
public void assertThat_chooseLockIconChanged_WhenFingerprintExtraSet() {
ShadowDrawable drawable = setActivityAndGetIconDrawable(true);
@@ -369,9 +392,8 @@ public class ChooseLockPasswordTest {
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, minComplexity);
ChooseLockPassword activity = buildChooseLockPasswordActivity(intent);
ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(activity);
- int validateResult = fragment.validatePassword(userEnteredPassword);
- String[] messages = fragment.convertErrorCodeToMessages(validateResult);
-
+ fragment.validatePassword(userEnteredPassword);
+ String[] messages = fragment.convertErrorCodeToMessages();
assertThat(messages).asList().containsExactly((Object[]) expectedValidationResult);
}
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
index ca759164b99..b8fdf89cd17 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
@@ -6,6 +6,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.PasswordMetrics;
+import android.app.admin.PasswordPolicy;
import android.content.ComponentName;
import org.robolectric.RuntimeEnvironment;
@@ -26,7 +28,6 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev
private ComponentName mDeviceOwnerComponentName;
private int mDeviceOwnerUserId = -1;
private int mPasswordMinQuality = PASSWORD_QUALITY_UNSPECIFIED;
- private int mPasswordMaxLength = 16;
private int mPasswordMinLength = 0;
private int mPasswordMinSymbols = 0;
@@ -77,41 +78,26 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev
}
@Implementation
- public int getPasswordQuality(ComponentName admin, int userHandle) {
- return mPasswordMinQuality;
+ public PasswordMetrics getPasswordMinimumMetrics(int userHandle) {
+ PasswordPolicy policy = new PasswordPolicy();
+ policy.quality = mPasswordMinQuality;
+ policy.length = mPasswordMinLength;
+ policy.symbols = mPasswordMinSymbols;
+ return policy.getMinMetrics();
}
public void setPasswordQuality(int quality) {
mPasswordMinQuality = quality;
}
- @Implementation
- public int getPasswordMinimumLength(ComponentName admin, int userHandle) {
- return mPasswordMinLength;
- }
-
public void setPasswordMinimumLength(int length) {
mPasswordMinLength = length;
}
- @Implementation
- public int getPasswordMinimumSymbols(ComponentName admin, int userHandle) {
- return mPasswordMinSymbols;
- }
-
public void setPasswordMinimumSymbols(int numOfSymbols) {
mPasswordMinSymbols = numOfSymbols;
}
- @Implementation
- public int getPasswordMaximumLength(int quality) {
- return mPasswordMaxLength;
- }
-
- public void setPasswordMaximumLength(int length) {
- mPasswordMaxLength = length;
- }
-
public static ShadowDevicePolicyManager getShadow() {
return (ShadowDevicePolicyManager) Shadow.extract(
RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class));