diff options
| author | Rubin Xu <rubinxu@google.com> | 2019-10-14 10:22:23 +0100 |
|---|---|---|
| committer | Rubin Xu <rubinxu@google.com> | 2019-10-21 15:49:53 +0100 |
| commit | 5e891bcc04556a3595ab349381acc2a2e36a69d1 (patch) | |
| tree | f8f247ca52aa3b4f601b9ad4db4e619b2175141a /core/java | |
| parent | bb8832087450b786d5ab6535fc63db9eee855f94 (diff) | |
Introduce Lockscreen PIN credential as first-class citizen
* Add CREDENTIAL_TYPE_PIN as the fourth credential type.
* Rename existing CREDENTIAL_TYPE_PASSWORD
to CREDENTIAL_TYPE_PASSWORD_OR_PIN which is still referenced
by password data persisted on disk.
* No longer store quality for new credentials (PASSWORD_TYPE_KEY).
Credential type stored in synthetic password blob is now the single
source of truth on what credential (None/Pin/Pattern/Password) the
device currently has.
* Adapt lockscreen FRP to work on a similar fashion (no more quality
being passed around and stored)
* Adapt RecoverableKeystore to use the new PIN credential type.
* Fix existing unit tests
* Add new unit tests for lockscreen FRP.
Upgrade path:
* Existing credentials will have CREDENTIAL_TYPE_PASSWORD_OR_PIN, and when
LSS sees this, it will further consult PASSWORD_TYPE_KEY to distinguish
between PIN and Pattern. The credential will stay this way until the next
password change i.e. no automatic credential upgrade.
* Existing FRP credential will have CREDENTIAL_TYPE_PASSWORD_OR_PIN, and
when LSS sees this, it will further consult the saved quality
PersistentData.qualityForUi to make that distinction.
* Normal and FRP credential enrolled after this CL will store
CREDENTIAL_TYPE_PIN to indicate this is a numeric PIN.
Bug: 65239740
Test: atest com.android.server.locksettings
Test: atest com.android.internal.widget.LockscreenCredentialTest
Test: atest com.android.internal.util.LockPatternUtilsTest
Test: atest LockSettingsShellCommandTest
Test: atest com.android.server.devicepolicy.DevicePolicyManagerTest
Test: atest FrameworksCoreTests:PasswordMetricsTest
Test: atest FrameworksCoreTests:PasswordPolicyTest
Test: atest MixedManagedProfileOwnerTest#testResetPasswordWithToken
Test: atest com.android.cts.devicepolicy.PasswordComplexityTest
Test: atest com.android.cts.devicepolicy.ManagedProfilePasswordTest
Test: flash an old build, enroll password and flash to new build.
Verify everything still works.
Test: manually set an PIN/Pattern/Password; then change to
PIN/Pattern/Password; finally remove password
Test: manually create a work profile; try unify and ununify work
challenge.
Test: manually test lockscreen FRP flow (change password via Settings /
DPC)
Change-Id: I781cea4c32d567aac4af692697c4569161580102
Diffstat (limited to 'core/java')
4 files changed, 127 insertions, 148 deletions
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java index d9bfde5af61a..0ecfca74b26e 100644 --- a/core/java/android/app/admin/PasswordMetrics.java +++ b/core/java/android/app/admin/PasswordMetrics.java @@ -73,6 +73,11 @@ public final class PasswordMetrics implements Parcelable { // consider it a complex PIN/password. public static final int MAX_ALLOWED_SEQUENCE = 3; + // One of CREDENTIAL_TYPE_NONE, CREDENTIAL_TYPE_PATTERN or CREDENTIAL_TYPE_PASSWORD. + // Note that this class still uses CREDENTIAL_TYPE_PASSWORD to represent both numeric PIN + // and alphabetic password. This is OK as long as this definition is only used internally, + // and the value never gets mixed up with credential types from other parts of the framework. + // TODO: fix this (ideally after we move logic to PasswordPolicy) public @CredentialType int credType; // Fields below only make sense when credType is PASSWORD. public int length = 0; @@ -161,24 +166,26 @@ public final class PasswordMetrics implements Parcelable { public static final @NonNull Parcelable.Creator<PasswordMetrics> CREATOR = new Parcelable.Creator<PasswordMetrics>() { - public PasswordMetrics createFromParcel(Parcel in) { - int credType = in.readInt(); - int length = in.readInt(); - int letters = in.readInt(); - int upperCase = in.readInt(); - int lowerCase = in.readInt(); - int numeric = in.readInt(); - int symbols = in.readInt(); - int nonLetter = in.readInt(); - int nonNumeric = in.readInt(); - int seqLength = in.readInt(); - return new PasswordMetrics(credType, length, letters, upperCase, lowerCase, numeric, - symbols, nonLetter, nonNumeric, seqLength); - } - - public PasswordMetrics[] newArray(int size) { - return new PasswordMetrics[size]; - } + @Override + public PasswordMetrics createFromParcel(Parcel in) { + int credType = in.readInt(); + int length = in.readInt(); + int letters = in.readInt(); + int upperCase = in.readInt(); + int lowerCase = in.readInt(); + int numeric = in.readInt(); + int symbols = in.readInt(); + int nonLetter = in.readInt(); + int nonNumeric = in.readInt(); + int seqLength = in.readInt(); + return new PasswordMetrics(credType, length, letters, upperCase, lowerCase, + numeric, symbols, nonLetter, nonNumeric, seqLength); + } + + @Override + public PasswordMetrics[] newArray(int size) { + return new PasswordMetrics[size]; + } }; /** @@ -189,7 +196,7 @@ public final class PasswordMetrics implements Parcelable { * {@link com.android.internal.widget.LockPatternUtils#CREDENTIAL_TYPE_PASSWORD}. */ public static PasswordMetrics computeForCredential(LockscreenCredential credential) { - if (credential.isPassword()) { + if (credential.isPassword() || credential.isPin()) { return PasswordMetrics.computeForPassword(credential.getCredential()); } else if (credential.isPattern()) { return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN); diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 6daac48d5045..897b982406dc 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -50,10 +50,7 @@ interface ILockSettings { VerifyCredentialResponse verifyCredential(in LockscreenCredential credential, long challenge, int userId); VerifyCredentialResponse verifyTiedProfileChallenge(in LockscreenCredential credential, long challenge, int userId); boolean checkVoldPassword(int userId); - @UnsupportedAppUsage - boolean havePattern(int userId); - @UnsupportedAppUsage - boolean havePassword(int userId); + int getCredentialType(int userId); byte[] getHashFactor(in LockscreenCredential currentCredential, int userId); void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in LockscreenCredential managedUserPassword); boolean getSeparateProfileChallengeEnabled(int userId); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 06448170822c..b534213ec859 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -17,9 +17,6 @@ package com.android.internal.widget; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; -import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC; -import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; -import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED; 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; @@ -117,13 +114,19 @@ public class LockPatternUtils { // NOTE: When modifying this, make sure credential sufficiency validation logic is intact. public static final int CREDENTIAL_TYPE_NONE = -1; public static final int CREDENTIAL_TYPE_PATTERN = 1; - public static final int CREDENTIAL_TYPE_PASSWORD = 2; + // This is the legacy value persisted on disk. Never return it to clients, but internally + // we still need it to handle upgrade cases. + public static final int CREDENTIAL_TYPE_PASSWORD_OR_PIN = 2; + public static final int CREDENTIAL_TYPE_PIN = 3; + public static final int CREDENTIAL_TYPE_PASSWORD = 4; @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"CREDENTIAL_TYPE_"}, value = { CREDENTIAL_TYPE_NONE, CREDENTIAL_TYPE_PATTERN, - CREDENTIAL_TYPE_PASSWORD, // Either pin or password. + CREDENTIAL_TYPE_PASSWORD, + CREDENTIAL_TYPE_PIN, + // CREDENTIAL_TYPE_PASSWORD_OR_PIN is missing on purpose. }) public @interface CredentialType {} @@ -169,6 +172,7 @@ public class LockPatternUtils { public static final String SYNTHETIC_PASSWORD_HANDLE_KEY = "sp-handle"; public static final String SYNTHETIC_PASSWORD_ENABLED_KEY = "enable-sp"; + public static final int SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT = 1; private static final String HISTORY_DELIMITER = ","; @UnsupportedAppUsage @@ -372,8 +376,8 @@ public class LockPatternUtils { * * @param credential The credential to check. * @param challenge The challenge to verify against the credential - * @return the attestation that the challenge was verified, or null * @param userId The user whose credential is being verified + * @return the attestation that the challenge was verified, or null * @throws RequestThrottledException if credential verification is being throttled due to * to many incorrect attempts. * @throws IllegalStateException if called on the main thread. @@ -392,6 +396,7 @@ public class LockPatternUtils { return null; } } catch (RemoteException re) { + Log.e(TAG, "failed to verify credential", re); return null; } } @@ -423,6 +428,7 @@ public class LockPatternUtils { return false; } } catch (RemoteException re) { + Log.e(TAG, "failed to check credential", re); return false; } } @@ -456,6 +462,7 @@ public class LockPatternUtils { return null; } } catch (RemoteException re) { + Log.e(TAG, "failed to verify tied profile credential", re); return null; } } @@ -469,6 +476,7 @@ public class LockPatternUtils { try { return getLockSettings().checkVoldPassword(userId); } catch (RemoteException re) { + Log.e(TAG, "failed to check vold password", re); return false; } } @@ -522,30 +530,6 @@ public class LockPatternUtils { } /** - * Check to see if the user has stored a lock pattern. - * @return Whether a saved pattern exists. - */ - private boolean savedPatternExists(int userId) { - try { - return getLockSettings().havePattern(userId); - } catch (RemoteException re) { - return false; - } - } - - /** - * Check to see if the user has stored a lock pattern. - * @return Whether a saved pattern exists. - */ - private boolean savedPasswordExists(int userId) { - try { - return getLockSettings().havePassword(userId); - } catch (RemoteException re) { - return false; - } - } - - /** * Return true if the user has ever chosen a pattern. This is true even if the pattern is * currently cleared. * @@ -566,22 +550,11 @@ public class LockPatternUtils { /** * Used by device policy manager to validate the current password * information it has. + * @Deprecated use {@link #getKeyguardStoredPasswordQuality} */ @UnsupportedAppUsage public int getActivePasswordQuality(int userId) { - int quality = getKeyguardStoredPasswordQuality(userId); - - if (isLockPasswordEnabled(quality, userId)) { - // Quality is a password and a password exists. Return the quality. - return quality; - } - - if (isLockPatternEnabled(quality, userId)) { - // Quality is a pattern and a pattern exists. Return the quality. - return quality; - } - - return PASSWORD_QUALITY_UNSPECIFIED; + return getKeyguardStoredPasswordQuality(userId); } /** @@ -639,6 +612,22 @@ public class LockPatternUtils { return quality == PASSWORD_QUALITY_NUMERIC || quality == PASSWORD_QUALITY_NUMERIC_COMPLEX; } + /** Returns the canonical password quality corresponding to the given credential type. */ + public static int credentialTypeToPasswordQuality(int credentialType) { + switch (credentialType) { + case CREDENTIAL_TYPE_NONE: + return PASSWORD_QUALITY_UNSPECIFIED; + case CREDENTIAL_TYPE_PATTERN: + return PASSWORD_QUALITY_SOMETHING; + case CREDENTIAL_TYPE_PIN: + return PASSWORD_QUALITY_NUMERIC; + case CREDENTIAL_TYPE_PASSWORD: + return PASSWORD_QUALITY_ALPHABETIC; + default: + throw new IllegalStateException("Unknown type: " + credentialType); + } + } + /** * Save a new lockscreen credential. * @@ -682,17 +671,12 @@ public class LockPatternUtils { } newCredential.checkLength(); - final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); - setKeyguardStoredPasswordQuality(newCredential.getQuality(), userHandle); - try { if (!getLockSettings().setLockCredential( newCredential, savedCredential, userHandle, allowUntrustedChange)) { - setKeyguardStoredPasswordQuality(currentQuality, userHandle); return false; } - } catch (RemoteException | RuntimeException e) { - setKeyguardStoredPasswordQuality(currentQuality, userHandle); + } catch (RemoteException e) { throw new RuntimeException("Unable to save lock password", e); } @@ -900,14 +884,12 @@ public class LockPatternUtils { * @see DevicePolicyManager#getPasswordQuality(android.content.ComponentName) * * @return stored password quality + * @deprecated use {@link #getCredentialTypeForUser(int)} instead */ @UnsupportedAppUsage + @Deprecated public int getKeyguardStoredPasswordQuality(int userHandle) { - return (int) getLong(PASSWORD_TYPE_KEY, PASSWORD_QUALITY_UNSPECIFIED, userHandle); - } - - private void setKeyguardStoredPasswordQuality(int quality, int userHandle) { - setLong(PASSWORD_TYPE_KEY, quality, userHandle); + return credentialTypeToPasswordQuality(getCredentialTypeForUser(userHandle)); } /** @@ -1094,28 +1076,33 @@ public class LockPatternUtils { } /** + * Returns the credential type of the user, can be one of {@link #CREDENTIAL_TYPE_NONE}, + * {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} and + * {@link #CREDENTIAL_TYPE_PASSWORD} + */ + public @CredentialType int getCredentialTypeForUser(int userHandle) { + try { + return getLockSettings().getCredentialType(userHandle); + } catch (RemoteException re) { + Log.e(TAG, "failed to get credential type", re); + return CREDENTIAL_TYPE_NONE; + } + } + + /** * @param userId the user for which to report the value * @return Whether the lock screen is secured. */ @UnsupportedAppUsage public boolean isSecure(int userId) { - int mode = getKeyguardStoredPasswordQuality(userId); - return isLockPatternEnabled(mode, userId) || isLockPasswordEnabled(mode, userId); + int type = getCredentialTypeForUser(userId); + return type != CREDENTIAL_TYPE_NONE; } @UnsupportedAppUsage public boolean isLockPasswordEnabled(int userId) { - return isLockPasswordEnabled(getKeyguardStoredPasswordQuality(userId), userId); - } - - private boolean isLockPasswordEnabled(int mode, int userId) { - final boolean passwordEnabled = mode == PASSWORD_QUALITY_ALPHABETIC - || mode == PASSWORD_QUALITY_NUMERIC - || mode == PASSWORD_QUALITY_NUMERIC_COMPLEX - || mode == PASSWORD_QUALITY_ALPHANUMERIC - || mode == PASSWORD_QUALITY_COMPLEX - || mode == PASSWORD_QUALITY_MANAGED; - return passwordEnabled && savedPasswordExists(userId); + int type = getCredentialTypeForUser(userId); + return type == CREDENTIAL_TYPE_PASSWORD || type == CREDENTIAL_TYPE_PIN; } /** @@ -1123,7 +1110,8 @@ public class LockPatternUtils { */ @UnsupportedAppUsage public boolean isLockPatternEnabled(int userId) { - return isLockPatternEnabled(getKeyguardStoredPasswordQuality(userId), userId); + int type = getCredentialTypeForUser(userId); + return type == CREDENTIAL_TYPE_PATTERN; } @Deprecated @@ -1139,10 +1127,6 @@ public class LockPatternUtils { setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, true, userId); } - private boolean isLockPatternEnabled(int mode, int userId) { - return mode == PASSWORD_QUALITY_SOMETHING && savedPatternExists(userId); - } - /** * @return Whether the visible pattern is enabled. */ @@ -1548,18 +1532,8 @@ public class LockPatternUtils { credential.checkLength(); LockSettingsInternal localService = getLockSettingsInternal(); - final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); - setKeyguardStoredPasswordQuality(credential.getQuality(), userHandle); - - try { - if (!localService.setLockCredentialWithToken( - credential, tokenHandle, token, userHandle)) { - setKeyguardStoredPasswordQuality(currentQuality, userHandle); - return false; - } - } catch (RuntimeException e) { - setKeyguardStoredPasswordQuality(currentQuality, userHandle); - throw new RuntimeException("Unable to save lock credential", e); + if (!localService.setLockCredentialWithToken(credential, tokenHandle, token, userHandle)) { + return false; } onPostPasswordChanged(credential, userHandle); @@ -1760,7 +1734,8 @@ public class LockPatternUtils { } public boolean isSyntheticPasswordEnabled() { - return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM) != 0; + return getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, SYNTHETIC_PASSWORD_ENABLED_BY_DEFAULT, + UserHandle.USER_SYSTEM) != 0; } /** diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java index ac471f0e8484..f456349a8937 100644 --- a/core/java/com/android/internal/widget/LockscreenCredential.java +++ b/core/java/com/android/internal/widget/LockscreenCredential.java @@ -16,14 +16,11 @@ package com.android.internal.widget; -import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; -import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; -import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; -import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import android.annotation.NonNull; import android.annotation.Nullable; @@ -61,9 +58,6 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { // Stores raw credential bytes, or null if credential has been zeroized. An empty password // is represented as a byte array of length 0. private byte[] mCredential; - // Store the quality of the password, this is used to distinguish between pin - // (PASSWORD_QUALITY_NUMERIC) and password (PASSWORD_QUALITY_ALPHABETIC). - private final int mQuality; /** * Private constructor, use static builder methods instead. @@ -72,15 +66,18 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { * LockscreenCredential will only store the reference internally without copying. This is to * minimize the number of extra copies introduced. */ - private LockscreenCredential(int type, int quality, byte[] credential) { + private LockscreenCredential(int type, byte[] credential) { Preconditions.checkNotNull(credential); if (type == CREDENTIAL_TYPE_NONE) { Preconditions.checkArgument(credential.length == 0); } else { + // Do not allow constructing a CREDENTIAL_TYPE_PASSWORD_OR_PIN object. + Preconditions.checkArgument(type == CREDENTIAL_TYPE_PIN + || type == CREDENTIAL_TYPE_PASSWORD + || type == CREDENTIAL_TYPE_PATTERN); Preconditions.checkArgument(credential.length > 0); } mType = type; - mQuality = quality; mCredential = credential; } @@ -88,8 +85,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { * Creates a LockscreenCredential object representing empty password. */ public static LockscreenCredential createNone() { - return new LockscreenCredential(CREDENTIAL_TYPE_NONE, PASSWORD_QUALITY_UNSPECIFIED, - new byte[0]); + return new LockscreenCredential(CREDENTIAL_TYPE_NONE, new byte[0]); } /** @@ -97,7 +93,6 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { */ public static LockscreenCredential createPattern(@NonNull List<LockPatternView.Cell> pattern) { return new LockscreenCredential(CREDENTIAL_TYPE_PATTERN, - PASSWORD_QUALITY_SOMETHING, LockPatternUtils.patternToByteArray(pattern)); } @@ -106,7 +101,6 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { */ public static LockscreenCredential createPassword(@NonNull CharSequence password) { return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD, - PASSWORD_QUALITY_ALPHABETIC, charSequenceToByteArray(password)); } @@ -118,7 +112,6 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { */ public static LockscreenCredential createManagedPassword(@NonNull byte[] password) { return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD, - PASSWORD_QUALITY_ALPHABETIC, Arrays.copyOf(password, password.length)); } @@ -126,8 +119,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { * Creates a LockscreenCredential object representing the given numeric PIN. */ public static LockscreenCredential createPin(@NonNull CharSequence pin) { - return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD, - PASSWORD_QUALITY_NUMERIC, + return new LockscreenCredential(CREDENTIAL_TYPE_PIN, charSequenceToByteArray(pin)); } @@ -160,10 +152,8 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { } /** * Returns the type of this credential. Can be one of {@link #CREDENTIAL_TYPE_NONE}, - * {@link #CREDENTIAL_TYPE_PATTERN} or {@link #CREDENTIAL_TYPE_PASSWORD}. - * - * TODO: Remove once credential type is internal. Callers should use {@link #isNone}, - * {@link #isPattern} and {@link #isPassword} instead. + * {@link #CREDENTIAL_TYPE_PATTERN}, {@link #CREDENTIAL_TYPE_PIN} or + * {@link #CREDENTIAL_TYPE_PASSWORD}. */ public int getType() { ensureNotZeroized(); @@ -171,14 +161,6 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { } /** - * Returns the quality type of the credential - */ - public int getQuality() { - ensureNotZeroized(); - return mQuality; - } - - /** * Returns the credential bytes. This is a direct reference of the internal field so * callers should not modify it. * @@ -200,9 +182,11 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { if (isPattern()) { return StorageManager.CRYPT_TYPE_PATTERN; } + if (isPin()) { + return StorageManager.CRYPT_TYPE_PIN; + } if (isPassword()) { - return mQuality == PASSWORD_QUALITY_NUMERIC - ? StorageManager.CRYPT_TYPE_PIN : StorageManager.CRYPT_TYPE_PASSWORD; + return StorageManager.CRYPT_TYPE_PASSWORD; } throw new IllegalStateException("Unhandled credential type"); } @@ -219,7 +203,13 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { return mType == CREDENTIAL_TYPE_PATTERN; } - /** Returns whether this is a password credential */ + /** Returns whether this is a numeric pin credential */ + public boolean isPin() { + ensureNotZeroized(); + return mType == CREDENTIAL_TYPE_PIN; + } + + /** Returns whether this is an alphabetic password credential */ public boolean isPassword() { ensureNotZeroized(); return mType == CREDENTIAL_TYPE_PASSWORD; @@ -233,7 +223,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { /** Create a copy of the credential */ public LockscreenCredential duplicate() { - return new LockscreenCredential(mType, mQuality, + return new LockscreenCredential(mType, mCredential != null ? Arrays.copyOf(mCredential, mCredential.length) : null); } @@ -263,7 +253,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { } return; } - if (isPassword()) { + if (isPassword() || isPin()) { if (size() < LockPatternUtils.MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + LockPatternUtils.MIN_LOCK_PASSWORD_SIZE); @@ -272,10 +262,22 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { } } + /** + * Check if this credential's type matches one that's retrieved from disk. The nuance here is + * that the framework used to not distinguish between PIN and password, so this method will + * allow a PIN/Password LockscreenCredential to match against the legacy + * {@link #CREDENTIAL_TYPE_PASSWORD_OR_PIN} stored on disk. + */ + public boolean checkAgainstStoredType(int storedCredentialType) { + if (storedCredentialType == CREDENTIAL_TYPE_PASSWORD_OR_PIN) { + return getType() == CREDENTIAL_TYPE_PASSWORD || getType() == CREDENTIAL_TYPE_PIN; + } + return getType() == storedCredentialType; + } + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); - dest.writeInt(mQuality); dest.writeByteArray(mCredential); } @@ -284,8 +286,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { @Override public LockscreenCredential createFromParcel(Parcel source) { - return new LockscreenCredential(source.readInt(), source.readInt(), - source.createByteArray()); + return new LockscreenCredential(source.readInt(), source.createByteArray()); } @Override @@ -307,7 +308,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { @Override public int hashCode() { // Effective Java — Item 9 - return ((17 + mType) * 31 + mQuality) * 31 + mCredential.hashCode(); + return (17 + mType) * 31 + mCredential.hashCode(); } @Override @@ -315,8 +316,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable { if (o == this) return true; if (!(o instanceof LockscreenCredential)) return false; final LockscreenCredential other = (LockscreenCredential) o; - return mType == other.mType && mQuality == other.mQuality - && Arrays.equals(mCredential, other.mCredential); + return mType == other.mType && Arrays.equals(mCredential, other.mCredential); } /** |
