Migrate haptic to view model and out of legacy components.
Fix: 272832355 Bug: 288175645 Test: atest PromptViewModelTest AuthContainerViewTest AuthControllerTest Change-Id: Ie7181b448b74e4f7322cfad59eced1ac872a9b85
This commit is contained in:
@@ -737,7 +737,7 @@ public abstract class AuthBiometricView extends LinearLayout implements AuthBiom
|
||||
});
|
||||
|
||||
mUseCredentialButton.setOnClickListener((view) -> {
|
||||
startTransitionToCredentialUI();
|
||||
startTransitionToCredentialUI(false /* isError */);
|
||||
});
|
||||
|
||||
mConfirmButton.setOnClickListener((view) -> {
|
||||
@@ -768,9 +768,12 @@ public abstract class AuthBiometricView extends LinearLayout implements AuthBiom
|
||||
|
||||
/**
|
||||
* Kicks off the animation process and invokes the callback.
|
||||
*
|
||||
* @param isError if this was triggered due to an error and not a user action (unused,
|
||||
* previously for haptics).
|
||||
*/
|
||||
@Override
|
||||
public void startTransitionToCredentialUI() {
|
||||
public void startTransitionToCredentialUI(boolean isError) {
|
||||
updateSize(AuthDialog.SIZE_LARGE);
|
||||
mCallback.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ interface AuthBiometricViewAdapter {
|
||||
|
||||
fun onHelp(@BiometricAuthenticator.Modality modality: Int, help: String)
|
||||
|
||||
fun startTransitionToCredentialUI()
|
||||
fun startTransitionToCredentialUI(isError: Boolean)
|
||||
|
||||
fun requestLayout()
|
||||
|
||||
|
||||
@@ -801,9 +801,9 @@ public class AuthContainerView extends LinearLayout
|
||||
}
|
||||
|
||||
@Override
|
||||
public void animateToCredentialUI() {
|
||||
public void animateToCredentialUI(boolean isError) {
|
||||
if (mBiometricView != null) {
|
||||
mBiometricView.startTransitionToCredentialUI();
|
||||
mBiometricView.startTransitionToCredentialUI(isError);
|
||||
} else {
|
||||
Log.e(TAG, "animateToCredentialUI(): mBiometricView is null");
|
||||
}
|
||||
|
||||
@@ -85,7 +85,6 @@ import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
import com.android.systemui.keyguard.data.repository.BiometricType;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.VibratorHelper;
|
||||
import com.android.systemui.util.concurrency.DelayableExecutor;
|
||||
import com.android.systemui.util.concurrency.Execution;
|
||||
|
||||
@@ -185,18 +184,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
private final @Background DelayableExecutor mBackgroundExecutor;
|
||||
private final DisplayInfo mCachedDisplayInfo = new DisplayInfo();
|
||||
|
||||
private final VibratorHelper mVibratorHelper;
|
||||
|
||||
private void vibrateSuccess(int modality) {
|
||||
mVibratorHelper.vibrateAuthSuccess(
|
||||
getClass().getSimpleName() + ", modality = " + modality + "BP::success");
|
||||
}
|
||||
|
||||
private void vibrateError(int modality) {
|
||||
mVibratorHelper.vibrateAuthError(
|
||||
getClass().getSimpleName() + ", modality = " + modality + "BP::error");
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
final TaskStackListener mTaskStackListener = new TaskStackListener() {
|
||||
@Override
|
||||
@@ -784,7 +771,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
@NonNull InteractionJankMonitor jankMonitor,
|
||||
@Main Handler handler,
|
||||
@Background DelayableExecutor bgExecutor,
|
||||
@NonNull VibratorHelper vibrator,
|
||||
@NonNull UdfpsUtils udfpsUtils) {
|
||||
mContext = context;
|
||||
mFeatureFlags = featureFlags;
|
||||
@@ -806,7 +792,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
mUdfpsEnrolledForUser = new SparseBooleanArray();
|
||||
mSfpsEnrolledForUser = new SparseBooleanArray();
|
||||
mFaceEnrolledForUser = new SparseBooleanArray();
|
||||
mVibratorHelper = vibrator;
|
||||
mUdfpsUtils = udfpsUtils;
|
||||
mApplicationCoroutineScope = applicationCoroutineScope;
|
||||
|
||||
@@ -995,8 +980,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
public void onBiometricAuthenticated(@Modality int modality) {
|
||||
if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: ");
|
||||
|
||||
vibrateSuccess(modality);
|
||||
|
||||
if (mCurrentDialog != null) {
|
||||
mCurrentDialog.onAuthenticationSucceeded(modality);
|
||||
} else {
|
||||
@@ -1093,8 +1076,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
Log.d(TAG, String.format("onBiometricError(%d, %d, %d)", modality, error, vendorCode));
|
||||
}
|
||||
|
||||
vibrateError(modality);
|
||||
|
||||
final boolean isLockout = (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT)
|
||||
|| (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT);
|
||||
|
||||
@@ -1111,7 +1092,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
|
||||
if (mCurrentDialog != null) {
|
||||
if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) {
|
||||
if (DEBUG) Log.d(TAG, "onBiometricError, lockout");
|
||||
mCurrentDialog.animateToCredentialUI();
|
||||
mCurrentDialog.animateToCredentialUI(true /* isError */);
|
||||
} else if (isSoftError) {
|
||||
final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED)
|
||||
? getNotRecognizedString(modality)
|
||||
|
||||
@@ -162,7 +162,7 @@ public interface AuthDialog extends Dumpable {
|
||||
/**
|
||||
* Animate to credential UI. Typically called after biometric is locked out.
|
||||
*/
|
||||
void animateToCredentialUI();
|
||||
void animateToCredentialUI(boolean isError);
|
||||
|
||||
/**
|
||||
* @return true if device credential is allowed.
|
||||
|
||||
@@ -522,6 +522,7 @@ private class Spaghetti(
|
||||
viewModel.showTemporaryError(
|
||||
help,
|
||||
messageAfterError = modalities.asDefaultHelpMessage(applicationContext),
|
||||
hapticFeedback = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -534,7 +535,7 @@ private class Spaghetti(
|
||||
else -> false
|
||||
}
|
||||
|
||||
override fun startTransitionToCredentialUI() {
|
||||
override fun startTransitionToCredentialUI(isError: Boolean) {
|
||||
applicationScope.launch {
|
||||
viewModel.onSwitchToCredential()
|
||||
legacyCallback?.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL)
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteracto
|
||||
import com.android.systemui.biometrics.domain.model.BiometricModalities
|
||||
import com.android.systemui.biometrics.domain.model.BiometricModality
|
||||
import com.android.systemui.biometrics.shared.model.PromptKind
|
||||
import com.android.systemui.statusbar.VibratorHelper
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
@@ -41,6 +42,7 @@ class PromptViewModel
|
||||
@Inject
|
||||
constructor(
|
||||
private val interactor: PromptSelectorInteractor,
|
||||
private val vibrator: VibratorHelper,
|
||||
) {
|
||||
/** The set of modalities available for this prompt */
|
||||
val modalities: Flow<BiometricModalities> =
|
||||
@@ -205,17 +207,19 @@ constructor(
|
||||
private var messageJob: Job? = null
|
||||
|
||||
/**
|
||||
* Show a temporary error [message] associated with an optional [failedModality].
|
||||
* Show a temporary error [message] associated with an optional [failedModality] and play
|
||||
* [hapticFeedback].
|
||||
*
|
||||
* An optional [messageAfterError] will be shown via [showAuthenticating] when
|
||||
* [authenticateAfterError] is set (or via [showHelp] when not set) after the error is
|
||||
* dismissed.
|
||||
*
|
||||
* The error is ignored if the user has already authenticated and it is treated as
|
||||
* [onSilentError] if [suppressIfErrorShowing] is set and an error message is already showing.
|
||||
* The error is ignored if the user has already authenticated or if [suppressIfErrorShowing] is
|
||||
* set and an error message is already showing.
|
||||
*/
|
||||
suspend fun showTemporaryError(
|
||||
message: String,
|
||||
hapticFeedback: Boolean = true,
|
||||
messageAfterError: String = "",
|
||||
authenticateAfterError: Boolean = false,
|
||||
suppressIfErrorShowing: Boolean = false,
|
||||
@@ -225,7 +229,9 @@ constructor(
|
||||
return@coroutineScope
|
||||
}
|
||||
if (_message.value.isErrorOrHelp && suppressIfErrorShowing) {
|
||||
onSilentError(failedModality)
|
||||
if (_isAuthenticated.value.isNotAuthenticated) {
|
||||
_canTryAgainNow.value = supportsRetry(failedModality)
|
||||
}
|
||||
return@coroutineScope
|
||||
}
|
||||
|
||||
@@ -236,6 +242,10 @@ constructor(
|
||||
_message.value = PromptMessage.Error(message)
|
||||
_legacyState.value = AuthBiometricView.STATE_ERROR
|
||||
|
||||
if (hapticFeedback) {
|
||||
vibrator.error(failedModality)
|
||||
}
|
||||
|
||||
messageJob?.cancel()
|
||||
messageJob = launch {
|
||||
delay(BiometricPrompt.HIDE_DIALOG_DELAY.toLong())
|
||||
@@ -247,18 +257,6 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call instead of [showTemporaryError] if an error from the HAL should be silently ignored to
|
||||
* enable retry (if the [failedModality] supports retrying).
|
||||
*
|
||||
* Ignored if the user has already authenticated.
|
||||
*/
|
||||
private fun onSilentError(failedModality: BiometricModality = BiometricModality.None) {
|
||||
if (_isAuthenticated.value.isNotAuthenticated) {
|
||||
_canTryAgainNow.value = supportsRetry(failedModality)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call to ensure the fingerprint sensor has started. Either when the dialog is first shown
|
||||
* (most cases) or when it should be enabled after a first error (coex implicit flow).
|
||||
@@ -376,6 +374,8 @@ constructor(
|
||||
AuthBiometricView.STATE_AUTHENTICATED
|
||||
}
|
||||
|
||||
vibrator.success(modality)
|
||||
|
||||
messageJob?.cancel()
|
||||
messageJob = null
|
||||
|
||||
@@ -386,18 +386,18 @@ constructor(
|
||||
|
||||
private suspend fun needsExplicitConfirmation(modality: BiometricModality): Boolean {
|
||||
val availableModalities = modalities.first()
|
||||
val confirmationRequested = interactor.isConfirmationRequired.first()
|
||||
val confirmationRequired = isConfirmationRequired.first()
|
||||
|
||||
if (availableModalities.hasFaceAndFingerprint) {
|
||||
// coex only needs confirmation when face is successful, unless it happens on the
|
||||
// first attempt (i.e. without failure) before fingerprint scanning starts
|
||||
val fingerprintStarted = fingerprintStartMode.first() != FingerprintStartMode.Pending
|
||||
if (modality == BiometricModality.Face) {
|
||||
return (fingerprintStartMode.first() != FingerprintStartMode.Pending) ||
|
||||
confirmationRequested
|
||||
return fingerprintStarted || confirmationRequired
|
||||
}
|
||||
}
|
||||
if (availableModalities.hasFaceOnly) {
|
||||
return confirmationRequested
|
||||
return confirmationRequired
|
||||
}
|
||||
// fingerprint only never requires confirmation
|
||||
return false
|
||||
@@ -412,7 +412,6 @@ constructor(
|
||||
fun confirmAuthenticated() {
|
||||
val authState = _isAuthenticated.value
|
||||
if (authState.isNotAuthenticated) {
|
||||
"Cannot show authenticated after authenticated"
|
||||
Log.w(TAG, "Cannot confirm authenticated when not authenticated")
|
||||
return
|
||||
}
|
||||
@@ -434,6 +433,12 @@ constructor(
|
||||
_forceLargeSize.value = true
|
||||
}
|
||||
|
||||
private fun VibratorHelper.success(modality: BiometricModality) =
|
||||
vibrateAuthSuccess("$TAG, modality = $modality BP::success")
|
||||
|
||||
private fun VibratorHelper.error(modality: BiometricModality = BiometricModality.None) =
|
||||
vibrateAuthError("$TAG, modality = $modality BP::error")
|
||||
|
||||
companion object {
|
||||
private const val TAG = "PromptViewModel"
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel
|
||||
import com.android.systemui.flags.FakeFeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle
|
||||
import com.android.systemui.statusbar.VibratorHelper
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
@@ -99,6 +100,8 @@ open class AuthContainerViewTest : SysuiTestCase() {
|
||||
lateinit var windowToken: IBinder
|
||||
@Mock
|
||||
lateinit var interactionJankMonitor: InteractionJankMonitor
|
||||
@Mock
|
||||
lateinit var vibrator: VibratorHelper
|
||||
|
||||
// TODO(b/278622168): remove with flag
|
||||
open val useNewBiometricPrompt = false
|
||||
@@ -325,7 +328,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
|
||||
authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
|
||||
BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
||||
)
|
||||
container.animateToCredentialUI()
|
||||
container.animateToCredentialUI(false)
|
||||
waitForIdleSync()
|
||||
|
||||
assertThat(container.hasCredentialView()).isTrue()
|
||||
@@ -514,7 +517,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
|
||||
{ authBiometricFingerprintViewModel },
|
||||
{ promptSelectorInteractor },
|
||||
{ bpCredentialInteractor },
|
||||
PromptViewModel(promptSelectorInteractor),
|
||||
PromptViewModel(promptSelectorInteractor, vibrator),
|
||||
{ credentialViewModel },
|
||||
Handler(TestableLooper.get(this).looper),
|
||||
fakeExecutor
|
||||
|
||||
@@ -202,9 +202,6 @@ public class AuthControllerTest extends SysuiTestCase {
|
||||
private TestableAuthController mAuthController;
|
||||
private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
|
||||
|
||||
@Mock
|
||||
private VibratorHelper mVibratorHelper;
|
||||
|
||||
@Before
|
||||
public void setup() throws RemoteException {
|
||||
// TODO(b/278622168): remove with flag
|
||||
@@ -267,7 +264,6 @@ public class AuthControllerTest extends SysuiTestCase {
|
||||
true /* supportsSelfIllumination */,
|
||||
true /* resetLockoutRequireHardwareAuthToken */));
|
||||
when(mFaceManager.getSensorPropertiesInternal()).thenReturn(faceProps);
|
||||
when(mVibratorHelper.hasVibrator()).thenReturn(true);
|
||||
|
||||
mAuthController = new TestableAuthController(mContextSpy);
|
||||
|
||||
@@ -594,7 +590,7 @@ public class AuthControllerTest extends SysuiTestCase {
|
||||
|
||||
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
|
||||
verify(mDialog1, never()).onError(anyInt(), anyString());
|
||||
verify(mDialog1).animateToCredentialUI();
|
||||
verify(mDialog1).animateToCredentialUI(eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -607,7 +603,7 @@ public class AuthControllerTest extends SysuiTestCase {
|
||||
|
||||
mAuthController.onBiometricError(BiometricAuthenticator.TYPE_FACE, error, vendorCode);
|
||||
verify(mDialog1, never()).onError(anyInt(), anyString());
|
||||
verify(mDialog1).animateToCredentialUI();
|
||||
verify(mDialog1).animateToCredentialUI(eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -622,7 +618,7 @@ public class AuthControllerTest extends SysuiTestCase {
|
||||
mAuthController.onBiometricError(modality, error, vendorCode);
|
||||
verify(mDialog1).onError(
|
||||
eq(modality), eq(FaceManager.getErrorString(mContext, error, vendorCode)));
|
||||
verify(mDialog1, never()).animateToCredentialUI();
|
||||
verify(mDialog1, never()).animateToCredentialUI(eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -637,7 +633,7 @@ public class AuthControllerTest extends SysuiTestCase {
|
||||
mAuthController.onBiometricError(modality, error, vendorCode);
|
||||
verify(mDialog1).onError(
|
||||
eq(modality), eq(FaceManager.getErrorString(mContext, error, vendorCode)));
|
||||
verify(mDialog1, never()).animateToCredentialUI();
|
||||
verify(mDialog1, never()).animateToCredentialUI(eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1100,7 +1096,7 @@ public class AuthControllerTest extends SysuiTestCase {
|
||||
() -> mBiometricPromptCredentialInteractor, () -> mPromptSelectionInteractor,
|
||||
() -> mCredentialViewModel, () -> mPromptViewModel,
|
||||
mInteractionJankMonitor, mHandler,
|
||||
mBackgroundExecutor, mVibratorHelper, mUdfpsUtils);
|
||||
mBackgroundExecutor, mUdfpsUtils);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -32,6 +32,8 @@ import com.android.systemui.biometrics.extractAuthenticatorTypes
|
||||
import com.android.systemui.biometrics.faceSensorPropertiesInternal
|
||||
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.statusbar.VibratorHelper
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.first
|
||||
@@ -45,6 +47,9 @@ import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.times
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
|
||||
private const val USER_ID = 4
|
||||
@@ -58,6 +63,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
|
||||
|
||||
@Mock private lateinit var lockPatternUtils: LockPatternUtils
|
||||
@Mock private lateinit var vibrator: VibratorHelper
|
||||
|
||||
private val testScope = TestScope()
|
||||
private val promptRepository = FakePromptRepository()
|
||||
@@ -70,11 +76,11 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
selector = PromptSelectorInteractorImpl(promptRepository, lockPatternUtils)
|
||||
selector.resetPrompt()
|
||||
|
||||
viewModel = PromptViewModel(selector)
|
||||
viewModel = PromptViewModel(selector, vibrator)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `start idle and show authenticating`() =
|
||||
fun start_idle_and_show_authenticating() =
|
||||
runGenericTest(doNotStart = true) {
|
||||
val expectedSize =
|
||||
if (testCase.shouldStartAsImplicitFlow) PromptSize.SMALL else PromptSize.MEDIUM
|
||||
@@ -107,7 +113,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shows authenticated - no errors`() = runGenericTest {
|
||||
fun shows_authenticated_with_no_errors() = runGenericTest {
|
||||
// this case can't happen until fingerprint is started
|
||||
// trigger it now since no error has occurred in this test
|
||||
val forceError = testCase.isCoex && testCase.authenticatedByFingerprint
|
||||
@@ -124,6 +130,22 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun plays_haptic_on_authenticated() = runGenericTest {
|
||||
viewModel.showAuthenticated(testCase.authenticatedModality, 1000L)
|
||||
|
||||
verify(vibrator).vibrateAuthSuccess(any())
|
||||
verify(vibrator, never()).vibrateAuthError(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun plays_no_haptic_on_confirm() = runGenericTest {
|
||||
viewModel.confirmAuthenticated()
|
||||
|
||||
verify(vibrator, never()).vibrateAuthSuccess(any())
|
||||
verify(vibrator, never()).vibrateAuthError(any())
|
||||
}
|
||||
|
||||
private suspend fun TestScope.showAuthenticated(
|
||||
authenticatedModality: BiometricModality,
|
||||
expectConfirmation: Boolean,
|
||||
@@ -172,7 +194,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shows temporary errors`() = runGenericTest {
|
||||
fun shows_temporary_errors() = runGenericTest {
|
||||
val checkAtEnd = suspend { assertButtonsVisible(negative = true) }
|
||||
|
||||
showTemporaryErrors(restart = false) { checkAtEnd() }
|
||||
@@ -180,6 +202,22 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
showTemporaryErrors(restart = true) { checkAtEnd() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun plays_haptic_on_errors() = runGenericTest {
|
||||
viewModel.showTemporaryError("so sad", hapticFeedback = true)
|
||||
|
||||
verify(vibrator).vibrateAuthError(any())
|
||||
verify(vibrator, never()).vibrateAuthSuccess(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun plays_haptic_on_errors_unless_skipped() = runGenericTest {
|
||||
viewModel.showTemporaryError("still sad", hapticFeedback = false)
|
||||
|
||||
verify(vibrator, never()).vibrateAuthError(any())
|
||||
verify(vibrator, never()).vibrateAuthSuccess(any())
|
||||
}
|
||||
|
||||
private suspend fun TestScope.showTemporaryErrors(
|
||||
restart: Boolean,
|
||||
helpAfterError: String = "",
|
||||
@@ -233,7 +271,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no errors or temporary help after authenticated`() = runGenericTest {
|
||||
fun no_errors_or_temporary_help_after_authenticated() = runGenericTest {
|
||||
val authenticating by collectLastValue(viewModel.isAuthenticating)
|
||||
val authenticated by collectLastValue(viewModel.isAuthenticated)
|
||||
val message by collectLastValue(viewModel.message)
|
||||
@@ -277,7 +315,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `authenticated at most once`() = runGenericTest {
|
||||
fun authenticated_at_most_once() = runGenericTest {
|
||||
val authenticating by collectLastValue(viewModel.isAuthenticating)
|
||||
val authenticated by collectLastValue(viewModel.isAuthenticated)
|
||||
|
||||
@@ -293,7 +331,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `authenticating cannot restart after authenticated`() = runGenericTest {
|
||||
fun authenticating_cannot_restart_after_authenticated() = runGenericTest {
|
||||
val authenticating by collectLastValue(viewModel.isAuthenticating)
|
||||
val authenticated by collectLastValue(viewModel.isAuthenticated)
|
||||
|
||||
@@ -309,7 +347,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `confirm authentication`() = runGenericTest {
|
||||
fun confirm_authentication() = runGenericTest {
|
||||
val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
|
||||
|
||||
viewModel.showAuthenticated(testCase.authenticatedModality, 0)
|
||||
@@ -341,7 +379,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `cannot confirm unless authenticated`() = runGenericTest {
|
||||
fun cannot_confirm_unless_authenticated() = runGenericTest {
|
||||
val authenticating by collectLastValue(viewModel.isAuthenticating)
|
||||
val authenticated by collectLastValue(viewModel.isAuthenticated)
|
||||
|
||||
@@ -360,7 +398,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shows help - before authenticated`() = runGenericTest {
|
||||
fun shows_help_before_authenticated() = runGenericTest {
|
||||
val helpMessage = "please help yourself to some cookies"
|
||||
val message by collectLastValue(viewModel.message)
|
||||
val messageVisible by collectLastValue(viewModel.isIndicatorMessageVisible)
|
||||
@@ -379,7 +417,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shows help - after authenticated`() = runGenericTest {
|
||||
fun shows_help_after_authenticated() = runGenericTest {
|
||||
val expectConfirmation = testCase.expectConfirmation(atLeastOneFailure = false)
|
||||
val helpMessage = "more cookies please"
|
||||
val authenticating by collectLastValue(viewModel.isAuthenticating)
|
||||
@@ -409,7 +447,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `retries after failure`() = runGenericTest {
|
||||
fun retries_after_failure() = runGenericTest {
|
||||
val errorMessage = "bad"
|
||||
val helpMessage = "again?"
|
||||
val expectTryAgainButton = testCase.isFaceOnly
|
||||
@@ -455,7 +493,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `switch to credential fallback`() = runGenericTest {
|
||||
fun switch_to_credential_fallback() = runGenericTest {
|
||||
val size by collectLastValue(viewModel.size)
|
||||
|
||||
// TODO(b/251476085): remove Spaghetti, migrate logic, and update this test
|
||||
|
||||
Reference in New Issue
Block a user