Loading api/system-current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -628,9 +628,12 @@ package android.app { public class KeyguardManager { method public android.content.Intent createConfirmFactoryResetCredentialIntent(CharSequence, CharSequence, CharSequence); method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public int getMinLockLength(boolean, int); method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public boolean getPrivateNotificationsAllowed(); method @RequiresPermission(android.Manifest.permission.SHOW_KEYGUARD_MESSAGE) public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable CharSequence, @Nullable android.app.KeyguardManager.KeyguardDismissCallback); method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean setLock(int, @NonNull byte[], int); method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public void setPrivateNotificationsAllowed(boolean); method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean validateLockPasswordComplexity(boolean, @NonNull byte[], int); } public class Notification implements android.os.Parcelable { Loading core/java/android/app/KeyguardManager.java +155 −2 Original line number Diff line number Diff line Loading @@ -17,19 +17,21 @@ package android.app; import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.admin.DevicePolicyManager; import android.app.admin.PasswordMetrics; import android.app.trust.ITrustManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.hardware.biometrics.BiometricPrompt; import android.os.Binder; import android.os.Build; import android.os.IBinder; Loading @@ -46,7 +48,11 @@ import android.view.WindowManagerGlobal; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockscreenCredential; import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; /** Loading Loading @@ -134,7 +140,7 @@ public class KeyguardManager { * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. * * @return the intent for launching the activity or null if no password is required. * @deprecated see {@link BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean)} * @deprecated see BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean) */ @Deprecated @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) Loading Loading @@ -655,4 +661,151 @@ public class KeyguardManager { } } private boolean checkInitialLockMethodUsage() { if (mContext.checkCallingOrSelfPermission(Manifest.permission.SET_INITIAL_LOCK) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires SET_INITIAL_LOCK permission."); } if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { return false; } return true; } /** * Determine if a given password is valid based off its lock type and expected complexity level. * * @param isPin - whether this is a PIN-type password (only digits) * @param password - password to validate * @param complexity - complexity level imposed by the requester * as defined in {@code DevicePolicyManager.PasswordComplexity} * @return true if the password is valid, false otherwise * @hide */ @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) @SystemApi public boolean validateLockPasswordComplexity( boolean isPin, @NonNull byte[] password, int complexity) { if (!checkInitialLockMethodUsage()) { return false; } complexity = PasswordMetrics.sanitizeComplexityLevel(complexity); // TODO: b/131755827 add devicePolicyManager support for Auto DevicePolicyManager devicePolicyManager = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); PasswordMetrics adminMetrics = devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId()); return PasswordMetrics.validatePassword( adminMetrics, complexity, isPin, password).size() == 0; } /** * Determine the minimum allowable length for a lock type for a given complexity level. * * @param isPin - whether this is a PIN-type password (only digits) * @param complexity - complexity level imposed by the requester * as defined in {@code DevicePolicyManager.PasswordComplexity} * @return minimum allowable password length * @hide */ @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) @SystemApi public int getMinLockLength(boolean isPin, int complexity) { if (!checkInitialLockMethodUsage()) { return -1; } complexity = PasswordMetrics.sanitizeComplexityLevel(complexity); // TODO: b/131755827 add devicePolicyManager support for Auto DevicePolicyManager devicePolicyManager = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); PasswordMetrics adminMetrics = devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId()); PasswordMetrics minMetrics = PasswordMetrics.applyComplexity(adminMetrics, isPin, complexity); return minMetrics.length; } /** * Set the lockscreen password after validating against its expected complexity level. * * @param lockType - type of lock as specified in {@link LockTypes} * @param password - password to validate * @param complexity - complexity level imposed by the requester * as defined in {@code DevicePolicyManager.PasswordComplexity} * @return true if the lock is successfully set, false otherwise * @hide */ @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) @SystemApi public boolean setLock(@LockTypes int lockType, @NonNull byte[] password, int complexity) { if (!checkInitialLockMethodUsage()) { return false; } LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); int userId = mContext.getUserId(); if (isDeviceSecure(userId)) { Log.e(TAG, "Password already set, rejecting call to setLock"); return false; } if (!validateLockPasswordComplexity(lockType != LockTypes.PASSWORD, password, complexity)) { Log.e(TAG, "Password is not valid, rejecting call to setLock"); return false; } boolean success = false; try { switch (lockType) { case LockTypes.PASSWORD: CharSequence passwordStr = new String(password, Charset.forName("UTF-8")); lockPatternUtils.setLockCredential( LockscreenCredential.createPassword(passwordStr), /* savedPassword= */ LockscreenCredential.createNone(), userId); success = true; break; case LockTypes.PIN: CharSequence pinStr = new String(password); lockPatternUtils.setLockCredential( LockscreenCredential.createPin(pinStr), /* savedPassword= */ LockscreenCredential.createNone(), userId); success = true; break; case LockTypes.PATTERN: List<LockPatternView.Cell> pattern = LockPatternUtils.byteArrayToPattern(password); lockPatternUtils.setLockCredential( LockscreenCredential.createPattern(pattern), /* savedPassword= */ LockscreenCredential.createNone(), userId); pattern.clear(); success = true; break; default: Log.e(TAG, "Unknown lock type, returning a failure"); } } catch (Exception e) { Log.e(TAG, "Save lock exception", e); success = false; } finally { Arrays.fill(password, (byte) 0); } return success; } /** * Available lock types */ @IntDef({ LockTypes.PASSWORD, LockTypes.PIN, LockTypes.PATTERN }) @interface LockTypes { int PASSWORD = 0; int PIN = 1; int PATTERN = 2; } } core/java/android/app/admin/PasswordMetrics.java +5 −0 Original line number Diff line number Diff line Loading @@ -682,6 +682,11 @@ public final class PasswordMetrics implements Parcelable { * * TODO: move to PasswordPolicy */ public static PasswordMetrics applyComplexity( PasswordMetrics adminMetrics, boolean isPin, int complexity) { return applyComplexity(adminMetrics, isPin, ComplexityBucket.forComplexity(complexity)); } private static PasswordMetrics applyComplexity( PasswordMetrics adminMetrics, boolean isPin, ComplexityBucket bucket) { final PasswordMetrics minMetrics = new PasswordMetrics(adminMetrics); Loading core/res/AndroidManifest.xml +5 −0 Original line number Diff line number Diff line Loading @@ -4307,6 +4307,11 @@ <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" android:protectionLevel="signature" /> <!-- Allows applications to set the initial lockscreen state. <p>Not for use by third-party applications. @hide --> <permission android:name="android.permission.SET_INITIAL_LOCK" android:protectionLevel="signature|setup"/> <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide --> <permission android:name="android.permission.MANAGE_FINGERPRINT" android:protectionLevel="signature|privileged" /> Loading Loading
api/system-current.txt +3 −0 Original line number Diff line number Diff line Loading @@ -628,9 +628,12 @@ package android.app { public class KeyguardManager { method public android.content.Intent createConfirmFactoryResetCredentialIntent(CharSequence, CharSequence, CharSequence); method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public int getMinLockLength(boolean, int); method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public boolean getPrivateNotificationsAllowed(); method @RequiresPermission(android.Manifest.permission.SHOW_KEYGUARD_MESSAGE) public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable CharSequence, @Nullable android.app.KeyguardManager.KeyguardDismissCallback); method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean setLock(int, @NonNull byte[], int); method @RequiresPermission(android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS) public void setPrivateNotificationsAllowed(boolean); method @RequiresPermission("android.permission.SET_INITIAL_LOCK") public boolean validateLockPasswordComplexity(boolean, @NonNull byte[], int); } public class Notification implements android.os.Parcelable { Loading
core/java/android/app/KeyguardManager.java +155 −2 Original line number Diff line number Diff line Loading @@ -17,19 +17,21 @@ package android.app; import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.admin.DevicePolicyManager; import android.app.admin.PasswordMetrics; import android.app.trust.ITrustManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.hardware.biometrics.BiometricPrompt; import android.os.Binder; import android.os.Build; import android.os.IBinder; Loading @@ -46,7 +48,11 @@ import android.view.WindowManagerGlobal; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockscreenCredential; import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; /** Loading Loading @@ -134,7 +140,7 @@ public class KeyguardManager { * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge. * * @return the intent for launching the activity or null if no password is required. * @deprecated see {@link BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean)} * @deprecated see BiometricPrompt.Builder#setDeviceCredentialAllowed(boolean) */ @Deprecated @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN) Loading Loading @@ -655,4 +661,151 @@ public class KeyguardManager { } } private boolean checkInitialLockMethodUsage() { if (mContext.checkCallingOrSelfPermission(Manifest.permission.SET_INITIAL_LOCK) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires SET_INITIAL_LOCK permission."); } if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { return false; } return true; } /** * Determine if a given password is valid based off its lock type and expected complexity level. * * @param isPin - whether this is a PIN-type password (only digits) * @param password - password to validate * @param complexity - complexity level imposed by the requester * as defined in {@code DevicePolicyManager.PasswordComplexity} * @return true if the password is valid, false otherwise * @hide */ @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) @SystemApi public boolean validateLockPasswordComplexity( boolean isPin, @NonNull byte[] password, int complexity) { if (!checkInitialLockMethodUsage()) { return false; } complexity = PasswordMetrics.sanitizeComplexityLevel(complexity); // TODO: b/131755827 add devicePolicyManager support for Auto DevicePolicyManager devicePolicyManager = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); PasswordMetrics adminMetrics = devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId()); return PasswordMetrics.validatePassword( adminMetrics, complexity, isPin, password).size() == 0; } /** * Determine the minimum allowable length for a lock type for a given complexity level. * * @param isPin - whether this is a PIN-type password (only digits) * @param complexity - complexity level imposed by the requester * as defined in {@code DevicePolicyManager.PasswordComplexity} * @return minimum allowable password length * @hide */ @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) @SystemApi public int getMinLockLength(boolean isPin, int complexity) { if (!checkInitialLockMethodUsage()) { return -1; } complexity = PasswordMetrics.sanitizeComplexityLevel(complexity); // TODO: b/131755827 add devicePolicyManager support for Auto DevicePolicyManager devicePolicyManager = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); PasswordMetrics adminMetrics = devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId()); PasswordMetrics minMetrics = PasswordMetrics.applyComplexity(adminMetrics, isPin, complexity); return minMetrics.length; } /** * Set the lockscreen password after validating against its expected complexity level. * * @param lockType - type of lock as specified in {@link LockTypes} * @param password - password to validate * @param complexity - complexity level imposed by the requester * as defined in {@code DevicePolicyManager.PasswordComplexity} * @return true if the lock is successfully set, false otherwise * @hide */ @RequiresPermission(Manifest.permission.SET_INITIAL_LOCK) @SystemApi public boolean setLock(@LockTypes int lockType, @NonNull byte[] password, int complexity) { if (!checkInitialLockMethodUsage()) { return false; } LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext); int userId = mContext.getUserId(); if (isDeviceSecure(userId)) { Log.e(TAG, "Password already set, rejecting call to setLock"); return false; } if (!validateLockPasswordComplexity(lockType != LockTypes.PASSWORD, password, complexity)) { Log.e(TAG, "Password is not valid, rejecting call to setLock"); return false; } boolean success = false; try { switch (lockType) { case LockTypes.PASSWORD: CharSequence passwordStr = new String(password, Charset.forName("UTF-8")); lockPatternUtils.setLockCredential( LockscreenCredential.createPassword(passwordStr), /* savedPassword= */ LockscreenCredential.createNone(), userId); success = true; break; case LockTypes.PIN: CharSequence pinStr = new String(password); lockPatternUtils.setLockCredential( LockscreenCredential.createPin(pinStr), /* savedPassword= */ LockscreenCredential.createNone(), userId); success = true; break; case LockTypes.PATTERN: List<LockPatternView.Cell> pattern = LockPatternUtils.byteArrayToPattern(password); lockPatternUtils.setLockCredential( LockscreenCredential.createPattern(pattern), /* savedPassword= */ LockscreenCredential.createNone(), userId); pattern.clear(); success = true; break; default: Log.e(TAG, "Unknown lock type, returning a failure"); } } catch (Exception e) { Log.e(TAG, "Save lock exception", e); success = false; } finally { Arrays.fill(password, (byte) 0); } return success; } /** * Available lock types */ @IntDef({ LockTypes.PASSWORD, LockTypes.PIN, LockTypes.PATTERN }) @interface LockTypes { int PASSWORD = 0; int PIN = 1; int PATTERN = 2; } }
core/java/android/app/admin/PasswordMetrics.java +5 −0 Original line number Diff line number Diff line Loading @@ -682,6 +682,11 @@ public final class PasswordMetrics implements Parcelable { * * TODO: move to PasswordPolicy */ public static PasswordMetrics applyComplexity( PasswordMetrics adminMetrics, boolean isPin, int complexity) { return applyComplexity(adminMetrics, isPin, ComplexityBucket.forComplexity(complexity)); } private static PasswordMetrics applyComplexity( PasswordMetrics adminMetrics, boolean isPin, ComplexityBucket bucket) { final PasswordMetrics minMetrics = new PasswordMetrics(adminMetrics); Loading
core/res/AndroidManifest.xml +5 −0 Original line number Diff line number Diff line Loading @@ -4307,6 +4307,11 @@ <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" android:protectionLevel="signature" /> <!-- Allows applications to set the initial lockscreen state. <p>Not for use by third-party applications. @hide --> <permission android:name="android.permission.SET_INITIAL_LOCK" android:protectionLevel="signature|setup"/> <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide --> <permission android:name="android.permission.MANAGE_FINGERPRINT" android:protectionLevel="signature|privileged" /> Loading