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

Commit 7770028a authored by Beverly's avatar Beverly
Browse files

Add ability to customize haptics on auth success/fail

Temporary change for UX:
With adb commands, you can customize haptic feedback for fingerprint and
face authentication fail / success.

Test: manual, atest BiometricsSchedulerTest
Bug: 185124905
Change-Id: If2c1a23095a74edc40409ad2bfc35ca704852e19
parent f98e690f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -143,6 +143,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
    private final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
    private final VibrationEffect mEffectHeavy =
            VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
    private final VibrationEffect mDoubleClick =
            VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
    private final Runnable mAcquiredVibration = new Runnable() {
        @Override
        public void run() {
@@ -714,6 +716,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
                return mEffectTextureTick;
            case "tick":
                return mEffectTick;
            case "double_tap":
                return mDoubleClick;
            default:
                return defaultEffect;
        }
+44 −4
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricConstants;
import android.media.AudioAttributes;
@@ -26,6 +27,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.text.TextUtils;
import android.util.Slog;

/**
@@ -43,6 +45,15 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement
                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
                    .build();

    private final VibrationEffect mEffectTick = VibrationEffect.get(VibrationEffect.EFFECT_TICK);
    private final VibrationEffect mEffectTextureTick =
            VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK);
    private final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
    private final VibrationEffect mEffectHeavy =
            VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
    private final VibrationEffect mDoubleClick =
            VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);

    private final PowerManager mPowerManager;
    private final VibrationEffect mSuccessVibrationEffect;
    private final VibrationEffect mErrorVibrationEffect;
@@ -61,8 +72,8 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement
        super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId, statsModality,
                statsAction, statsClient);
        mPowerManager = context.getSystemService(PowerManager.class);
        mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
        mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
        mSuccessVibrationEffect = mEffectClick;
        mErrorVibrationEffect = mDoubleClick;
    }

    @Override
@@ -181,18 +192,47 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement
        mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
    }

    protected @NonNull VibrationEffect getSuccessVibrationEffect() {
        return mSuccessVibrationEffect;
    }

    protected @NonNull VibrationEffect getErrorVibrationEffect() {
        return mErrorVibrationEffect;
    }

    protected final void vibrateSuccess() {
        Vibrator vibrator = getContext().getSystemService(Vibrator.class);
        if (vibrator != null) {
            vibrator.vibrate(mSuccessVibrationEffect, VIBRATION_SONFICATION_ATTRIBUTES);
            vibrator.vibrate(getSuccessVibrationEffect(), VIBRATION_SONFICATION_ATTRIBUTES);
        }
    }

    protected final void vibrateError() {
        Vibrator vibrator = getContext().getSystemService(Vibrator.class);
        if (vibrator != null) {
            vibrator.vibrate(mErrorVibrationEffect, VIBRATION_SONFICATION_ATTRIBUTES);
            vibrator.vibrate(getErrorVibrationEffect(), VIBRATION_SONFICATION_ATTRIBUTES);
        }
    }

    protected final @NonNull VibrationEffect getVibration(@Nullable String effect,
            @NonNull VibrationEffect defaultEffect) {
        if (TextUtils.isEmpty(effect)) {
            return defaultEffect;
        }

        switch (effect.toLowerCase()) {
            case "click":
                return mEffectClick;
            case "heavy":
                return mEffectHeavy;
            case "texture_tick":
                return mEffectTextureTick;
            case "tick":
                return mEffectTick;
            case "double_click":
                return mDoubleClick;
            default:
                return defaultEffect;
        }
    }
}
+30 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.TaskStackListener;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -30,6 +31,8 @@ import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.VibrationEffect;
import android.provider.Settings;
import android.security.KeyStore;
import android.util.EventLog;
import android.util.Slog;
@@ -56,12 +59,14 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
    private final LockoutTracker mLockoutTracker;
    private final boolean mIsRestricted;
    private final boolean mAllowBackgroundAuthentication;
    @NonNull private final ContentResolver mContentResolver;

    protected final long mOperationId;

    private long mStartTimeMs;

    protected boolean mAuthAttempted;
    private final boolean mCustomHaptics;

    public AuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
            @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
@@ -80,6 +85,10 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
        mLockoutTracker = lockoutTracker;
        mIsRestricted = restricted;
        mAllowBackgroundAuthentication = allowBackgroundAuthentication;

        mContentResolver = context.getContentResolver();
        mCustomHaptics = Settings.Global.getInt(mContentResolver,
                "fp_custom_success_error", 0) == 1;
    }

    public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
@@ -333,4 +342,25 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
    public boolean interruptsPrecedingClients() {
        return true;
    }

    @Override
    protected @NonNull VibrationEffect getSuccessVibrationEffect() {
        if (!mCustomHaptics) {
            return super.getSuccessVibrationEffect();
        }

        return getVibration(Settings.Global.getString(mContentResolver,
                "fp_success_type"), super.getSuccessVibrationEffect());
    }

    @Override
    protected @NonNull VibrationEffect getErrorVibrationEffect() {
        if (!mCustomHaptics) {
            return super.getErrorVibrationEffect();
        }

        return getVibration(Settings.Global.getString(mContentResolver,
                "fp_error_type"), super.getErrorVibrationEffect());

    }
}
+30 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.face.aidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -32,6 +33,8 @@ import android.hardware.face.FaceAuthenticationFrame;
import android.hardware.face.FaceManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.VibrationEffect;
import android.provider.Settings;
import android.util.Slog;

import com.android.internal.R;
@@ -57,6 +60,9 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
    @Nullable private final NotificationManager mNotificationManager;
    @Nullable private ICancellationSignal mCancellationSignal;

    @NonNull private final ContentResolver mContentResolver;
    private final boolean mCustomHaptics;

    private final int[] mBiometricPromptIgnoreList;
    private final int[] mBiometricPromptIgnoreListVendor;
    private final int[] mKeyguardIgnoreList;
@@ -87,6 +93,10 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
                R.array.config_face_acquire_keyguard_ignorelist);
        mKeyguardIgnoreListVendor = resources.getIntArray(
                R.array.config_face_acquire_vendor_keyguard_ignorelist);

        mContentResolver = context.getContentResolver();
        mCustomHaptics = Settings.Global.getInt(mContentResolver,
                "face_custom_success_error", 0) == 1;
    }

    @Override
@@ -243,4 +253,24 @@ class FaceAuthenticationClient extends AuthenticationClient<ISession> implements
            Slog.e(TAG, "Remote exception", e);
        }
    }

    @Override
    protected @NonNull VibrationEffect getSuccessVibrationEffect() {
        if (!mCustomHaptics) {
            return super.getSuccessVibrationEffect();
        }

        return getVibration(Settings.Global.getString(mContentResolver,
                "face_success_type"), super.getSuccessVibrationEffect());
    }

    @Override
    protected @NonNull VibrationEffect getErrorVibrationEffect() {
        if (!mCustomHaptics) {
            return super.getErrorVibrationEffect();
        }

        return getVibration(Settings.Global.getString(mContentResolver,
                "face_error_type"), super.getErrorVibrationEffect());
    }
}
+29 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors.face.hidl;

import android.annotation.NonNull;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -27,6 +28,8 @@ import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.hardware.face.FaceManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.VibrationEffect;
import android.provider.Settings;
import android.util.Slog;

import com.android.internal.R;
@@ -47,7 +50,8 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {

    private static final String TAG = "FaceAuthenticationClient";


    @NonNull private final ContentResolver mContentResolver;
    private final boolean mCustomHaptics;
    private final UsageStats mUsageStats;

    private final int[] mBiometricPromptIgnoreList;
@@ -78,6 +82,10 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
                R.array.config_face_acquire_keyguard_ignorelist);
        mKeyguardIgnoreListVendor = resources.getIntArray(
                R.array.config_face_acquire_vendor_keyguard_ignorelist);

        mContentResolver = context.getContentResolver();
        mCustomHaptics = Settings.Global.getInt(mContentResolver,
                "face_custom_success_error", 0) == 1;
    }

    @Override
@@ -188,4 +196,24 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
        final boolean shouldSend = shouldSend(acquireInfo, vendorCode);
        onAcquiredInternal(acquireInfo, vendorCode, shouldSend);
    }

    @Override
    protected @NonNull VibrationEffect getSuccessVibrationEffect() {
        if (!mCustomHaptics) {
            return super.getSuccessVibrationEffect();
        }

        return getVibration(Settings.Global.getString(mContentResolver,
                "face_success_type"), super.getSuccessVibrationEffect());
    }

    @Override
    protected @NonNull VibrationEffect getErrorVibrationEffect() {
        if (!mCustomHaptics) {
            return super.getErrorVibrationEffect();
        }

        return getVibration(Settings.Global.getString(mContentResolver,
                "face_error_type"), super.getErrorVibrationEffect());
    }
}
Loading