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

Commit 9f65a6c4 authored by Joshua Mccloskey's avatar Joshua Mccloskey Committed by Automerger Merge Worker
Browse files

Merge "Announce feedback for udfps misses during enroll" into tm-dev am: 23751ef8

parents 78664c52 23751ef8
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -804,6 +804,14 @@
    <!-- Message shown when non-bypass face authentication succeeds and UDFPS is supported. Provides extra instructions for how the user can enter their device [CHAR LIMIT=60] -->
    <string name="keyguard_face_successful_unlock_press">Unlocked by face. Press the unlock icon to open.</string>

    <!-- Messages shown when users press outside of udfps region during -->
    <string-array name="udfps_accessibility_touch_hints">
        <item>Move left</item>
        <item>Move down</item>
        <item>Move right</item>
        <item>Move up</item>
    </string-array>

    <!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] -->
    <string name="keyguard_retry">Swipe up to try again</string>

+5 −0
Original line number Diff line number Diff line
@@ -192,4 +192,9 @@ abstract class UdfpsAnimationViewController<T : UdfpsAnimationView>(
     * Called on touches outside of the view if listenForTouchesOutsideView returns true
     */
    open fun onTouchOutsideView() {}

    /**
     * Called when a view should announce an accessibility event.
     */
    open fun doAnnounceForAccessibility(str: String) {}
}
 No newline at end of file
