Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5eb161d9 authored by Julius D'souza's avatar Julius D'souza Committed by Android (Google) Code Review
Browse files

Merge "KeyguardManager: add lock set and validation methods"

parents ac4abe2c 9367eb81
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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 {
+155 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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;

/**
@@ -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)
@@ -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;
    }
}
+5 −0
Original line number Diff line number Diff line
@@ -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);
+5 −0
Original line number Diff line number Diff line
@@ -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" />