summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorRubin Xu <rubinxu@google.com>2019-10-14 10:22:23 +0100
committerRubin Xu <rubinxu@google.com>2019-10-21 15:49:53 +0100
commit5e891bcc04556a3595ab349381acc2a2e36a69d1 (patch)
treef8f247ca52aa3b4f601b9ad4db4e619b2175141a /core/java
parentbb8832087450b786d5ab6535fc63db9eee855f94 (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')
-rw-r--r--core/java/android/app/admin/PasswordMetrics.java45
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl5
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java145
-rw-r--r--core/java/com/android/internal/widget/LockscreenCredential.java80
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);
}
/**