Dan Ballard pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android
Commits: a00861a6 by clairehurst at 2024-05-09T14:47:16-06:00 fixup! Implement Android-native Connection Assist UI
- - - - -
4 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/res/layout/fragment_tor_connection_assist.xml
Changes:
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/ConnectAssistUiState.kt ===================================== @@ -31,7 +31,8 @@ enum class ConnectAssistUiState( val torBootstrapButton2Visible: Boolean, @StringRes val torBootstrapButton2TextStringResource: Int? = R.string.connection_assist_configure_connection_button, val torBootstrapButton2ShouldOpenSettings: Boolean = true, - val wordmarkLogoVisible: Boolean, + val wordmarkLogoVisible: Boolean = false, + val torBootstrapButton2ShouldRestartApp: Boolean = false, ) { Splash( progressBarVisible = false, @@ -65,9 +66,8 @@ enum class ConnectAssistUiState( torBootstrapButton2Visible = true, torBootstrapButton2TextStringResource = R.string.connection_assist_configure_connection_button, torBootstrapButton2ShouldOpenSettings = true, - wordmarkLogoVisible = false, ), - Bootstrapping( + Connecting( progressBarVisible = true, progress = 0, backButtonVisible = false, @@ -85,7 +85,6 @@ enum class ConnectAssistUiState( torBootstrapButton2Visible = true, torBootstrapButton2TextStringResource = R.string.btn_cancel, torBootstrapButton2ShouldOpenSettings = false, - wordmarkLogoVisible = false, ), InternetError( progressBarVisible = true, @@ -109,7 +108,6 @@ enum class ConnectAssistUiState( torBootstrapButton2Visible = true, torBootstrapButton2TextStringResource = R.string.connection_assist_configure_connection_button, torBootstrapButton2ShouldOpenSettings = true, - wordmarkLogoVisible = false, ), TryingAgain( progressBarVisible = true, @@ -132,9 +130,8 @@ enum class ConnectAssistUiState( torBootstrapButton2Visible = true, torBootstrapButton2TextStringResource = R.string.btn_cancel, torBootstrapButton2ShouldOpenSettings = false, - wordmarkLogoVisible = false, ), - TryABridge( + ConnectionAssist( progressBarVisible = true, progress = 100, progressTintColorResource = R.color.warning_yellow, @@ -157,7 +154,6 @@ enum class ConnectAssistUiState( torBootstrapButton2Visible = false, torBootstrapButton2TextStringResource = null, torBootstrapButton2ShouldOpenSettings = true, - wordmarkLogoVisible = false, ), TryingABridge( progressBarVisible = true, @@ -180,7 +176,6 @@ enum class ConnectAssistUiState( torBootstrapButton2Visible = true, torBootstrapButton2TextStringResource = R.string.btn_cancel, torBootstrapButton2ShouldOpenSettings = false, - wordmarkLogoVisible = false, ), LocationError( progressBarVisible = true, @@ -207,7 +202,6 @@ enum class ConnectAssistUiState( torBootstrapButton2Visible = false, torBootstrapButton2TextStringResource = null, torBootstrapButton2ShouldOpenSettings = true, - wordmarkLogoVisible = false, ), LocationCheck( progressBarVisible = true, @@ -234,7 +228,6 @@ enum class ConnectAssistUiState( torBootstrapButton2Visible = false, torBootstrapButton2TextStringResource = null, torBootstrapButton2ShouldOpenSettings = true, - wordmarkLogoVisible = false, ), LastTry( progressBarVisible = true, @@ -258,7 +251,6 @@ enum class ConnectAssistUiState( torBootstrapButton2Visible = true, torBootstrapButton2TextStringResource = R.string.btn_cancel, torBootstrapButton2ShouldOpenSettings = false, - wordmarkLogoVisible = false, ), FinalError( progressBarVisible = true, @@ -279,10 +271,10 @@ enum class ConnectAssistUiState( unblockTheInternetInCountryDescriptionVisible = false, countryDropDownVisible = false, torBootstrapButton1Visible = true, - torBootstrapButton1TextStringResource = R.string.connection_assist_internet_error_try_again, + torBootstrapButton1TextStringResource = R.string.connection_assist_configure_connection_button, torBootstrapButton2Visible = true, - torBootstrapButton2TextStringResource = R.string.connection_assist_configure_connection_button, - torBootstrapButton2ShouldOpenSettings = true, - wordmarkLogoVisible = false, + torBootstrapButton2TextStringResource = R.string.mozac_lib_crash_dialog_button_restart, + torBootstrapButton2ShouldOpenSettings = false, + torBootstrapButton2ShouldRestartApp = true, ) }
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistFragment.kt ===================================== @@ -4,6 +4,7 @@
package org.mozilla.fenix.tor
+import android.content.Intent import android.graphics.Color import android.os.Build import android.os.Bundle @@ -25,6 +26,7 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController import kotlinx.coroutines.launch import mozilla.components.support.base.feature.UserInteractionHandler +import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.databinding.FragmentTorConnectionAssistBinding import org.mozilla.fenix.ext.hideToolbar @@ -33,14 +35,15 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
private val TAG = "TorConnectionAssistFrag" private val viewModel: TorConnectionAssistViewModel by viewModels() - private lateinit var binding: FragmentTorConnectionAssistBinding + private var _binding: FragmentTorConnectionAssistBinding? = null + private val binding get() = _binding!!
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View { - binding = FragmentTorConnectionAssistBinding.inflate( + _binding = FragmentTorConnectionAssistBinding.inflate( inflater, container, false, )
@@ -90,96 +93,148 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
}
- 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 - ) - } - - settingsButton.visibility = if (screen.settingsButtonVisible) View.VISIBLE else View.GONE - settingsButton.setOnClickListener { - viewModel.cancelTorBootstrap() - openSettings() - } + setProgressBar(screen) + setSettingsButton(screen) + setBackButton(screen) + setTorConnectImage(screen) + setTitle(screen) + setQuickStart(screen) + setCountryDropDown(screen) + setButton1(screen) + setButton2(screen) + setSplashLogo(screen) + }
- backButton.visibility = if (screen.backButtonVisible) View.VISIBLE else View.INVISIBLE - backButton.setOnClickListener { - viewModel.handleBackButtonPressed() + private fun setProgressBar(screen: ConnectAssistUiState) { + binding.torBootstrapProgressBar.visibility = + if (screen.progressBarVisible) View.VISIBLE else View.GONE + binding.torBootstrapProgressBar.progress = screen.progress + binding.torBootstrapProgressBar.progressTintList = + screen.progressTintColorResource?.let { + AppCompatResources.getColorStateList( + requireContext(), + it, + ) } + }
- 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 setSettingsButton(screen: ConnectAssistUiState) { + binding.settingsButton.visibility = if (screen.settingsButtonVisible) View.VISIBLE else View.GONE + binding.settingsButton.setOnClickListener { + viewModel.cancelTorBootstrap() + openSettings() + } + }
- unblockTheInternetInCountryDescription.visibility = if (screen.unblockTheInternetInCountryDescriptionVisible) View.VISIBLE else View.GONE - countryDropDown.visibility = if (screen.countryDropDownVisible) View.VISIBLE else View.GONE + private fun setBackButton(screen: ConnectAssistUiState) { + binding.backButton.visibility = if (screen.backButtonVisible) View.VISIBLE else View.INVISIBLE + binding.backButton.setOnClickListener { + viewModel.handleBackButtonPressed() + } + }
- torBootstrapButton1.visibility = if (screen.torBootstrapButton1Visible) View.VISIBLE else View.GONE - torBootstrapButton1.text = getString(screen.torBootstrapButton1TextStringResource) - torBootstrapButton1.setOnClickListener { viewModel.handleButton1Pressed(screen, lifecycleScope) } + private fun setTorConnectImage(screen: ConnectAssistUiState) { + binding.torConnectImage.visibility = if (screen.torConnectImageVisible) View.VISIBLE else View.GONE + binding.torConnectImage.setImageResource(screen.torConnectImageResource) + }
- 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() + private fun setTitle(screen: ConnectAssistUiState) { + binding.titleLargeTextView.visibility = + if (screen.titleLargeTextViewVisible) View.VISIBLE else View.GONE + binding.titleLargeTextView.text = getString(screen.titleLargeTextViewTextStringResource) + binding.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 { - showScreen(ConnectAssistUiState.Configuring) + getString( + screen.internetErrorDescription, + getString(screen.internetErrorDescription1), + getString(screen.internetErrorDescription2), + learnMore, + ) } - } + handleDescriptionWithClickable(internetErrorDescription, learnMore) + } else if (screen.titleDescriptionTextStringResource != null) { + binding.titleDescription.text = getString(screen.titleDescriptionTextStringResource) + } + } + + private fun setQuickStart(screen: ConnectAssistUiState) { + binding.quickstartSwitch.visibility = + if (screen.quickstartSwitchVisible) View.VISIBLE else View.GONE + binding.quickstartSwitch.isChecked = viewModel.quickstartToggle().value == true + binding.quickstartSwitch.setOnCheckedChangeListener { _, isChecked -> + viewModel.handleQuickstartChecked(isChecked) + } + } + + private fun setCountryDropDown(screen: ConnectAssistUiState) { + binding.unblockTheInternetInCountryDescription.visibility = + if (screen.unblockTheInternetInCountryDescriptionVisible) View.VISIBLE else View.GONE + binding.countryDropDown.visibility = if (screen.countryDropDownVisible) View.VISIBLE else View.GONE + }
- wordmarkLogo.visibility = if(screen.wordmarkLogoVisible) View.VISIBLE else View.GONE + private fun setButton1(screen: ConnectAssistUiState) { + binding.torBootstrapButton1.visibility = + if (screen.torBootstrapButton1Visible) View.VISIBLE else View.GONE + binding.torBootstrapButton1.text = getString(screen.torBootstrapButton1TextStringResource) + binding.torBootstrapButton1.setOnClickListener { + viewModel.handleButton1Pressed( + screen, + lifecycleScope, + ) + } + } + + private fun setButton2(screen: ConnectAssistUiState) { + binding.torBootstrapButton2.visibility = + if (screen.torBootstrapButton2Visible) View.VISIBLE else View.GONE + if (screen.torBootstrapButton2ShouldRestartApp) { + binding.torBootstrapButton2.text = + screen.torBootstrapButton2TextStringResource?.let { + getString( + it, + getString(R.string.app_name), + ) + } + } else { + binding.torBootstrapButton2.text = + screen.torBootstrapButton2TextStringResource?.let { + getString( + it, + ) + } + } + binding.torBootstrapButton2.setOnClickListener { + viewModel.cancelTorBootstrap() + if (screen.torBootstrapButton2ShouldOpenSettings) { + openTorConnectionSettings() + } else if (screen.torBootstrapButton2ShouldRestartApp) { + restartApplication() + } else { + showScreen(ConnectAssistUiState.Configuring) + } } }
+ private fun setSplashLogo(screen: ConnectAssistUiState) { + binding.wordmarkLogo.visibility = if (screen.wordmarkLogoVisible) View.VISIBLE else View.GONE + } + /** * from https://stackoverflow.com/questions/10696986/how-to-set-the-part-of-the-text... */ @@ -207,6 +262,7 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler { }
private fun showLearnMore() { + Log.d(TAG, "showLearnMore() tapped") //TODO("Not yet implemented") }
@@ -231,6 +287,15 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler { ) }
+ private fun restartApplication() { + startActivity( + Intent(requireContext(), HomeActivity::class.java).addFlags( + Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK, + ), + ) + Runtime.getRuntime().exit(0) + } + override fun onBackPressed(): Boolean { return viewModel.handleBackButtonPressed() }
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistViewModel.kt ===================================== @@ -124,7 +124,7 @@ class TorConnectionAssistViewModel( /** stay here */ }
- ConnectAssistUiState.TryABridge -> { + ConnectAssistUiState.ConnectionAssist -> { _torConnectScreen.value = ConnectAssistUiState.TryingABridge }
@@ -144,7 +144,7 @@ class TorConnectionAssistViewModel( /** stay here */ }
- else -> _torConnectScreen.value = ConnectAssistUiState.Bootstrapping + else -> _torConnectScreen.value = ConnectAssistUiState.Connecting } }
@@ -155,28 +155,58 @@ class TorConnectionAssistViewModel( "TorError(message = $message, details = $details, phase = $phase, reason = $reason", ) // TODO better error handling - _torConnectScreen.value = ConnectAssistUiState.InternetError + when (reason) { +// "noroute" -> handleNoRoute() TODO re-add when working better + else -> handleUnknownError() + } + } + } + + private fun handleNoRoute() { + Log.d(TAG, "handleNoRoute(), _torConnectScreen.value = ${_torConnectScreen.value}") + when (_torConnectScreen.value) { + ConnectAssistUiState.Connecting -> _torConnectScreen.value = ConnectAssistUiState.ConnectionAssist + ConnectAssistUiState.ConnectionAssist -> {/** no op, likely a duplicate error */} + ConnectAssistUiState.TryingABridge -> _torConnectScreen.value = ConnectAssistUiState.LocationCheck + ConnectAssistUiState.LocationCheck -> {/** no op, likely a duplicate error */} + ConnectAssistUiState.LastTry -> _torConnectScreen.value = ConnectAssistUiState.FinalError + ConnectAssistUiState.FinalError -> {/** no op, likely a duplicate error */} + else -> _torConnectScreen.value = ConnectAssistUiState.InternetError } }
+ private fun handleUnknownError() { + // TODO should we have a dedicated screen for unknown errors? + _torConnectScreen.value = ConnectAssistUiState.InternetError + } + override fun onTorStopped() { Log.d(TAG, "onTorStopped()") }
private fun tryABridge() { + if (!locationFound()) { + _torConnectScreen.value = ConnectAssistUiState.LocationError + return + } if (!_torController.bridgesEnabled) { _torController.bridgesEnabled = true _torController.bridgeTransport = - TorBridgeTransportConfig.BUILTIN_OBFS4 // TODO select based on country + TorBridgeTransportConfig.BUILTIN_SNOWFLAKE // TODO select based on country } handleConnect(withDebugLogging = true) }
+ private fun locationFound(): Boolean { + // TODO try to find location + return true + } + fun handleBackButtonPressed(): Boolean { when (torConnectScreen.value) { ConnectAssistUiState.Splash -> return false ConnectAssistUiState.Configuring -> return false - ConnectAssistUiState.Bootstrapping -> cancelTorBootstrap() + ConnectAssistUiState.Connecting -> cancelTorBootstrap() ConnectAssistUiState.InternetError -> { _torController.lastKnownError = null _torConnectScreen.value = ConnectAssistUiState.Configuring @@ -186,18 +216,18 @@ class TorConnectionAssistViewModel( cancelTorBootstrap() }
- ConnectAssistUiState.TryABridge -> { + ConnectAssistUiState.ConnectionAssist -> { _torController.lastKnownError = null _torConnectScreen.value = ConnectAssistUiState.Configuring }
ConnectAssistUiState.TryingABridge -> { _torController.stopTor() - _torConnectScreen.value = ConnectAssistUiState.TryABridge + _torConnectScreen.value = ConnectAssistUiState.ConnectionAssist }
ConnectAssistUiState.LocationError -> { - _torConnectScreen.value = ConnectAssistUiState.TryABridge + _torConnectScreen.value = ConnectAssistUiState.ConnectionAssist }
ConnectAssistUiState.LocationCheck -> {
===================================== fenix/app/src/main/res/layout/fragment_tor_connection_assist.xml ===================================== @@ -126,7 +126,6 @@ android:layout_marginTop="8dp" android:layout_marginEnd="24dp" android:textColor="@color/photonLightGrey05" - android:tooltipText="@string/connection_assist_share_my_location_country_or_region" android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/a008...
tbb-commits@lists.torproject.org