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

Commit 15fd1a11 authored by Kevin Chyn's avatar Kevin Chyn Committed by Android (Google) Code Review
Browse files

Merge "Update error haptics for coex" into sc-dev

parents 4b68ed1f 9fb4c309
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>

    private long mStartTimeMs;

    protected boolean mAuthAttempted;
    private boolean mAuthAttempted;

    // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update
    //  the state. We should think of a way to improve this in the future.
@@ -98,6 +98,12 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
     */
    protected abstract void handleLifecycleAfterAuth(boolean authenticated);

    /**
     * @return true if a user was detected (i.e. face was found, fingerprint sensor was touched.
     *         etc)
     */
    public abstract boolean wasUserDetected();

    public AuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
            @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
            int targetUserId, long operationId, boolean restricted, @NonNull String owner,
@@ -381,9 +387,11 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
    }

    @Override
    public void onError(int errorCode, int vendorCode) {
    public void onError(@BiometricConstants.Errors int errorCode, int vendorCode) {
        super.onError(errorCode, vendorCode);
        mState = STATE_STOPPED;

        CoexCoordinator.getInstance().onAuthenticationError(this, errorCode, this::vibrateError);
    }

    /**
@@ -445,4 +453,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
    public boolean interruptsPrecedingClients() {
        return true;
    }

    public boolean wasAuthAttempted() {
        return mAuthAttempted;
    }
}
+67 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTyp

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.biometrics.BiometricConstants;
import android.os.Handler;
import android.os.Looper;
import android.util.Slog;
@@ -54,7 +55,7 @@ public class CoexCoordinator {

    /**
     * Callback interface notifying the owner of "results" from the CoexCoordinator's business
     * logic.
     * logic for accept and reject.
     */
    interface Callback {
        /**
@@ -80,6 +81,17 @@ public class CoexCoordinator {
        void sendAuthenticationCanceled();
    }

    /**
     * Callback interface notifying the owner of "results" from the CoexCoordinator's business
     * logic for errors.
     */
    interface ErrorCallback {
        /**
         * Requests the owner to initiate a vibration for this event.
         */
        void sendHapticFeedback();
    }

    private static CoexCoordinator sInstance;

    @VisibleForTesting
@@ -203,6 +215,9 @@ public class CoexCoordinator {
        mClientMap.remove(sensorType);
    }

    /**
     * Notify the coordinator that authentication succeeded (accepted)
     */
    public void onAuthenticationSucceeded(long currentTimeMillis,
            @NonNull AuthenticationClient<?> client,
            @NonNull Callback callback) {
@@ -273,6 +288,9 @@ public class CoexCoordinator {
        }
    }

    /**
     * Notify the coordinator that a rejection has occurred.
     */
    public void onAuthenticationRejected(long currentTimeMillis,
            @NonNull AuthenticationClient<?> client,
            @LockoutTracker.LockoutMode int lockoutMode,
@@ -357,6 +375,54 @@ public class CoexCoordinator {
        }
    }

    /**
     * Notify the coordinator that an error has occurred.
     */
    public void onAuthenticationError(@NonNull AuthenticationClient<?> client,
            @BiometricConstants.Errors int error, @NonNull ErrorCallback callback) {
        // Figure out non-coex state
        final boolean shouldUsuallyVibrate;
        if (isCurrentFaceAuth(client)) {
            final boolean notDetectedOnKeyguard = client.isKeyguard() && !client.wasUserDetected();
            final boolean authAttempted = client.wasAuthAttempted();

            switch (error) {
                case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
                case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
                case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
                    shouldUsuallyVibrate = authAttempted && !notDetectedOnKeyguard;
                    break;
                default:
                    shouldUsuallyVibrate = false;
                    break;
            }
        } else {
            shouldUsuallyVibrate = false;
        }

        // Figure out coex state
        final boolean keyguardAdvancedLogic = mAdvancedLogicEnabled && client.isKeyguard();
        final boolean hapticSuppressedByCoex;

        if (keyguardAdvancedLogic) {
            if (isSingleAuthOnly(client)) {
                hapticSuppressedByCoex = false;
            } else {
                hapticSuppressedByCoex = isCurrentFaceAuth(client)
                        && !client.isKeyguardBypassEnabled();
            }
        } else {
            hapticSuppressedByCoex = false;
        }

        // Combine and send feedback if appropriate
        Slog.d(TAG, "shouldUsuallyVibrate: " + shouldUsuallyVibrate
                + ", hapticSuppressedByCoex: " + hapticSuppressedByCoex);
        if (shouldUsuallyVibrate && !hapticSuppressedByCoex) {
            callback.sendHapticFeedback();
        }
    }

    @Nullable
    private SuccessfulAuth popSuccessfulFaceAuthIfExists(long currentTimeMillis) {
        for (SuccessfulAuth auth : mSuccessfulAuths) {
+5 −21
Original line number Diff line number Diff line
@@ -127,7 +127,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
        }
    }

    private boolean wasUserDetected() {
    @Override
    public boolean wasUserDetected() {
        // Do not provide haptic feedback if the user was not detected, and an error (usually
        // ERROR_TIMEOUT) is received.
        return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
@@ -160,7 +161,7 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
    }

    @Override
    public void onError(int error, int vendorCode) {
    public void onError(@BiometricConstants.Errors int error, int vendorCode) {
        mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
                getStartTimeMs(),
                System.currentTimeMillis() - getStartTimeMs() /* latency */,
@@ -169,25 +170,8 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
                vendorCode,
                getTargetUserId()));

        switch (error) {
            case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
                if (!wasUserDetected() && !isBiometricPrompt()) {
                    // No vibration if user was not detected on keyguard
                    break;
                }
            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
                if (mAuthAttempted) {
                    // Only vibrate if auth was attempted. If the user was already locked out prior
                    // to starting authentication, do not vibrate.
                    vibrateError();
                }
                break;
            case BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL:
        if (error == BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL) {
            BiometricNotificationUtils.showReEnrollmentNotification(getContext());
                break;
            default:
                break;
        }

        super.onError(error, vendorCode);
+3 −20
Original line number Diff line number Diff line
@@ -115,7 +115,8 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
        }
    }

    private boolean wasUserDetected() {
    @Override
    public boolean wasUserDetected() {
        // Do not provide haptic feedback if the user was not detected, and an error (usually
        // ERROR_TIMEOUT) is received.
        return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
@@ -147,7 +148,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
    }

    @Override
    public void onError(int error, int vendorCode) {
    public void onError(@BiometricConstants.Errors int error, int vendorCode) {
        mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
                getStartTimeMs(),
                System.currentTimeMillis() - getStartTimeMs() /* latency */,
@@ -156,24 +157,6 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
                vendorCode,
                getTargetUserId()));

        switch (error) {
            case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
                if (!wasUserDetected() && !isBiometricPrompt()) {
                    // No vibration if user was not detected on keyguard
                    break;
                }
            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
                if (mAuthAttempted) {
                    // Only vibrate if auth was attempted. If the user was already locked out prior
                    // to starting authentication, do not vibrate.
                    vibrateError();
                }
                break;
            default:
                break;
        }

        super.onError(error, vendorCode);
    }

+6 −0
Original line number Diff line number Diff line
@@ -105,6 +105,12 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
        }
    }

    @Override
    public boolean wasUserDetected() {
        // TODO: Update if it needs to be used for fingerprint, i.e. success/reject, error_timeout
        return false;
    }

    @Override
    public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
            boolean authenticated, ArrayList<Byte> token) {
Loading