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

Commit 5082eadb authored by Beverly's avatar Beverly Committed by Beverly Tai
Browse files

Support slide to udfps auth on keyguard

- Allow udfps fingerprint to run when the bouncer is about to show;
instead, we'll manually pause auth in UdfpsKeyguardViewController when
we don't want to allow the user to authenticate
- On Keyguard, when bringing up the bouncer (swipe up on LS), continue
to show the udfps target until it hits a threshold - then we fade out
the icon

Test: manual
Bug: 178509275
Change-Id: I6e883a619b38a1a136f9d6e39b755a75c5028553
parent f98e690f
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2112,13 +2112,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
                        && mBiometricEnabledForUser.get(getCurrentUser());

        final boolean shouldListenBouncerState =
                isUdfps ? !mBouncer
                        : !(mFingerprintLockedOut && mBouncer && mCredentialAttempted);
                !(mFingerprintLockedOut && mBouncer && mCredentialAttempted);

        final boolean shouldListenUdfpsState = !isUdfps
                || (!getUserCanSkipBouncer(getCurrentUser())
                && !isEncryptedOrLockdown(getCurrentUser())
                && mStrongAuthTracker.hasUserAuthenticatedSinceBoot());

        return shouldListenKeyguardState && shouldListenUserState && shouldListenBouncerState
                && shouldListenUdfpsState;
    }
+3 −3
Original line number Diff line number Diff line
@@ -265,7 +265,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
    /**
     * @return where the UDFPS exists on the screen in pixels in portrait mode.
     */
    public RectF getUdfpsRegion() {
    @Nullable public RectF getUdfpsRegion() {
        return mUdfpsController == null
                ? null
                : mUdfpsController.getSensorLocation();
@@ -274,7 +274,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
    /**
     * @return where the UDFPS exists on the screen in pixels in portrait mode.
     */
    public PointF getUdfpsSensorLocation() {
    @Nullable public PointF getUdfpsSensorLocation() {
        if (mUdfpsController == null) {
            return null;
        }
@@ -286,7 +286,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
     * @return where the face authentication sensor exists relative to the screen in pixels in
     * portrait mode.
     */
    public PointF getFaceAuthSensorLocation() {
    @Nullable public PointF getFaceAuthSensorLocation() {
        if (mFaceProps == null || mFaceAuthSensorLocation == null) {
            return null;
        }
+67 −31
Original line number Diff line number Diff line
@@ -260,10 +260,36 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
        }
    };

    /**
     * Forwards touches to the udfps controller / view
     */
    public boolean onTouch(MotionEvent event) {
        if (mView == null) {
            return false;
        }
        return onTouch(mView, event, false);
    }

    @SuppressLint("ClickableViewAccessibility")
    private final UdfpsView.OnTouchListener mOnTouchListener = this::onTouch;
    private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) ->
            onTouch(view, event, true);

    private boolean onTouch(View view, MotionEvent event) {
    /**
     * @param x coordinate
     * @param y coordinate
     * @param relativeToUdfpsView true if the coordinates are relative to the udfps view; else,
     *                            calculate from the display dimensions in portrait orientation
     */
    private boolean isWithinSensorArea(UdfpsView udfpsView, float x, float y,
            boolean relativeToUdfpsView) {
        if (relativeToUdfpsView) {
            // TODO: move isWithinSensorArea to UdfpsController.
            return udfpsView.isWithinSensorArea(x, y);
        }
        return getSensorLocation().contains(x, y);
    }

    private boolean onTouch(View view, MotionEvent event, boolean fromUdfpsView) {
        UdfpsView udfpsView = (UdfpsView) view;
        final boolean isFingerDown = udfpsView.isIlluminationRequested();
        boolean handled = false;
@@ -281,8 +307,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
                    // ACTION_DOWN, in that case we should just reuse the old instance.
                    mVelocityTracker.clear();
                }
                // TODO: move isWithinSensorArea to UdfpsController.
                if (udfpsView.isWithinSensorArea(event.getX(), event.getY())) {
                if (isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView)) {
                    Trace.beginAsyncSection(
                            "UdfpsController.mOnTouchListener#isWithinSensorArea", 1);
                    // The pointer that causes ACTION_DOWN is always at index 0.
@@ -290,37 +315,23 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
                    // data for many other pointers because of multi-touch support.
                    mActivePointerId = event.getPointerId(0);
                    mVelocityTracker.addMovement(event);

                    // TODO: (b/185124905) these settings are for ux testing purposes and should
                    // be removed (or cached) before going into production
                    final ContentResolver contentResolver = mContext.getContentResolver();
                    int startEnabled = Settings.Global.getInt(contentResolver,
                            "udfps_start", 0);
                    if (startEnabled > 0) {
                        String startEffectSetting = Settings.Global.getString(contentResolver,
                                "udfps_start_type");
                        mVibrator.vibrate(getVibration(startEffectSetting, mEffectClick),
                                VIBRATION_SONIFICATION_ATTRIBUTES);
                    }

                    int acquiredEnabled = Settings.Global.getInt(contentResolver,
                            "udfps_acquired", 0);
                    if (acquiredEnabled > 0) {
                        int delay = Settings.Global.getInt(contentResolver,
                                "udfps_acquired_delay", 500);
                        mMainHandler.removeCallbacks(mAcquiredVibration);
                        mMainHandler.postDelayed(mAcquiredVibration, delay);
                    }
                    handled = true;
                }
                break;

            case MotionEvent.ACTION_MOVE:
                final int idx = event.findPointerIndex(mActivePointerId);
                final int idx = mActivePointerId == -1
                        ? event.getPointerId(0)
                        : event.findPointerIndex(mActivePointerId);
                if (idx == event.getActionIndex()) {
                    final float x = event.getX(idx);
                    final float y = event.getY(idx);
                    if (udfpsView.isWithinSensorArea(x, y)) {
                    if (isWithinSensorArea(udfpsView, x, y, fromUdfpsView)) {
                        if (mVelocityTracker == null) {
                            // touches could be injected, so the velocity tracker may not have
                            // been initialized (via ACTION_DOWN).
                            mVelocityTracker = VelocityTracker.obtain();
                        }
                        mVelocityTracker.addMovement(event);
                        // Compute pointer velocity in pixels per second.
                        mVelocityTracker.computeCurrentVelocity(1000);
@@ -328,10 +339,12 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
                        final float v = computePointerSpeed(mVelocityTracker, mActivePointerId);
                        final float minor = event.getTouchMinor(idx);
                        final float major = event.getTouchMajor(idx);
                        final String touchInfo = String.format("minor: %.1f, major: %.1f, v: %.1f",
                                minor, major, v);
                        final boolean exceedsVelocityThreshold = v > 750f;
                        final String touchInfo = String.format(
                                "minor: %.1f, major: %.1f, v: %.1f, exceedsVelocityThreshold: %b",
                                minor, major, v, exceedsVelocityThreshold);
                        final long sinceLastLog = SystemClock.elapsedRealtime() - mTouchLogTime;
                        if (!isFingerDown) {
                        if (!isFingerDown && !exceedsVelocityThreshold) {
                            Trace.endAsyncSection(
                                    "UdfpsController.mOnTouchListener#isWithinSensorArea", 1);
                            onFingerDown((int) x, (int) y, minor, major);
@@ -339,6 +352,26 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
                            mTouchLogTime = SystemClock.elapsedRealtime();
                            mPowerManager.userActivity(SystemClock.uptimeMillis(),
                                    PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);

                            // TODO: this should eventually be removed after ux testing
                            final ContentResolver contentResolver = mContext.getContentResolver();
                            int startEnabled = Settings.Global.getInt(contentResolver,
                                    "udfps_start", 0);
                            if (startEnabled > 0) {
                                String startEffectSetting = Settings.Global.getString(
                                        contentResolver, "udfps_start_type");
                                mVibrator.vibrate(getVibration(startEffectSetting, mEffectClick),
                                        VIBRATION_SONIFICATION_ATTRIBUTES);
                            }

                            int acquiredEnabled = Settings.Global.getInt(contentResolver,
                                    "udfps_acquired", 0);
                            if (acquiredEnabled > 0) {
                                int delay = Settings.Global.getInt(contentResolver,
                                        "udfps_acquired_delay", 500);
                                mMainHandler.removeCallbacks(mAcquiredVibration);
                                mMainHandler.postDelayed(mAcquiredVibration, delay);
                            }
                            handled = true;
                        } else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
                            Log.v(TAG, "onTouch | finger move: " + touchInfo);
@@ -353,6 +386,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mActivePointerId = -1;
                if (mVelocityTracker != null) {
                    mVelocityTracker.recycle();
                    mVelocityTracker = null;
@@ -577,7 +611,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
                        mKeyguardUpdateMonitor,
                        mFgExecutor,
                        mDumpManager,
                        mKeyguardViewMediator
                        mKeyguardViewMediator,
                        this
                );
            case IUdfpsOverlayController.REASON_AUTH_BP:
                // note: empty controller, currently shows no visual affordance
@@ -679,6 +714,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {

    // This method can be called from the UI thread.
    private void onFingerUp() {
        mActivePointerId = -1;
        mMainHandler.removeCallbacks(mAcquiredVibration);
        if (mView == null) {
            Log.w(TAG, "Null view in onFingerUp");
+13 −1
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
    private ImageView mBgProtection;

    private AnimatorSet mAnimatorSet;
    private int mAlpha; // 0-255

    public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
@@ -97,9 +98,20 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
        }
    }

    /**
     * @param alpha between 0 and 255
     */
    void setUnpausedAlpha(int alpha) {
        mAlpha = alpha;
        updateAlpha();
    }

    @Override
    int calculateAlpha() {
        return mPauseAuth ? 0 : 255;
        if (mPauseAuth) {
            return 0;
        }
        return mAlpha;
    }

    void onDozeAmountChanged(float linear, float eased) {
+44 −3
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;

import android.annotation.NonNull;
import android.hardware.biometrics.BiometricSourceType;
import android.util.MathUtils;
import android.view.MotionEvent;

import androidx.annotation.Nullable;

@@ -29,6 +31,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -50,6 +53,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
    @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
    @NonNull private final DelayableExecutor mExecutor;
    @NonNull private final KeyguardViewMediator mKeyguardViewMediator;
    @NonNull private final UdfpsController mUdfpsController;

    @Nullable private Runnable mCancelRunnable;
    private boolean mShowingUdfpsBouncer;
@@ -60,6 +64,13 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
    private int mStatusBarState;
    private boolean mKeyguardIsVisible;

    /**
     * hidden amount of pin/pattern/password bouncer
     * {@link KeyguardBouncer#EXPANSION_VISIBLE} (0f) to
     * {@link KeyguardBouncer#EXPANSION_HIDDEN} (1f)
     */
    private float mInputBouncerHiddenAmount;

    protected UdfpsKeyguardViewController(
            @NonNull UdfpsKeyguardView view,
            @NonNull StatusBarStateController statusBarStateController,
@@ -68,12 +79,14 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
            @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
            @NonNull DelayableExecutor mainDelayableExecutor,
            @NonNull DumpManager dumpManager,
            @NonNull KeyguardViewMediator keyguardViewMediator) {
            @NonNull KeyguardViewMediator keyguardViewMediator,
            @NonNull UdfpsController udfpsController) {
        super(view, statusBarStateController, statusBar, dumpManager);
        mKeyguardViewManager = statusBarKeyguardViewManager;
        mKeyguardUpdateMonitor = keyguardUpdateMonitor;
        mExecutor = mainDelayableExecutor;
        mKeyguardViewMediator = keyguardViewMediator;
        mUdfpsController = udfpsController;
    }

    @Override
@@ -89,11 +102,14 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
        updateFaceDetectRunning(mKeyguardUpdateMonitor.isFaceDetectionRunning());

        final float dozeAmount = mStatusBarStateController.getDozeAmount();
        mStatusBarStateController.addCallback(mStateListener);
        mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
        mStatusBarStateController.addCallback(mStateListener);

        mStatusBarState = mStatusBarStateController.getState();
        mQsExpanded = mKeyguardViewManager.isQsExpanded();
        mKeyguardIsVisible = mKeyguardUpdateMonitor.isKeyguardVisible();
        mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
        updateAlpha();
        updatePauseAuth();

        mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
@@ -124,6 +140,8 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
        pw.println("mStatusBarState" + StatusBarState.toShortString(mStatusBarState));
        pw.println("mQsExpanded=" + mQsExpanded);
        pw.println("mKeyguardVisible=" + mKeyguardIsVisible);
        pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount);
        pw.println("mAlpha=" + mView.getAlpha());
    }

    /**
@@ -140,7 +158,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
        if (mShowingUdfpsBouncer) {
            mView.animateUdfpsBouncer();
        } else {
            // TODO: beverlyt, we not always want to cancelPostAuthActions
            mView.animateAwayUdfpsBouncer(() -> mKeyguardViewManager.cancelPostAuthActions());
        }
        return true;
@@ -172,6 +189,10 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
            return true;
        }

        if (mInputBouncerHiddenAmount < .4f) {
            return true;
        }

        return false;
    }

@@ -228,6 +249,14 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
        }
    }

    private void updateAlpha() {
        // fade icon on transition to showing bouncer
        int alpha = mShowingUdfpsBouncer ? 255
                : Math.abs((int) MathUtils.map(.4f, 0f, .7f, 255f,
                        mInputBouncerHiddenAmount));
        mView.setUnpausedAlpha(alpha);
    }

    private final StatusBarStateController.StateListener mStateListener =
            new StatusBarStateController.StateListener() {
        @Override
@@ -314,6 +343,18 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
                    updatePauseAuth();
                }

                @Override
                public boolean onTouch(MotionEvent event) {
                    return mUdfpsController.onTouch(event);
                }

                @Override
                public void setBouncerExpansionChanged(float expansion) {
                    mInputBouncerHiddenAmount = expansion;
                    updateAlpha();
                    updatePauseAuth();
                }

                @Override
                public void dump(PrintWriter pw) {
                    pw.println(getTag());
Loading