Merge "Fix feedback and animations for face to fingerprint fallback authentication." into sc-dev

This commit is contained in:
Joe Bolinger
2021-06-04 00:12:40 +00:00
committed by Android (Google) Code Review
17 changed files with 219 additions and 92 deletions

View File

@@ -67,7 +67,8 @@ public interface BiometricAuthenticator {
TYPE_NONE, TYPE_NONE,
TYPE_CREDENTIAL, TYPE_CREDENTIAL,
TYPE_FINGERPRINT, TYPE_FINGERPRINT,
TYPE_IRIS TYPE_IRIS,
TYPE_FACE
}) })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@interface Modality {} @interface Modality {}

View File

@@ -143,17 +143,25 @@ oneway interface IStatusBar
void showShutdownUi(boolean isReboot, String reason); void showShutdownUi(boolean isReboot, String reason);
// Used to show the authentication dialog (Biometrics, Device Credential) /**
* Used to show the authentication dialog (Biometrics, Device Credential).
*/
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver, void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId, in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
String opPackageName, long operationId, int multiSensorConfig); String opPackageName, long operationId, int multiSensorConfig);
// Used to notify the authentication dialog that a biometric has been authenticated /**
* Used to notify the authentication dialog that a biometric has been authenticated.
*/
void onBiometricAuthenticated(); void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc /**
void onBiometricHelp(String message); * Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc.
// Used to show an error - the dialog will dismiss after a certain amount of time */
void onBiometricHelp(int modality, String message);
/** Used to show an error - the dialog will dismiss after a certain amount of time. */
void onBiometricError(int modality, int error, int vendorCode); void onBiometricError(int modality, int error, int vendorCode);
// Used to hide the authentication dialog, e.g. when the application cancels authentication /**
* Used to hide the authentication dialog, e.g. when the application cancels authentication.
*/
void hideAuthenticationDialog(); void hideAuthenticationDialog();
/** /**

View File

@@ -115,7 +115,7 @@ interface IStatusBarService
// Used to notify the authentication dialog that a biometric has been authenticated // Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated(); void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
void onBiometricHelp(String message); void onBiometricHelp(int modality, String message);
// Used to show an error - the dialog will dismiss after a certain amount of time // Used to show an error - the dialog will dismiss after a certain amount of time
void onBiometricError(int modality, int error, int vendorCode); void onBiometricError(int modality, int error, int vendorCode);
// Used to hide the authentication dialog, e.g. when the application cancels authentication // Used to hide the authentication dialog, e.g. when the application cancels authentication

View File

@@ -22,7 +22,7 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRIN
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
@@ -87,9 +87,11 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
} }
} }
@BiometricAuthenticator.Modality private int mActiveSensorType = TYPE_FACE; @Modality
private int mActiveSensorType = TYPE_FACE;
@Nullable UdfpsDialogMeasureAdapter mUdfpsMeasureAdapter; @Nullable
private UdfpsDialogMeasureAdapter mUdfpsMeasureAdapter;
public AuthBiometricFaceToFingerprintView(Context context) { public AuthBiometricFaceToFingerprintView(Context context) {
super(context); super(context);
@@ -125,6 +127,16 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
return false; return false;
} }
@Override
public void onAuthenticationFailed(
@Modality int modality, @Nullable String failureReason) {
if (modality == TYPE_FACE && mActiveSensorType == TYPE_FACE) {
// switching from face -> fingerprint mode, suppress soft error messages
failureReason = mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead);
}
super.onAuthenticationFailed(modality, failureReason);
}
@Override @Override
@BiometricState @BiometricState
protected int getStateForAfterError() { protected int getStateForAfterError() {
@@ -155,7 +167,7 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
} }
@Override @Override
public void updateState(int newState) { public void updateState(@BiometricState int newState) {
if (mState == STATE_HELP || mState == STATE_ERROR) { if (mState == STATE_HELP || mState == STATE_ERROR) {
mActiveSensorType = TYPE_FINGERPRINT; mActiveSensorType = TYPE_FINGERPRINT;

View File

@@ -21,6 +21,7 @@ import android.content.Context;
import android.graphics.drawable.Animatable2; import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.AttributeSet; import android.util.AttributeSet;
@@ -29,6 +30,8 @@ import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R; import com.android.systemui.R;
@@ -206,7 +209,7 @@ public class AuthBiometricFaceView extends AuthBiometricView {
} }
@Override @Override
public void onAuthenticationFailed(String failureReason) { public void onAuthenticationFailed(@Modality int modality, @Nullable String failureReason) {
if (getSize() == AuthDialog.SIZE_MEDIUM) { if (getSize() == AuthDialog.SIZE_MEDIUM) {
if (supportsManualRetry()) { if (supportsManualRetry()) {
mTryAgainButton.setVisibility(View.VISIBLE); mTryAgainButton.setVisibility(View.VISIBLE);
@@ -216,7 +219,7 @@ public class AuthBiometricFaceView extends AuthBiometricView {
// Do this last since we want to know if the button is being animated (in the case of // Do this last since we want to know if the button is being animated (in the case of
// small -> medium dialog) // small -> medium dialog)
super.onAuthenticationFailed(failureReason); super.onAuthenticationFailed(modality, failureReason);
} }
private void resetErrorView() { private void resetErrorView() {

View File

@@ -16,6 +16,8 @@
package com.android.systemui.biometrics; package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet; import android.animation.AnimatorSet;
@@ -24,6 +26,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.PromptInfo;
import android.os.Bundle; import android.os.Bundle;
@@ -542,12 +545,25 @@ public abstract class AuthBiometricView extends LinearLayout {
} }
} }
public void onAuthenticationFailed(String failureReason) { /**
* Notify the view that auth has failed.
*
* @param modality sensor modality that failed
* @param failureReason message
*/
public void onAuthenticationFailed(
@Modality int modality, @Nullable String failureReason) {
showTemporaryMessage(failureReason, mResetErrorRunnable); showTemporaryMessage(failureReason, mResetErrorRunnable);
updateState(STATE_ERROR); updateState(STATE_ERROR);
} }
public void onError(String error) { /**
* Notify the view that an error occurred.
*
* @param modality sensor modality that failed
* @param error message
*/
public void onError(@Modality int modality, String error) {
showTemporaryMessage(error, mResetErrorRunnable); showTemporaryMessage(error, mResetErrorRunnable);
updateState(STATE_ERROR); updateState(STATE_ERROR);
@@ -556,11 +572,22 @@ public abstract class AuthBiometricView extends LinearLayout {
}, mInjector.getDelayAfterError()); }, mInjector.getDelayAfterError());
} }
public void onHelp(String help) { /**
* Show a help message to the user.
*
* @param modality sensor modality
* @param help message
*/
public void onHelp(@Modality int modality, String help) {
if (mSize != AuthDialog.SIZE_MEDIUM) { if (mSize != AuthDialog.SIZE_MEDIUM) {
Log.w(TAG, "Help received in size: " + mSize); Log.w(TAG, "Help received in size: " + mSize);
return; return;
} }
if (TextUtils.isEmpty(help)) {
Log.w(TAG, "Ignoring blank help message");
return;
}
showTemporaryMessage(help, mResetHelpRunnable); showTemporaryMessage(help, mResetHelpRunnable);
updateState(STATE_HELP); updateState(STATE_HELP);
} }
@@ -828,10 +855,10 @@ public abstract class AuthBiometricView extends LinearLayout {
final String indicatorText = final String indicatorText =
mSavedState.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING); mSavedState.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING);
if (mSavedState.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_HELP_SHOWING)) { if (mSavedState.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_HELP_SHOWING)) {
onHelp(indicatorText); onHelp(TYPE_NONE, indicatorText);
} else if (mSavedState.getBoolean( } else if (mSavedState.getBoolean(
AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)) { AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)) {
onAuthenticationFailed(indicatorText); onAuthenticationFailed(TYPE_NONE, indicatorText);
} }
} }
} }

