Skip to content
Snippets Groups Projects
Commit 6355af29 authored by Juan Sebastian Martinez's avatar Juan Sebastian Martinez
Browse files

Ignoring user touch feedback settings for biometric prompt UDFPS

authentication.

The FLAG_IGONRE_GLOBAL_SETTING will ensure that confirm and reject
haptics always play when the user succeeds or fails to authenticate.

Test: manual: Turn off Touch Feedback on Settings > Sound & Vibration >
  Vibration & haptics. Verified that haptics play on successful and
  failed authetication when a biometric prompt is used from a 3P app.
Test: atest SystemUITests:PromptViewModelTest
Bug: 305949781
Flag: NONE
Change-Id: I4d24e6fc606ccba7350094f6974210a3d0e80f8a
parent 3baae7bc
No related branches found
No related tags found
No related merge requests found
......@@ -438,9 +438,20 @@ object BiometricViewBinder {
// Play haptics
launch {
viewModel.hapticsToPlay.collect { hapticFeedbackConstant ->
if (hapticFeedbackConstant != HapticFeedbackConstants.NO_HAPTICS) {
vibratorHelper.performHapticFeedback(view, hapticFeedbackConstant)
viewModel.hapticsToPlay.collect { haptics ->
if (haptics.hapticFeedbackConstant != HapticFeedbackConstants.NO_HAPTICS) {
if (haptics.flag != null) {
vibratorHelper.performHapticFeedback(
view,
haptics.hapticFeedbackConstant,
haptics.flag,
)
} else {
vibratorHelper.performHapticFeedback(
view,
haptics.hapticFeedbackConstant,
)
}
viewModel.clearHaptics()
}
}
......
......@@ -53,6 +53,7 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
/** ViewModel for BiometricPrompt. */
......@@ -144,9 +145,10 @@ constructor(
private val _forceLargeSize = MutableStateFlow(false)
private val _forceMediumSize = MutableStateFlow(false)
private val _hapticsToPlay = MutableStateFlow(HapticFeedbackConstants.NO_HAPTICS)
private val _hapticsToPlay =
MutableStateFlow(HapticsToPlay(HapticFeedbackConstants.NO_HAPTICS, /* flag= */ null))
/** Event fired to the view indicating a [HapticFeedbackConstants] to be played */
/** Event fired to the view indicating a [HapticsToPlay] */
val hapticsToPlay = _hapticsToPlay.asStateFlow()
/** The current position of the prompt */
......@@ -686,16 +688,26 @@ constructor(
}
private fun vibrateOnSuccess() {
_hapticsToPlay.value = HapticFeedbackConstants.CONFIRM
_hapticsToPlay.value =
HapticsToPlay(
HapticFeedbackConstants.CONFIRM,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING,
)
}
private fun vibrateOnError() {
_hapticsToPlay.value = HapticFeedbackConstants.REJECT
_hapticsToPlay.value =
HapticsToPlay(
HapticFeedbackConstants.REJECT,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING,
)
}
/** Clears the [hapticsToPlay] variable by setting it to the NO_HAPTICS default. */
/** Clears the [hapticsToPlay] variable by setting its constant to the NO_HAPTICS default. */
fun clearHaptics() {
_hapticsToPlay.value = HapticFeedbackConstants.NO_HAPTICS
_hapticsToPlay.update { previous ->
HapticsToPlay(HapticFeedbackConstants.NO_HAPTICS, previous.flag)
}
}
companion object {
......@@ -724,3 +736,9 @@ 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?)
......@@ -241,19 +241,27 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
viewModel.showAuthenticated(testCase.authenticatedModality, 1_000L)
val confirmConstant by collectLastValue(viewModel.hapticsToPlay)
assertThat(confirmConstant)
val confirmHaptics by collectLastValue(viewModel.hapticsToPlay)
assertThat(confirmHaptics?.hapticFeedbackConstant)
.isEqualTo(
if (expectConfirmation) HapticFeedbackConstants.NO_HAPTICS
else HapticFeedbackConstants.CONFIRM
)
assertThat(confirmHaptics?.flag)
.isEqualTo(
if (expectConfirmation) null
else HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
)
if (expectConfirmation) {
viewModel.confirmAuthenticated()
}
val confirmedConstant by collectLastValue(viewModel.hapticsToPlay)
assertThat(confirmedConstant).isEqualTo(HapticFeedbackConstants.CONFIRM)
val confirmedHaptics by collectLastValue(viewModel.hapticsToPlay)
assertThat(confirmedHaptics?.hapticFeedbackConstant)
.isEqualTo(HapticFeedbackConstants.CONFIRM)
assertThat(confirmedHaptics?.flag)
.isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING)
}
@Test
......@@ -265,16 +273,21 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
viewModel.confirmAuthenticated()
}
val currentConstant by collectLastValue(viewModel.hapticsToPlay)
assertThat(currentConstant).isEqualTo(HapticFeedbackConstants.CONFIRM)
val currentHaptics by collectLastValue(viewModel.hapticsToPlay)
assertThat(currentHaptics?.hapticFeedbackConstant)
.isEqualTo(HapticFeedbackConstants.CONFIRM)
assertThat(currentHaptics?.flag)
.isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING)
}
@Test
fun playErrorHaptic_SetsRejectConstant() = runGenericTest {
viewModel.showTemporaryError("test", "messageAfterError", false)
val currentConstant by collectLastValue(viewModel.hapticsToPlay)
assertThat(currentConstant).isEqualTo(HapticFeedbackConstants.REJECT)
val currentHaptics by collectLastValue(viewModel.hapticsToPlay)
assertThat(currentHaptics?.hapticFeedbackConstant).isEqualTo(HapticFeedbackConstants.REJECT)
assertThat(currentHaptics?.flag)
.isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING)
}
@Test
......@@ -800,8 +813,9 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
hapticFeedback = true,
)
val constant by collectLastValue(viewModel.hapticsToPlay)
assertThat(constant).isEqualTo(HapticFeedbackConstants.REJECT)
val haptics by collectLastValue(viewModel.hapticsToPlay)
assertThat(haptics?.hapticFeedbackConstant).isEqualTo(HapticFeedbackConstants.REJECT)
assertThat(haptics?.flag).isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING)
}
@Test
......@@ -813,8 +827,8 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
hapticFeedback = false,
)
val constant by collectLastValue(viewModel.hapticsToPlay)
assertThat(constant).isEqualTo(HapticFeedbackConstants.NO_HAPTICS)
val haptics by collectLastValue(viewModel.hapticsToPlay)
assertThat(haptics?.hapticFeedbackConstant).isEqualTo(HapticFeedbackConstants.NO_HAPTICS)
}
private suspend fun TestScope.showTemporaryErrors(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment