Enable biometric support to unlock profiles
This change ensures the ConfirmCredentialActivity allows biometric
authentication to unlock (or disable quiet mode for) a profile if
the profile storage is unlocked when in quiet mode.
Test: atest SettingsRoboTest
Bug: 312184187
Change-Id: Iefcebf2f93403591a1a4c50ff5da8d6055a37b03
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
index a0db4ce..2a299c5 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
@@ -43,6 +43,7 @@
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.util.Log;
import android.view.WindowManager;
@@ -292,7 +293,7 @@
// use, which optionally accepts a challenge.
mForceVerifyPath = true;
if (isBiometricAllowed(effectiveUserId, mUserId)) {
- showBiometricPrompt(promptInfo);
+ showBiometricPrompt(promptInfo, mUserId);
launchedBiometric = true;
} else {
showConfirmCredentials();
@@ -302,19 +303,25 @@
&& userProperties != null
&& userProperties.isAuthAlwaysRequiredToDisableQuietMode()
&& isInternalActivity()) {
- // Force verification path is required to be invoked as we might need to verify the tied
- // profile challenge if the profile is using the unified challenge mode. This would
- // result in ConfirmLockPassword.startVerifyPassword/
+ // Force verification path is required to be invoked as we might need to verify the
+ // tied profile challenge if the profile is using the unified challenge mode. This
+ // would result in ConfirmLockPassword.startVerifyPassword/
// ConfirmLockPattern.startVerifyPattern being called instead of the
// startCheckPassword/startCheckPattern
mForceVerifyPath = userProperties.isCredentialShareableWithParent();
- showConfirmCredentials();
- launchedCDC = true;
+ if (android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()
+ && isBiometricAllowed(effectiveUserId, mUserId)) {
+ showBiometricPrompt(promptInfo, effectiveUserId);
+ launchedBiometric = true;
+ } else {
+ showConfirmCredentials();
+ launchedCDC = true;
+ }
} else {
if (isBiometricAllowed(effectiveUserId, mUserId)) {
// Don't need to check if biometrics / pin/pattern/pass are enrolled. It will go to
// onAuthenticationError and do the right thing automatically.
- showBiometricPrompt(promptInfo);
+ showBiometricPrompt(promptInfo, mUserId);
launchedBiometric = true;
} else {
showConfirmCredentials();
@@ -400,7 +407,19 @@
// biometric is disabled due to device restart.
private boolean isStrongAuthRequired(int effectiveUserId) {
return !mLockPatternUtils.isBiometricAllowedForUser(effectiveUserId)
- || !mUserManager.isUserUnlocked(mUserId);
+ || doesUserStateEnforceStrongAuth(mUserId);
+ }
+
+ private boolean doesUserStateEnforceStrongAuth(int userId) {
+ if (android.os.Flags.allowPrivateProfile()
+ && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
+ // Check if CE storage for user is locked since biometrics can't unlock fbe/keystore of
+ // the profile user using verifyTiedProfileChallenge. Biometrics can still be used if
+ // the user is stopped with delayed locking (i.e., with storage unlocked), so the user
+ // state (whether the user is in the RUNNING_UNLOCKED state) should not be relied upon.
+ return !StorageManager.isUserKeyUnlocked(userId);
+ }
+ return !mUserManager.isUserUnlocked(userId);
}
private boolean isBiometricAllowed(int effectiveUserId, int realUserId) {
@@ -408,7 +427,7 @@
.hasPendingEscrowToken(realUserId);
}
- private void showBiometricPrompt(PromptInfo promptInfo) {
+ private void showBiometricPrompt(PromptInfo promptInfo, int userId) {
mBiometricFragment = (BiometricFragment) getSupportFragmentManager()
.findFragmentByTag(TAG_BIOMETRIC_FRAGMENT);
boolean newFragment = false;
@@ -418,7 +437,9 @@
newFragment = true;
}
mBiometricFragment.setCallbacks(mExecutor, mAuthenticationCallback);
- mBiometricFragment.setUser(mUserId);
+ // TODO(b/315864564): Move the logic of choosing the user id against which the
+ // authentication needs to happen to the BiometricPrompt API
+ mBiometricFragment.setUser(userId);
if (newFragment) {
getSupportFragmentManager().beginTransaction()