Verified Commit 9d4ddc89 authored by clairehurst's avatar clairehurst 🌱 Committed by ma1
Browse files

fixup! [android] Implement Android-native Connection Assist UI

Bug 41188: Wire up stages to UI
parent 2ec8efd7
Loading
Loading
Loading
Loading
+65 −44
Changes for mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/ConnectAssistUiState.kt: 65 added lines, 44 removed lines.
Original line number Diff line number Diff line
@@ -2,14 +2,12 @@ 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,
    @ColorRes val progressBackgroundTintColorResource: Int = R.color.progress_background_tint,
    val backButtonVisible: Boolean,
    val settingsButtonVisible: Boolean,
    val torConnectImageVisible: Boolean,
@@ -23,18 +21,19 @@ enum class ConnectAssistUiState(
    @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,
    @StringRes val countryDropDownDefaultItem: Int = R.string.connection_assist_automatic_country_detection,
    val torBootstrapButton1Visible: Boolean,
    @StringRes val torBootstrapButton1TextStringResource: Int = R.string.tor_bootstrap_connect,
    val torBootstrapButton1ShouldShowTryingABridge: Boolean = false,
    val torBootstrapButton1ShouldTryABridge: Boolean = false,
    val torBootstrapButton1ShouldOpenSettings: Boolean = false,
    val torBootstrapButton2Visible: Boolean,
    @StringRes val torBootstrapButton2TextStringResource: Int? = R.string.connection_assist_configure_connection_button,
    val torBootstrapButton2ShouldOpenSettings: Boolean = true,
    val wordmarkLogoVisible: Boolean = false,
    val torBootstrapButton2ShouldRestartApp: Boolean = false,
) {
    Splash(
    Loading(
        progressBarVisible = false,
        backButtonVisible = false,
        settingsButtonVisible = false,
@@ -42,15 +41,13 @@ enum class ConnectAssistUiState(
        titleLargeTextViewVisible = false,
        titleDescriptionVisible = false,
        quickstartSwitchVisible = false,
        unblockTheInternetInCountryDescriptionVisible = false,
        countryDropDownVisible = false,
        torBootstrapButton1Visible = false,
        torBootstrapButton2Visible = false,
        wordmarkLogoVisible = true,
    ),
    Configuring(
    Start(
        progressBarVisible = false,
        progress = 0,
        backButtonVisible = false,
        settingsButtonVisible = true,
        torConnectImageVisible = true,
@@ -60,16 +57,14 @@ enum class ConnectAssistUiState(
        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,
    ),
    Connecting(
    Bootstrapping(
        progressBarVisible = true,
        progress = 0,
        backButtonVisible = false,
        settingsButtonVisible = true,
        torConnectImageVisible = true,
@@ -79,17 +74,15 @@ enum class ConnectAssistUiState(
        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,
    ),
    InternetError(
    Offline(
        progressBarVisible = true,
        progress = 100,
        progressTintColorResource = R.color.warning_yellow,
        progressBackgroundTintColorResource = R.color.warning_yellow,
        backButtonVisible = true,
        settingsButtonVisible = true,
        torConnectImageVisible = true,
@@ -101,7 +94,6 @@ enum class ConnectAssistUiState(
        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,
@@ -111,8 +103,6 @@ enum class ConnectAssistUiState(
    ),
    TryingAgain(
        progressBarVisible = true,
        progress = 0,
        progressTintColorResource = null,
        backButtonVisible = true,
        settingsButtonVisible = true,
        torConnectImageVisible = true,
@@ -124,17 +114,15 @@ enum class ConnectAssistUiState(
        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,
    ),
    ConnectionAssist(
    ChooseRegion(
        progressBarVisible = true,
        progress = 100,
        progressTintColorResource = R.color.warning_yellow,
        progressBackgroundTintColorResource = R.color.warning_yellow,
        backButtonVisible = true,
        settingsButtonVisible = true,
        torConnectImageVisible = true,
@@ -146,19 +134,16 @@ enum class ConnectAssistUiState(
        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,
        torBootstrapButton1ShouldTryABridge = true,
        torBootstrapButton2Visible = false,
        torBootstrapButton2TextStringResource = null,
        torBootstrapButton2ShouldOpenSettings = true,
    ),
    TryingABridge(
        progressBarVisible = true,
        progress = 0,
        progressTintColorResource = null,
        backButtonVisible = true,
        settingsButtonVisible = true,
        torConnectImageVisible = true,
@@ -167,20 +152,18 @@ enum class ConnectAssistUiState(
        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,
        internetErrorDescription = ChooseRegion.internetErrorDescription,
        titleDescriptionTextStringResource = null,
        quickstartSwitchVisible = true,
        unblockTheInternetInCountryDescriptionVisible = false,
        countryDropDownVisible = false,
        torBootstrapButton1Visible = false,
        torBootstrapButton2Visible = true,
        torBootstrapButton2TextStringResource = R.string.btn_cancel,
        torBootstrapButton2ShouldOpenSettings = false,
    ),
    LocationError(
    RegionNotFound(
        progressBarVisible = true,
        progress = 100,
        progressTintColorResource = R.color.warning_yellow,
        progressBackgroundTintColorResource = R.color.warning_yellow,
        backButtonVisible = true,
        settingsButtonVisible = true,
        torConnectImageVisible = true,
@@ -194,19 +177,39 @@ enum class ConnectAssistUiState(
        internetErrorDescription2 = R.string.connection_assist_select_country_try_again,
        titleDescriptionTextStringResource = null,
        quickstartSwitchVisible = false,
        unblockTheInternetInCountryDescriptionVisible = true,
        countryDropDownVisible = true,
        countryDropDownDefaultItem = R.string.connection_assist_select_country_or_region,
        torBootstrapButton1Visible = true,
        torBootstrapButton1TextStringResource = R.string.connection_assist_try_a_bridge_button,
        torBootstrapButton1ShouldShowTryingABridge = true,
        torBootstrapButton1ShouldTryABridge = true,
        torBootstrapButton2Visible = false,
        torBootstrapButton2TextStringResource = null,
        torBootstrapButton2ShouldOpenSettings = true,
    ),
    LocationCheck(
    TryingABridgeRegionNotFound(
        progressBarVisible = true,
        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 = RegionNotFound.internetErrorDescription,
        internetErrorDescription1 = RegionNotFound.internetErrorDescription1,
        internetErrorDescription2 = RegionNotFound.internetErrorDescription2,
        titleDescriptionTextStringResource = null,
        quickstartSwitchVisible = true,
        countryDropDownVisible = false,
        torBootstrapButton1Visible = false,
        torBootstrapButton2Visible = true,
        torBootstrapButton2TextStringResource = R.string.btn_cancel,
        torBootstrapButton2ShouldOpenSettings = false,
    ),
    ConfirmRegion(
        progressBarVisible = true,
        progress = 100,
        progressTintColorResource = R.color.warning_yellow,
        progressBackgroundTintColorResource = R.color.warning_yellow,
        backButtonVisible = true,
        settingsButtonVisible = true,
        torConnectImageVisible = true,
@@ -220,18 +223,38 @@ enum class ConnectAssistUiState(
        internetErrorDescription2 = R.string.connection_assist_select_country_try_again,
        titleDescriptionTextStringResource = null,
        quickstartSwitchVisible = false,
        unblockTheInternetInCountryDescriptionVisible = true,
        countryDropDownVisible = true,
        countryDropDownDefaultItem = R.string.connection_assist_select_country_or_region,
        torBootstrapButton1Visible = true,
        torBootstrapButton1TextStringResource = R.string.connection_assist_try_a_bridge_button,
        torBootstrapButton1ShouldShowTryingABridge = true,
        torBootstrapButton1ShouldTryABridge = true,
        torBootstrapButton2Visible = false,
        torBootstrapButton2TextStringResource = null,
        torBootstrapButton2ShouldOpenSettings = true,
    ),
    TryingABridgeConfirmRegion(
        progressBarVisible = true,
        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 = ConfirmRegion.internetErrorDescription,
        internetErrorDescription1 = ConfirmRegion.internetErrorDescription1,
        internetErrorDescription2 = ConfirmRegion.internetErrorDescription2,
        titleDescriptionTextStringResource = null,
        quickstartSwitchVisible = true,
        countryDropDownVisible = false,
        torBootstrapButton1Visible = false,
        torBootstrapButton2Visible = true,
        torBootstrapButton2TextStringResource = R.string.btn_cancel,
        torBootstrapButton2ShouldOpenSettings = false,
    ),
    LastTry(
        progressBarVisible = true,
        progress = 0,
        backButtonVisible = true,
        settingsButtonVisible = true,
        torConnectImageVisible = true,
@@ -245,7 +268,6 @@ enum class ConnectAssistUiState(
        internetErrorDescription2 = R.string.connection_assist_select_country_try_again,
        titleDescriptionTextStringResource = null,
        quickstartSwitchVisible = true,
        unblockTheInternetInCountryDescriptionVisible = false,
        countryDropDownVisible = false,
        torBootstrapButton1Visible = false,
        torBootstrapButton2Visible = true,
@@ -254,8 +276,7 @@ enum class ConnectAssistUiState(
    ),
    FinalError(
        progressBarVisible = true,
        progress = 100,
        progressTintColorResource = R.color.warning_yellow,
        progressBackgroundTintColorResource = R.color.warning_yellow,
        backButtonVisible = true,
        settingsButtonVisible = true,
        torConnectImageVisible = true,
@@ -268,10 +289,10 @@ enum class ConnectAssistUiState(
        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_configure_connection_button,
        torBootstrapButton1ShouldOpenSettings = true,
        torBootstrapButton2Visible = true,
        torBootstrapButton2TextStringResource = R.string.mozac_lib_crash_dialog_button_restart,
        torBootstrapButton2ShouldOpenSettings = false,
+4 −4
Changes for mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/QuickstartViewModel.kt: 4 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -12,19 +12,19 @@ class QuickstartViewModel(
) : AndroidViewModel(application) {

    private val components = getApplication<Application>().components
    private val torIntegrationAndroid =
    private val torAndroidIntegration =
        (components.core.engine as GeckoEngine).getTorIntegrationController()

    /**
     * NOTE: Whilst the initial value for _quickstart is fetched from
     * TorIntegrationAndroid.quickstartGet (which is surfaced from TorConnect.quickstart), and we
     * TorAndroidIntegration.quickstartGet (which is surfaced from TorConnect.quickstart), and we
     * pass on any changes in value up to TorConnect.quickstart (via quickstartSet()), we do not
     * listen for any changes to the TorConnect.quickstart value via "QuickstartChange" because we
     * do not expect anything outside of TorConnectViewModel to change its value, so we expect its
     * value to remain in sync with our local value.
     */
    init {
        torIntegrationAndroid.quickstartGet {
        torAndroidIntegration.quickstartGet {
            _quickstart.value = it
            components.settings.quickStart = it
        }
@@ -36,7 +36,7 @@ class QuickstartViewModel(
    }

    fun quickstartSet(value: Boolean) {
        torIntegrationAndroid.quickstartSet(value)
        torAndroidIntegration.quickstartSet(value)
        _quickstart.value = value
        components.settings.quickStart = value
    }
+3 −3
Changes for mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapProgressViewModel.kt: 3 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ class TorBootstrapProgressViewModel(
    application: Application,
) : AndroidViewModel(application), BootstrapStateChangeListener {

    private val torIntegrationAndroid =
    private val torAndroidIntegration =
        application.components.core.geckoRuntime.torIntegrationController

    val progress: MutableLiveData<Int> by lazy {
@@ -19,11 +19,11 @@ class TorBootstrapProgressViewModel(
    }

    init {
        torIntegrationAndroid.registerBootstrapStateChangeListener(this)
        torAndroidIntegration.registerBootstrapStateChangeListener(this)
    }

    override fun onCleared() {
        torIntegrationAndroid.unregisterBootstrapStateChangeListener(this)
        torAndroidIntegration.unregisterBootstrapStateChangeListener(this)
        super.onCleared()
    }

+111 −20
Changes for mobile/android/fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistFragment.kt: 111 added lines, 20 removed lines.
Original line number Diff line number Diff line
@@ -17,7 +17,10 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.isEmpty
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
@@ -54,7 +57,7 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {

        viewLifecycleOwner.lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                torConnectionAssistViewModel.collectLastKnownStatus()
                torConnectionAssistViewModel.collectTorConnectStage()
            }
        }

@@ -129,15 +132,11 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
    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(
        binding.torBootstrapProgressBar.progressBackgroundTintList = AppCompatResources.getColorStateList(
            requireContext(),
                    it,
            screen.progressBackgroundTintColorResource,
        )
    }
    }

    private fun setSettingsButton(screen: ConnectAssistUiState) {
        binding.settingsButton.visibility = if (screen.settingsButtonVisible) View.VISIBLE else View.GONE
@@ -201,19 +200,116 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
    }

    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
        if (screen.countryDropDownVisible) {
            val spinnerAdapter: ArrayAdapter<String> = initializeSpinner()
            if (binding.countryDropDown.isEmpty()) {
                spinnerAdapter.add(getString(screen.countryDropDownDefaultItem))
                populateCountryDropDown(spinnerAdapter)
                setOnItemSelectedListener()
            }
            spinnerAdapter.remove(spinnerAdapter.getItem(0))
            spinnerAdapter.insert(getString(screen.countryDropDownDefaultItem), 0)

            if (screen == ConnectAssistUiState.ChooseRegion || screen == ConnectAssistUiState.ConfirmRegion || screen == ConnectAssistUiState.RegionNotFound) {
                torConnectionAssistViewModel.selectDefaultRegion()
                binding.countryDropDown.setSelection(spinnerAdapter.getPosition(torConnectionAssistViewModel.selectedCountryCode.value))
            }

            binding.unblockTheInternetInCountryDescription.visibility = View.VISIBLE
            binding.countryDropDown.visibility = View.VISIBLE
        } else {
            binding.unblockTheInternetInCountryDescription.visibility = View.GONE
            binding.countryDropDown.visibility = View.GONE
        }
    }

    private fun initializeSpinner(): ArrayAdapter<String> {
        val spinnerAdapter: ArrayAdapter<String> =
            ArrayAdapter<String>(
                requireContext(),
                android.R.layout.simple_spinner_item,
                android.R.id.text1,
            )
        spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        binding.countryDropDown.adapter = spinnerAdapter
        return spinnerAdapter
    }

    private fun populateCountryDropDown(spinnerAdapter: ArrayAdapter<String>) {
        viewLifecycleOwner.lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                torConnectionAssistViewModel.countryCodeNameMap.collect {
                    if (it != null) {
                        spinnerAdapter.addAll(it.values)
                    }
                }
            }
        }
        spinnerAdapter.notifyDataSetChanged()
    }

    private fun setOnItemSelectedListener() {
        binding.countryDropDown.onItemSelectedListener =
            object : AdapterView.OnItemSelectedListener {
                override fun onItemSelected(
                    parent: AdapterView<*>?,
                    view: View?,
                    position: Int,
                    id: Long,
                ) {
                    torConnectionAssistViewModel.setCountryCodeToSelectedItem(position)
                    updateButton1(torConnectionAssistViewModel.torConnectScreen.value)
                }

                override fun onNothingSelected(parent: AdapterView<*>?) {}
            }
    }

    private fun setButton1(screen: ConnectAssistUiState) {
        binding.torBootstrapButton1.visibility =
        binding.torBootstrapButton1.apply {
            visibility =
                if (screen.torBootstrapButton1Visible) View.VISIBLE else View.GONE
        binding.torBootstrapButton1.text = getString(screen.torBootstrapButton1TextStringResource)
        binding.torBootstrapButton1.setOnClickListener {
            text = getString(screen.torBootstrapButton1TextStringResource)
            setOnClickListener {
                if (screen.torBootstrapButton1ShouldOpenSettings) {
                    openTorConnectionSettings()
                } else {
                    torConnectionAssistViewModel.handleConnect()
                }
            }
            updateButton1(screen)
        }
    }

    private fun updateButton1(screen: ConnectAssistUiState) {
        binding.torBootstrapButton1.apply {
            if (!torConnectionAssistViewModel.button1ShouldBeDisabled(screen)) {
                isEnabled = true
                backgroundTintList = AppCompatResources.getColorStateList(
                    requireContext(),
                    R.color.connect_button_purple,
                )
                setTextColor(
                    AppCompatResources.getColorStateList(
                        requireContext(),
                        R.color.photonLightGrey05,
                    ),
                )
            } else {
                isEnabled = false
                backgroundTintList = AppCompatResources.getColorStateList(
                    requireContext(),
                    R.color.disabled_connect_button_purple,
                )
                setTextColor(
                    AppCompatResources.getColorStateList(
                        requireContext(),
                        R.color.disabled_text_gray_purple,
                    ),
                )
            }
        }
    }

    private fun setButton2(screen: ConnectAssistUiState) {
        binding.torBootstrapButton2.visibility =
@@ -235,13 +331,12 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
                }
        }
        binding.torBootstrapButton2.setOnClickListener {
            torConnectionAssistViewModel.cancelTorBootstrap()
            if (screen.torBootstrapButton2ShouldOpenSettings) {
                openTorConnectionSettings()
            } else if (screen.torBootstrapButton2ShouldRestartApp) {
                restartApplication()
            } else {
                showScreen(ConnectAssistUiState.Configuring)
                torConnectionAssistViewModel.cancelTorBootstrap()
            }
        }
    }
@@ -297,11 +392,7 @@ class TorConnectionAssistFragment : Fragment(), UserInteractionHandler {
    }

    private fun openTorConnectionSettings() {
        findNavController().navigate(
            TorConnectionAssistFragmentDirections.actionTorConnectionAssistFragmentToSettingsFragment(
                requireContext().getString(R.string.pref_key_connection)
            ),
        )
        openSettings(requireContext().getString(R.string.pref_key_connection))
    }

    private fun restartApplication() {
+83 −129

File changed.

Preview size limit exceeded, changes collapsed.

Loading