View File

@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.PromptInfo;
import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.FaceSensorPropertiesInternal;
@@ -598,18 +599,18 @@ public class AuthContainerView extends LinearLayout
} }
@Override @Override
public void onAuthenticationFailed(String failureReason) { public void onAuthenticationFailed(@Modality int modality, String failureReason) {
mBiometricView.onAuthenticationFailed(failureReason); mBiometricView.onAuthenticationFailed(modality, failureReason);
} }
@Override @Override
public void onHelp(String help) { public void onHelp(@Modality int modality, String help) {
mBiometricView.onHelp(help); mBiometricView.onHelp(modality, help);
} }
@Override @Override
public void onError(String error) { public void onError(@Modality int modality, String error) {
mBiometricView.onError(error); mBiometricView.onError(modality, error);
} }
@Override @Override

View File

@@ -18,8 +18,6 @@ package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators;
import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
@@ -33,7 +31,10 @@ import android.content.IntentFilter;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.RectF; import android.graphics.RectF;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.PromptInfo;
@@ -525,11 +526,11 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
} }
@Override @Override
public void onBiometricHelp(String message) { public void onBiometricHelp(@Modality int modality, String message) {
if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message); if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
if (mCurrentDialog != null) { if (mCurrentDialog != null) {
mCurrentDialog.onHelp(message); mCurrentDialog.onHelp(modality, message);
} else { } else {
Log.w(TAG, "onBiometricHelp callback but dialog gone"); Log.w(TAG, "onBiometricHelp callback but dialog gone");
} }
@@ -540,7 +541,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
return mUdfpsProps; return mUdfpsProps;
} }
private String getErrorString(int modality, int error, int vendorCode) { private String getErrorString(@Modality int modality, int error, int vendorCode) {
switch (modality) { switch (modality) {
case TYPE_FACE: case TYPE_FACE:
return FaceManager.getErrorString(mContext, error, vendorCode); return FaceManager.getErrorString(mContext, error, vendorCode);
@@ -559,7 +560,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
* example, KeyguardUpdateMonitor has its own {@link FingerprintManager.AuthenticationCallback}. * example, KeyguardUpdateMonitor has its own {@link FingerprintManager.AuthenticationCallback}.
*/ */
@Override @Override
public void onBiometricError(int modality, int error, int vendorCode) { public void onBiometricError(@Modality int modality, int error, int vendorCode) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, String.format("onBiometricError(%d, %d, %d)", modality, error, vendorCode)); Log.d(TAG, String.format("onBiometricError(%d, %d, %d)", modality, error, vendorCode));
} }
@@ -580,11 +581,11 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
? mContext.getString(R.string.biometric_not_recognized) ? mContext.getString(R.string.biometric_not_recognized)
: getErrorString(modality, error, vendorCode); : getErrorString(modality, error, vendorCode);
if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage); if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
mCurrentDialog.onAuthenticationFailed(errorMessage); mCurrentDialog.onAuthenticationFailed(modality, errorMessage);
} else { } else {
final String errorMessage = getErrorString(modality, error, vendorCode); final String errorMessage = getErrorString(modality, error, vendorCode);
if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage); if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
mCurrentDialog.onError(errorMessage); mCurrentDialog.onError(modality, errorMessage);
} }
} else { } else {
Log.w(TAG, "onBiometricError callback but dialog is gone"); Log.w(TAG, "onBiometricError callback but dialog is gone");

View File

@@ -19,6 +19,7 @@ package com.android.systemui.biometrics;
import android.annotation.IntDef; import android.annotation.IntDef;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.os.Bundle; import android.os.Bundle;
import android.view.WindowManager; import android.view.WindowManager;
@@ -112,21 +113,24 @@ public interface AuthDialog {
/** /**
* Authentication failed (reject, timeout). Dialog stays showing. * Authentication failed (reject, timeout). Dialog stays showing.
* @param failureReason * @param modality sensor modality that triggered the error
* @param failureReason message
*/ */
void onAuthenticationFailed(String failureReason); void onAuthenticationFailed(@Modality int modality, String failureReason);
/** /**
* Authentication rejected, or help message received. * Authentication rejected, or help message received.
* @param help * @param modality sensor modality that triggered the help message
* @param help message
*/ */
void onHelp(String help); void onHelp(@Modality int modality, String help);
/** /**
* Authentication failed. Dialog going away. * Authentication failed. Dialog going away.
* @param error * @param modality sensor modality that triggered the error
* @param error message
*/ */
void onError(String error); void onError(@Modality int modality, String error);
/** /**
* Save the current state. * Save the current state.

View File

@@ -18,7 +18,6 @@ package com.android.systemui.statusbar;
import static android.app.StatusBarManager.DISABLE2_NONE; import static android.app.StatusBarManager.DISABLE2_NONE;
import static android.app.StatusBarManager.DISABLE_NONE; import static android.app.StatusBarManager.DISABLE_NONE;
import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT; import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
import static android.inputmethodservice.InputMethodService.IME_INVISIBLE; import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
@@ -35,6 +34,8 @@ import android.app.StatusBarManager.WindowType;
import android.app.StatusBarManager.WindowVisibleState; import android.app.StatusBarManager.WindowVisibleState;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.PromptInfo;
import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager;
@@ -293,13 +294,16 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
long operationId, @BiometricMultiSensorMode int multiSensorConfig) { long operationId, @BiometricMultiSensorMode int multiSensorConfig) {
} }
/** @see IStatusBar#onBiometricAuthenticated() */
default void onBiometricAuthenticated() { default void onBiometricAuthenticated() {
} }
default void onBiometricHelp(String message) { /** @see IStatusBar#onBiometricHelp(String) */
default void onBiometricHelp(@Modality int modality, String message) {
} }
default void onBiometricError(int modality, int error, int vendorCode) { /** @see IStatusBar#onBiometricError(int, int, int) */
default void onBiometricError(@Modality int modality, int error, int vendorCode) {
} }
default void hideAuthenticationDialog() { default void hideAuthenticationDialog() {
@@ -891,9 +895,12 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
} }
@Override @Override
public void onBiometricHelp(String message) { public void onBiometricHelp(@Modality int modality, String message) {
synchronized (mLock) { synchronized (mLock) {
mHandler.obtainMessage(MSG_BIOMETRIC_HELP, message).sendToTarget(); SomeArgs args = SomeArgs.obtain();
args.argi1 = modality;
args.arg1 = message;
mHandler.obtainMessage(MSG_BIOMETRIC_HELP, args).sendToTarget();
} }
} }
@@ -1318,11 +1325,16 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
} }
break; break;
} }
case MSG_BIOMETRIC_HELP: case MSG_BIOMETRIC_HELP: {
SomeArgs someArgs = (SomeArgs) msg.obj;
for (int i = 0; i < mCallbacks.size(); i++) { for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onBiometricHelp((String) msg.obj); mCallbacks.get(i).onBiometricHelp(
someArgs.argi1 /* modality */,
(String) someArgs.arg1 /* message */);
} }
someArgs.recycle();
break; break;
}
case MSG_BIOMETRIC_ERROR: { case MSG_BIOMETRIC_ERROR: {
SomeArgs someArgs = (SomeArgs) msg.obj; SomeArgs someArgs = (SomeArgs) msg.obj;
for (int i = 0; i < mCallbacks.size(); i++) { for (int i = 0; i < mCallbacks.size(); i++) {

View File

@@ -16,10 +16,12 @@
package com.android.systemui.biometrics; package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import android.content.Context; import android.content.Context;
@@ -31,6 +33,7 @@ import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import org.junit.Before; import org.junit.Before;
@@ -61,15 +64,14 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Mock private TextView mIndicatorView; @Mock private TextView mIndicatorView;
@Mock private ImageView mIconView; @Mock private ImageView mIconView;
@Mock private View mIconHolderView; @Mock private View mIconHolderView;
@Mock private AuthBiometricFaceView.IconController mIconController;
@Mock private TextView mErrorView;
@Before @Before
public void setup() { public void setup() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mFaceToFpView = new TestableView(mContext); mFaceToFpView = new TestableView(mContext);
mFaceToFpView.mIconController = mock(AuthBiometricFaceView.IconController.class); mFaceToFpView.mIconController = mIconController;
mFaceToFpView.setCallback(mCallback); mFaceToFpView.setCallback(mCallback);
mFaceToFpView.mNegativeButton = mNegativeButton; mFaceToFpView.mNegativeButton = mNegativeButton;
@@ -77,8 +79,7 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
mFaceToFpView.mUseCredentialButton = mUseCredentialButton; mFaceToFpView.mUseCredentialButton = mUseCredentialButton;
mFaceToFpView.mConfirmButton = mConfirmButton; mFaceToFpView.mConfirmButton = mConfirmButton;
mFaceToFpView.mTryAgainButton = mTryAgainButton; mFaceToFpView.mTryAgainButton = mTryAgainButton;
mFaceToFpView.mIndicatorView = mIndicatorView;
mFaceToFpView.mIndicatorView = mErrorView;
} }
@Test @Test
@@ -90,7 +91,7 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Test @Test
public void testIconUpdatesState_whenDialogStateUpdated() { public void testIconUpdatesState_whenDialogStateUpdated() {
mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING); mFaceToFpView.onDialogAnimatedIn();
verify(mFaceToFpView.mIconController) verify(mFaceToFpView.mIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING)); .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
@@ -98,11 +99,13 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
verify(mFaceToFpView.mIconController).updateState( verify(mFaceToFpView.mIconController).updateState(
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED)); eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED));
assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED, mFaceToFpView.mState);
} }
@Test @Test
public void testStateUpdated_whenSwitchToFingerprint() { public void testStateUpdated_whenSwitchToFingerprint() {
mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING); mFaceToFpView.onDialogAnimatedIn();
verify(mFaceToFpView.mIconController) verify(mFaceToFpView.mIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING)); .updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
@@ -120,6 +123,17 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
verify(mConfirmButton).setVisibility(eq(View.GONE)); verify(mConfirmButton).setVisibility(eq(View.GONE));
} }
@Test
public void testModeUpdated_whenSwitchToFingerprint() {
mFaceToFpView.onDialogAnimatedIn();
mFaceToFpView.onAuthenticationFailed(TYPE_FACE, "no face");
waitForIdleSync();
verify(mIndicatorView).setText(
eq(mContext.getString(R.string.fingerprint_dialog_use_fingerprint_instead)));
assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING, mFaceToFpView.mState);
}
public class TestableView extends AuthBiometricFaceToFingerprintView { public class TestableView extends AuthBiometricFaceToFingerprintView {
public TestableView(Context context) { public TestableView(Context context) {
super(context, null, new MockInjector()); super(context, null, new MockInjector());
@@ -132,7 +146,7 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Override @Override
protected IconController createUdfpsIconController() { protected IconController createUdfpsIconController() {
return mIconController; return AuthBiometricFaceToFingerprintViewTest.this.mIconController;
} }
} }

View File

@@ -16,10 +16,13 @@
package com.android.systemui.biometrics; package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.Authenticators; import static android.hardware.biometrics.BiometricManager.Authenticators;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@@ -199,10 +202,10 @@ public class AuthBiometricViewTest extends SysuiTestCase {
public void testError_sendsActionError() { public void testError_sendsActionError() {
initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector()); initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector());
final String testError = "testError"; final String testError = "testError";
mBiometricView.onError(testError); mBiometricView.onError(TYPE_FACE, testError);
waitForIdleSync(); waitForIdleSync();
verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_ERROR); verify(mCallback).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR));
assertEquals(AuthBiometricView.STATE_IDLE, mBiometricView.mState); assertEquals(AuthBiometricView.STATE_IDLE, mBiometricView.mState);
} }
@@ -239,6 +242,23 @@ public class AuthBiometricViewTest extends SysuiTestCase {
verify(mCallback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED)); verify(mCallback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED));
} }
@Test
public void testIgnoresUselessHelp() {
initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector());
mBiometricView.onDialogAnimatedIn();
waitForIdleSync();
assertEquals(AuthBiometricView.STATE_AUTHENTICATING, mBiometricView.mState);
mBiometricView.onHelp(TYPE_FINGERPRINT, "");
waitForIdleSync();
verify(mIndicatorView, never()).setText(any());
verify(mCallback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR));
assertEquals(AuthBiometricView.STATE_AUTHENTICATING, mBiometricView.mState);
}
@Test @Test
public void testRestoresState() { public void testRestoresState() {
final boolean requireConfirmation = true; // set/init from AuthController final boolean requireConfirmation = true; // set/init from AuthController
@@ -264,7 +284,7 @@ public class AuthBiometricViewTest extends SysuiTestCase {
final String failureMessage = "testFailureMessage"; final String failureMessage = "testFailureMessage";
mBiometricView.setRequireConfirmation(requireConfirmation); mBiometricView.setRequireConfirmation(requireConfirmation);
mBiometricView.onAuthenticationFailed(failureMessage); mBiometricView.onAuthenticationFailed(TYPE_FACE, failureMessage);
waitForIdleSync(); waitForIdleSync();
Bundle state = new Bundle(); Bundle state = new Bundle();

View File

@@ -252,52 +252,67 @@ public class AuthControllerTest extends SysuiTestCase {
@Test @Test
public void testOnAuthenticationFailedInvoked_whenBiometricRejected() { public void testOnAuthenticationFailedInvoked_whenBiometricRejected() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_NONE, final int modality = BiometricAuthenticator.TYPE_NONE;
mAuthController.onBiometricError(modality,
BiometricConstants.BIOMETRIC_PAUSED_REJECTED, BiometricConstants.BIOMETRIC_PAUSED_REJECTED,
0 /* vendorCode */); 0 /* vendorCode */);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mDialog1).onAuthenticationFailed(captor.capture()); ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
verify(mDialog1).onAuthenticationFailed(modalityCaptor.capture(), messageCaptor.capture());
assertEquals(captor.getValue(), mContext.getString(R.string.biometric_not_recognized)); assertEquals(modalityCaptor.getValue().intValue(), modality);
assertEquals(messageCaptor.getValue(),
mContext.getString(R.string.biometric_not_recognized));
} }
@Test @Test
public void testOnAuthenticationFailedInvoked_whenBiometricTimedOut() { public void testOnAuthenticationFailedInvoked_whenBiometricTimedOut() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int modality = BiometricAuthenticator.TYPE_FACE;
final int error = BiometricConstants.BIOMETRIC_ERROR_TIMEOUT; final int error = BiometricConstants.BIOMETRIC_ERROR_TIMEOUT;
final int vendorCode = 0; final int vendorCode = 0;
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode); mAuthController.onBiometricError(modality, error, vendorCode);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mDialog1).onAuthenticationFailed(captor.capture()); ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
verify(mDialog1).onAuthenticationFailed(modalityCaptor.capture(), messageCaptor.capture());
assertEquals(captor.getValue(), FaceManager.getErrorString(mContext, error, vendorCode)); assertEquals(modalityCaptor.getValue().intValue(), modality);
assertEquals(messageCaptor.getValue(),
FaceManager.getErrorString(mContext, error, vendorCode));
} }
@Test @Test
public void testOnHelpInvoked_whenSystemRequested() { public void testOnHelpInvoked_whenSystemRequested() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int modality = BiometricAuthenticator.TYPE_IRIS;
final String helpMessage = "help"; final String helpMessage = "help";
mAuthController.onBiometricHelp(helpMessage); mAuthController.onBiometricHelp(modality, helpMessage);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mDialog1).onHelp(captor.capture()); ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
verify(mDialog1).onHelp(modalityCaptor.capture(), messageCaptor.capture());
assertEquals(captor.getValue(), helpMessage); assertEquals(modalityCaptor.getValue().intValue(), modality);
assertEquals(messageCaptor.getValue(), helpMessage);
} }
@Test @Test
public void testOnErrorInvoked_whenSystemRequested() { public void testOnErrorInvoked_whenSystemRequested() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int modality = BiometricAuthenticator.TYPE_FACE;
final int error = 1; final int error = 1;
final int vendorCode = 0; final int vendorCode = 0;
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode); mAuthController.onBiometricError(modality, error, vendorCode);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mDialog1).onError(captor.capture()); ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
verify(mDialog1).onError(modalityCaptor.capture(), messageCaptor.capture());
assertEquals(captor.getValue(), FaceManager.getErrorString(mContext, error, vendorCode)); assertEquals(modalityCaptor.getValue().intValue(), modality);
assertEquals(messageCaptor.getValue(),
FaceManager.getErrorString(mContext, error, vendorCode));
} }
@Test @Test
@@ -309,7 +324,7 @@ public class AuthControllerTest extends SysuiTestCase {
when(mDialog1.isAllowDeviceCredentials()).thenReturn(true); when(mDialog1.isAllowDeviceCredentials()).thenReturn(true);
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode); mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
verify(mDialog1, never()).onError(anyString()); verify(mDialog1, never()).onError(anyInt(), anyString());
verify(mDialog1).animateToCredentialUI(); verify(mDialog1).animateToCredentialUI();
} }
@@ -322,33 +337,37 @@ public class AuthControllerTest extends SysuiTestCase {
when(mDialog1.isAllowDeviceCredentials()).thenReturn(true); when(mDialog1.isAllowDeviceCredentials()).thenReturn(true);
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode); mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
verify(mDialog1, never()).onError(anyString()); verify(mDialog1, never()).onError(anyInt(), anyString());
verify(mDialog1).animateToCredentialUI(); verify(mDialog1).animateToCredentialUI();
} }
@Test @Test
public void testErrorLockout_whenCredentialNotAllowed_sendsOnError() { public void testErrorLockout_whenCredentialNotAllowed_sendsOnError() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int modality = BiometricAuthenticator.TYPE_FACE;
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT; final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT;
final int vendorCode = 0; final int vendorCode = 0;
when(mDialog1.isAllowDeviceCredentials()).thenReturn(false); when(mDialog1.isAllowDeviceCredentials()).thenReturn(false);
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode); mAuthController.onBiometricError(modality, error, vendorCode);
verify(mDialog1).onError(eq(FaceManager.getErrorString(mContext, error, vendorCode))); verify(mDialog1).onError(
eq(modality), eq(FaceManager.getErrorString(mContext, error, vendorCode)));
verify(mDialog1, never()).animateToCredentialUI(); verify(mDialog1, never()).animateToCredentialUI();
} }
@Test @Test
public void testErrorLockoutPermanent_whenCredentialNotAllowed_sendsOnError() { public void testErrorLockoutPermanent_whenCredentialNotAllowed_sendsOnError() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
final int modality = BiometricAuthenticator.TYPE_FACE;
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT; final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
final int vendorCode = 0; final int vendorCode = 0;
when(mDialog1.isAllowDeviceCredentials()).thenReturn(false); when(mDialog1.isAllowDeviceCredentials()).thenReturn(false);
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode); mAuthController.onBiometricError(modality, error, vendorCode);
verify(mDialog1).onError(eq(FaceManager.getErrorString(mContext, error, vendorCode))); verify(mDialog1).onError(
eq(modality), eq(FaceManager.getErrorString(mContext, error, vendorCode)));
verify(mDialog1, never()).animateToCredentialUI(); verify(mDialog1, never()).animateToCredentialUI();
} }

