Dan Ballard pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android
Commits: 4d86739b by clairehurst at 2024-04-30T15:25:18-06:00 fixup! Implement Android-native Connection Assist UI
- - - - -
6 changed files:
- + fenix/app/src/main/java/org/mozilla/fenix/tor/ConnectAssistUiState.kt - fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistFragment.kt - fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistViewModel.kt - fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerGV.kt - + fenix/app/src/main/res/drawable/browser_location.xml - fenix/app/src/main/res/layout/fragment_tor_connection_assist.xml
Changes:
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/ConnectAssistUiState.kt ===================================== @@ -0,0 +1,288 @@ +package org.mozilla.fenix.tor + +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes +import androidx.annotation.IntRange +import androidx.annotation.StringRes +import org.mozilla.fenix.R + +enum class ConnectAssistUiState( + val progressBarVisible: Boolean, + @IntRange(0, 100) var progress: Int = 0, + @ColorRes val progressTintColorResource: Int? = null, + val backButtonVisible: Boolean, + val settingsButtonVisible: Boolean, + val torConnectImageVisible: Boolean, + @DrawableRes val torConnectImageResource: Int = R.drawable.connect, + val titleLargeTextViewVisible: Boolean, + @StringRes val titleLargeTextViewTextStringResource: Int = R.string.connection_assist_tor_connect_title, + val titleDescriptionVisible: Boolean, + @StringRes val learnMoreStringResource: Int? = null, + @StringRes val internetErrorDescription: Int? = null, + @StringRes val internetErrorDescription1: Int? = null, + @StringRes val internetErrorDescription2: Int? = null, + @StringRes val titleDescriptionTextStringResource: Int? = R.string.preferences_tor_network_settings_explanation, + val quickstartSwitchVisible: Boolean, + val unblockTheInternetInCountryDescriptionVisible: Boolean, + val countryDropDownVisible: Boolean, + val torBootstrapButton1Visible: Boolean, + @StringRes val torBootstrapButton1TextStringResource: Int = R.string.tor_bootstrap_connect, + val torBootstrapButton1ShouldShowTryingABridge: Boolean = false, + val torBootstrapButton2Visible: Boolean, + @StringRes val torBootstrapButton2TextStringResource: Int? = R.string.connection_assist_configure_connection_button, + val torBootstrapButton2ShouldOpenSettings: Boolean = true, + val wordmarkLogoVisible: Boolean, +) { + Splash( + progressBarVisible = false, + backButtonVisible = false, + settingsButtonVisible = false, + torConnectImageVisible = false, + titleLargeTextViewVisible = false, + titleDescriptionVisible = false, + quickstartSwitchVisible = false, + unblockTheInternetInCountryDescriptionVisible = false, + countryDropDownVisible = false, + torBootstrapButton1Visible = false, + torBootstrapButton2Visible = false, + wordmarkLogoVisible = true, + ), + Configuring( + progressBarVisible = false, + progress = 0, + backButtonVisible = false, + settingsButtonVisible = true, + torConnectImageVisible = true, + torConnectImageResource = R.drawable.connect, + titleLargeTextViewVisible = true, + titleLargeTextViewTextStringResource = R.string.connection_assist_tor_connect_title, + titleDescriptionVisible = true, + titleDescriptionTextStringResource = R.string.preferences_tor_network_settings_explanation, + quickstartSwitchVisible = true, + unblockTheInternetInCountryDescriptionVisible = false, + countryDropDownVisible = false, + torBootstrapButton1Visible = true, + torBootstrapButton2Visible = true, + torBootstrapButton2TextStringResource = R.string.connection_assist_configure_connection_button, + torBootstrapButton2ShouldOpenSettings = true, + wordmarkLogoVisible = false, + ), + Bootstrapping( + progressBarVisible = true, + progress = 0, + backButtonVisible = false, + settingsButtonVisible = true, + torConnectImageVisible = true, + torConnectImageResource = R.drawable.connect, + titleLargeTextViewVisible = true, + titleLargeTextViewTextStringResource = R.string.connection_assist_connecting_title, + titleDescriptionVisible = true, + titleDescriptionTextStringResource = R.string.preferences_tor_network_settings_explanation, + quickstartSwitchVisible = true, + unblockTheInternetInCountryDescriptionVisible = false, + countryDropDownVisible = false, + torBootstrapButton1Visible = false, + torBootstrapButton2Visible = true, + torBootstrapButton2TextStringResource = R.string.btn_cancel, + torBootstrapButton2ShouldOpenSettings = false, + wordmarkLogoVisible = false, + ), + InternetError( + progressBarVisible = true, + progress = 100, + progressTintColorResource = R.color.warning_yellow, + backButtonVisible = true, + settingsButtonVisible = true, + torConnectImageVisible = true, + torConnectImageResource = R.drawable.globe_broken, + titleLargeTextViewVisible = true, + titleLargeTextViewTextStringResource = R.string.connection_assist_internet_error_title, + titleDescriptionVisible = true, + learnMoreStringResource = R.string.connection_assist_internet_error_learn_more, + internetErrorDescription = R.string.connection_assist_internet_error_description, + titleDescriptionTextStringResource = null, + quickstartSwitchVisible = false, + unblockTheInternetInCountryDescriptionVisible = false, + countryDropDownVisible = false, + torBootstrapButton1Visible = true, + torBootstrapButton1TextStringResource = R.string.connection_assist_internet_error_try_again, + torBootstrapButton2Visible = true, + torBootstrapButton2TextStringResource = R.string.connection_assist_configure_connection_button, + torBootstrapButton2ShouldOpenSettings = true, + wordmarkLogoVisible = false, + ), + TryingAgain( + progressBarVisible = true, + progress = 0, + progressTintColorResource = null, + backButtonVisible = true, + settingsButtonVisible = true, + torConnectImageVisible = true, + torConnectImageResource = R.drawable.connect, + titleLargeTextViewVisible = true, + titleLargeTextViewTextStringResource = R.string.connection_assist_trying_again_waiting_title, + titleDescriptionVisible = true, + learnMoreStringResource = R.string.connection_assist_internet_error_learn_more, + internetErrorDescription = R.string.connection_assist_internet_error_description, + titleDescriptionTextStringResource = null, + quickstartSwitchVisible = false, + unblockTheInternetInCountryDescriptionVisible = false, + countryDropDownVisible = false, + torBootstrapButton1Visible = false, + torBootstrapButton2Visible = true, + torBootstrapButton2TextStringResource = R.string.btn_cancel, + torBootstrapButton2ShouldOpenSettings = false, + wordmarkLogoVisible = false, + ), + TryABridge( + progressBarVisible = true, + progress = 100, + progressTintColorResource = R.color.warning_yellow, + backButtonVisible = true, + settingsButtonVisible = true, + torConnectImageVisible = true, + torConnectImageResource = R.drawable.connect_broken, + titleLargeTextViewVisible = true, + titleLargeTextViewTextStringResource = R.string.connection_assist_cant_connect_to_tor_title, + titleDescriptionVisible = true, + learnMoreStringResource = R.string.connection_assist_internet_error_learn_more, + internetErrorDescription = R.string.connection_assist_try_a_bridge_description, + titleDescriptionTextStringResource = null, + quickstartSwitchVisible = false, + unblockTheInternetInCountryDescriptionVisible = true, + countryDropDownVisible = true, + torBootstrapButton1Visible = true, + torBootstrapButton1TextStringResource = R.string.connection_assist_try_a_bridge_button, + torBootstrapButton1ShouldShowTryingABridge = true, + torBootstrapButton2Visible = false, + torBootstrapButton2TextStringResource = null, + torBootstrapButton2ShouldOpenSettings = true, + wordmarkLogoVisible = false, + ), + TryingABridge( + progressBarVisible = true, + progress = 0, + progressTintColorResource = null, + backButtonVisible = true, + settingsButtonVisible = true, + torConnectImageVisible = true, + torConnectImageResource = R.drawable.connect, + titleLargeTextViewVisible = true, + titleLargeTextViewTextStringResource = R.string.connection_assist_trying_a_bridge_title, + titleDescriptionVisible = true, + learnMoreStringResource = R.string.connection_assist_internet_error_learn_more, + internetErrorDescription = R.string.connection_assist_try_a_bridge_description, + titleDescriptionTextStringResource = null, + quickstartSwitchVisible = true, + unblockTheInternetInCountryDescriptionVisible = false, + countryDropDownVisible = false, + torBootstrapButton1Visible = false, + torBootstrapButton2Visible = true, + torBootstrapButton2TextStringResource = R.string.btn_cancel, + torBootstrapButton2ShouldOpenSettings = false, + wordmarkLogoVisible = false, + ), + LocationError( + progressBarVisible = true, + progress = 100, + progressTintColorResource = R.color.warning_yellow, + backButtonVisible = true, + settingsButtonVisible = true, + torConnectImageVisible = true, + torConnectImageResource = R.drawable.browser_location, + titleLargeTextViewVisible = true, + titleLargeTextViewTextStringResource = R.string.connection_assist_location_error_title, + titleDescriptionVisible = true, + learnMoreStringResource = R.string.connection_assist_location_error_learn_more_link, + internetErrorDescription = R.string.connection_assist_location_error_description, + internetErrorDescription1 = R.string.connection_assist_find_bridge_location_description, + internetErrorDescription2 = R.string.connection_assist_select_country_try_again, + titleDescriptionTextStringResource = null, + quickstartSwitchVisible = false, + unblockTheInternetInCountryDescriptionVisible = true, + countryDropDownVisible = true, + torBootstrapButton1Visible = true, + torBootstrapButton1TextStringResource = R.string.connection_assist_try_a_bridge_button, + torBootstrapButton1ShouldShowTryingABridge = true, + torBootstrapButton2Visible = false, + torBootstrapButton2TextStringResource = null, + torBootstrapButton2ShouldOpenSettings = true, + wordmarkLogoVisible = false, + ), + LocationCheck( + progressBarVisible = true, + progress = 100, + progressTintColorResource = R.color.warning_yellow, + backButtonVisible = true, + settingsButtonVisible = true, + torConnectImageVisible = true, + torConnectImageResource = R.drawable.browser_location, + titleLargeTextViewVisible = true, + titleLargeTextViewTextStringResource = R.string.connection_assist_location_check_title, + titleDescriptionVisible = true, + learnMoreStringResource = R.string.connection_assist_location_error_learn_more_link, + internetErrorDescription = R.string.connection_assist_location_error_description, + internetErrorDescription1 = R.string.connection_assist_find_bridge_location_description, + internetErrorDescription2 = R.string.connection_assist_select_country_try_again, + titleDescriptionTextStringResource = null, + quickstartSwitchVisible = false, + unblockTheInternetInCountryDescriptionVisible = true, + countryDropDownVisible = true, + torBootstrapButton1Visible = true, + torBootstrapButton1TextStringResource = R.string.connection_assist_try_a_bridge_button, + torBootstrapButton1ShouldShowTryingABridge = true, + torBootstrapButton2Visible = false, + torBootstrapButton2TextStringResource = null, + torBootstrapButton2ShouldOpenSettings = true, + wordmarkLogoVisible = false, + ), + LastTry( + progressBarVisible = true, + progress = 0, + backButtonVisible = true, + settingsButtonVisible = true, + torConnectImageVisible = true, + torConnectImageResource = R.drawable.connect, + titleLargeTextViewVisible = true, + titleLargeTextViewTextStringResource = R.string.connection_assist_last_try_title, + titleDescriptionVisible = true, + learnMoreStringResource = R.string.connection_assist_location_error_learn_more_link, + internetErrorDescription = R.string.connection_assist_location_error_description, + internetErrorDescription1 = R.string.connection_assist_find_bridge_location_description, + internetErrorDescription2 = R.string.connection_assist_select_country_try_again, + titleDescriptionTextStringResource = null, + quickstartSwitchVisible = true, + unblockTheInternetInCountryDescriptionVisible = false, + countryDropDownVisible = false, + torBootstrapButton1Visible = false, + torBootstrapButton2Visible = true, + torBootstrapButton2TextStringResource = R.string.btn_cancel, + torBootstrapButton2ShouldOpenSettings = false, + wordmarkLogoVisible = false, + ), + FinalError( + progressBarVisible = true, + progress = 100, + progressTintColorResource = R.color.warning_yellow, + backButtonVisible = true, + settingsButtonVisible = true, + torConnectImageVisible = true, + torConnectImageResource = R.drawable.connect_broken, + titleLargeTextViewVisible = true, + titleLargeTextViewTextStringResource = R.string.connection_assist_final_error_title, + titleDescriptionVisible = true, + learnMoreStringResource = R.string.connection_assist_final_error_learn_more_link, + internetErrorDescription = R.string.connection_assist_final_error_description1, + internetErrorDescription1 = R.string.connection_assist_final_error_troubleshoot_connection_link, + titleDescriptionTextStringResource = null, + quickstartSwitchVisible = false, + unblockTheInternetInCountryDescriptionVisible = false, + countryDropDownVisible = false, + torBootstrapButton1Visible = true, + torBootstrapButton1TextStringResource = R.string.connection_assist_internet_error_try_again, + torBootstrapButton2Visible = true, + torBootstrapButton2TextStringResource = R.string.connection_assist_configure_connection_button, + torBootstrapButton2ShouldOpenSettings = true, + wordmarkLogoVisible = false, + ) +}
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistFragment.kt ===================================== @@ -24,27 +24,35 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import kotlinx.coroutines.launch +import mozilla.components.support.base.feature.UserInteractionHandler import org.mozilla.fenix.R import org.mozilla.fenix.databinding.FragmentTorConnectionAssistBinding import org.mozilla.fenix.ext.hideToolbar
-class TorConnectionAssistFragment : Fragment() { +class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
private val TAG = "TorConnectionAssistFrag" - private var _binding: FragmentTorConnectionAssistBinding? = null - private val binding get() = _binding!! - private val viewModel: TorConnectionAssistViewModel by viewModels() + private lateinit var binding: FragmentTorConnectionAssistBinding
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View { - _binding = FragmentTorConnectionAssistBinding.inflate( + binding = FragmentTorConnectionAssistBinding.inflate( inflater, container, false, )
+ viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.torConnectScreen.collect { screen -> + Log.d(TAG, "torConnectScreen is $screen") + showScreen(screen) + } + } + } + return binding.root }
@@ -56,23 +64,6 @@ class TorConnectionAssistFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState)
- lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.torConnectState.collect { torConnectState -> - Log.d(TAG, "torConnectState is ${torConnectState.state}") - when (torConnectState) { - TorConnectState.Initial -> showSplash() - TorConnectState.Configuring -> showConfiguring() - TorConnectState.AutoBootstrapping -> showBootstrapping() - TorConnectState.Bootstrapping -> showBootstrapping() - TorConnectState.Error -> showError() - TorConnectState.Bootstrapped -> openHome() - TorConnectState.Disabled -> openHome() - } - } - } - } - viewModel.progress().observe( viewLifecycleOwner, ) { progress -> @@ -88,243 +79,96 @@ class TorConnectionAssistFragment : Fragment() { ) { binding.quickstartSwitch.isChecked = it == true } - - binding.quickstartSwitch.setOnCheckedChangeListener { _, isChecked -> - viewModel.handleQuickstartChecked(isChecked) - } }
- - private fun showSplash() { - binding.torBootstrapProgressBar.visibility = View.GONE - binding.settingsButton.visibility = View.GONE - binding.backButton.visibility = View.GONE - binding.torConnectImage.visibility = View.GONE - binding.titleLargeTextView.visibility = View.GONE - binding.titleDescription.visibility = View.GONE - binding.quickstartSwitch.visibility = View.GONE - binding.torBootstrapButton1.visibility = View.GONE - binding.torBootstrapButton2.visibility = View.GONE - binding.wordmarkLogo.visibility = View.VISIBLE + override fun onDestroyView() { + super.onDestroyView() }
+ private fun showScreen(screen: ConnectAssistUiState) { + binding.apply { + torBootstrapProgressBar.visibility = if (screen.progressBarVisible) View.VISIBLE else View.GONE + torBootstrapProgressBar.progress = screen.progress + torBootstrapProgressBar.progressTintList = + screen.progressTintColorResource?.let { + AppCompatResources.getColorStateList(requireContext(), + it + ) + }
- private fun showConfiguring() { - binding.wordmarkLogo.visibility = View.GONE - - binding.torBootstrapProgressBar.visibility = View.INVISIBLE - binding.torBootstrapProgressBar.progress = 0 - binding.backButton.visibility = View.INVISIBLE - binding.settingsButton.visibility = View.VISIBLE - binding.settingsButton.setOnClickListener { - viewModel.cancelTorBootstrap() - openSettings() - } - binding.torConnectImage.visibility = View.VISIBLE - binding.torConnectImage.setImageResource(R.drawable.connect) - binding.titleLargeTextView.visibility = View.VISIBLE - binding.titleLargeTextView.text = getString(R.string.connection_assist_tor_connect_title) - binding.titleDescription.visibility = View.VISIBLE - binding.titleDescription.text = - getString(R.string.preferences_tor_network_settings_explanation) - binding.quickstartSwitch.visibility = View.VISIBLE - binding.quickstartSwitch.isChecked = viewModel.quickstartToggle().value == true - - binding.unblockTheInternetInCountryDescription.visibility = View.GONE - binding.countryDropDown.visibility = View.GONE + settingsButton.visibility = if (screen.settingsButtonVisible) View.VISIBLE else View.GONE + settingsButton.setOnClickListener { + viewModel.cancelTorBootstrap() + openSettings() + }
- binding.torBootstrapButton1.visibility = View.VISIBLE - binding.torBootstrapButton1.text = getString(R.string.tor_bootstrap_connect) - binding.torBootstrapButton1.setOnClickListener { - viewModel.handleConnect(lifecycleScope = lifecycleScope) - showBootstrapping() - } + backButton.visibility = if (screen.backButtonVisible) View.VISIBLE else View.INVISIBLE + backButton.setOnClickListener { + viewModel.handleBackButtonPressed() + }
- binding.torBootstrapButton2.visibility = View.VISIBLE - binding.torBootstrapButton2.text = - getString(R.string.connection_assist_configure_connection_button) - binding.torBootstrapButton2.setOnClickListener { - viewModel.cancelTorBootstrap() - openTorConnectionSettings() - } - } + torConnectImage.visibility = if (screen.torConnectImageVisible) View.VISIBLE else View.GONE + torConnectImage.setImageResource(screen.torConnectImageResource) + + titleLargeTextView.visibility = if (screen.titleLargeTextViewVisible) View.VISIBLE else View.GONE + titleLargeTextView.text = getString(screen.titleLargeTextViewTextStringResource) + titleDescription.visibility = if (screen.titleDescriptionVisible) View.VISIBLE else View.GONE + if (screen.learnMoreStringResource != null && screen.internetErrorDescription != null) { + val learnMore: String = getString(screen.learnMoreStringResource) + val internetErrorDescription: String = + if (screen.internetErrorDescription1 == null) { + getString( + screen.internetErrorDescription, + learnMore, + ) + } else if (screen.internetErrorDescription2 == null) { + getString( + screen.internetErrorDescription, + getString(screen.internetErrorDescription1), + learnMore, + ) + } else { + getString( + screen.internetErrorDescription, + getString(screen.internetErrorDescription1), + getString(screen.internetErrorDescription2), + learnMore, + ) + } + handleDescriptionWithClickable(internetErrorDescription, learnMore) + } else if (screen.titleDescriptionTextStringResource != null) { + titleDescription.text = getString(screen.titleDescriptionTextStringResource) + } + quickstartSwitch.visibility = if (screen.quickstartSwitchVisible) View.VISIBLE else View.GONE + quickstartSwitch.isChecked = viewModel.quickstartToggle().value == true + quickstartSwitch.setOnCheckedChangeListener { _, isChecked -> + viewModel.handleQuickstartChecked(isChecked) + }
- private fun showBootstrapping() { - binding.wordmarkLogo.visibility = View.GONE + unblockTheInternetInCountryDescription.visibility = if (screen.unblockTheInternetInCountryDescriptionVisible) View.VISIBLE else View.GONE + countryDropDown.visibility = if (screen.countryDropDownVisible) View.VISIBLE else View.GONE
- binding.torBootstrapProgressBar.visibility = View.VISIBLE - binding.torBootstrapProgressBar.progress = 0 - binding.backButton.visibility = View.INVISIBLE - binding.settingsButton.visibility = View.VISIBLE - binding.settingsButton.setOnClickListener { - viewModel.cancelTorBootstrap() - openSettings() - } - binding.torConnectImage.visibility = View.VISIBLE - binding.torConnectImage.setImageResource(R.drawable.connect) - binding.titleLargeTextView.visibility = View.VISIBLE - binding.titleLargeTextView.text = getString(R.string.connection_assist_connecting_title) - binding.titleDescription.visibility = View.VISIBLE - binding.titleDescription.text = - getString(R.string.preferences_tor_network_settings_explanation) - binding.quickstartSwitch.visibility = View.VISIBLE - binding.quickstartSwitch.isChecked = viewModel.quickstartToggle().value == true - binding.quickstartSwitch.jumpDrawablesToCurrentState() - binding.torBootstrapButton1.visibility = View.INVISIBLE - binding.torBootstrapButton2.visibility = View.VISIBLE - binding.torBootstrapButton2.text = getString(R.string.btn_cancel) - binding.torBootstrapButton2.setOnClickListener { viewModel.cancelTorBootstrap() } - } + torBootstrapButton1.visibility = if (screen.torBootstrapButton1Visible) View.VISIBLE else View.GONE + torBootstrapButton1.text = getString(screen.torBootstrapButton1TextStringResource) + torBootstrapButton1.setOnClickListener { viewModel.handleButton1Pressed(screen, lifecycleScope) }
- private suspend fun showError() { - viewModel.torError.collect { - Log.d( - TAG, - "TorError: details = ${it?.details ?: "null details"}, message = ${it?.message ?: "null message"}", - ) - when (viewModel.handleError(it)) { - ErrorScreen.CantConnectToInternet -> showCantConnectToInternet() - ErrorScreen.CantConnectToTorDirectly -> showCantConnectToTorDirectly() - ErrorScreen.WeCouldntFindYourLocation -> showWeCouldntFindYourLocation() - ErrorScreen.WereStillHavingTroubleConnecting -> showWereStillHavingTroubleConnecting() - ErrorScreen.WeWerentAbleToConnectAutomatically -> showWeWerentAbleToConnectAutomatically() - null -> { - // no op - Log.d(TAG, "ErrorScreen: null, nothing shown") + torBootstrapButton2.visibility = if (screen.torBootstrapButton2Visible) View.VISIBLE else View.GONE + torBootstrapButton2.text = screen.torBootstrapButton2TextStringResource?.let { + getString( + it + ) + } + torBootstrapButton2.setOnClickListener { + viewModel.cancelTorBootstrap() + if (screen.torBootstrapButton2ShouldOpenSettings){ + openTorConnectionSettings() + } else { + showScreen(ConnectAssistUiState.Configuring) } } - } - } - - private fun showCantConnectToInternet() { - Log.d(TAG, "showCantConnectToInternet()") - binding.torBootstrapProgressBar.visibility = View.VISIBLE - binding.torBootstrapProgressBar.progressTintList = - AppCompatResources.getColorStateList(requireContext(), R.color.warning_yellow) - binding.torBootstrapProgressBar.progress = 100 - - binding.backButton.visibility = View.VISIBLE - binding.backButton.setOnClickListener { - showConfiguring() - } - - binding.torConnectImage.setImageResource(R.drawable.globe_broken) - binding.titleLargeTextView.text = getString(R.string.connection_assist_internet_error_title)
- val learnMore: String = getString(R.string.connection_assist_internet_error_learn_more) - val internetErrorDescription: String = getString( - R.string.connection_assist_internet_error_description, - learnMore, - ) - handleDescriptionWithClickable(internetErrorDescription, learnMore) - - binding.quickstartSwitch.visibility = View.GONE - - binding.torBootstrapButton1.visibility = View.VISIBLE - binding.torBootstrapButton1.text = - getString(R.string.connection_assist_internet_error_try_again) - binding.torBootstrapButton1.setOnClickListener { - showTryingAgain() - viewModel.handleConnect(lifecycleScope = lifecycleScope) - } - - binding.torBootstrapButton2.text = - getString(R.string.connection_assist_configure_connection_button) - binding.torBootstrapButton2.setOnClickListener { - openTorConnectionSettings() - } - } - - private fun showTryingAgain() { - Log.d(TAG, "showTryingAgain()") - binding.torBootstrapProgressBar.progress = 0 - binding.torBootstrapProgressBar.visibility = View.VISIBLE - binding.torBootstrapProgressBar.progressTintList = null - binding.torConnectImage.setImageResource(R.drawable.connect) - binding.titleLargeTextView.text = - getString(R.string.connection_assist_trying_again_waiting_title) - - binding.quickstartSwitch.visibility = View.GONE - binding.torBootstrapButton1.visibility = View.INVISIBLE - binding.torBootstrapButton2.visibility = View.VISIBLE - binding.torBootstrapButton2.text = getString(R.string.btn_cancel) - binding.torBootstrapButton2.setOnClickListener { - viewModel.cancelTorBootstrap() - showConfiguring() - } - } - - private fun showCantConnectToTorDirectly() { - Log.d(TAG, "showCantConnectToTorDirectly()") - binding.torBootstrapProgressBar.visibility = View.VISIBLE - binding.torBootstrapProgressBar.progressTintList = - AppCompatResources.getColorStateList(requireContext(), R.color.warning_yellow) - binding.torBootstrapProgressBar.progress = 100 - - binding.backButton.visibility = View.VISIBLE - binding.backButton.setOnClickListener { - showConfiguring() - } - - binding.torConnectImage.setImageResource(R.drawable.globe_broken) - binding.titleLargeTextView.text = - getString(R.string.connection_assist_cant_connect_to_tor_title) - - val learnMore: String = getString(R.string.connection_assist_internet_error_learn_more) - val tryABridge: String = getString( - R.string.connection_assist_try_a_bridge_description, - learnMore, - ) - handleDescriptionWithClickable(tryABridge, learnMore) - - binding.quickstartSwitch.visibility = View.GONE - binding.unblockTheInternetInCountryDescription.visibility = View.VISIBLE - binding.countryDropDown.visibility = View.VISIBLE - // TODO implement countryDropDown - - binding.torBootstrapButton1.visibility = View.VISIBLE - binding.torBootstrapButton1.text = getString(R.string.connection_assist_try_a_bridge_button) - binding.torBootstrapButton1.setOnClickListener { - viewModel.tryABridge() - showTryingABridge() + wordmarkLogo.visibility = if(screen.wordmarkLogoVisible) View.VISIBLE else View.GONE } - binding.torBootstrapButton2.visibility = View.GONE - } - - private fun showTryingABridge() { - Log.d(TAG, "showTryingABridge()") - // TODO(Not implemented) - binding.torBootstrapButton2.setOnClickListener { - showTryingABridge() - } - } - - private fun showWeCouldntFindYourLocation() { - Log.d(TAG, "showWeCouldntFindYourLocation()") - // TODO(Not implemented) - binding.torBootstrapButton2.setOnClickListener { - showTryingABridge() - } - } - - private fun showWereStillHavingTroubleConnecting() { - Log.d(TAG, "showWereStillHavingTroubleConnecting()") - TODO("Not yet implemented") - } - - private fun showTryingOneMoreTime() { - Log.d(TAG, "showTryingOneMoreTime()") - TODO("Not yet implemented") - } - - private fun showWeWerentAbleToConnectAutomatically() { - Log.d(TAG, "showWeWerentAbleToConnectAutomatically()") - TODO("Not yet implemented") - } - - private fun showUnknownError() { - Log.d(TAG, "showUnknownError()") - TODO("Not yet implemented") }
/** @@ -377,4 +221,9 @@ class TorConnectionAssistFragment : Fragment() { ), ) } + + override fun onBackPressed(): Boolean { + return viewModel.handleBackButtonPressed() + } + }
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistViewModel.kt ===================================== @@ -23,11 +23,8 @@ class TorConnectionAssistViewModel(
private val _torController: TorControllerGV = components.torController as TorControllerGV
- private val _torConnectState = MutableStateFlow(TorConnectState.Initial) - internal val torConnectState: StateFlow<TorConnectState> = _torConnectState - - private val _torError = MutableStateFlow(_torController.getLastErrorState()) - internal val torError: StateFlow<TorError?> = _torError + private val _torConnectScreen = MutableStateFlow(ConnectAssistUiState.Splash) + internal val torConnectScreen: StateFlow<ConnectAssistUiState> = _torConnectScreen
private val _progress = MutableLiveData(0) fun progress(): LiveData<Int> { @@ -45,7 +42,7 @@ class TorConnectionAssistViewModel( _torController.registerTorListener(this) }
- fun handleConnect( + private fun handleConnect( withDebugLogging: Boolean = false, lifecycleScope: LifecycleCoroutineScope? = null, ) { @@ -61,6 +58,17 @@ class TorConnectionAssistViewModel( _quickStartToggle.value = checked }
+ fun handleButton1Pressed( + screen: ConnectAssistUiState, + lifecycleScope: LifecycleCoroutineScope?, + ) { + if (screen.torBootstrapButton1ShouldShowTryingABridge) { + tryABridge() + } else { + handleConnect(lifecycleScope = lifecycleScope) + } + } + fun cancelTorBootstrap() { _torController.stopTor() _torController.setTorStopped() @@ -80,33 +88,126 @@ class TorConnectionAssistViewModel( if (progress != null) { _progress.value = progress.toInt() } - _torConnectState.value = _torController.lastKnownStatus - _torError.value = _torController.getLastErrorState() + + when (_torController.lastKnownStatus) { + TorConnectState.Initial -> _torConnectScreen.value = ConnectAssistUiState.Splash + TorConnectState.Configuring -> handleConfiguring() + TorConnectState.AutoBootstrapping -> handleBootstrap() + TorConnectState.Bootstrapping -> handleBootstrap() + TorConnectState.Error -> handleError() + else -> {} + } + } + + private fun handleConfiguring() { + if (_torController.lastKnownError == null) { + _torConnectScreen.value = ConnectAssistUiState.Configuring + } else { + handleError() + } + } + + private fun handleBootstrap() { + when (_torConnectScreen.value) { + ConnectAssistUiState.InternetError -> { + _torConnectScreen.value = ConnectAssistUiState.TryingAgain + } + + ConnectAssistUiState.TryingAgain -> { + /** stay here */ + } + + ConnectAssistUiState.TryABridge -> { + _torConnectScreen.value = ConnectAssistUiState.TryingABridge + } + + ConnectAssistUiState.LocationError -> { + _torConnectScreen.value = ConnectAssistUiState.TryingABridge + } + + ConnectAssistUiState.TryingABridge -> { + /** stay here */ + } + + ConnectAssistUiState.LocationCheck -> { + _torConnectScreen.value = ConnectAssistUiState.LastTry + } + + ConnectAssistUiState.LastTry -> { + /** stay here */ + } + + else -> _torConnectScreen.value = ConnectAssistUiState.Bootstrapping + } + } + + private fun handleError() { + _torController.lastKnownError?.apply { + Log.d( + TAG, + "TorError(message = $message, details = $details, phase = $phase, reason = $reason", + ) + // TODO better error handling + _torConnectScreen.value = ConnectAssistUiState.InternetError + } }
override fun onTorStopped() { Log.d(TAG, "onTorStopped()") }
- internal fun handleError(it: TorError?): ErrorScreen? { - // TODO(Only partly implemented) - if (it?.message == null){ - return null + private fun tryABridge() { + if (!_torController.bridgesEnabled) { + _torController.bridgesEnabled = true + _torController.bridgeTransport = + TorBridgeTransportConfig.BUILTIN_OBFS4 // TODO select based on country } - return ErrorScreen.CantConnectToInternet + handleConnect(withDebugLogging = true) }
- fun tryABridge() { - // TODO("Try a bridge not enabled") - // connect to bridge based on country - // try connecting + fun handleBackButtonPressed(): Boolean { + when (torConnectScreen.value) { + ConnectAssistUiState.Splash -> return false + ConnectAssistUiState.Configuring -> return false + ConnectAssistUiState.Bootstrapping -> cancelTorBootstrap() + ConnectAssistUiState.InternetError -> { + _torController.lastKnownError = null + _torConnectScreen.value = ConnectAssistUiState.Configuring + } + + ConnectAssistUiState.TryingAgain -> { + cancelTorBootstrap() + } + + ConnectAssistUiState.TryABridge -> { + _torController.lastKnownError = null + _torConnectScreen.value = ConnectAssistUiState.Configuring + } + + ConnectAssistUiState.TryingABridge -> { + _torController.stopTor() + _torConnectScreen.value = ConnectAssistUiState.TryABridge + } + + ConnectAssistUiState.LocationError -> { + _torConnectScreen.value = ConnectAssistUiState.TryABridge + } + + ConnectAssistUiState.LocationCheck -> { + _torConnectScreen.value = ConnectAssistUiState.LocationError + } + + ConnectAssistUiState.LastTry -> { + _torController.stopTor() + _torConnectScreen.value = ConnectAssistUiState.LocationCheck + } + + ConnectAssistUiState.FinalError -> { + _torConnectScreen.value = ConnectAssistUiState.LocationCheck + } + } + return true } -}
-internal enum class ErrorScreen { - CantConnectToInternet, - CantConnectToTorDirectly, - WeCouldntFindYourLocation, - WereStillHavingTroubleConnecting, - WeWerentAbleToConnectAutomatically, } +
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerGV.kt ===================================== @@ -285,7 +285,7 @@ class TorControllerGV(
// TorEventsBootstrapStateChangeListener override fun onBootstrapStateChange(newStateVal: String?) { - Log.d(TAG, "onBootstrapStateChange($newStateVal)") + Log.d(TAG, "onBootstrapStateChange(newStateVal = $newStateVal)") val newState: TorConnectState = TorConnectState.valueOf(newStateVal ?: "Error")
if (newState.isError() && wasTorBootstrapped) {
===================================== fenix/app/src/main/res/drawable/browser_location.xml ===================================== @@ -0,0 +1,17 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportWidth="40" + android:viewportHeight="40"> + <group> + <clip-path + android:pathData="M0,0h40v40h-40z"/> + <path + android:pathData="M19.332,28.605C19.332,23.853 23.361,20 28.332,20C33.303,20 37.332,23.853 37.332,28.605C37.332,32.002 32.736,36.822 30.113,39.296C29.636,39.748 28.997,40 28.332,40C27.667,40 27.028,39.748 26.551,39.296C23.928,36.822 19.332,32.001 19.332,28.605ZM26.865,24.958C27.33,24.766 27.829,24.667 28.332,24.667C29.349,24.667 30.324,25.07 31.043,25.789C31.761,26.508 32.165,27.483 32.165,28.5C32.165,29.517 31.761,30.492 31.043,31.211C30.324,31.93 29.349,32.333 28.332,32.333C27.829,32.333 27.33,32.234 26.865,32.042C26.4,31.849 25.977,31.566 25.621,31.211C25.265,30.855 24.983,30.432 24.791,29.967C24.598,29.502 24.499,29.003 24.499,28.5C24.499,27.997 24.598,27.498 24.791,27.033C24.983,26.568 25.265,26.146 25.621,25.789C25.977,25.434 26.4,25.151 26.865,24.958Z" + android:fillColor="#FFA436" + android:fillType="evenOdd"/> + <path + android:pathData="M38.509,22.9C38.721,21.771 38.832,20.607 38.832,19.417C38.832,9.061 30.438,0.667 20.082,0.667C9.727,0.667 1.332,9.061 1.332,19.417C1.332,29.772 9.727,38.167 20.082,38.167C20.825,38.167 21.559,38.124 22.279,38.039C19.438,34.942 16.665,31.167 16.665,28.233C16.665,25.223 17.971,22.499 20.082,20.526V14.846C22.098,14.846 23.809,16.151 24.416,17.962C25.33,17.658 26.298,17.458 27.301,17.375C26.412,14.225 23.517,11.917 20.082,11.917L20.082,9.221C25.042,9.221 29.175,12.764 30.089,17.456C31.169,17.608 32.2,17.899 33.161,18.308C32.598,11.578 26.957,6.292 20.082,6.292V3.596C28.819,3.596 35.903,10.679 35.903,19.417C35.903,19.589 35.9,19.761 35.894,19.933C36.942,20.767 37.83,21.771 38.509,22.9Z" + android:fillColor="#FBFBFE"/> + </group> +</vector>
===================================== fenix/app/src/main/res/layout/fragment_tor_connection_assist.xml ===================================== @@ -3,7 +3,6 @@ - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/tor_bootstrap_background_gradient"
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/4d86...