+44 −17
Original line number Diff line number Diff line
@@ -381,6 +381,27 @@ public class UdfpsController implements DozeReceiver {
                && mOverlayParams.getSensorBounds().contains((int) x, (int) y);
    }

    private Point getTouchInNativeCoordinates(@NonNull MotionEvent event, int idx) {
        Point portraitTouch = new Point(
                (int) event.getRawX(idx),
                (int) event.getRawY(idx)
        );
        final int rot = mOverlayParams.getRotation();
        if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
            RotationUtils.rotatePoint(portraitTouch,
                    RotationUtils.deltaRotation(rot, Surface.ROTATION_0),
                    mOverlayParams.getLogicalDisplayWidth(),
                    mOverlayParams.getLogicalDisplayHeight()
            );
        }

        // Scale the coordinates to native resolution.
        final float scale = mOverlayParams.getScaleFactor();
        portraitTouch.x = (int) (portraitTouch.x / scale);
        portraitTouch.y = (int) (portraitTouch.y / scale);
        return portraitTouch;
    }

    @VisibleForTesting
    boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
        if (mOverlay == null) {
@@ -434,6 +455,7 @@ public class UdfpsController implements DozeReceiver {
                    mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
                    mAttemptedToDismissKeyguard = true;
                }

                Trace.endSection();
                break;

@@ -457,6 +479,8 @@ public class UdfpsController implements DozeReceiver {
                        mAttemptedToDismissKeyguard = true;
                        break;
                    }
                    // Map the touch to portrait mode if the device is in landscape mode.
                    final Point scaledTouch = getTouchInNativeCoordinates(event, idx);
                    if (actionMoveWithinSensorArea) {
                        if (mVelocityTracker == null) {
                            // touches could be injected, so the velocity tracker may not have
@@ -477,28 +501,13 @@ public class UdfpsController implements DozeReceiver {
                        final long sinceLastLog = mSystemClock.elapsedRealtime() - mTouchLogTime;
                        if (!isIlluminationRequested && !mAcquiredReceived
                                && !exceedsVelocityThreshold) {
                            // Map the touch to portrait mode if the device is in landscape mode.
                            Point portraitTouch = new Point(
                                    (int) event.getRawX(idx),
                                    (int) event.getRawY(idx)
                            );
                            final int rot = mOverlayParams.getRotation();
                            if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
                                RotationUtils.rotatePoint(portraitTouch,
                                        RotationUtils.deltaRotation(rot, Surface.ROTATION_0),
                                        mOverlayParams.getLogicalDisplayWidth(),
                                        mOverlayParams.getLogicalDisplayHeight()
                                );
                            }

                            // Scale the coordinates to native resolution.
                            final float scale = mOverlayParams.getScaleFactor();
                            int scaledX = (int) (portraitTouch.x / scale);
                            int scaledY = (int) (portraitTouch.y / scale);
                            float scaledMinor = minor / scale;
                            float scaledMajor = major / scale;

                            onFingerDown(requestId, scaledX, scaledY, scaledMinor, scaledMajor);
                            onFingerDown(requestId, scaledTouch.x, scaledTouch.y, scaledMinor,
                                    scaledMajor);
                            Log.v(TAG, "onTouch | finger down: " + touchInfo);
                            mTouchLogTime = mSystemClock.elapsedRealtime();
                            mPowerManager.userActivity(mSystemClock.uptimeMillis(),
@@ -511,6 +520,24 @@ public class UdfpsController implements DozeReceiver {
                    } else {
                        Log.v(TAG, "onTouch | finger outside");
                        onFingerUp(requestId, udfpsView);
                        // Maybe announce for accessibility.
                        mFgExecutor.execute(() -> {
                            if (mOverlay == null) {
                                Log.e(TAG, "touch outside sensor area received"
                                        + "but serverRequest is null");
                                return;
                            }
                            // Scale the coordinates to native resolution.
                            final float scale = mOverlayParams.getScaleFactor();
                            final float scaledSensorX =
                                    mOverlayParams.getSensorBounds().centerX() / scale;
                            final float scaledSensorY =
                                    mOverlayParams.getSensorBounds().centerY() / scale;

                            mOverlay.onTouchOutsideOfSensorArea(
                                    scaledTouch.x, scaledTouch.y, scaledSensorX, scaledSensorY,
                                    mOverlayParams.getRotation());
                        });
                    }
                }
                Trace.endSection();
+88 −2
Original line number Diff line number Diff line
@@ -130,6 +130,8 @@ class UdfpsControllerOverlay(
    val animationViewController: UdfpsAnimationViewController<*>?
        get() = overlayView?.animationViewController

    private var touchExplorationEnabled = false

    /** Show the overlay or return false and do nothing if it is already showing. */
    @SuppressLint("ClickableViewAccessibility")
    fun show(controller: UdfpsController, params: UdfpsOverlayParams): Boolean {
@@ -154,14 +156,16 @@ class UdfpsControllerOverlay(
                    }

                    windowManager.addView(this, coreLayoutParams.updateDimensions(animation))

                    touchExplorationEnabled = accessibilityManager.isTouchExplorationEnabled
                    overlayTouchListener = TouchExplorationStateChangeListener {
                        if (accessibilityManager.isTouchExplorationEnabled) {
                            setOnHoverListener { v, event -> onTouch(v, event, true) }
                            setOnTouchListener(null)
                            touchExplorationEnabled = true
                        } else {
                            setOnHoverListener(null)
                            setOnTouchListener { v, event -> onTouch(v, event, true) }
                            touchExplorationEnabled = false
                        }
                    }
                    accessibilityManager.addTouchExplorationStateChangeListener(
@@ -179,7 +183,7 @@ class UdfpsControllerOverlay(
        return false
    }

    private fun inflateUdfpsAnimation(
    fun inflateUdfpsAnimation(
        view: UdfpsView,
        controller: UdfpsController
    ): UdfpsAnimationViewController<*>? {
@@ -278,6 +282,88 @@ class UdfpsControllerOverlay(
        enrollHelper?.onEnrollmentHelp()
    }

    /**
     * This function computes the angle of touch relative to the sensor and maps
     * the angle to a list of help messages which are announced if accessibility is enabled.
     *
     */
    fun onTouchOutsideOfSensorArea(
        touchX: Float,
        touchY: Float,
        sensorX: Float,
        sensorY: Float,
        rotation: Int
    ) {

        if (!touchExplorationEnabled) {
            return
        }
        val touchHints =
            context.resources.getStringArray(R.array.udfps_accessibility_touch_hints)
        if (touchHints.size != 4) {
            Log.e(TAG, "expected exactly 4 touch hints, got $touchHints.size?")
            return
        }
        val theStr = onTouchOutsideOfSensorAreaImpl(touchX, touchY, sensorX, sensorY, rotation)
        Log.v(TAG, "Announcing touch outside : " + theStr)
        animationViewController?.doAnnounceForAccessibility(theStr)
    }

    /**
     * This function computes the angle of touch relative to the sensor and maps
     * the angle to a list of help messages which are announced if accessibility is enabled.
     *
     * There are 4 quadrants of the circle (90 degree arcs)
     *
     * [315, 360] && [0, 45) -> touchHints[0] = "Move Fingerprint to the left"
     * [45,  135)            -> touchHints[1] = "Move Fingerprint down"
     * And so on.
     */
    fun onTouchOutsideOfSensorAreaImpl(
        touchX: Float,
        touchY: Float,
        sensorX: Float,
        sensorY: Float,
        rotation: Int
    ): String {
        val touchHints =
            context.resources.getStringArray(R.array.udfps_accessibility_touch_hints)

        val xRelativeToSensor = touchX - sensorX
        // Touch coordinates are with respect to the upper left corner, so reverse
        // this calculation
        val yRelativeToSensor = sensorY - touchY

        var angleInRad =
            Math.atan2(yRelativeToSensor.toDouble(), xRelativeToSensor.toDouble())
        // If the radians are negative, that means we are counting clockwise.
        // So we need to add 360 degrees
        if (angleInRad < 0.0) {
            angleInRad += 2.0 * Math.PI
        }
        // rad to deg conversion
        val degrees = Math.toDegrees(angleInRad)

        val degreesPerBucket = 360.0 / touchHints.size
        val halfBucketDegrees = degreesPerBucket / 2.0
        // The mapping should be as follows
        // [315, 360] && [0, 45] -> 0
        // [45, 135]             -> 1
        var index = (((degrees + halfBucketDegrees) % 360) / degreesPerBucket).toInt()
        index %= touchHints.size

        // A rotation of 90 degrees corresponds to increasing the index by 1.
        if (rotation == Surface.ROTATION_90) {
            index = (index + 1) % touchHints.size
        }

        if (rotation == Surface.ROTATION_270) {
            index = (index + 3) % touchHints.size
        }

        return touchHints[index]
    }

    /** Cancel this request. */
    fun cancel() {
        try {
+6 −0
Original line number Diff line number Diff line
@@ -99,4 +99,10 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp
    public int getPaddingY() {
        return mEnrollProgressBarRadius;
    }

    @Override
    public void doAnnounceForAccessibility(String str) {
        mView.announceForAccessibility(str);
    }

}
Loading