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

Commit e2bde5de authored by Juan Sebastian Martinez's avatar Juan Sebastian Martinez Committed by Android (Google) Code Review
Browse files

Merge "Adding MSDL feedback to the Biometric prompt." into main

parents 01f77ce0 b0a6eec6
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -97,6 +97,8 @@ import com.android.systemui.util.concurrency.FakeExecution;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;

import com.google.android.msdl.domain.MSDLPlayer;

import dagger.Lazy;

import org.junit.Before;
@@ -185,6 +187,8 @@ public class AuthControllerTest extends SysuiTestCase {
    private Resources mResources;
    @Mock
    private VibratorHelper mVibratorHelper;
    @Mock
    private MSDLPlayer mMSDLPlayer;

    private TestableContext mContextSpy;
    private Execution mExecution;
@@ -1066,7 +1070,7 @@ public class AuthControllerTest extends SysuiTestCase {
                    () -> mLogContextInteractor, () -> mPromptSelectionInteractor,
                    () -> mCredentialViewModel, () -> mPromptViewModel, mInteractionJankMonitor,
                    mHandler, mBackgroundExecutor, mUdfpsUtils, mVibratorHelper,
                    mLazyViewCapture);
                    mLazyViewCapture, mMSDLPlayer);
        }

        @Override
+8 −2
Original line number Diff line number Diff line
@@ -78,6 +78,8 @@ import com.android.systemui.res.R;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.concurrency.DelayableExecutor;

import com.google.android.msdl.domain.MSDLPlayer;

import kotlin.Lazy;

import kotlinx.coroutines.CoroutineScope;
@@ -157,6 +159,8 @@ public class AuthContainerView extends LinearLayout

    private final @Background DelayableExecutor mBackgroundExecutor;

    private final MSDLPlayer mMSDLPlayer;

    // Non-null only if the dialog is in the act of dismissing and has not sent the reason yet.
    @Nullable @AuthDialogCallback.DismissedReason private Integer mPendingCallbackReason;
    // HAT received from LockSettingsService when credential is verified.
@@ -292,7 +296,8 @@ public class AuthContainerView extends LinearLayout
            @NonNull Provider<CredentialViewModel> credentialViewModelProvider,
            @NonNull @Background DelayableExecutor bgExecutor,
            @NonNull VibratorHelper vibratorHelper,
            Lazy<ViewCapture> lazyViewCapture) {
            Lazy<ViewCapture> lazyViewCapture,
            @NonNull MSDLPlayer msdlPlayer) {
        super(config.mContext);

        mConfig = config;
@@ -309,6 +314,7 @@ public class AuthContainerView extends LinearLayout
                .getDimension(R.dimen.biometric_dialog_animation_translation_offset);
        mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN;
        mBiometricCallback = new BiometricCallback();
        mMSDLPlayer = msdlPlayer;

        final BiometricModalities biometricModalities = new BiometricModalities(
                Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
@@ -379,7 +385,7 @@ public class AuthContainerView extends LinearLayout
                getJankListener(mLayout, TRANSIT,
                        BiometricViewSizeBinder.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS),
                mBackgroundView, mBiometricCallback, mApplicationCoroutineScope,
                vibratorHelper);
                vibratorHelper, mMSDLPlayer);
    }

    @VisibleForTesting
+7 −2
Original line number Diff line number Diff line
@@ -89,6 +89,8 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;

import com.google.android.msdl.domain.MSDLPlayer;

import dagger.Lazy;

import kotlin.Unit;
@@ -183,6 +185,7 @@ public class AuthController implements
    private final @Background DelayableExecutor mBackgroundExecutor;
    private final DisplayInfo mCachedDisplayInfo = new DisplayInfo();
    @NonNull private final VibratorHelper mVibratorHelper;
    @NonNull private final MSDLPlayer mMSDLPlayer;

    private final kotlin.Lazy<ViewCapture> mLazyViewCapture;

@@ -742,7 +745,8 @@ public class AuthController implements
            @Background DelayableExecutor bgExecutor,
            @NonNull UdfpsUtils udfpsUtils,
            @NonNull VibratorHelper vibratorHelper,
            Lazy<ViewCapture> daggerLazyViewCapture) {
            Lazy<ViewCapture> daggerLazyViewCapture,
            @NonNull MSDLPlayer msdlPlayer) {
        mContext = context;
        mExecution = execution;
        mUserManager = userManager;
@@ -764,6 +768,7 @@ public class AuthController implements
        mUdfpsUtils = udfpsUtils;
        mApplicationCoroutineScope = applicationCoroutineScope;
        mVibratorHelper = vibratorHelper;
        mMSDLPlayer = msdlPlayer;

        mLogContextInteractor = logContextInteractor;
        mPromptSelectorInteractor = promptSelectorInteractorProvider;
@@ -1327,7 +1332,7 @@ public class AuthController implements
                wakefulnessLifecycle, userManager, lockPatternUtils,
                mInteractionJankMonitor, mPromptSelectorInteractor, viewModel,
                mCredentialViewModelProvider, bgExecutor, mVibratorHelper,
                mLazyViewCapture);
                mLazyViewCapture, mMSDLPlayer);
    }

    @Override
