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

Commit e1a4b9e0 authored by Juan Sebastian Martinez's avatar Juan Sebastian Martinez Committed by Automerger Merge Worker
Browse files

Merge "Using performHapticFeedback on UdfpsController" into udc-qpr-dev am: 2588c8d5

parents 68652cf3 2588c8d5
Loading
Loading
Loading
Loading
+40 −12
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROL

import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;

import android.content.BroadcastReceiver;
import android.content.Context;
@@ -50,6 +51,7 @@ import android.os.Trace;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -234,6 +236,8 @@ public class UdfpsController implements DozeReceiver, Dumpable {
    public static final VibrationEffect EFFECT_CLICK =
            VibrationEffect.get(VibrationEffect.EFFECT_CLICK);

    public static final int LONG_PRESS = HapticFeedbackConstants.LONG_PRESS;

    private final ScreenLifecycle.Observer mScreenObserver = new ScreenLifecycle.Observer() {
        @Override
        public void onScreenTurnedOn() {
@@ -926,6 +930,17 @@ public class UdfpsController implements DozeReceiver, Dumpable {
    @VisibleForTesting
    public void playStartHaptic() {
        if (mAccessibilityManager.isTouchExplorationEnabled()) {
            if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
                if (mOverlay != null && mOverlay.getOverlayView() != null) {
                    mVibrator.performHapticFeedback(
                            mOverlay.getOverlayView(),
                            HapticFeedbackConstants.CONTEXT_CLICK
                    );
                } else {
                    Log.e(TAG, "No haptics played. Could not obtain overlay view to perform"
                            + "vibration. Either the controller overlay is null or has no view");
                }
            } else {
                mVibrator.vibrate(
                        Process.myUid(),
                        mContext.getOpPackageName(),
@@ -934,6 +949,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
                        UDFPS_VIBRATION_ATTRIBUTES);
            }
        }
    }

    @Override
    public void dozeTimeTick() {
@@ -1024,12 +1040,24 @@ public class UdfpsController implements DozeReceiver, Dumpable {
            mKeyguardViewManager.showPrimaryBouncer(true);

            // play the same haptic as the LockIconViewController longpress
            if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
                if (mOverlay != null && mOverlay.getOverlayView() != null) {
                    mVibrator.performHapticFeedback(
                            mOverlay.getOverlayView(),
                            UdfpsController.LONG_PRESS
                    );
                } else {
                    Log.e(TAG, "No haptics played. Could not obtain overlay view to perform"
                            + "vibration. Either the controller overlay is null or has no view");
                }
            } else {
                mVibrator.vibrate(
                        Process.myUid(),
                        mContext.getOpPackageName(),
                        UdfpsController.EFFECT_CLICK,
                        "aod-lock-icon-longpress",
                        LOCK_ICON_VIBRATION_ATTRIBUTES);
            }
            return;
        }

+102 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.view.MotionEvent.ACTION_UP;

import static com.android.internal.util.FunctionalUtils.ThrowingConsumer;
import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
import static com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -61,6 +62,7 @@ import android.os.RemoteException;
import android.os.VibrationAttributes;
import android.testing.TestableLooper.RunWithLooper;
import android.util.Pair;
import android.view.HapticFeedbackConstants;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
@@ -1127,6 +1129,36 @@ public class UdfpsControllerTest extends SysuiTestCase {
                UdfpsController.UDFPS_VIBRATION_ATTRIBUTES.getUsage());
    }

    @Test
    public void playHapticOnTouchUdfpsArea_a11yTouchExplorationEnabled_oneWayHapticsEnabled()
            throws RemoteException {
        when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
        // Configure UdfpsView to accept the ACTION_DOWN event
        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);

        // GIVEN that the overlay is showing and a11y touch exploration enabled
        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true);
        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
        mFgExecutor.runAllReady();

        // WHEN ACTION_HOVER is received
        verify(mUdfpsView).setOnHoverListener(mHoverListenerCaptor.capture());
        MotionEvent enterEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
        mHoverListenerCaptor.getValue().onHover(mUdfpsView, enterEvent);
        enterEvent.recycle();
        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
        mHoverListenerCaptor.getValue().onHover(mUdfpsView, moveEvent);
        moveEvent.recycle();

        // THEN context click haptic is played
        verify(mVibrator).performHapticFeedback(
                any(),
                eq(HapticFeedbackConstants.CONTEXT_CLICK)
        );
    }

    @Test
    public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled() throws RemoteException {
        // Configure UdfpsView to accept the ACTION_DOWN event
@@ -1159,6 +1191,35 @@ public class UdfpsControllerTest extends SysuiTestCase {
                any());
    }

    @Test
    public void noHapticOnTouchUdfpsArea_a11yTouchExplorationDisabled__oneWayHapticsEnabled()
            throws RemoteException {
        when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
        // Configure UdfpsView to accept the ACTION_DOWN event
        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);

        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
        mFgExecutor.runAllReady();

        // WHEN ACTION_DOWN is received
        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
        mBiometricExecutor.runAllReady();
        downEvent.recycle();
        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
        mBiometricExecutor.runAllReady();
        moveEvent.recycle();

        // THEN NO haptic played
        verify(mVibrator, never()).performHapticFeedback(any(), anyInt());
    }

    @Test
    public void onTouch_withoutNewTouchDetection_shouldCallOldFingerprintManagerPath()
            throws RemoteException {
@@ -1514,4 +1575,45 @@ public class UdfpsControllerTest extends SysuiTestCase {
        // THEN is fingerDown should be FALSE
        assertFalse(mUdfpsController.isFingerDown());
    }

    @Test
    public void playHaptic_onAodInterrupt_oneWayHapticsDisabled_onAcquiredBad_usesVibrate()
            throws RemoteException {
        // GIVEN UDFPS overlay is showing
        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
        mFgExecutor.runAllReady();

        // GIVEN there's been an AoD interrupt
        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
        mScreenObserver.onScreenTurnedOn();
        mUdfpsController.onAodInterrupt(0, 0, 0, 0);

        // THEN vibrate is used
        verify(mVibrator).vibrate(
                anyInt(),
                anyString(),
                eq(UdfpsController.EFFECT_CLICK),
                eq("aod-lock-icon-longpress"),
                eq(UdfpsController.LOCK_ICON_VIBRATION_ATTRIBUTES)
        );
    }

    @Test
    public void playHaptic_onAodInterrupt_oneWayHapticsEnabled_onAcquiredBad_performHapticFeedback()
            throws RemoteException {
        when(mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)).thenReturn(true);
        // GIVEN UDFPS overlay is showing
        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
        mFgExecutor.runAllReady();

        // GIVEN there's been an AoD interrupt
        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
        mScreenObserver.onScreenTurnedOn();
        mUdfpsController.onAodInterrupt(0, 0, 0, 0);

        // THEN vibrate is used
        verify(mVibrator).performHapticFeedback(any(), eq(UdfpsController.LONG_PRESS));
    }
}