Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ed94180f authored by Kevin Chyn's avatar Kevin Chyn
Browse files

Move error delay logic from Manager to Service

For BiometricPrompt, sometimes the error should be delayed. E.g. after
receiving certain signal from the daemon, the UI needs to show the message
for a few seconds before the application should receive the actual error.
The logic was previously added in FingerprintManager and missed a case.
It's cleaner to have it done at the service level, since it will
automatically be inherited for each modality.

Fixes: 78546315
Bug: 77337939
Bug: 78185698

Test: Keyguard (FingerprintManager) errors are not affected

Test: Using BiometricPromptDemo test app, do the following
Test: Starting authentication without FP enrolled returns error immediately
Test: Start authentication, lock device - error returns immediately
Test: User canceled (tapping outside) returns error immediately
Test: User canceled (negative button) returns error immediately
Test: Lockout returns error when dialog dismisses

Change-Id: Ie828e0cf1fd4261ded31bb0b0adb6d93e7692993
parent 8b3274e7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
     * @hide
     */
    public static final int HIDE_DIALOG_DELAY = 2000; // ms

    /**
     * @hide
     */
+3 −18
Original line number Diff line number Diff line
@@ -1162,24 +1162,9 @@ public class FingerprintManager implements BiometricFingerprintConstants {
        @Override // binder call
        public void onError(long deviceId, int error, int vendorCode) {
            if (mExecutor != null) {
                // BiometricPrompt case
                if (error == FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED
                        || error == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
                    // User tapped somewhere to cancel, or authentication was cancelled by the app
                    // or got kicked out. The prompt is already gone, so send the error immediately.
                mExecutor.execute(() -> {
                    sendErrorResult(deviceId, error, vendorCode);
                });
                } else {
                    // User got an error that needs to be displayed on the dialog, post a delayed
                    // runnable on the FingerprintManager handler that sends the error message after
                    // FingerprintDialog.HIDE_DIALOG_DELAY to send the error to the application.
                    mHandler.postDelayed(() -> {
                        mExecutor.execute(() -> {
                            sendErrorResult(deviceId, error, vendorCode);
                        });
                    }, BiometricPrompt.HIDE_DIALOG_DELAY);
                }
            } else {
                mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
            }
+13 −6
Original line number Diff line number Diff line
@@ -21,10 +21,11 @@ import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.IBiometricPromptReceiver;
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Slog;

@@ -35,6 +36,7 @@ import com.android.internal.statusbar.IStatusBarService;
 */
public abstract class AuthenticationClient extends ClientMonitor {
    private long mOpId;
    private Handler mHandler;

    public abstract int handleFailedAttempt();
    public abstract void resetFailedAttempts();
@@ -97,6 +99,7 @@ public abstract class AuthenticationClient extends ClientMonitor {
        mStatusBarService = statusBarService;
        mFingerprintManager = (FingerprintManager) getContext()
                .getSystemService(Context.FINGERPRINT_SERVICE);
        mHandler = new Handler(Looper.getMainLooper());
    }

    @Override
@@ -217,15 +220,19 @@ public abstract class AuthenticationClient extends ClientMonitor {
                            BiometricConstants.BIOMETRIC_ERROR_LOCKOUT :
                            BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT;

                    // TODO: if the dialog is showing, this error should be delayed. On a similar
                    // note, AuthenticationClient should override onError and delay all other errors
                    // as well, if the dialog is showing
                    listener.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);

                    // Send the lockout message to the system dialog
                    if (mBundle != null) {
                        mStatusBarService.onBiometricError(
                                mFingerprintManager.getErrorString(errorCode, 0 /* vendorCode */));
                        mHandler.postDelayed(() -> {
                            try {
                                listener.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
                            } catch (RemoteException e) {
                                Slog.w(getLogTag(), "RemoteException while sending error");
                            }
                        }, BiometricPrompt.HIDE_DIALOG_DELAY);
                    } else {
                        listener.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
                    }
                } catch (RemoteException e) {
                    Slog.w(getLogTag(), "Failed to notify lockout:", e);
+0 −1
Original line number Diff line number Diff line
@@ -58,7 +58,6 @@ import android.util.SparseIntArray;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.server.SystemService;
import com.android.server.biometrics.face.FaceService;
import com.android.server.biometrics.fingerprint.FingerprintService;

import java.util.ArrayList;