Update registration error strings for SMS send failures.

This commit is contained in:
Greyson Parrelli
2026-02-25 16:30:59 +00:00
committed by Cody Henthorne
parent d6ec4bfbd3
commit 179908fba6
11 changed files with 36 additions and 26 deletions
@@ -507,7 +507,7 @@ class EnterPhoneNumberFragment : LoggingFragment(R.layout.fragment_registration_
} else {
Log.w(TAG, "Unable to request new verification code, prompting to start new session")
MaterialAlertDialogBuilder(requireContext()).apply {
setMessage(R.string.RegistrationActivity_unable_to_connect_to_service)
setMessage(R.string.RegistrationActivity_sms_provider_error)
setPositiveButton(R.string.NetworkFailure__retry) { _, _ ->
onRegistrationButtonClicked()
}
+2 -2
View File
@@ -2842,8 +2842,8 @@
<!-- During registration, if the user attempts (and fails) to register, we display this error message with a number of minutes timer they are allowed to try again.-->
<string name="RegistrationActivity_rate_limited_to_try_again">You\'ve made too many attempts to register this number. Please try again in %s.</string>
<string name="RegistrationActivity_unable_to_connect_to_service">Unable to connect to service. Please check network connection and try again.</string>
<!-- Dialog error message shown when attempting to register and the SMS provider fails to send an SMS -->
<string name="RegistrationActivity_sms_provider_error">Signal couldn\'t send an SMS code because of issues with the SMS provider. Try again in several hours.</string>
<!-- Dialog error message shown when we are unable to send an SMS to the user's number -->
<string name="RegistrationActivity_sms_provider_error">We are unable to send an SMS to your number. Please try again in several hours.</string>
<!-- A description text for an alert dialog when the entered phone number is not eligible for a verification SMS. -->
<string name="RegistrationActivity_we_couldnt_send_you_a_verification_code">We couldn\'t send you a verification code via SMS. Try receiving your code via voice call instead.</string>
<!-- Generic error when the app is unable to request an SMS code for an unknown reason. -->
@@ -65,6 +65,7 @@ fun PhoneNumberScreen(
onEvent: (PhoneNumberEntryScreenEvents) -> Unit,
modifier: Modifier = Modifier
) {
val unableToSendSmsMsg = stringResource(R.string.VerificationCodeScreen__unable_to_send_sms)
var simpleErrorMessage: String? by remember { mutableStateOf(null) }
LaunchedEffect(state.oneTimeEvent) {
@@ -74,7 +75,7 @@ fun PhoneNumberScreen(
is OneTimeEvent.RateLimited -> simpleErrorMessage = "Rate limited"
OneTimeEvent.UnknownError -> simpleErrorMessage = "Unknown error"
OneTimeEvent.CouldNotRequestCodeWithSelectedTransport -> simpleErrorMessage = "Could not request code with selected transport"
OneTimeEvent.ThirdPartyError -> simpleErrorMessage = "Third party error"
OneTimeEvent.UnableToSendSms -> simpleErrorMessage = unableToSendSmsMsg
null -> Unit
}
}
@@ -32,7 +32,7 @@ data class PhoneNumberEntryState(
data object NetworkError : OneTimeEvent
data object UnknownError : OneTimeEvent
data class RateLimited(val retryAfter: Duration) : OneTimeEvent
data object ThirdPartyError : OneTimeEvent
data object UnableToSendSms : OneTimeEvent
data object CouldNotRequestCodeWithSelectedTransport : OneTimeEvent
}
}
@@ -463,6 +463,11 @@ class PhoneNumberEntryViewModel(
return state
}
if (!sessionMetadata.allowedToRequestCode && sessionMetadata.requestedInformation.isEmpty()) {
Log.w(TAG, "Not allowed to request code and no challenges requested. Unable to send SMS.")
return state.copy(oneTimeEvent = OneTimeEvent.UnableToSendSms)
}
val verificationCodeResponse = this@PhoneNumberEntryViewModel.repository.requestVerificationCode(
sessionMetadata.id,
smsAutoRetrieveCodeSupported = false,
@@ -495,7 +500,7 @@ class PhoneNumberEntryViewModel(
}
is NetworkController.RequestVerificationCodeError.MissingRequestInformationOrAlreadyVerified -> {
Log.w(TAG, "[RequestVerificationCode] Missing request information or already verified.")
state.copy(oneTimeEvent = OneTimeEvent.NetworkError)
state.copy(oneTimeEvent = OneTimeEvent.UnableToSendSms)
}
is NetworkController.RequestVerificationCodeError.SessionNotFound -> {
Log.w(TAG, "[RequestVerificationCode] Session not found when requesting verification code.")
@@ -504,7 +509,7 @@ class PhoneNumberEntryViewModel(
}
is NetworkController.RequestVerificationCodeError.ThirdPartyServiceError -> {
Log.w(TAG, "[RequestVerificationCode] Third party service error.")
state.copy(oneTimeEvent = OneTimeEvent.ThirdPartyError)
state.copy(oneTimeEvent = OneTimeEvent.UnableToSendSms)
}
}
}
@@ -563,12 +568,16 @@ class PhoneNumberEntryViewModel(
state = state.copy(sessionMetadata = sessionMetadata)
// TODO should we be reading "allowedToRequestCode"?
if (sessionMetadata.requestedInformation.contains("captcha")) {
parentEventEmitter.navigateTo(RegistrationRoute.Captcha(sessionMetadata))
return state
}
if (!sessionMetadata.allowedToRequestCode && sessionMetadata.requestedInformation.isEmpty()) {
Log.w(TAG, "Not allowed to request code and no challenges requested after captcha. Unable to send SMS.")
return state.copy(oneTimeEvent = OneTimeEvent.UnableToSendSms)
}
val verificationCodeResponse = this@PhoneNumberEntryViewModel.repository.requestVerificationCode(
sessionId = sessionMetadata.id,
smsAutoRetrieveCodeSupported = false, // TODO eventually support this
@@ -593,15 +602,15 @@ class PhoneNumberEntryViewModel(
state
}
is NetworkController.RequestVerificationCodeError.MissingRequestInformationOrAlreadyVerified -> {
// TODO [registration] - Error handling not implemented
throw NotImplementedError()
Log.w(TAG, "When requesting verification code after captcha, missing request information or already verified.")
state.copy(oneTimeEvent = OneTimeEvent.UnableToSendSms)
}
is NetworkController.RequestVerificationCodeError.SessionNotFound -> {
parentEventEmitter(RegistrationFlowEvent.ResetState)
state
}
is NetworkController.RequestVerificationCodeError.ThirdPartyServiceError -> {
state.copy(oneTimeEvent = OneTimeEvent.ThirdPartyError)
state.copy(oneTimeEvent = OneTimeEvent.UnableToSendSms)
}
}
}
@@ -76,7 +76,7 @@ fun VerificationCodeScreen(
val incorrectCodeMsg = stringResource(R.string.VerificationCodeScreen__incorrect_code)
val networkErrorMsg = stringResource(R.string.VerificationCodeScreen__network_error)
val unknownErrorMsg = stringResource(R.string.VerificationCodeScreen__an_unexpected_error_occurred)
val smsProviderErrorMsg = stringResource(R.string.VerificationCodeScreen__sms_provider_error)
val unableToSendSmsMsg = stringResource(R.string.VerificationCodeScreen__unable_to_send_sms)
val transportErrorMsg = stringResource(R.string.VerificationCodeScreen__could_not_send_code_via_selected_method)
val registrationErrorMsg = stringResource(R.string.VerificationCodeScreen__registration_error)
// Preformat the rate-limited message template
@@ -121,8 +121,8 @@ fun VerificationCodeScreen(
is VerificationCodeState.OneTimeEvent.RateLimited -> {
snackbarHostState.showSnackbar(rateLimitedMsg)
}
VerificationCodeState.OneTimeEvent.ThirdPartyError -> {
snackbarHostState.showSnackbar(smsProviderErrorMsg)
VerificationCodeState.OneTimeEvent.UnableToSendSms -> {
snackbarHostState.showSnackbar(unableToSendSmsMsg)
}
VerificationCodeState.OneTimeEvent.CouldNotRequestCodeWithSelectedTransport -> {
snackbarHostState.showSnackbar(transportErrorMsg)
@@ -23,7 +23,7 @@ data class VerificationCodeState(
data object NetworkError : OneTimeEvent
data object UnknownError : OneTimeEvent
data class RateLimited(val retryAfter: Duration) : OneTimeEvent
data object ThirdPartyError : OneTimeEvent
data object UnableToSendSms : OneTimeEvent
data object CouldNotRequestCodeWithSelectedTransport : OneTimeEvent
data object IncorrectVerificationCode : OneTimeEvent
data object RegistrationError : OneTimeEvent
@@ -287,7 +287,7 @@ class VerificationCodeViewModel(
Log.w(TAG, "[RequestCode][$transport] Missing request information or already verified.")
parentEventEmitter(RegistrationFlowEvent.SessionUpdated(error.session))
state.copy(
oneTimeEvent = OneTimeEvent.NetworkError,
oneTimeEvent = OneTimeEvent.UnableToSendSms,
sessionMetadata = error.session,
rateLimits = computeRateLimits(error.session)
)
@@ -300,7 +300,7 @@ class VerificationCodeViewModel(
}
is NetworkController.RequestVerificationCodeError.ThirdPartyServiceError -> {
Log.w(TAG, "[RequestCode][$transport] Third party service error. ${error.data}")
state.copy(oneTimeEvent = OneTimeEvent.ThirdPartyError)
state.copy(oneTimeEvent = OneTimeEvent.UnableToSendSms)
}
}
}
@@ -76,8 +76,8 @@
<string name="VerificationCodeScreen__too_many_attempts_try_again_in_s">Too many attempts. Try again in %s.</string>
<!-- Snackbar shown for generic/unknown errors -->
<string name="VerificationCodeScreen__an_unexpected_error_occurred">An unexpected error occurred. Please try again.</string>
<!-- Snackbar shown when the SMS provider has an error -->
<string name="VerificationCodeScreen__sms_provider_error">There was a problem sending your verification code. Please try again.</string>
<!-- Snackbar shown when we are unable to send an SMS to the user's number -->
<string name="VerificationCodeScreen__unable_to_send_sms">We are unable to send an SMS to your number. Please try again in several hours.</string>
<!-- Snackbar shown when the selected transport (SMS/voice) is unavailable -->
<string name="VerificationCodeScreen__could_not_send_code_via_selected_method">Could not send code via the selected method. Please try another option.</string>
<!-- Snackbar shown for registration errors -->
@@ -540,7 +540,7 @@ class PhoneNumberEntryViewModelTest {
assertThat(emittedStates.first().showSpinner).isTrue()
assertThat(emittedStates.last().showSpinner).isFalse()
assertThat(emittedStates.last().oneTimeEvent).isEqualTo(PhoneNumberEntryState.OneTimeEvent.ThirdPartyError)
assertThat(emittedStates.last().oneTimeEvent).isEqualTo(PhoneNumberEntryState.OneTimeEvent.UnableToSendSms)
}
// ==================== Push Challenge Tests ====================
@@ -654,7 +654,7 @@ class VerificationCodeViewModelTest {
}
@Test
fun `ResendSms with MissingRequestInformationOrAlreadyVerified returns NetworkError event`() = runTest {
fun `ResendSms with MissingRequestInformationOrAlreadyVerified returns UnableToSendSms event`() = runTest {
val sessionMetadata = createSessionMetadata()
val initialState = VerificationCodeState(sessionMetadata = sessionMetadata)
@@ -665,11 +665,11 @@ class VerificationCodeViewModelTest {
viewModel.applyEvent(initialState, VerificationCodeScreenEvents.ResendSms, stateEmitter)
assertThat(emittedStates.last().oneTimeEvent).isEqualTo(VerificationCodeState.OneTimeEvent.NetworkError)
assertThat(emittedStates.last().oneTimeEvent).isEqualTo(VerificationCodeState.OneTimeEvent.UnableToSendSms)
}
@Test
fun `ResendSms with ThirdPartyServiceError returns ThirdPartyError event`() = runTest {
fun `ResendSms with ThirdPartyServiceError returns UnableToSendSms event`() = runTest {
val sessionMetadata = createSessionMetadata()
val initialState = VerificationCodeState(sessionMetadata = sessionMetadata)
@@ -682,7 +682,7 @@ class VerificationCodeViewModelTest {
viewModel.applyEvent(initialState, VerificationCodeScreenEvents.ResendSms, stateEmitter)
assertThat(emittedStates.last().oneTimeEvent).isEqualTo(VerificationCodeState.OneTimeEvent.ThirdPartyError)
assertThat(emittedStates.last().oneTimeEvent).isEqualTo(VerificationCodeState.OneTimeEvent.UnableToSendSms)
}
@Test
@@ -772,7 +772,7 @@ class VerificationCodeViewModelTest {
}
@Test
fun `CallMe with ThirdPartyServiceError returns ThirdPartyError event`() = runTest {
fun `CallMe with ThirdPartyServiceError returns UnableToSendSms event`() = runTest {
val sessionMetadata = createSessionMetadata()
val initialState = VerificationCodeState(sessionMetadata = sessionMetadata)
@@ -785,7 +785,7 @@ class VerificationCodeViewModelTest {
viewModel.applyEvent(initialState, VerificationCodeScreenEvents.CallMe, stateEmitter)
assertThat(emittedStates.last().oneTimeEvent).isEqualTo(VerificationCodeState.OneTimeEvent.ThirdPartyError)
assertThat(emittedStates.last().oneTimeEvent).isEqualTo(VerificationCodeState.OneTimeEvent.UnableToSendSms)
}
// ==================== Helper Functions ====================