mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 12:38:33 +00:00
Fix phone number autofill in Registration V2.
This commit is contained in:
committed by
Cody Henthorne
parent
380c33642c
commit
220d3877a2
@@ -5,7 +5,10 @@
|
|||||||
|
|
||||||
package org.thoughtcrime.securesms.registration.v2.ui
|
package org.thoughtcrime.securesms.registration.v2.ui
|
||||||
|
|
||||||
|
import com.google.i18n.phonenumbers.NumberParseException
|
||||||
|
import com.google.i18n.phonenumbers.PhoneNumberUtil
|
||||||
import com.google.i18n.phonenumbers.Phonenumber
|
import com.google.i18n.phonenumbers.Phonenumber
|
||||||
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.registration.v2.data.network.Challenge
|
import org.thoughtcrime.securesms.registration.v2.data.network.Challenge
|
||||||
import org.whispersystems.signalservice.internal.push.AuthCredentials
|
import org.whispersystems.signalservice.internal.push.AuthCredentials
|
||||||
@@ -16,7 +19,7 @@ import org.whispersystems.signalservice.internal.push.AuthCredentials
|
|||||||
data class RegistrationV2State(
|
data class RegistrationV2State(
|
||||||
val sessionId: String? = null,
|
val sessionId: String? = null,
|
||||||
val enteredCode: String = "",
|
val enteredCode: String = "",
|
||||||
val phoneNumber: Phonenumber.PhoneNumber? = null,
|
val phoneNumber: Phonenumber.PhoneNumber? = fetchExistingE164FromValues(),
|
||||||
val inProgress: Boolean = false,
|
val inProgress: Boolean = false,
|
||||||
val isReRegister: Boolean = false,
|
val isReRegister: Boolean = false,
|
||||||
val recoveryPassword: String? = SignalStore.svr().getRecoveryPassword(),
|
val recoveryPassword: String? = SignalStore.svr().getRecoveryPassword(),
|
||||||
@@ -43,4 +46,22 @@ data class RegistrationV2State(
|
|||||||
val networkError: Throwable? = null
|
val networkError: Throwable? = null
|
||||||
) {
|
) {
|
||||||
val challengesRemaining: List<Challenge> = challengesRequested.filterNot { it in challengesPresented }
|
val challengesRemaining: List<Challenge> = challengesRequested.filterNot { it in challengesPresented }
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = Log.tag(RegistrationV2State::class)
|
||||||
|
|
||||||
|
private fun fetchExistingE164FromValues(): Phonenumber.PhoneNumber? {
|
||||||
|
val existingE164 = SignalStore.registrationValues().sessionE164
|
||||||
|
if (existingE164 != null) {
|
||||||
|
try {
|
||||||
|
return PhoneNumberUtil.getInstance().parse(existingE164, null)
|
||||||
|
} catch (ex: NumberParseException) {
|
||||||
|
Log.w(TAG, "Could not parse stored E164.", ex)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import android.content.Context
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.asLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.google.i18n.phonenumbers.NumberParseException
|
|
||||||
import com.google.i18n.phonenumbers.PhoneNumberUtil
|
|
||||||
import com.google.i18n.phonenumbers.Phonenumber
|
import com.google.i18n.phonenumbers.Phonenumber
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -106,19 +104,8 @@ class RegistrationV2ViewModel : ViewModel() {
|
|||||||
val isReregister: Boolean
|
val isReregister: Boolean
|
||||||
get() = store.value.isReRegister
|
get() = store.value.isReRegister
|
||||||
|
|
||||||
init {
|
val phoneNumber: Phonenumber.PhoneNumber?
|
||||||
val existingE164 = SignalStore.registrationValues().sessionE164
|
get() = store.value.phoneNumber
|
||||||
if (existingE164 != null) {
|
|
||||||
try {
|
|
||||||
val existingPhoneNumber = PhoneNumberUtil.getInstance().parse(existingE164, null)
|
|
||||||
if (existingPhoneNumber != null) {
|
|
||||||
setPhoneNumber(existingPhoneNumber)
|
|
||||||
}
|
|
||||||
} catch (ex: NumberParseException) {
|
|
||||||
Log.w(TAG, "Could not parse stored E164.", ex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun maybePrefillE164(context: Context) {
|
fun maybePrefillE164(context: Context) {
|
||||||
Log.v(TAG, "maybePrefillE164()")
|
Log.v(TAG, "maybePrefillE164()")
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||||
@@ -101,7 +102,7 @@ class GrantPermissionsV2Fragment : ComposeFragment() {
|
|||||||
|
|
||||||
private fun proceedToNextScreen() {
|
private fun proceedToNextScreen() {
|
||||||
when (welcomeAction) {
|
when (welcomeAction) {
|
||||||
WelcomeAction.CONTINUE -> NavHostFragment.findNavController(this).safeNavigate(GrantPermissionsV2FragmentDirections.actionEnterPhoneNumber())
|
WelcomeAction.CONTINUE -> findNavController().safeNavigate(GrantPermissionsV2FragmentDirections.actionEnterPhoneNumber())
|
||||||
WelcomeAction.RESTORE_BACKUP -> {
|
WelcomeAction.RESTORE_BACKUP -> {
|
||||||
val restoreIntent = RestoreActivity.getIntentForRestore(requireActivity())
|
val restoreIntent = RestoreActivity.getIntentForRestore(requireActivity())
|
||||||
launchRestoreActivity.launch(restoreIntent)
|
launchRestoreActivity.launch(restoreIntent)
|
||||||
|
|||||||
@@ -130,15 +130,7 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio
|
|||||||
fragmentViewModel.uiState.observe(viewLifecycleOwner) { fragmentState ->
|
fragmentViewModel.uiState.observe(viewLifecycleOwner) { fragmentState ->
|
||||||
|
|
||||||
fragmentState.phoneNumberFormatter?.let {
|
fragmentState.phoneNumberFormatter?.let {
|
||||||
if (it != currentPhoneNumberFormatter) {
|
bindPhoneNumberFormatter(it)
|
||||||
currentPhoneNumberFormatter?.let { oldWatcher ->
|
|
||||||
Log.d(TAG, "Removing current phone number formatter in fragment")
|
|
||||||
phoneNumberInputLayout.removeTextChangedListener(oldWatcher)
|
|
||||||
}
|
|
||||||
phoneNumberInputLayout.addTextChangedListener(it)
|
|
||||||
currentPhoneNumberFormatter = it
|
|
||||||
Log.d(TAG, "Updating phone number formatter in fragment")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fragmentViewModel.isEnteredNumberValid(fragmentState)) {
|
if (fragmentViewModel.isEnteredNumberValid(fragmentState)) {
|
||||||
@@ -154,19 +146,33 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio
|
|||||||
|
|
||||||
initializeInputFields()
|
initializeInputFields()
|
||||||
|
|
||||||
val existingPhoneNumber = sharedViewModel.uiState.value?.phoneNumber
|
val existingPhoneNumber = sharedViewModel.phoneNumber
|
||||||
if (existingPhoneNumber != null) {
|
if (existingPhoneNumber != null) {
|
||||||
fragmentViewModel.restoreState(existingPhoneNumber)
|
fragmentViewModel.restoreState(existingPhoneNumber)
|
||||||
fragmentViewModel.phoneNumber()?.let {
|
spinnerView.setText(existingPhoneNumber.countryCode.toString())
|
||||||
phoneNumberInputLayout.setText(it.nationalNumber.toString())
|
fragmentViewModel.formatter?.let {
|
||||||
|
bindPhoneNumberFormatter(it)
|
||||||
}
|
}
|
||||||
|
phoneNumberInputLayout.setText(existingPhoneNumber.nationalNumber.toString())
|
||||||
|
} else {
|
||||||
|
spinnerView.setText(fragmentViewModel.countryPrefix().toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
spinnerView.setText(fragmentViewModel.countryPrefix().toString())
|
|
||||||
|
|
||||||
ViewUtil.focusAndShowKeyboard(phoneNumberInputLayout)
|
ViewUtil.focusAndShowKeyboard(phoneNumberInputLayout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun bindPhoneNumberFormatter(formatter: TextWatcher) {
|
||||||
|
if (formatter != currentPhoneNumberFormatter) {
|
||||||
|
currentPhoneNumberFormatter?.let { oldWatcher ->
|
||||||
|
Log.d(TAG, "Removing current phone number formatter in fragment")
|
||||||
|
phoneNumberInputLayout.removeTextChangedListener(oldWatcher)
|
||||||
|
}
|
||||||
|
phoneNumberInputLayout.addTextChangedListener(formatter)
|
||||||
|
currentPhoneNumberFormatter = formatter
|
||||||
|
Log.d(TAG, "Updating phone number formatter in fragment")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleChallenges(remainingChallenges: List<Challenge>) {
|
private fun handleChallenges(remainingChallenges: List<Challenge>) {
|
||||||
when (remainingChallenges.first()) {
|
when (remainingChallenges.first()) {
|
||||||
Challenge.CAPTCHA -> moveToCaptcha()
|
Challenge.CAPTCHA -> moveToCaptcha()
|
||||||
@@ -187,11 +193,13 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio
|
|||||||
phoneNumberInputLayout.addTextChangedListener {
|
phoneNumberInputLayout.addTextChangedListener {
|
||||||
fragmentViewModel.setPhoneNumber(it?.toString())
|
fragmentViewModel.setPhoneNumber(it?.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
phoneNumberInputLayout.onFocusChangeListener = View.OnFocusChangeListener { _: View?, hasFocus: Boolean ->
|
phoneNumberInputLayout.onFocusChangeListener = View.OnFocusChangeListener { _: View?, hasFocus: Boolean ->
|
||||||
if (hasFocus) {
|
if (hasFocus) {
|
||||||
binding.scrollView.postDelayed({ binding.scrollView.smoothScrollTo(0, binding.registerButton.bottom) }, 250)
|
binding.scrollView.postDelayed({ binding.scrollView.smoothScrollTo(0, binding.registerButton.bottom) }, 250)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
phoneNumberInputLayout.imeOptions = EditorInfo.IME_ACTION_DONE
|
phoneNumberInputLayout.imeOptions = EditorInfo.IME_ACTION_DONE
|
||||||
phoneNumberInputLayout.setOnEditorActionListener { v: TextView?, actionId: Int, _: KeyEvent? ->
|
phoneNumberInputLayout.setOnEditorActionListener { v: TextView?, actionId: Int, _: KeyEvent? ->
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE && v != null) {
|
if (actionId == EditorInfo.IME_ACTION_DONE && v != null) {
|
||||||
@@ -298,7 +306,7 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio
|
|||||||
is VerificationCodeRequestResult.ExternalServiceFailure -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
is VerificationCodeRequestResult.ExternalServiceFailure -> presentRemoteErrorDialog(getString(R.string.RegistrationActivity_unable_to_connect_to_service), skipToNextScreen)
|
||||||
is VerificationCodeRequestResult.ImpossibleNumber -> {
|
is VerificationCodeRequestResult.ImpossibleNumber -> {
|
||||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||||
setMessage(getString(R.string.RegistrationActivity_the_number_you_specified_s_is_invalid, fragmentViewModel.phoneNumber()?.toE164()))
|
setMessage(getString(R.string.RegistrationActivity_the_number_you_specified_s_is_invalid, fragmentViewModel.phoneNumber?.toE164()))
|
||||||
setPositiveButton(android.R.string.ok, null)
|
setPositiveButton(android.R.string.ok, null)
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
@@ -369,7 +377,7 @@ class EnterPhoneNumberV2Fragment : LoggingFragment(R.layout.fragment_registratio
|
|||||||
Dialogs.showAlertDialog(
|
Dialogs.showAlertDialog(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
getString(R.string.RegistrationActivity_invalid_number),
|
getString(R.string.RegistrationActivity_invalid_number),
|
||||||
getString(R.string.RegistrationActivity_the_number_you_specified_s_is_invalid, fragmentViewModel.phoneNumber()?.toE164())
|
getString(R.string.RegistrationActivity_the_number_you_specified_s_is_invalid, fragmentViewModel.phoneNumber?.toE164())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.thoughtcrime.securesms.registration.v2.ui.phonenumber
|
package org.thoughtcrime.securesms.registration.v2.ui.phonenumber
|
||||||
|
|
||||||
import android.telephony.PhoneNumberFormattingTextWatcher
|
import android.telephony.PhoneNumberFormattingTextWatcher
|
||||||
|
import android.text.TextWatcher
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.asLiveData
|
import androidx.lifecycle.asLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
@@ -31,6 +32,17 @@ class EnterPhoneNumberV2ViewModel : ViewModel() {
|
|||||||
private val store = MutableStateFlow(EnterPhoneNumberV2State())
|
private val store = MutableStateFlow(EnterPhoneNumberV2State())
|
||||||
val uiState = store.asLiveData()
|
val uiState = store.asLiveData()
|
||||||
|
|
||||||
|
val formatter: TextWatcher?
|
||||||
|
get() = store.value.phoneNumberFormatter
|
||||||
|
|
||||||
|
val phoneNumber: PhoneNumber?
|
||||||
|
get() = try {
|
||||||
|
parsePhoneNumber(store.value)
|
||||||
|
} catch (ex: NumberParseException) {
|
||||||
|
Log.w(TAG, "Could not parse phone number in current state.", ex)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
val supportedCountryPrefixes: List<CountryPrefix> = PhoneNumberUtil.getInstance().supportedCallingCodes
|
val supportedCountryPrefixes: List<CountryPrefix> = PhoneNumberUtil.getInstance().supportedCallingCodes
|
||||||
.map { CountryPrefix(it, PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(it)) }
|
.map { CountryPrefix(it, PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(it)) }
|
||||||
.sortedBy { it.digits }
|
.sortedBy { it.digits }
|
||||||
@@ -45,15 +57,6 @@ class EnterPhoneNumberV2ViewModel : ViewModel() {
|
|||||||
return supportedCountryPrefixes[store.value.countryPrefixIndex]
|
return supportedCountryPrefixes[store.value.countryPrefixIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
fun phoneNumber(): PhoneNumber? {
|
|
||||||
return try {
|
|
||||||
parsePhoneNumber(store.value)
|
|
||||||
} catch (ex: NumberParseException) {
|
|
||||||
Log.w(TAG, "Could not parse phone number in current state.", ex)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setPhoneNumber(phoneNumber: String?) {
|
fun setPhoneNumber(phoneNumber: String?) {
|
||||||
store.update { it.copy(phoneNumber = phoneNumber ?: "") }
|
store.update { it.copy(phoneNumber = phoneNumber ?: "") }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user