diff options
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()); } |