Do not dismiss BiometricPrompt when "soft" errors are received
Some errors such as ERROR_TIMEOUT should not caues the BiometricPrompt dialog to be dismissed. Updated plumbing to allow onBiometricAuthenticated to pass a string indicating the failure reason Fixes: 131240917 Test: BiometricPromptDemo Change-Id: I63a6f1138a24fbc3736184efefc620dd5bb640dd
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -102,7 +102,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
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user