summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/hardware/biometrics/BiometricAuthenticator.java3
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl20
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java63
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java8
-rw-r--r--services/core/java/com/android/server/biometrics/AuthSession.java9
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java5
17 files changed, 219 insertions, 92 deletions
diff --git a/core/java/android/hardware/biometrics/BiometricAuthenticator.java b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
index 31d1b69182f1..a0027077e1a3 100644
--- a/core/java/android/hardware/biometrics/BiometricAuthenticator.java
+++ b/core/java/android/hardware/biometrics/BiometricAuthenticator.java
@@ -67,7 +67,8 @@ public interface BiometricAuthenticator {
TYPE_NONE,
TYPE_CREDENTIAL,
TYPE_FINGERPRINT,
- TYPE_IRIS
+ TYPE_IRIS,
+ TYPE_FACE
})
@Retention(RetentionPolicy.SOURCE)
@interface Modality {}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 4d7139ca24fe..10f14b42ae42 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -143,17 +143,25 @@ oneway interface IStatusBar
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,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
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();
- // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
- void onBiometricHelp(String message);
- // Used to show an error - the dialog will dismiss after a certain amount of time
+ /**
+ * Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc.
+ */
+ 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);
- // 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();
/**
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 6a8d9838fcd2..e7d6d6cf8936 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -115,7 +115,7 @@ interface IStatusBarService
// 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
- 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
void onBiometricError(int modality, int error, int vendorCode);
// Used to hide the authentication dialog, e.g. when the application cancels authentication
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
index ebfd2068c55b..ca59393577c0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintView.java
@@ -22,7 +22,7 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRIN
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.util.AttributeSet;
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) {
super(context);
@@ -126,6 +128,16 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
}
@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
@BiometricState
protected int getStateForAfterError() {
if (mActiveSensorType == TYPE_FACE) {
@@ -155,7 +167,7 @@ public class AuthBiometricFaceToFingerprintView extends AuthBiometricFaceView {
}
@Override
- public void updateState(int newState) {
+ public void updateState(@BiometricState int newState) {
if (mState == STATE_HELP || mState == STATE_ERROR) {
mActiveSensorType = TYPE_FINGERPRINT;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
index f7d2d8c6d2ea..e8da7c51bf0d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
+import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
@@ -29,6 +30,8 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
@@ -206,7 +209,7 @@ public class AuthBiometricFaceView extends AuthBiometricView {
}
@Override
- public void onAuthenticationFailed(String failureReason) {
+ public void onAuthenticationFailed(@Modality int modality, @Nullable String failureReason) {
if (getSize() == AuthDialog.SIZE_MEDIUM) {
if (supportsManualRetry()) {
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
// small -> medium dialog)
- super.onAuthenticationFailed(failureReason);
+ super.onAuthenticationFailed(modality, failureReason);
}
private void resetErrorView() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 29cd76da23a3..f37495ef5f48 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -16,6 +16,8 @@
package com.android.systemui.biometrics;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -24,6 +26,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.PromptInfo;
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);
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);
updateState(STATE_ERROR);
@@ -556,11 +572,22 @@ public abstract class AuthBiometricView extends LinearLayout {
}, 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) {
Log.w(TAG, "Help received in size: " + mSize);
return;
}
+ if (TextUtils.isEmpty(help)) {
+ Log.w(TAG, "Ignoring blank help message");
+ return;
+ }
+
showTemporaryMessage(help, mResetHelpRunnable);
updateState(STATE_HELP);
}
@@ -828,10 +855,10 @@ public abstract class AuthBiometricView extends LinearLayout {
final String indicatorText =
mSavedState.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING);
if (mSavedState.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_HELP_SHOWING)) {
- onHelp(indicatorText);
+ onHelp(TYPE_NONE, indicatorText);
} else if (mSavedState.getBoolean(
AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)) {
- onAuthenticationFailed(indicatorText);
+ onAuthenticationFailed(TYPE_NONE, indicatorText);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 9ec7bd0c1549..d1cb6ec7a072 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.PixelFormat;
+import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.PromptInfo;
import android.hardware.face.FaceSensorPropertiesInternal;
@@ -598,18 +599,18 @@ public class AuthContainerView extends LinearLayout
}
@Override
- public void onAuthenticationFailed(String failureReason) {
- mBiometricView.onAuthenticationFailed(failureReason);
+ public void onAuthenticationFailed(@Modality int modality, String failureReason) {
+ mBiometricView.onAuthenticationFailed(modality, failureReason);
}
@Override
- public void onHelp(String help) {
- mBiometricView.onHelp(help);
+ public void onHelp(@Modality int modality, String help) {
+ mBiometricView.onHelp(modality, help);
}
@Override
- public void onError(String error) {
- mBiometricView.onError(error);
+ public void onError(@Modality int modality, String error) {
+ mBiometricView.onError(modality, error);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index f8e4bdc83fbb..5e6b904c1527 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -18,8 +18,6 @@ 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.BiometricMultiSensorMode;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,7 +31,10 @@ import android.content.IntentFilter;
import android.content.res.Configuration;
import android.graphics.PointF;
import android.graphics.RectF;
+import android.hardware.biometrics.BiometricAuthenticator.Modality;
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.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
@@ -525,11 +526,11 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
}
@Override
- public void onBiometricHelp(String message) {
+ public void onBiometricHelp(@Modality int modality, String message) {
if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
if (mCurrentDialog != null) {
- mCurrentDialog.onHelp(message);
+ mCurrentDialog.onHelp(modality, message);
} else {
Log.w(TAG, "onBiometricHelp callback but dialog gone");
}
@@ -540,7 +541,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
return mUdfpsProps;
}
- private String getErrorString(int modality, int error, int vendorCode) {
+ private String getErrorString(@Modality int modality, int error, int vendorCode) {
switch (modality) {
case TYPE_FACE:
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}.
*/
@Override
- public void onBiometricError(int modality, int error, int vendorCode) {
+ public void onBiometricError(@Modality int modality, int error, int vendorCode) {
if (DEBUG) {
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)
: getErrorString(modality, error, vendorCode);
if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
- mCurrentDialog.onAuthenticationFailed(errorMessage);
+ mCurrentDialog.onAuthenticationFailed(modality, errorMessage);
} else {
final String errorMessage = getErrorString(modality, error, vendorCode);
if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
- mCurrentDialog.onError(errorMessage);
+ mCurrentDialog.onError(modality, errorMessage);
}
} else {
Log.w(TAG, "onBiometricError callback but dialog is gone");
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
index 0f3643c8c359..cbd166e6e0b1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
@@ -19,6 +19,7 @@ package com.android.systemui.biometrics;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.os.Bundle;
import android.view.WindowManager;
@@ -112,21 +113,24 @@ public interface AuthDialog {
/**
* 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.
- * @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.
- * @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.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 56941b9c02e5..8e52b0da54ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar;
import static android.app.StatusBarManager.DISABLE2_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.IME_INVISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -35,6 +34,8 @@ import android.app.StatusBarManager.WindowType;
import android.app.StatusBarManager.WindowVisibleState;
import android.content.ComponentName;
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.PromptInfo;
import android.hardware.display.DisplayManager;
@@ -293,13 +294,16 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
long operationId, @BiometricMultiSensorMode int multiSensorConfig) {
}
+ /** @see IStatusBar#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() {
@@ -891,9 +895,12 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
@Override
- public void onBiometricHelp(String message) {
+ public void onBiometricHelp(@Modality int modality, String message) {
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;
}
- case MSG_BIOMETRIC_HELP:
+ case MSG_BIOMETRIC_HELP: {
+ SomeArgs someArgs = (SomeArgs) msg.obj;
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;
+ }
case MSG_BIOMETRIC_ERROR: {
SomeArgs someArgs = (SomeArgs) msg.obj;
for (int i = 0; i < mCallbacks.size(); i++) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
index 5f3d3cb2f7d3..aed0da656e86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
@@ -16,10 +16,12 @@
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.eq;
import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -31,6 +33,7 @@ import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
@@ -61,15 +64,14 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Mock private TextView mIndicatorView;
@Mock private ImageView mIconView;
@Mock private View mIconHolderView;
-
- @Mock private TextView mErrorView;
+ @Mock private AuthBiometricFaceView.IconController mIconController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mFaceToFpView = new TestableView(mContext);
- mFaceToFpView.mIconController = mock(AuthBiometricFaceView.IconController.class);
+ mFaceToFpView.mIconController = mIconController;
mFaceToFpView.setCallback(mCallback);
mFaceToFpView.mNegativeButton = mNegativeButton;
@@ -77,8 +79,7 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
mFaceToFpView.mUseCredentialButton = mUseCredentialButton;
mFaceToFpView.mConfirmButton = mConfirmButton;
mFaceToFpView.mTryAgainButton = mTryAgainButton;
-
- mFaceToFpView.mIndicatorView = mErrorView;
+ mFaceToFpView.mIndicatorView = mIndicatorView;
}
@Test
@@ -90,7 +91,7 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Test
public void testIconUpdatesState_whenDialogStateUpdated() {
- mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
+ mFaceToFpView.onDialogAnimatedIn();
verify(mFaceToFpView.mIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
@@ -98,11 +99,13 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
verify(mFaceToFpView.mIconController).updateState(
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING),
eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED));
+
+ assertEquals(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATED, mFaceToFpView.mState);
}
@Test
public void testStateUpdated_whenSwitchToFingerprint() {
- mFaceToFpView.updateState(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING);
+ mFaceToFpView.onDialogAnimatedIn();
verify(mFaceToFpView.mIconController)
.updateState(anyInt(), eq(AuthBiometricFaceToFingerprintView.STATE_AUTHENTICATING));
@@ -120,6 +123,17 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
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 TestableView(Context context) {
super(context, null, new MockInjector());
@@ -132,7 +146,7 @@ public class AuthBiometricFaceToFingerprintViewTest extends SysuiTestCase {
@Override
protected IconController createUdfpsIconController() {
- return mIconController;
+ return AuthBiometricFaceToFingerprintViewTest.this.mIconController;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index 06f925397f0c..bd518ff9a1ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -16,10 +16,13 @@
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 org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
@@ -199,10 +202,10 @@ public class AuthBiometricViewTest extends SysuiTestCase {
public void testError_sendsActionError() {
initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector());
final String testError = "testError";
- mBiometricView.onError(testError);
+ mBiometricView.onError(TYPE_FACE, testError);
waitForIdleSync();
- verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_ERROR);
+ verify(mCallback).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR));
assertEquals(AuthBiometricView.STATE_IDLE, mBiometricView.mState);
}
@@ -240,6 +243,23 @@ public class AuthBiometricViewTest extends SysuiTestCase {
}
@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
public void testRestoresState() {
final boolean requireConfirmation = true; // set/init from AuthController
@@ -264,7 +284,7 @@ public class AuthBiometricViewTest extends SysuiTestCase {
final String failureMessage = "testFailureMessage";
mBiometricView.setRequireConfirmation(requireConfirmation);
- mBiometricView.onAuthenticationFailed(failureMessage);
+ mBiometricView.onAuthenticationFailed(TYPE_FACE, failureMessage);
waitForIdleSync();
Bundle state = new Bundle();
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 db5648ab1ebc..9774ea98ff0d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -252,52 +252,67 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testOnAuthenticationFailedInvoked_whenBiometricRejected() {
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,
0 /* vendorCode */);
- ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
- verify(mDialog1).onAuthenticationFailed(captor.capture());
+ ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
+ 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
public void testOnAuthenticationFailedInvoked_whenBiometricTimedOut() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
+ final int modality = BiometricAuthenticator.TYPE_FACE;
final int error = BiometricConstants.BIOMETRIC_ERROR_TIMEOUT;
final int vendorCode = 0;
- mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
+ mAuthController.onBiometricError(modality, error, vendorCode);
- ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
- verify(mDialog1).onAuthenticationFailed(captor.capture());
+ ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
+ 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
public void testOnHelpInvoked_whenSystemRequested() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
+ final int modality = BiometricAuthenticator.TYPE_IRIS;
final String helpMessage = "help";
- mAuthController.onBiometricHelp(helpMessage);
+ mAuthController.onBiometricHelp(modality, helpMessage);
- ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
- verify(mDialog1).onHelp(captor.capture());
+ ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
+ 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
public void testOnErrorInvoked_whenSystemRequested() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
+ final int modality = BiometricAuthenticator.TYPE_FACE;
final int error = 1;
final int vendorCode = 0;
- mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
+ mAuthController.onBiometricError(modality, error, vendorCode);
- ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
- verify(mDialog1).onError(captor.capture());
+ ArgumentCaptor<Integer> modalityCaptor = ArgumentCaptor.forClass(Integer.class);
+ 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
@@ -309,7 +324,7 @@ public class AuthControllerTest extends SysuiTestCase {
when(mDialog1.isAllowDeviceCredentials()).thenReturn(true);
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
- verify(mDialog1, never()).onError(anyString());
+ verify(mDialog1, never()).onError(anyInt(), anyString());
verify(mDialog1).animateToCredentialUI();
}
@@ -322,33 +337,37 @@ public class AuthControllerTest extends SysuiTestCase {
when(mDialog1.isAllowDeviceCredentials()).thenReturn(true);
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
- verify(mDialog1, never()).onError(anyString());
+ verify(mDialog1, never()).onError(anyInt(), anyString());
verify(mDialog1).animateToCredentialUI();
}
@Test
public void testErrorLockout_whenCredentialNotAllowed_sendsOnError() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
+ final int modality = BiometricAuthenticator.TYPE_FACE;
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT;
final int vendorCode = 0;
when(mDialog1.isAllowDeviceCredentials()).thenReturn(false);
- mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
- verify(mDialog1).onError(eq(FaceManager.getErrorString(mContext, error, vendorCode)));
+ mAuthController.onBiometricError(modality, error, vendorCode);
+ verify(mDialog1).onError(
+ eq(modality), eq(FaceManager.getErrorString(mContext, error, vendorCode)));
verify(mDialog1, never()).animateToCredentialUI();
}
@Test
public void testErrorLockoutPermanent_whenCredentialNotAllowed_sendsOnError() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
+ final int modality = BiometricAuthenticator.TYPE_FACE;
final int error = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;
final int vendorCode = 0;
when(mDialog1.isAllowDeviceCredentials()).thenReturn(false);
- mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
- verify(mDialog1).onError(eq(FaceManager.getErrorString(mContext, error, vendorCode)));
+ mAuthController.onBiometricError(modality, error, vendorCode);
+ verify(mDialog1).onError(
+ eq(modality), eq(FaceManager.getErrorString(mContext, error, vendorCode)));
verify(mDialog1, never()).animateToCredentialUI();
}
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 d1b846fb5236..21c6292c151f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -14,6 +14,7 @@
package com.android.systemui.statusbar;
+import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -444,10 +445,11 @@ public class CommandQueueTest extends SysuiTestCase {
@Test
public void testOnBiometricHelp() {
- String helpMessage = "test_help_message";
- mCommandQueue.onBiometricHelp(helpMessage);
+ final int modality = TYPE_FACE;
+ final String helpMessage = "test_help_message";
+ mCommandQueue.onBiometricHelp(modality, helpMessage);
waitForIdleSync();
- verify(mCallbacks).onBiometricHelp(eq(helpMessage));
+ verify(mCallbacks).onBiometricHelp(eq(modality), eq(helpMessage));
}
@Test
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index 1e3eec87aede..36dc5cd21288 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -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.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
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_FP_SCANNING;
@@ -44,8 +43,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricAuthenticator.Modality;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -498,7 +499,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
}
try {
- mStatusBarService.onBiometricHelp(message);
+ mStatusBarService.onBiometricHelp(sensorIdToModality(sensorId), message);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
}
@@ -873,7 +874,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
return modality;
}
- private @BiometricAuthenticator.Modality int sensorIdToModality(int sensorId) {
+ private @Modality int sensorIdToModality(int sensorId) {
for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
if (sensorId == sensor.id) {
return sensor.modality;
@@ -884,7 +885,7 @@ public final class AuthSession implements IBinder.DeathRecipient {
}
private String getAcquiredMessageForSensor(int sensorId, int acquiredInfo, int vendorCode) {
- final @BiometricAuthenticator.Modality int modality = sensorIdToModality(sensorId);
+ final @Modality int modality = sensorIdToModality(sensorId);
switch (modality) {
case BiometricAuthenticator.TYPE_FINGERPRINT:
return FingerprintManager.getAcquiredString(mContext, acquiredInfo, vendorCode);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 8926af48783d..6255d77dc7cd 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -18,7 +18,6 @@ package com.android.server.statusbar;
import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
-import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import static android.view.Display.DEFAULT_DISPLAY;
import android.Manifest;
@@ -33,6 +32,8 @@ import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
import android.content.Context;
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.PromptInfo;
import android.hardware.display.DisplayManager;
@@ -814,11 +815,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
@Override
- public void onBiometricHelp(String message) {
+ public void onBiometricHelp(@Modality int modality, String message) {
enforceBiometricDialog();
if (mBar != null) {
try {
- mBar.onBiometricHelp(message);
+ mBar.onBiometricHelp(modality, message);
} 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 98777acc808f..ae836cead3b8 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -1108,7 +1108,8 @@ public class BiometricServiceTest {
public void testAcquire_whenAuthenticating_sentToSystemUI() throws Exception {
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,
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
// string is retrieved for now, but it's also very unlikely to break anyway.
verify(mBiometricService.mStatusBarService)
- .onBiometricHelp(anyString());
+ .onBiometricHelp(eq(modality), anyString());
assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
}