+21 −14
Original line number Diff line number Diff line
@@ -25,7 +25,6 @@ import android.hardware.biometrics.BiometricPrompt
import android.hardware.biometrics.Flags
import android.hardware.face.FaceManager
import android.util.Log
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import android.view.View
import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO
@@ -59,6 +58,7 @@ import com.android.systemui.common.ui.view.onTouchListener
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
import com.google.android.msdl.domain.MSDLPlayer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
@@ -83,6 +83,7 @@ object BiometricViewBinder {
        legacyCallback: Spaghetti.Callback,
        applicationScope: CoroutineScope,
        vibratorHelper: VibratorHelper,
        msdlPlayer: MSDLPlayer,
    ): Spaghetti {
        val accessibilityManager = view.context.getSystemService(AccessibilityManager::class.java)!!

@@ -434,21 +435,27 @@ object BiometricViewBinder {
                // Play haptics
                launch {
                    viewModel.hapticsToPlay.collect { haptics ->
                        if (haptics.hapticFeedbackConstant != HapticFeedbackConstants.NO_HAPTICS) {
                        when (haptics) {
                            is PromptViewModel.HapticsToPlay.HapticConstant -> {
                                if (haptics.flag != null) {
                                    vibratorHelper.performHapticFeedback(
                                        view,
                                    haptics.hapticFeedbackConstant,
                                        haptics.constant,
                                        haptics.flag,
                                    )
                                } else {
                                    vibratorHelper.performHapticFeedback(
                                        view,
                                    haptics.hapticFeedbackConstant,
                                        haptics.constant,
                                    )
                                }
                            viewModel.clearHaptics()
                            }
                            is PromptViewModel.HapticsToPlay.MSDL -> {
                                msdlPlayer.playToken(haptics.token, haptics.properties)
                            }
                            is PromptViewModel.HapticsToPlay.None -> {}
                        }
                        viewModel.clearHaptics()
                    }
                }

+46 −21
Original line number Diff line number Diff line
@@ -35,7 +35,9 @@ import android.util.Log
import android.util.RotationUtils
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
import com.android.keyguard.AuthInteractionProperties
import com.android.launcher3.icons.IconProvider
import com.android.systemui.Flags.msdlFeedback
import com.android.systemui.biometrics.UdfpsUtils
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.Utils.isSystem
@@ -53,6 +55,8 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
import com.android.systemui.res.R
import com.android.systemui.util.kotlin.combine
import com.google.android.msdl.data.model.MSDLToken
import com.google.android.msdl.domain.InteractionProperties
import javax.inject.Inject
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
@@ -245,8 +249,9 @@ constructor(
    private val _forceLargeSize = MutableStateFlow(false)
    private val _forceMediumSize = MutableStateFlow(false)

    private val _hapticsToPlay =
        MutableStateFlow(HapticsToPlay(HapticFeedbackConstants.NO_HAPTICS, /* flag= */ null))
    private val authInteractionProperties = AuthInteractionProperties()
    private val _hapticsToPlay: MutableStateFlow<HapticsToPlay> =
        MutableStateFlow(HapticsToPlay.None)

    /** Event fired to the view indicating a [HapticsToPlay] */
    val hapticsToPlay = _hapticsToPlay.asStateFlow()
@@ -939,26 +944,52 @@ constructor(
    }

    private fun vibrateOnSuccess() {
        _hapticsToPlay.value =
            HapticsToPlay(
        val haptics =
            if (msdlFeedback()) {
                HapticsToPlay.MSDL(MSDLToken.UNLOCK, authInteractionProperties)
            } else {
                HapticsToPlay.HapticConstant(
                    HapticFeedbackConstants.BIOMETRIC_CONFIRM,
                null,
                    flag = null,
                )
            }
        _hapticsToPlay.value = haptics
    }

    private fun vibrateOnError() {
        _hapticsToPlay.value =
            HapticsToPlay(
        val haptics =
            if (msdlFeedback()) {
                HapticsToPlay.MSDL(MSDLToken.FAILURE, authInteractionProperties)
            } else {
                HapticsToPlay.HapticConstant(
                    HapticFeedbackConstants.BIOMETRIC_REJECT,
                null,
                    flag = null,
                )
            }
        _hapticsToPlay.value = haptics
    }

    /** Clears the [hapticsToPlay] variable by setting its constant to the NO_HAPTICS default. */
    fun clearHaptics() {
        _hapticsToPlay.update { previous ->
            HapticsToPlay(HapticFeedbackConstants.NO_HAPTICS, previous.flag)
        _hapticsToPlay.update { HapticsToPlay.None }
    }

    /** The state of haptic feedback to play. */
    sealed interface HapticsToPlay {
        /**
         * Haptics using [HapticFeedbackConstants]. It is composed by a [HapticFeedbackConstants]
         * and a [HapticFeedbackConstants] flag.
         */
        data class HapticConstant(val constant: Int, val flag: Int?) : HapticsToPlay

        /**
         * Haptics using MSDL feedback. It is composed by a [MSDLToken] and optional
         * [InteractionProperties]
         */
        data class MSDL(val token: MSDLToken, val properties: InteractionProperties?) :
            HapticsToPlay

        data object None : HapticsToPlay
    }

    companion object {
@@ -1095,9 +1126,3 @@ enum class FingerprintStartMode {
    val isStarted: Boolean
        get() = this == Normal || this == Delayed
}

/**
 * The state of haptic feedback to play. It is composed by a [HapticFeedbackConstants] and a
 * [HapticFeedbackConstants] flag.
 */
data class HapticsToPlay(val hapticFeedbackConstant: Int, val flag: Int?)
Loading