diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 943c726b173e5..cfc32cf67016b 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -153,7 +153,7 @@ oneway interface IStatusBar void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type, boolean requireConfirmation, int userId); // Used to hide the dialog when a biometric is authenticated - void onBiometricAuthenticated(boolean authenticated); + void onBiometricAuthenticated(boolean authenticated, String failureReason); // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc void onBiometricHelp(String message); // Used to set a message - the dialog will dismiss after a certain amount of time diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index f22b6cd3d601c..598c3917bf95b 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -103,7 +103,7 @@ interface IStatusBarService void showBiometricDialog(in Bundle bundle, IBiometricServiceReceiverInternal receiver, int type, boolean requireConfirmation, int userId); // Used to hide the dialog when a biometric is authenticated - void onBiometricAuthenticated(boolean authenticated); + void onBiometricAuthenticated(boolean authenticated, String failureReason); // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc void onBiometricHelp(String message); // Used to set a message - the dialog will dismiss after a certain amount of time diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java index 402810902d390..5860230e85738 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java @@ -24,6 +24,7 @@ import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.IBiometricServiceReceiverInternal; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.Log; @@ -58,7 +59,7 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba private boolean mDialogShowing; private Callback mCallback = new Callback(); - private Handler mHandler = new Handler() { + private Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch(msg.what) { @@ -66,15 +67,20 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba handleShowDialog((SomeArgs) msg.obj, false /* skipAnimation */, null /* savedState */); break; - case MSG_BIOMETRIC_AUTHENTICATED: - handleBiometricAuthenticated((boolean) msg.obj); + case MSG_BIOMETRIC_AUTHENTICATED: { + SomeArgs args = (SomeArgs) msg.obj; + handleBiometricAuthenticated((boolean) args.arg1 /* authenticated */, + (String) args.arg2 /* failureReason */); + args.recycle(); break; - case MSG_BIOMETRIC_HELP: + } + case MSG_BIOMETRIC_HELP: { SomeArgs args = (SomeArgs) msg.obj; handleBiometricHelp((String) args.arg1 /* message */, (boolean) args.arg2 /* requireTryAgain */); args.recycle(); break; + } case MSG_BIOMETRIC_ERROR: handleBiometricError((String) msg.obj); break; @@ -161,9 +167,14 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba } @Override - public void onBiometricAuthenticated(boolean authenticated) { - if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: " + authenticated); - mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, authenticated).sendToTarget(); + public void onBiometricAuthenticated(boolean authenticated, String failureReason) { + if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: " + authenticated + + " reason: " + failureReason); + + SomeArgs args = SomeArgs.obtain(); + args.arg1 = authenticated; + args.arg2 = failureReason; + mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, args).sendToTarget(); } @Override @@ -230,7 +241,7 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba mDialogShowing = true; } - private void handleBiometricAuthenticated(boolean authenticated) { + private void handleBiometricAuthenticated(boolean authenticated, String failureReason) { if (DEBUG) Log.d(TAG, "handleBiometricAuthenticated: " + authenticated); if (authenticated) { @@ -246,9 +257,7 @@ public class BiometricDialogImpl extends SystemUI implements CommandQueue.Callba }, mCurrentDialog.getDelayAfterAuthenticatedDurationMs()); } } else { - handleBiometricHelp(mContext.getResources() - .getString(com.android.internal.R.string.biometric_not_recognized), - true /* requireTryAgain */); + handleBiometricHelp(failureReason, true /* requireTryAgain */); mCurrentDialog.showTryAgainButton(true /* show */); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index d5849598342fd..a688f36b47a6e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -280,7 +280,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< default void showBiometricDialog(Bundle bundle, IBiometricServiceReceiverInternal receiver, int type, boolean requireConfirmation, int userId) { } - default void onBiometricAuthenticated(boolean authenticated) { } + default void onBiometricAuthenticated(boolean authenticated, String failureReason) { } default void onBiometricHelp(String message) { } default void onBiometricError(String error) { } default void hideBiometricDialog() { } @@ -760,9 +760,12 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } @Override - public void onBiometricAuthenticated(boolean authenticated) { + public void onBiometricAuthenticated(boolean authenticated, String failureReason) { synchronized (mLock) { - mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, authenticated).sendToTarget(); + SomeArgs args = SomeArgs.obtain(); + args.arg1 = authenticated; + args.arg2 = failureReason; + mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED, args).sendToTarget(); } } @@ -1023,7 +1026,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< mCallbacks.get(i).onRotationProposal(msg.arg1, msg.arg2 != 0); } break; - case MSG_BIOMETRIC_SHOW: + case MSG_BIOMETRIC_SHOW: { mHandler.removeMessages(MSG_BIOMETRIC_ERROR); mHandler.removeMessages(MSG_BIOMETRIC_HELP); mHandler.removeMessages(MSG_BIOMETRIC_AUTHENTICATED); @@ -1038,11 +1041,17 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } someArgs.recycle(); break; - case MSG_BIOMETRIC_AUTHENTICATED: + } + case MSG_BIOMETRIC_AUTHENTICATED: { + SomeArgs someArgs = (SomeArgs) msg.obj; for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).onBiometricAuthenticated((boolean) msg.obj); + mCallbacks.get(i).onBiometricAuthenticated( + (boolean) someArgs.arg1 /* authenticated */, + (String) someArgs.arg2 /* failureReason */); } + someArgs.recycle(); break; + } case MSG_BIOMETRIC_HELP: for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).onBiometricHelp((String) msg.obj); diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index 91da7af44f0af..74b72210859c3 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -104,6 +104,7 @@ public abstract class AuthenticationClient extends ClientMonitor { public boolean onError(long deviceId, int error, int vendorCode) { if (!shouldFrameworkHandleLockout()) { switch (error) { + case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT: case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT: case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT: if (mStarted) { diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 4c59e608398c2..6933ee84837b4 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -306,11 +306,7 @@ public class BiometricService extends SystemService { } case MSG_ON_AUTHENTICATION_FAILED: { - SomeArgs args = (SomeArgs) msg.obj; - handleAuthenticationFailed( - args.argi1 /* cookie */, - (boolean) args.arg1 /* requireConfirmation */); - args.recycle(); + handleAuthenticationFailed((String) msg.obj /* failureReason */); break; } @@ -567,19 +563,24 @@ public class BiometricService extends SystemService { @Override public void onAuthenticationFailed(int cookie, boolean requireConfirmation) throws RemoteException { - SomeArgs args = SomeArgs.obtain(); - args.argi1 = cookie; - args.arg1 = requireConfirmation; - mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, args).sendToTarget(); + String failureReason = getContext().getString(R.string.biometric_not_recognized); + mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, failureReason).sendToTarget(); } @Override public void onError(int cookie, int error, String message) throws RemoteException { - SomeArgs args = SomeArgs.obtain(); - args.argi1 = cookie; - args.argi2 = error; - args.arg1 = message; - mHandler.obtainMessage(MSG_ON_ERROR, args).sendToTarget(); + // Determine if error is hard or soft error. Certain errors (such as TIMEOUT) are + // soft errors and we should allow the user to try authenticating again instead of + // dismissing BiometricPrompt. + if (error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT) { + mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, message).sendToTarget(); + } else { + SomeArgs args = SomeArgs.obtain(); + args.argi1 = cookie; + args.argi2 = error; + args.arg1 = message; + mHandler.obtainMessage(MSG_ON_ERROR, args).sendToTarget(); + } } @Override @@ -1151,13 +1152,13 @@ public class BiometricService extends SystemService { // Notify SysUI that the biometric has been authenticated. SysUI already knows // the implicit/explicit state and will react accordingly. - mStatusBarService.onBiometricAuthenticated(true); + mStatusBarService.onBiometricAuthenticated(true, null /* failureReason */); } catch (RemoteException e) { Slog.e(TAG, "Remote exception", e); } } - private void handleAuthenticationFailed(int cookie, boolean requireConfirmation) { + private void handleAuthenticationFailed(String failureReason) { try { // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded // after user dismissed/canceled dialog). @@ -1166,7 +1167,7 @@ public class BiometricService extends SystemService { return; } - mStatusBarService.onBiometricAuthenticated(false); + mStatusBarService.onBiometricAuthenticated(false, failureReason); // TODO: This logic will need to be updated if BP is multi-modal if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) { diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index af009ecb8c3eb..a5656c3e40f08 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -610,11 +610,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override - public void onBiometricAuthenticated(boolean authenticated) { + public void onBiometricAuthenticated(boolean authenticated, String failureReason) { enforceBiometricDialog(); if (mBar != null) { try { - mBar.onBiometricAuthenticated(authenticated); + mBar.onBiometricAuthenticated(authenticated, failureReason); } catch (RemoteException ex) { } }