diff options
| author | TreeHugger Robot <treehugger-gerrit@google.com> | 2018-12-12 21:12:43 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-12-12 21:12:43 +0000 |
| commit | 559ff8acbc482a2351f3182eb571e7c071491c6c (patch) | |
| tree | 512293a1f0c75852c3d0afce0c200a0727f6a522 /core/java/android | |
| parent | 987712e02ce7db9359b4d8aa79ccb16991f19dc1 (diff) | |
| parent | e95865582912d712327560b2e13c41e4780957ae (diff) | |
Merge "New API for getting the screen lock complexity"
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/app/admin/DevicePolicyManager.java | 95 | ||||
| -rw-r--r-- | core/java/android/app/admin/IDevicePolicyManager.aidl | 1 | ||||
| -rw-r--r-- | core/java/android/app/admin/PasswordMetrics.java | 116 |
3 files changed, 212 insertions, 0 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 76a16cd24fd3..670f8db7c588 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -16,6 +16,7 @@ package android.app.admin; +import android.Manifest.permission; import android.annotation.CallbackExecutor; import android.annotation.ColorInt; import android.annotation.IntDef; @@ -1382,6 +1383,73 @@ public class DevicePolicyManager { = "android.app.action.SET_NEW_PASSWORD"; /** + * Constant for {@link #getPasswordComplexity()}: no password. + * + * <p>Note that these complexity constants are ordered so that higher values are more complex. + */ + public static final int PASSWORD_COMPLEXITY_NONE = 0; + + /** + * Constant for {@link #getPasswordComplexity()}: password satisfies one of the following: + * <ul> + * <li>pattern + * <li>PIN with repeating (4444) or ordered (1234, 4321, 2468) sequences + * </ul> + * + * <p>Note that these complexity constants are ordered so that higher values are more complex. + * + * @see #PASSWORD_QUALITY_SOMETHING + * @see #PASSWORD_QUALITY_NUMERIC + */ + public static final int PASSWORD_COMPLEXITY_LOW = 0x10000; + + /** + * Constant for {@link #getPasswordComplexity()}: password satisfies one of the following: + * <ul> + * <li>PIN with <b>no</b> repeating (4444) or ordered (1234, 4321, 2468) sequences, length at + * least 4 + * <li>alphabetic, length at least 4 + * <li>alphanumeric, length at least 4 + * </ul> + * + * <p>Note that these complexity constants are ordered so that higher values are more complex. + * + * @see #PASSWORD_QUALITY_NUMERIC_COMPLEX + * @see #PASSWORD_QUALITY_ALPHABETIC + * @see #PASSWORD_QUALITY_ALPHANUMERIC + */ + public static final int PASSWORD_COMPLEXITY_MEDIUM = 0x30000; + + /** + * Constant for {@link #getPasswordComplexity()}: password satisfies one of the following: + * <ul> + * <li>PIN with <b>no</b> repeating (4444) or ordered (1234, 4321, 2468) sequences, length at + * least 4 + * <li>alphabetic, length at least 6 + * <li>alphanumeric, length at least 6 + * </ul> + * + * <p>Note that these complexity constants are ordered so that higher values are more complex. + * + * @see #PASSWORD_QUALITY_NUMERIC_COMPLEX + * @see #PASSWORD_QUALITY_ALPHABETIC + * @see #PASSWORD_QUALITY_ALPHANUMERIC + */ + public static final int PASSWORD_COMPLEXITY_HIGH = 0x50000; + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"PASSWORD_COMPLEXITY_"}, value = { + PASSWORD_COMPLEXITY_NONE, + PASSWORD_COMPLEXITY_LOW, + PASSWORD_COMPLEXITY_MEDIUM, + PASSWORD_COMPLEXITY_HIGH, + }) + public @interface PasswordComplexity {} + + /** * Activity action: have the user enter a new password for the parent profile. * If the intent is launched from within a managed profile, this will trigger * entering a new password for the parent of the profile. In all other cases @@ -3106,6 +3174,33 @@ public class DevicePolicyManager { } /** + * Returns how complex the current user's screen lock is. + * + * <p>Note that when called from a profile which uses an unified challenge with its parent, the + * screen lock complexity of the parent will be returned. However, this API does not support + * explicitly querying the parent profile screen lock complexity via {@link + * #getParentProfileInstance}. + * + * @throws IllegalStateException if the user is not unlocked. + * @throws SecurityException if the calling application does not have the permission + * {@link permission#GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY} + */ + @PasswordComplexity + @RequiresPermission(android.Manifest.permission.GET_AND_REQUEST_SCREEN_LOCK_COMPLEXITY) + public int getPasswordComplexity() { + throwIfParentInstance("getPasswordComplexity"); + if (mService == null) { + return PASSWORD_COMPLEXITY_NONE; + } + + try { + return mService.getPasswordComplexity(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * When called by a profile owner of a managed profile returns true if the profile uses unified * challenge with its parent user. * diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 74cb22c3e645..568becfcdd1a 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -82,6 +82,7 @@ interface IDevicePolicyManager { boolean isActivePasswordSufficient(int userHandle, boolean parent); boolean isProfileActivePasswordSufficientForParent(int userHandle); + int getPasswordComplexity(); boolean isUsingUnifiedPassword(in ComponentName admin); int getCurrentFailedPasswordAttempts(int userHandle, boolean parent); int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent); diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java index 5fee853275fb..8b41755f6dec 100644 --- a/core/java/android/app/admin/PasswordMetrics.java +++ b/core/java/android/app/admin/PasswordMetrics.java @@ -16,8 +16,14 @@ package android.app.admin; +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 android.annotation.IntDef; import android.annotation.NonNull; +import android.app.admin.DevicePolicyManager.PasswordComplexity; import android.os.Parcel; import android.os.Parcelable; @@ -35,6 +41,8 @@ public class PasswordMetrics implements Parcelable { // consider it a complex PIN/password. public static final int MAX_ALLOWED_SEQUENCE = 3; + // TODO(b/120536847): refactor isActivePasswordSufficient logic so that the actual password + // quality is not overwritten public int quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; public int length = 0; public int letters = 0; @@ -46,6 +54,10 @@ public class PasswordMetrics implements Parcelable { public PasswordMetrics() {} + public PasswordMetrics(int quality) { + this.quality = quality; + } + public PasswordMetrics(int quality, int length) { this.quality = quality; this.length = length; @@ -173,6 +185,15 @@ public class PasswordMetrics implements Parcelable { && this.nonLetter == o.nonLetter; } + private boolean satisfiesBucket(PasswordMetrics... bucket) { + for (PasswordMetrics metrics : bucket) { + if (this.quality == metrics.quality) { + return this.length >= metrics.length; + } + } + return false; + } + /* * Returns the maximum length of a sequential characters. A sequence is defined as * monotonically increasing characters with a constant interval or the same character repeated. @@ -254,4 +275,99 @@ public class PasswordMetrics implements Parcelable { return 0; } } + + /** Determines the {@link PasswordComplexity} of this {@link PasswordMetrics}. */ + @PasswordComplexity + public int determineComplexity() { + for (PasswordComplexityBucket bucket : PasswordComplexityBucket.BUCKETS) { + if (satisfiesBucket(bucket.getMetrics())) { + return bucket.mComplexityLevel; + } + } + return PASSWORD_COMPLEXITY_NONE; + } + + /** + * Requirements in terms of {@link PasswordMetrics} for each {@link PasswordComplexity}. + */ + public static class PasswordComplexityBucket { + /** + * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_HIGH} in terms of + * {@link PasswordMetrics}. + */ + private static final PasswordComplexityBucket HIGH = + new PasswordComplexityBucket( + PASSWORD_COMPLEXITY_HIGH, + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, /* length= */ 6), + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, /* length= */ 6), + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, /* length= */ + 8)); + + /** + * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_MEDIUM} in terms of + * {@link PasswordMetrics}. + */ + private static final PasswordComplexityBucket MEDIUM = + new PasswordComplexityBucket( + PASSWORD_COMPLEXITY_MEDIUM, + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, /* length= */ 4), + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, /* length= */ 4), + new PasswordMetrics( + DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, /* length= */ + 4)); + + /** + * Definition of {@link DevicePolicyManager#PASSWORD_COMPLEXITY_LOW} in terms of + * {@link PasswordMetrics}. + */ + private static final PasswordComplexityBucket LOW = + new PasswordComplexityBucket( + PASSWORD_COMPLEXITY_LOW, + new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC), + new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC), + new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX), + new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC), + new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)); + + /** + * A special bucket to represent {@link DevicePolicyManager#PASSWORD_COMPLEXITY_NONE}. + */ + private static final PasswordComplexityBucket NONE = + new PasswordComplexityBucket(PASSWORD_COMPLEXITY_NONE, new PasswordMetrics()); + + /** Array containing all buckets from high to low. */ + private static final PasswordComplexityBucket[] BUCKETS = + new PasswordComplexityBucket[] {HIGH, MEDIUM, LOW}; + + @PasswordComplexity + private final int mComplexityLevel; + private final PasswordMetrics[] mMetrics; + + private PasswordComplexityBucket(@PasswordComplexity int complexityLevel, + PasswordMetrics... metrics) { + this.mComplexityLevel = complexityLevel; + this.mMetrics = metrics; + } + + /** Returns the {@link PasswordMetrics} that meet the min requirements of this bucket. */ + public PasswordMetrics[] getMetrics() { + return mMetrics; + } + + /** Returns the bucket that {@code complexityLevel} represents. */ + public static PasswordComplexityBucket complexityLevelToBucket( + @PasswordComplexity int complexityLevel) { + for (PasswordComplexityBucket bucket : BUCKETS) { + if (bucket.mComplexityLevel == complexityLevel) { + return bucket; + } + } + return NONE; + } + } } |