View File

@@ -14,6 +14,7 @@
package com.android.systemui.statusbar; package com.android.systemui.statusbar;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -444,10 +445,11 @@ public class CommandQueueTest extends SysuiTestCase {
@Test @Test
public void testOnBiometricHelp() { public void testOnBiometricHelp() {
String helpMessage = "test_help_message"; final int modality = TYPE_FACE;
mCommandQueue.onBiometricHelp(helpMessage); final String helpMessage = "test_help_message";
mCommandQueue.onBiometricHelp(modality, helpMessage);
waitForIdleSync(); waitForIdleSync();
verify(mCallbacks).onBiometricHelp(eq(helpMessage)); verify(mCallbacks).onBiometricHelp(eq(modality), eq(helpMessage));
} }
@Test @Test

View File

@@ -21,7 +21,6 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRIN
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT;
import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_FACE_SCANNING; import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_FACE_SCANNING;
import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_FP_SCANNING; import static com.android.server.biometrics.BiometricServiceStateProto.MULTI_SENSOR_STATE_FP_SCANNING;
@@ -44,8 +43,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver; import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -498,7 +499,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
} }
try { try {
mStatusBarService.onBiometricHelp(message); mStatusBarService.onBiometricHelp(sensorIdToModality(sensorId), message);
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e); Slog.e(TAG, "Remote exception", e);
} }
@@ -873,7 +874,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
return modality; return modality;
} }
private @BiometricAuthenticator.Modality int sensorIdToModality(int sensorId) { private @Modality int sensorIdToModality(int sensorId) {
for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) { for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
if (sensorId == sensor.id) { if (sensorId == sensor.id) {
return sensor.modality; return sensor.modality;
@@ -884,7 +885,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
} }
private String getAcquiredMessageForSensor(int sensorId, int acquiredInfo, int vendorCode) { private String getAcquiredMessageForSensor(int sensorId, int acquiredInfo, int vendorCode) {
final @BiometricAuthenticator.Modality int modality = sensorIdToModality(sensorId); final @Modality int modality = sensorIdToModality(sensorId);
switch (modality) { switch (modality) {
case BiometricAuthenticator.TYPE_FINGERPRINT: case BiometricAuthenticator.TYPE_FINGERPRINT:
return FingerprintManager.getAcquiredString(mContext, acquiredInfo, vendorCode); return FingerprintManager.getAcquiredString(mContext, acquiredInfo, vendorCode);

View File

@@ -18,7 +18,6 @@ package com.android.server.statusbar;
import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS; import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE; import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.DEFAULT_DISPLAY;
import android.Manifest; import android.Manifest;
@@ -33,6 +32,8 @@ import android.compat.annotation.EnabledSince;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import android.hardware.biometrics.IBiometricSysuiReceiver; import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo; import android.hardware.biometrics.PromptInfo;
import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager;
@@ -814,11 +815,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
} }
@Override @Override
public void onBiometricHelp(String message) { public void onBiometricHelp(@Modality int modality, String message) {
enforceBiometricDialog(); enforceBiometricDialog();
if (mBar != null) { if (mBar != null) {
try { try {
mBar.onBiometricHelp(message); mBar.onBiometricHelp(modality, message);
} catch (RemoteException ex) { } catch (RemoteException ex) {
} }
} }

View File

@@ -1108,7 +1108,8 @@ public class BiometricServiceTest {
public void testAcquire_whenAuthenticating_sentToSystemUI() throws Exception { public void testAcquire_whenAuthenticating_sentToSystemUI() throws Exception {
when(mContext.getResources().getString(anyInt())).thenReturn("test string"); when(mContext.getResources().getString(anyInt())).thenReturn("test string");
setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG); final int modality = BiometricAuthenticator.TYPE_FINGERPRINT;
setupAuthForOnly(modality, Authenticators.BIOMETRIC_STRONG);
invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1, invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, null /* authenticators */); false /* requireConfirmation */, null /* authenticators */);
@@ -1121,7 +1122,7 @@ public class BiometricServiceTest {
// Sends to SysUI and stays in authenticating state. We don't test that the correct // Sends to SysUI and stays in authenticating state. We don't test that the correct
// string is retrieved for now, but it's also very unlikely to break anyway. // string is retrieved for now, but it's also very unlikely to break anyway.
verify(mBiometricService.mStatusBarService) verify(mBiometricService.mStatusBarService)
.onBiometricHelp(anyString()); .onBiometricHelp(eq(modality), anyString());
assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState()); assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
} }