diff --git a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/phonenumber/EnterPhoneNumberFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/phonenumber/EnterPhoneNumberFragment.kt index 21fa83b029..e84352839e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registration/ui/phonenumber/EnterPhoneNumberFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registration/ui/phonenumber/EnterPhoneNumberFragment.kt @@ -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() } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b79614bba6..2b9af3b6f8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2842,8 +2842,8 @@ You\'ve made too many attempts to register this number. Please try again in %s. Unable to connect to service. Please check network connection and try again. - - Signal couldn\'t send an SMS code because of issues with the SMS provider. Try again in several hours. + + We are unable to send an SMS to your number. Please try again in several hours. We couldn\'t send you a verification code via SMS. Try receiving your code via voice call instead. diff --git a/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryScreen.kt b/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryScreen.kt index 72959eaadf..b572713d51 100644 --- a/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryScreen.kt +++ b/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryScreen.kt @@ -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 } } diff --git a/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryState.kt b/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryState.kt index 1f16f005db..10e99b370f 100644 --- a/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryState.kt +++ b/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryState.kt @@ -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 } } diff --git a/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryViewModel.kt b/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryViewModel.kt index ee5e5f0647..c529f0d127 100644 --- a/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryViewModel.kt +++ b/feature/registration/src/main/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryViewModel.kt @@ -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) } } } diff --git a/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeScreen.kt b/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeScreen.kt index dca35d717c..c16b25777b 100644 --- a/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeScreen.kt +++ b/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeScreen.kt @@ -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) diff --git a/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeState.kt b/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeState.kt index f1d0c915d6..933526485c 100644 --- a/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeState.kt +++ b/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeState.kt @@ -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 diff --git a/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeViewModel.kt b/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeViewModel.kt index 7532912769..3561d2fa27 100644 --- a/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeViewModel.kt +++ b/feature/registration/src/main/java/org/signal/registration/screens/verificationcode/VerificationCodeViewModel.kt @@ -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) } } } diff --git a/feature/registration/src/main/res/values/strings.xml b/feature/registration/src/main/res/values/strings.xml index 3e5481e3e6..d269cc2577 100644 --- a/feature/registration/src/main/res/values/strings.xml +++ b/feature/registration/src/main/res/values/strings.xml @@ -76,8 +76,8 @@ Too many attempts. Try again in %s. An unexpected error occurred. Please try again. - - There was a problem sending your verification code. Please try again. + + We are unable to send an SMS to your number. Please try again in several hours. Could not send code via the selected method. Please try another option. diff --git a/feature/registration/src/test/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryViewModelTest.kt b/feature/registration/src/test/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryViewModelTest.kt index 52c5fd97a7..0bce171d76 100644 --- a/feature/registration/src/test/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryViewModelTest.kt +++ b/feature/registration/src/test/java/org/signal/registration/screens/phonenumber/PhoneNumberEntryViewModelTest.kt @@ -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 ==================== diff --git a/feature/registration/src/test/java/org/signal/registration/screens/verificationcode/VerificationCodeViewModelTest.kt b/feature/registration/src/test/java/org/signal/registration/screens/verificationcode/VerificationCodeViewModelTest.kt index 03df4c6591..2d6951f754 100644 --- a/feature/registration/src/test/java/org/signal/registration/screens/verificationcode/VerificationCodeViewModelTest.kt +++ b/feature/registration/src/test/java/org/signal/registration/screens/verificationcode/VerificationCodeViewModelTest.kt @@ -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 ====================