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

Commit 4a468bd4 authored by Kevin Chyn's avatar Kevin Chyn
Browse files

Disable face haptics during coex non-bypass by default

Face haptic should still be played when bypass is enabled. Adds test
cases for both paths.

Bug: 193089985

Test: adb shell dumpsys biometric
Test: atest com.android.server.biometrics
Change-Id: I0dd89ee9a63307cd5cef886aded5a7b618c580d7
parent ab3f902c
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -1106,6 +1106,11 @@ public class BiometricService extends SystemService {
            return Settings.Secure.getInt(context.getContentResolver(),
            return Settings.Secure.getInt(context.getContentResolver(),
                    CoexCoordinator.SETTING_ENABLE_NAME, 1) != 0;
                    CoexCoordinator.SETTING_ENABLE_NAME, 1) != 0;
        }
        }

        public boolean isCoexFaceNonBypassHapticsDisabled(Context context) {
            return Settings.Secure.getInt(context.getContentResolver(),
                    CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0;
        }
    }
    }


    /**
    /**
@@ -1137,6 +1142,8 @@ public class BiometricService extends SystemService {
        //  by default.
        //  by default.
        CoexCoordinator coexCoordinator = CoexCoordinator.getInstance();
        CoexCoordinator coexCoordinator = CoexCoordinator.getInstance();
        coexCoordinator.setAdvancedLogicEnabled(injector.isAdvancedCoexLogicEnabled(context));
        coexCoordinator.setAdvancedLogicEnabled(injector.isAdvancedCoexLogicEnabled(context));
        coexCoordinator.setFaceHapticDisabledWhenNonBypass(
                injector.isCoexFaceNonBypassHapticsDisabled(context));


        try {
        try {
            injector.getActivityManagerService().registerUserSwitchObserver(
            injector.getActivityManagerService().registerUserSwitchObserver(
+9 −3
Original line number Original line Diff line number Diff line
@@ -54,12 +54,18 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
    public static final int STATE_NEW = 0;
    public static final int STATE_NEW = 0;
    // Framework/HAL have started this operation
    // Framework/HAL have started this operation
    public static final int STATE_STARTED = 1;
    public static final int STATE_STARTED = 1;
    // Operation is started, but requires some user action (such as finger lift & re-touch)
    // Operation is started, but requires some user action to start (such as finger lift & re-touch)
    public static final int STATE_STARTED_PAUSED = 2;
    public static final int STATE_STARTED_PAUSED = 2;
    // Same as above, except auth was attempted (rejected, timed out, etc).
    public static final int STATE_STARTED_PAUSED_ATTEMPTED = 3;
    // Done, errored, canceled, etc. HAL/framework are not running this sensor anymore.
    // Done, errored, canceled, etc. HAL/framework are not running this sensor anymore.
    public static final int STATE_STOPPED = 3;
    public static final int STATE_STOPPED = 4;


    @IntDef({STATE_NEW, STATE_STARTED, STATE_STARTED_PAUSED, STATE_STOPPED})
    @IntDef({STATE_NEW,
            STATE_STARTED,
            STATE_STARTED_PAUSED,
            STATE_STARTED_PAUSED_ATTEMPTED,
            STATE_STOPPED})
    @interface State {}
    @interface State {}


    private final boolean mIsStrongBiometric;
    private final boolean mIsStrongBiometric;
+34 −4
Original line number Original line Diff line number Diff line
@@ -45,6 +45,8 @@ public class CoexCoordinator {
    private static final String TAG = "BiometricCoexCoordinator";
    private static final String TAG = "BiometricCoexCoordinator";
    public static final String SETTING_ENABLE_NAME =
    public static final String SETTING_ENABLE_NAME =
            "com.android.server.biometrics.sensors.CoexCoordinator.enable";
            "com.android.server.biometrics.sensors.CoexCoordinator.enable";
    public static final String FACE_HAPTIC_DISABLE =
            "com.android.server.biometrics.sensors.CoexCoordinator.disable_face_haptics";
    private static final boolean DEBUG = true;
    private static final boolean DEBUG = true;


    // Successful authentications should be used within this amount of time.
    // Successful authentications should be used within this amount of time.
@@ -144,6 +146,10 @@ public class CoexCoordinator {
        mAdvancedLogicEnabled = enabled;
        mAdvancedLogicEnabled = enabled;
    }
    }


    public void setFaceHapticDisabledWhenNonBypass(boolean disabled) {
        mFaceHapticDisabledWhenNonBypass = disabled;
    }

    @VisibleForTesting
    @VisibleForTesting
    void reset() {
    void reset() {
        mClientMap.clear();
        mClientMap.clear();
@@ -153,6 +159,7 @@ public class CoexCoordinator {
    private final Map<Integer, AuthenticationClient<?>> mClientMap;
    private final Map<Integer, AuthenticationClient<?>> mClientMap;
    @VisibleForTesting final LinkedList<SuccessfulAuth> mSuccessfulAuths;
    @VisibleForTesting final LinkedList<SuccessfulAuth> mSuccessfulAuths;
    private boolean mAdvancedLogicEnabled;
    private boolean mAdvancedLogicEnabled;
    private boolean mFaceHapticDisabledWhenNonBypass;
    private final Handler mHandler;
    private final Handler mHandler;


    private CoexCoordinator() {
    private CoexCoordinator() {
@@ -224,8 +231,12 @@ public class CoexCoordinator {
                        // 2) UDFPS rejected - use this face auth success to notify clients
                        // 2) UDFPS rejected - use this face auth success to notify clients
                        mSuccessfulAuths.add(new SuccessfulAuth(mHandler, mSuccessfulAuths,
                        mSuccessfulAuths.add(new SuccessfulAuth(mHandler, mSuccessfulAuths,
                                currentTimeMillis, SENSOR_TYPE_FACE, client, callback));
                                currentTimeMillis, SENSOR_TYPE_FACE, client, callback));
                    } else {
                        if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) {
                            Slog.w(TAG, "Skipping face success haptic");
                        } else {
                        } else {
                            callback.sendHapticFeedback();
                            callback.sendHapticFeedback();
                        }
                        callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
                        callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
                        callback.handleLifecycleAfterAuth();
                        callback.handleLifecycleAfterAuth();
                    }
                    }
@@ -278,10 +289,21 @@ public class CoexCoordinator {
                        // BiometricScheduler do not get stuck.
                        // BiometricScheduler do not get stuck.
                        Slog.d(TAG, "Face rejected in multi-sensor auth, udfps: " + udfps);
                        Slog.d(TAG, "Face rejected in multi-sensor auth, udfps: " + udfps);
                        callback.handleLifecycleAfterAuth();
                        callback.handleLifecycleAfterAuth();
                    } else if (isUdfpsAuthAttempted(udfps)) {
                        // If UDFPS is STATE_STARTED_PAUSED (e.g. finger rejected but can still
                        // auth after pointer goes down, it means UDFPS encountered a rejection. In
                        // this case, we need to play the final reject haptic since face auth is
                        // also done now.
                        callback.sendHapticFeedback();
                        callback.handleLifecycleAfterAuth();
                    }
                    else {
                        // UDFPS auth has never been attempted.
                        if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) {
                            Slog.w(TAG, "Skipping face reject haptic");
                        } else {
                        } else {
                        // UDFPS is not actively authenticating (finger not touching, already
                        // rejected, etc).
                            callback.sendHapticFeedback();
                            callback.sendHapticFeedback();
                        }
                        callback.handleLifecycleAfterAuth();
                        callback.handleLifecycleAfterAuth();
                    }
                    }
                } else if (isCurrentUdfps(client)) {
                } else if (isCurrentUdfps(client)) {
@@ -374,6 +396,13 @@ public class CoexCoordinator {
        return false;
        return false;
    }
    }


    private static boolean isUdfpsAuthAttempted(@Nullable AuthenticationClient<?> client) {
        if (client instanceof Udfps) {
            return client.getState() == AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED;
        }
        return false;
    }

    private boolean isUnknownClient(@NonNull AuthenticationClient<?> client) {
    private boolean isUnknownClient(@NonNull AuthenticationClient<?> client) {
        for (AuthenticationClient<?> c : mClientMap.values()) {
        for (AuthenticationClient<?> c : mClientMap.values()) {
            if (c == client) {
            if (c == client) {
@@ -400,6 +429,7 @@ public class CoexCoordinator {
    public String toString() {
    public String toString() {
        StringBuilder sb = new StringBuilder();
        StringBuilder sb = new StringBuilder();
        sb.append("Enabled: ").append(mAdvancedLogicEnabled);
        sb.append("Enabled: ").append(mAdvancedLogicEnabled);
        sb.append(", Face Haptic Disabled: ").append(mFaceHapticDisabledWhenNonBypass);
        sb.append(", Queue size: " ).append(mSuccessfulAuths.size());
        sb.append(", Queue size: " ).append(mSuccessfulAuths.size());
        for (SuccessfulAuth auth : mSuccessfulAuths) {
        for (SuccessfulAuth auth : mSuccessfulAuths) {
            sb.append(", Auth: ").append(auth.toString());
            sb.append(", Auth: ").append(auth.toString());
+2 −2
Original line number Original line Diff line number Diff line
@@ -114,7 +114,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
            mState = STATE_STOPPED;
            mState = STATE_STOPPED;
            UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
            UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
        } else {
        } else {
            mState = STATE_STARTED_PAUSED;
            mState = STATE_STARTED_PAUSED_ATTEMPTED;
        }
        }
    }
    }


@@ -188,7 +188,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
    public void onPointerUp() {
    public void onPointerUp() {
        try {
        try {
            mIsPointerDown = false;
            mIsPointerDown = false;
            mState = STATE_STARTED_PAUSED;
            mState = STATE_STARTED_PAUSED_ATTEMPTED;
            mALSProbeCallback.getProbe().disable();
            mALSProbeCallback.getProbe().disable();
            getFreshDaemon().onPointerUp(0 /* pointerId */);
            getFreshDaemon().onPointerUp(0 /* pointerId */);


+2 −2
Original line number Original line Diff line number Diff line
@@ -112,7 +112,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
            resetFailedAttempts(getTargetUserId());
            resetFailedAttempts(getTargetUserId());
            UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
            UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
        } else {
        } else {
            mState = STATE_STARTED_PAUSED;
            mState = STATE_STARTED_PAUSED_ATTEMPTED;
            final @LockoutTracker.LockoutMode int lockoutMode =
            final @LockoutTracker.LockoutMode int lockoutMode =
                    mLockoutFrameworkImpl.getLockoutModeForUser(getTargetUserId());
                    mLockoutFrameworkImpl.getLockoutModeForUser(getTargetUserId());
            if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
            if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
@@ -206,7 +206,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
    @Override
    @Override
    public void onPointerUp() {
    public void onPointerUp() {
        mIsPointerDown = false;
        mIsPointerDown = false;
        mState = STATE_STARTED_PAUSED;
        mState = STATE_STARTED_PAUSED_ATTEMPTED;
        mALSProbeCallback.getProbe().disable();
        mALSProbeCallback.getProbe().disable();
        UdfpsHelper.onFingerUp(getFreshDaemon());
        UdfpsHelper.onFingerUp(getFreshDaemon());


Loading