Change BiometricService/AuthController interface to sensorId
This way, AuthController (SystemUI) can query the system to check
specific info for each sensor.
Test: No effect on existing devices
Test: atest com.android.systemui.biometrics
Test: atest com.android.server.biometrics
Bug: 171071087
Change-Id: I2a33aa25aac880764000d296de328d326709d1a0
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 77c7ce8..b9c2fd5 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -145,8 +145,8 @@
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
- int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId);
+ in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
+ String opPackageName, long operationId);
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index bcbbf6e..bb0fd7f 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -106,8 +106,9 @@
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
- int biometricModality, boolean requireConfirmation, int userId, String opPackageName,
- long operationId);
+ in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
+ int userId, String opPackageName,long operationId);
+
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index ab4025f..24ab635 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -24,6 +24,9 @@
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.PromptInfo;
+import android.hardware.face.FaceSensorPropertiesInternal;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -51,6 +54,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
/**
* Top level container/controller for the BiometricPrompt UI.
@@ -76,6 +80,8 @@
final Config mConfig;
final int mEffectiveUserId;
+ @Nullable private final List<FingerprintSensorPropertiesInternal> mFpProps;
+ @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
private final Handler mHandler;
private final Injector mInjector;
private final IBinder mWindowToken = new Binder();
@@ -111,7 +117,8 @@
boolean mRequireConfirmation;
int mUserId;
String mOpPackageName;
- @BiometricAuthenticator.Modality int mModalityMask;
+ int[] mSensorIds;
+ boolean mCredentialAllowed;
boolean mSkipIntro;
long mOperationId;
}
@@ -159,9 +166,12 @@
return this;
}
- public AuthContainerView build(@BiometricAuthenticator.Modality int modalityMask) {
- mConfig.mModalityMask = modalityMask;
- return new AuthContainerView(mConfig, new Injector());
+ public AuthContainerView build(int[] sensorIds, boolean credentialAllowed,
+ @Nullable List<FingerprintSensorPropertiesInternal> fpProps,
+ @Nullable List<FaceSensorPropertiesInternal> faceProps) {
+ mConfig.mSensorIds = sensorIds;
+ mConfig.mCredentialAllowed = credentialAllowed;
+ return new AuthContainerView(mConfig, new Injector(), fpProps, faceProps);
}
}
@@ -242,11 +252,15 @@
}
@VisibleForTesting
- AuthContainerView(Config config, Injector injector) {
+ AuthContainerView(Config config, Injector injector,
+ @Nullable List<FingerprintSensorPropertiesInternal> fpProps,
+ @Nullable List<FaceSensorPropertiesInternal> faceProps) {
super(config.mContext);
mConfig = config;
mInjector = injector;
+ mFpProps = fpProps;
+ mFaceProps = faceProps;
mEffectiveUserId = mInjector.getUserManager(mContext)
.getCredentialOwnerProfile(mConfig.mUserId);
@@ -269,24 +283,29 @@
// Inflate biometric view only if necessary.
if (Utils.isBiometricAllowed(mConfig.mPromptInfo)) {
- final @BiometricAuthenticator.Modality int biometricModality =
- config.mModalityMask & ~BiometricAuthenticator.TYPE_CREDENTIAL;
-
- switch (biometricModality) {
- case BiometricAuthenticator.TYPE_FINGERPRINT:
+ if (config.mSensorIds.length == 1) {
+ final int singleSensorAuthId = config.mSensorIds[0];
+ if (Utils.containsSensorId(mFpProps, singleSensorAuthId)) {
mBiometricView = (AuthBiometricFingerprintView)
factory.inflate(R.layout.auth_biometric_fingerprint_view, null, false);
- break;
- case BiometricAuthenticator.TYPE_FACE:
+ } else if (Utils.containsSensorId(mFaceProps, singleSensorAuthId)) {
mBiometricView = (AuthBiometricFaceView)
factory.inflate(R.layout.auth_biometric_face_view, null, false);
- break;
- default:
- Log.e(TAG, "Unsupported biometric modality: " + biometricModality);
+ } else {
+ // Unknown sensorId
+ Log.e(TAG, "Unknown sensorId: " + singleSensorAuthId);
mBiometricView = null;
mBackgroundView = null;
mBiometricScrollView = null;
return;
+ }
+ } else {
+ // The UI currently only supports authentication with a single sensor.
+ Log.e(TAG, "Unsupported sensor array, length: " + config.mSensorIds.length);
+ mBiometricView = null;
+ mBackgroundView = null;
+ mBiometricScrollView = null;
+ return;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index b1ae56a..a677e91 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -29,12 +29,12 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
-import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.hardware.face.FaceManager;
+import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
@@ -74,8 +74,12 @@
private final StatusBarStateController mStatusBarStateController;
private final IActivityTaskManager mActivityTaskManager;
@Nullable private final FingerprintManager mFingerprintManager;
+ @Nullable private final FaceManager mFaceManager;
private final Provider<UdfpsController> mUdfpsControllerFactory;
+ @Nullable private final List<FingerprintSensorPropertiesInternal> mFpProps;
+ @Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
+
// TODO: These should just be saved from onSaveState
private SomeArgs mCurrentDialogArgs;
@VisibleForTesting
@@ -285,14 +289,20 @@
StatusBarStateController statusBarStateController,
IActivityTaskManager activityTaskManager,
@Nullable FingerprintManager fingerprintManager,
+ @Nullable FaceManager faceManager,
Provider<UdfpsController> udfpsControllerFactory) {
super(context);
mCommandQueue = commandQueue;
mStatusBarStateController = statusBarStateController;
mActivityTaskManager = activityTaskManager;
mFingerprintManager = fingerprintManager;
+ mFaceManager = faceManager;
mUdfpsControllerFactory = udfpsControllerFactory;
+ mFpProps = mFingerprintManager != null ? mFingerprintManager.getSensorPropertiesInternal()
+ : null;
+ mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
+
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -326,24 +336,30 @@
@Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
- @BiometricAuthenticator.Modality int biometricModality, boolean requireConfirmation,
+ int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
int userId, String opPackageName, long operationId) {
@Authenticators.Types final int authenticators = promptInfo.getAuthenticators();
if (DEBUG) {
+ StringBuilder ids = new StringBuilder();
+ for (int sensorId : sensorIds) {
+ ids.append(sensorId).append(" ");
+ }
Log.d(TAG, "showAuthenticationDialog, authenticators: " + authenticators
- + ", biometricModality: " + biometricModality
+ + ", sensorIds: " + ids.toString()
+ + ", credentialAllowed: " + credentialAllowed
+ ", requireConfirmation: " + requireConfirmation
+ ", operationId: " + operationId);
}
SomeArgs args = SomeArgs.obtain();
args.arg1 = promptInfo;
args.arg2 = receiver;
- args.argi1 = biometricModality;
- args.arg3 = requireConfirmation;
- args.argi2 = userId;
- args.arg4 = opPackageName;
- args.arg5 = operationId;
+ args.arg3 = sensorIds;
+ args.arg4 = credentialAllowed;
+ args.arg5 = requireConfirmation;
+ args.argi1 = userId;
+ args.arg6 = opPackageName;
+ args.arg7 = operationId;
boolean skipAnimation = false;
if (mCurrentDialog != null) {
@@ -458,25 +474,28 @@
private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
mCurrentDialogArgs = args;
- final @BiometricAuthenticator.Modality int type = args.argi1;
+
final PromptInfo promptInfo = (PromptInfo) args.arg1;
- final boolean requireConfirmation = (boolean) args.arg3;
- final int userId = args.argi2;
- final String opPackageName = (String) args.arg4;
- final long operationId = (long) args.arg5;
+ final int[] sensorIds = (int[]) args.arg3;
+ final boolean credentialAllowed = (boolean) args.arg4;
+ final boolean requireConfirmation = (boolean) args.arg5;
+ final int userId = args.argi1;
+ final String opPackageName = (String) args.arg6;
+ final long operationId = (long) args.arg7;
// Create a new dialog but do not replace the current one yet.
final AuthDialog newDialog = buildDialog(
promptInfo,
requireConfirmation,
userId,
- type,
+ sensorIds,
+ credentialAllowed,
opPackageName,
skipAnimation,
operationId);
if (newDialog == null) {
- Log.e(TAG, "Unsupported type: " + type);
+ Log.e(TAG, "Unsupported type configuration");
return;
}
@@ -484,8 +503,7 @@
Log.d(TAG, "userId: " + userId
+ " savedState: " + savedState
+ " mCurrentDialog: " + mCurrentDialog
- + " newDialog: " + newDialog
- + " type: " + type);
+ + " newDialog: " + newDialog);
}
if (mCurrentDialog != null) {
@@ -541,7 +559,7 @@
}
protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation,
- int userId, @BiometricAuthenticator.Modality int type, String opPackageName,
+ int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName,
boolean skipIntro, long operationId) {
return new AuthContainerView.Builder(mContext)
.setCallback(this)
@@ -551,6 +569,6 @@
.setOpPackageName(opPackageName)
.setSkipIntro(skipIntro)
.setOperationId(operationId)
- .build(type);
+ .build(sensorIds, credentialAllowed, mFpProps, mFaceProps);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
index 2e9afa5..fd5e85a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
@@ -20,9 +20,11 @@
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.hardware.biometrics.PromptInfo;
+import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.UserManager;
import android.util.DisplayMetrics;
import android.view.ViewGroup;
@@ -33,6 +35,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
public class Utils {
@@ -98,4 +101,19 @@
final UserManager userManager = context.getSystemService(UserManager.class);
return userManager.isManagedProfile(userId);
}
+
+ static boolean containsSensorId(@Nullable List<? extends SensorPropertiesInternal> properties,
+ int sensorId) {
+ if (properties == null) {
+ return false;
+ }
+
+ for (SensorPropertiesInternal prop : properties) {
+ if (prop.sensorId == sensorId) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index dcee9fa..5b3763e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -284,7 +284,7 @@
default void showAuthenticationDialog(PromptInfo promptInfo,
IBiometricSysuiReceiver receiver,
- @BiometricAuthenticator.Modality int biometricModality,
+ int[] sensorIds, boolean credentialAllowed,
boolean requireConfirmation, int userId, String opPackageName,
long operationId) { }
default void onBiometricAuthenticated() { }
@@ -829,17 +829,18 @@
@Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
- @BiometricAuthenticator.Modality int biometricModality, boolean requireConfirmation,
+ int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
int userId, String opPackageName, long operationId) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = promptInfo;
args.arg2 = receiver;
- args.argi1 = biometricModality;
- args.arg3 = requireConfirmation;
- args.argi2 = userId;
- args.arg4 = opPackageName;
- args.arg5 = operationId;
+ args.arg3 = sensorIds; //
+ args.arg4 = credentialAllowed; //
+ args.arg5 = requireConfirmation;
+ args.argi1 = userId;
+ args.arg6 = opPackageName;
+ args.arg7 = operationId;
mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
.sendToTarget();
}
@@ -1264,11 +1265,12 @@
mCallbacks.get(i).showAuthenticationDialog(
(PromptInfo) someArgs.arg1,
(IBiometricSysuiReceiver) someArgs.arg2,
- someArgs.argi1 /* biometricModality */,
- (boolean) someArgs.arg3 /* requireConfirmation */,
- someArgs.argi2 /* userId */,
- (String) someArgs.arg4 /* opPackageName */,
- (long) someArgs.arg5 /* operationId */);
+ (int[]) someArgs.arg3 /* sensorIds */,
+ (boolean) someArgs.arg4 /* credentialAllowed */,
+ (boolean) someArgs.arg5 /* requireConfirmation */,
+ someArgs.argi1 /* userId */,
+ (String) someArgs.arg6 /* opPackageName */,
+ (long) someArgs.arg7 /* operationId */);
}
someArgs.recycle();
break;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
index b60fa4f..777db95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java
@@ -32,10 +32,15 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.PromptInfo;
+import android.hardware.biometrics.SensorProperties;
+import android.hardware.face.FaceSensorPropertiesInternal;
+import android.hardware.fingerprint.FingerprintSensorProperties;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.IBinder;
import android.os.UserManager;
import android.test.suitebuilder.annotation.SmallTest;
@@ -58,6 +63,9 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
+
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
@@ -222,18 +230,28 @@
AuthContainerView.Config config = new AuthContainerView.Config();
config.mContext = mContext;
config.mCallback = mCallback;
- config.mModalityMask |= BiometricAuthenticator.TYPE_FINGERPRINT;
+ config.mSensorIds = new int[] {0};
+ config.mCredentialAllowed = false;
PromptInfo promptInfo = new PromptInfo();
promptInfo.setAuthenticators(authenticators);
config.mPromptInfo = promptInfo;
- mAuthContainer = new TestableAuthContainer(config);
+ final List<FingerprintSensorPropertiesInternal> fpProps = new ArrayList<>();
+ fpProps.add(new FingerprintSensorPropertiesInternal(0,
+ SensorProperties.STRENGTH_STRONG,
+ 5 /* maxEnrollmentsPerUser */,
+ FingerprintSensorProperties.TYPE_REAR,
+ false /* resetLockoutRequiresHardwareAuthToken */));
+ mAuthContainer = new TestableAuthContainer(config, fpProps, null /* faceProps */);
}
private class TestableAuthContainer extends AuthContainerView {
- TestableAuthContainer(AuthContainerView.Config config) {
- super(config, new MockInjector());
+ TestableAuthContainer(AuthContainerView.Config config,
+ @Nullable List<FingerprintSensorPropertiesInternal> fpProps,
+ @Nullable List<FaceSensorPropertiesInternal> faceProps) {
+
+ super(config, new MockInjector(), fpProps, faceProps);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index e0420ca..0186d73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -97,6 +97,8 @@
@Mock
private FingerprintManager mFingerprintManager;
@Mock
+ private FaceManager mFaceManager;
+ @Mock
private UdfpsController mUdfpsController;
private TestableAuthController mAuthController;
@@ -132,7 +134,7 @@
when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
mAuthController = new TestableAuthController(context, mCommandQueue,
- mStatusBarStateController, mActivityTaskManager, mFingerprintManager,
+ mStatusBarStateController, mActivityTaskManager, mFingerprintManager, mFaceManager,
() -> mUdfpsController);
mAuthController.start();
@@ -142,7 +144,7 @@
@Test
public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
null /* credentialAttestation */);
verify(mReceiver).onDialogDismissed(
@@ -152,7 +154,7 @@
@Test
public void testSendsReasonNegative_whenDismissedByButtonNegative() throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE,
null /* credentialAttestation */);
verify(mReceiver).onDialogDismissed(
@@ -162,7 +164,7 @@
@Test
public void testSendsReasonConfirmed_whenDismissedByButtonPositive() throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE,
null /* credentialAttestation */);
verify(mReceiver).onDialogDismissed(
@@ -172,7 +174,7 @@
@Test
public void testSendsReasonConfirmNotRequired_whenDismissedByAuthenticated() throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED,
null /* credentialAttestation */);
verify(mReceiver).onDialogDismissed(
@@ -182,7 +184,7 @@
@Test
public void testSendsReasonError_whenDismissedByError() throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onDismissed(AuthDialogCallback.DISMISSED_ERROR,
null /* credentialAttestation */);
verify(mReceiver).onDialogDismissed(
@@ -192,7 +194,7 @@
@Test
public void testSendsReasonServerRequested_whenDismissedByServer() throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onDismissed(AuthDialogCallback.DISMISSED_BY_SYSTEM_SERVER,
null /* credentialAttestation */);
verify(mReceiver).onDialogDismissed(
@@ -203,7 +205,7 @@
@Test
public void testSendsReasonCredentialConfirmed_whenDeviceCredentialAuthenticated()
throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final byte[] credentialAttestation = generateRandomHAT();
@@ -217,22 +219,21 @@
// Statusbar tests
@Test
- public void testShowInvoked_whenSystemRequested()
- throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ public void testShowInvoked_whenSystemRequested() {
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
verify(mDialog1).show(any(), any());
}
@Test
public void testOnAuthenticationSucceededInvoked_whenSystemRequested() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onBiometricAuthenticated();
verify(mDialog1).onAuthenticationSucceeded();
}
@Test
public void testOnAuthenticationFailedInvoked_whenBiometricRejected() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_NONE,
BiometricConstants.BIOMETRIC_PAUSED_REJECTED,
0 /* vendorCode */);
@@ -245,7 +246,7 @@
@Test
public void testOnAuthenticationFailedInvoked_whenBiometricTimedOut() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int error = BiometricConstants.BIOMETRIC_ERROR_TIMEOUT;
final int vendorCode = 0;
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
@@ -258,7 +259,7 @@
@Test
public void testOnHelpInvoked_whenSystemRequested() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final String helpMessage = "help";
mAuthController.onBiometricHelp(helpMessage);
@@ -269,8 +270,8 @@
}
@Test
- public void testOnErrorInvoked_whenSystemRequested() throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ public void testOnErrorInvoked_whenSystemRequested() {
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int error = 1;
final int vendorCode = 0;
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
@@ -283,7 +284,7 @@
@Test
public void testErrorLockout_whenCredentialAllowed_AnimatesToCredentialUI() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT;
final int vendorCode = 0;
@@ -296,7 +297,7 @@
@Test
public void testErrorLockoutPermanent_whenCredentialAllowed_AnimatesToCredentialUI() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
final int vendorCode = 0;
@@ -309,7 +310,7 @@
@Test
public void testErrorLockout_whenCredentialNotAllowed_sendsOnError() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT;
final int vendorCode = 0;
@@ -322,7 +323,7 @@
@Test
public void testErrorLockoutPermanent_whenCredentialNotAllowed_sendsOnError() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
final int vendorCode = 0;
@@ -335,7 +336,7 @@
@Test
public void testHideAuthenticationDialog_invokesDismissFromSystemServer() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.hideAuthenticationDialog();
verify(mDialog1).dismissFromSystemServer();
@@ -355,7 +356,7 @@
// 1) Credential is confirmed
// 2) Client cancels authentication
- showDialog(Authenticators.DEVICE_CREDENTIAL, BiometricPrompt.TYPE_NONE);
+ showDialog(new int[0] /* sensorIds */, true /* credentialAllowed */);
verify(mDialog1).show(any(), any());
final byte[] credentialAttestation = generateRandomHAT();
@@ -371,10 +372,10 @@
@Test
public void testShowNewDialog_beforeOldDialogDismissed_SkipsAnimations() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
verify(mDialog1).show(any(), any());
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
// First dialog should be dismissed without animation
verify(mDialog1).dismissWithoutCallback(eq(false) /* animate */);
@@ -385,7 +386,7 @@
@Test
public void testConfigurationPersists_whenOnConfigurationChanged() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
verify(mDialog1).show(any(), any());
// Return that the UI is in "showing" state
@@ -415,8 +416,7 @@
@Test
public void testConfigurationPersists_whenBiometricFallbackToCredential() {
- showDialog(Authenticators.DEVICE_CREDENTIAL | Authenticators.BIOMETRIC_WEAK,
- BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, true /* credentialAllowed */);
verify(mDialog1).show(any(), any());
// Pretend that the UI is now showing device credential UI.
@@ -440,7 +440,7 @@
@Test
public void testClientNotified_whenTaskStackChangesDuringAuthentication() throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
List<ActivityManager.RunningTaskInfo> tasks = new ArrayList<>();
ActivityManager.RunningTaskInfo taskInfo = mock(ActivityManager.RunningTaskInfo.class);
@@ -462,7 +462,7 @@
@Test
public void testDoesNotCrash_whenTryAgainPressedAfterDismissal() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
null /* credentialAttestation */);
mAuthController.onTryAgainPressed();
@@ -470,7 +470,7 @@
@Test
public void testDoesNotCrash_whenDeviceCredentialPressedAfterDismissal() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onDismissed(AuthDialogCallback.DISMISSED_USER_CANCELED,
null /* credentialAttestation */);
mAuthController.onDeviceCredentialPressed();
@@ -478,7 +478,7 @@
@Test
public void testActionCloseSystemDialogs_dismissesDialogIfShowing() throws Exception {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FACE);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
mAuthController.mBroadcastReceiver.onReceive(mContext, intent);
waitForIdleSync();
@@ -500,14 +500,14 @@
@Test
public void testOnBiometricAuthenticated_OnCancelAodInterrupt() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FINGERPRINT);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onBiometricAuthenticated();
verify(mUdfpsController).onCancelAodInterrupt();
}
@Test
public void testOnBiometricError_OnCancelAodInterrupt() {
- showDialog(Authenticators.BIOMETRIC_WEAK, BiometricPrompt.TYPE_FINGERPRINT);
+ showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onBiometricError(0, 0, 0);
verify(mUdfpsController).onCancelAodInterrupt();
}
@@ -538,17 +538,18 @@
// Helpers
- private void showDialog(int authenticators, int biometricModality) {
- mAuthController.showAuthenticationDialog(createTestPromptInfo(authenticators),
+ private void showDialog(int[] sensorIds, boolean credentialAllowed) {
+ mAuthController.showAuthenticationDialog(createTestPromptInfo(),
mReceiver /* receiver */,
- biometricModality,
+ sensorIds,
+ credentialAllowed,
true /* requireConfirmation */,
0 /* userId */,
"testPackage",
0 /* operationId */);
}
- private PromptInfo createTestPromptInfo(int authenticators) {
+ private PromptInfo createTestPromptInfo() {
PromptInfo promptInfo = new PromptInfo();
promptInfo.setTitle("Title");
@@ -560,8 +561,6 @@
// by user settings, and should be tested in BiometricService.
promptInfo.setConfirmationRequested(true);
- promptInfo.setAuthenticators(authenticators);
-
return promptInfo;
}
@@ -580,15 +579,16 @@
StatusBarStateController statusBarStateController,
IActivityTaskManager activityTaskManager,
FingerprintManager fingerprintManager,
+ FaceManager faceManager,
Provider<UdfpsController> udfpsControllerFactory) {
super(context, commandQueue, statusBarStateController, activityTaskManager,
- fingerprintManager, udfpsControllerFactory);
+ fingerprintManager, faceManager, udfpsControllerFactory);
}
@Override
protected AuthDialog buildDialog(PromptInfo promptInfo,
- boolean requireConfirmation, int userId, int type, String opPackageName,
- boolean skipIntro, long operationId) {
+ boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed,
+ String opPackageName, boolean skipIntro, long operationId) {
mLastBiometricPromptInfo = promptInfo;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index 8617a83..d2d5708 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -26,6 +26,7 @@
import android.content.ComponentName;
import android.graphics.Rect;
+import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
import android.os.Bundle;
import android.view.WindowInsetsController.Appearance;
@@ -409,13 +410,20 @@
@Test
public void testShowAuthenticationDialog() {
PromptInfo promptInfo = new PromptInfo();
- String packageName = "test";
+ final IBiometricSysuiReceiver receiver = mock(IBiometricSysuiReceiver.class);
+ final int[] sensorIds = {1, 2};
+ final boolean credentialAllowed = true;
+ final boolean requireConfirmation = true;
+ final int userId = 10;
+ final String packageName = "test";
final long operationId = 1;
- mCommandQueue.showAuthenticationDialog(promptInfo, null /* receiver */, 1, true, 3,
- packageName, operationId);
+
+ mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds,
+ credentialAllowed, requireConfirmation , userId, packageName, operationId);
waitForIdleSync();
- verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(null), eq(1), eq(true),
- eq(3), eq(packageName), eq(operationId));
+ verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds),
+ eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(packageName),
+ eq(operationId));
}
@Test
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index 15dc956..3c18cd4 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -44,6 +44,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
/**
@@ -241,7 +243,8 @@
mStatusBarService.showAuthenticationDialog(
mPromptInfo,
mSysuiReceiver,
- 0 /* biometricModality */,
+ new int[0] /* sensorIds */,
+ true /* credentialAllowed */,
false /* requireConfirmation */,
mUserId,
mOpPackageName,
@@ -271,11 +274,16 @@
try {
// If any sensor requires confirmation, request it to be shown.
final boolean requireConfirmation = isConfirmationRequiredByAnyEligibleSensor();
- final @BiometricAuthenticator.Modality int modality =
- getEligibleModalities();
+
+ final int[] sensorIds = new int[mPreAuthInfo.eligibleSensors.size()];
+ for (int i = 0; i < mPreAuthInfo.eligibleSensors.size(); i++) {
+ sensorIds[i] = mPreAuthInfo.eligibleSensors.get(i).id;
+ }
+
mStatusBarService.showAuthenticationDialog(mPromptInfo,
mSysuiReceiver,
- modality,
+ sensorIds,
+ mPreAuthInfo.shouldShowCredential(),
requireConfirmation,
mUserId,
mOpPackageName,
@@ -369,7 +377,8 @@
mStatusBarService.showAuthenticationDialog(
mPromptInfo,
mSysuiReceiver,
- 0 /* biometricModality */,
+ new int[0] /* sensorIds */,
+ true /* credentialAllowed */,
false /* requireConfirmation */,
mUserId,
mOpPackageName,
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index 08a6171..6905b3d 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -32,7 +32,6 @@
import android.util.Pair;
import android.util.Slog;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.sensors.LockoutTracker;
import java.lang.annotation.Retention;
@@ -356,6 +355,13 @@
}
/**
+ * @return true if SystemUI should show the credential UI.
+ */
+ boolean shouldShowCredential() {
+ return credentialRequested && credentialAvailable;
+ }
+
+ /**
* @return bitmask representing the modalities that are running or could be running for the
* current session.
*/
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 55cb7f3..fb47ebb 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -706,12 +706,12 @@
@Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
- @BiometricAuthenticator.Modality int biometricModality, boolean requireConfirmation,
+ int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
int userId, String opPackageName, long operationId) {
enforceBiometricDialog();
if (mBar != null) {
try {
- mBar.showAuthenticationDialog(promptInfo, receiver, biometricModality,
+ mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed,
requireConfirmation, userId, opPackageName, operationId);
} catch (RemoteException ex) {
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index f0be9f1..3b60594 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -262,7 +262,8 @@
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mPromptInfo),
any(IBiometricSysuiReceiver.class),
- eq(0),
+ AdditionalMatchers.aryEq(new int[0]) /* sensorIds */,
+ eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
@@ -345,7 +346,8 @@
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mPromptInfo),
any(IBiometricSysuiReceiver.class),
- eq(BiometricAuthenticator.TYPE_FACE),
+ AdditionalMatchers.aryEq(new int[] {SENSOR_ID_FACE}),
+ eq(false) /* credentialAllowed */,
eq(false) /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
@@ -477,7 +479,8 @@
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mPromptInfo),
any(IBiometricSysuiReceiver.class),
- eq(BiometricAuthenticator.TYPE_FINGERPRINT),
+ any(),
+ eq(false) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
@@ -530,7 +533,8 @@
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mPromptInfo),
any(IBiometricSysuiReceiver.class),
- eq(0 /* biometricModality */),
+ AdditionalMatchers.aryEq(new int[0]) /* sensorIds */,
+ eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
@@ -696,7 +700,8 @@
verify(mBiometricService.mStatusBarService, never()).showAuthenticationDialog(
any(PromptInfo.class),
any(IBiometricSysuiReceiver.class),
- anyInt(),
+ any() /* sensorIds */,
+ anyBoolean() /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
anyString(),
@@ -796,7 +801,8 @@
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mPromptInfo),
any(IBiometricSysuiReceiver.class),
- eq(0 /* biometricModality */),
+ AdditionalMatchers.aryEq(new int[0]) /* sensorIds */,
+ eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
@@ -874,7 +880,8 @@
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mPromptInfo),
any(IBiometricSysuiReceiver.class),
- eq(0 /* biometricModality */),
+ AdditionalMatchers.aryEq(new int[0]) /* sensorIds */,
+ eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
@@ -1383,7 +1390,8 @@
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mPromptInfo),
any(IBiometricSysuiReceiver.class),
- eq(BiometricAuthenticator.TYPE_FINGERPRINT /* biometricModality */),
+ AdditionalMatchers.aryEq(new int[] {testId}),
+ eq(false) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
@@ -1403,7 +1411,8 @@
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mPromptInfo),
any(IBiometricSysuiReceiver.class),
- eq(BiometricAuthenticator.TYPE_NONE /* biometricModality */),
+ AdditionalMatchers.aryEq(new int[0]) /* sensorIds */,
+ eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),
@@ -1426,7 +1435,8 @@
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
eq(mBiometricService.mCurrentAuthSession.mPromptInfo),
any(IBiometricSysuiReceiver.class),
- eq(BiometricAuthenticator.TYPE_FINGERPRINT /* biometricModality */),
+ AdditionalMatchers.aryEq(new int[] {testId}) /* sensorIds */,
+ eq(false) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
eq(TEST_PACKAGE_NAME),