Dan Ballard pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android
Commits: 333d9284 by clairehurst at 2024-03-26T17:06:53-06:00 fixup! Implement Android-native Connection Assist UI
- - - - - 86815386 by clairehurst at 2024-03-26T17:06:54-06:00 fixup! Bug 41878: Add standalone Tor Bootstrap
- - - - - 99f95c30 by clairehurst at 2024-03-26T17:06:54-06:00 fixup! Add Tor integration and UI
- - - - -
12 changed files:
- fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.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/TorController.kt - fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerGV.kt - fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerTAS.kt - + fenix/app/src/main/res/drawable/connect_broken.xml - + fenix/app/src/main/res/drawable/globe_broken.xml - fenix/app/src/main/res/drawable/tor_bootstrap_background_gradient.xml - fenix/app/src/main/res/layout/fragment_tor_connection_assist.xml - fenix/app/src/main/res/values/colors.xml - fenix/app/src/main/res/values/styles.xml
Changes:
===================================== fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt ===================================== @@ -168,6 +168,7 @@ import java.util.Locale import androidx.navigation.fragment.findNavController import mozilla.components.browser.engine.gecko.GeckoEngine import mozilla.components.browser.state.selector.findCustomTab +import org.mozilla.fenix.home.HomeFragment import org.mozilla.geckoview.TorIntegrationAndroid
/** @@ -815,6 +816,10 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorIn
final override fun onBackPressed() { supportFragmentManager.primaryNavigationFragment?.childFragmentManager?.fragments?.forEach { + if (it is HomeFragment){ + finish() + return + } if (it is UserInteractionHandler && it.onBackPressed()) { return }
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistFragment.kt ===================================== @@ -4,11 +4,19 @@
package org.mozilla.fenix.tor
+import android.graphics.Color import android.os.Build import android.os.Bundle +import android.text.SpannableString +import android.text.Spanned +import android.text.TextPaint +import android.text.method.LinkMovementMethod +import android.text.style.ClickableSpan +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.appcompat.content.res.AppCompatResources import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle @@ -22,6 +30,7 @@ import org.mozilla.fenix.ext.hideToolbar
class TorConnectionAssistFragment : Fragment() {
+ private val TAG = "TorConnectionAssistFrag" private var _binding: FragmentTorConnectionAssistBinding? = null private val binding get() = _binding!!
@@ -49,13 +58,14 @@ class TorConnectionAssistFragment : Fragment() {
lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.torConnectState.collect { - when (it) { - TorConnectState.Initial -> showConfiguring() + 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 -> TODO() + TorConnectState.Error -> showError() TorConnectState.Bootstrapped -> openHome() TorConnectState.Disabled -> openHome() } @@ -73,59 +83,302 @@ class TorConnectionAssistFragment : Fragment() { } }
- viewModel.quickconnectToggle().observe( - viewLifecycleOwner + viewModel.quickstartToggle().observe( + viewLifecycleOwner, ) { - binding.quickstartSwitch.isChecked = it + 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.quickStartDescription.visibility = View.GONE + binding.quickstartSwitch.visibility = View.GONE + binding.torBootstrapButton1.visibility = View.GONE + binding.torBootstrapButton2.visibility = View.GONE + binding.wordmarkLogo.visibility = View.VISIBLE + } + + + 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.quickStartDescription.visibility = View.VISIBLE + binding.quickstartSwitch.visibility = View.VISIBLE + binding.quickstartSwitch.isChecked = viewModel.quickstartToggle().value == true + + binding.unblockTheInternetInCountryDescription.visibility = View.GONE + binding.countryDropDown.visibility = View.GONE
- binding.torBootstrapConnectButton.setOnClickListener { + binding.torBootstrapButton1.visibility = View.VISIBLE + binding.torBootstrapButton1.text = getString(R.string.tor_bootstrap_connect) + binding.torBootstrapButton1.setOnClickListener { viewModel.handleConnect(lifecycleScope = lifecycleScope) + showBootstrapping() }
- binding.quickstartSwitch.setOnCheckedChangeListener { _, isChecked -> - viewModel.handleQuickstartChecked(isChecked) + binding.torBootstrapButton2.visibility = View.VISIBLE + binding.torBootstrapButton2.text = + getString(R.string.connection_assist_configure_connection_button) + binding.torBootstrapButton2.setOnClickListener { + viewModel.cancelTorBootstrap() + openTorNetworkSettings() } }
- private fun showConfiguring() { - binding.torBootstrapConnectButton.visibility = View.VISIBLE - binding.torBootstrapNetworkSettingsButton.text = + private fun showBootstrapping() { + binding.wordmarkLogo.visibility = 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.quickStartDescription.visibility = View.VISIBLE + binding.torBootstrapButton1.visibility = View.INVISIBLE + binding.torBootstrapButton2.visibility = View.VISIBLE + binding.torBootstrapButton2.text = getString(R.string.btn_cancel) + binding.torBootstrapButton2.setOnClickListener { viewModel.cancelTorBootstrap() } + } + + 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") + } + } + } + } + + 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.quickStartDescription.visibility = View.GONE + 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.torBootstrapNetworkSettingsButton.setOnClickListener { + binding.torBootstrapButton2.setOnClickListener { openTorNetworkSettings() } }
- private fun showBootstrapping() { - binding.torBootstrapConnectButton.visibility = View.INVISIBLE - binding.torBootstrapNetworkSettingsButton.text = getString(R.string.btn_cancel) - binding.torBootstrapNetworkSettingsButton.setOnClickListener { + 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.quickStartDescription.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 openSettings(preferenceToScrollTo: String? = null) { - findNavController().navigate( - TorConnectionAssistFragmentDirections - .actionTorConnectionAssistFragmentToSettingsFragment(preferenceToScrollTo), + 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.quickStartDescription.visibility = View.GONE + 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() + } + binding.torBootstrapButton2.visibility = View.GONE }
- private fun openTorNetworkSettings() { - findNavController().navigate( - TorConnectionAssistFragmentDirections - .actionTorConnectionAssistFragmentToTorNetworkSettings(), + 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") + } + + /** + * from https://stackoverflow.com/questions/10696986/how-to-set-the-part-of-the-text... + */ + private fun handleDescriptionWithClickable(errorDescription: String, learnMore: String) { + val errorDescriptionSpannableString = SpannableString(errorDescription) + val clickableSpan: ClickableSpan = object : ClickableSpan() { + override fun onClick(textView: View) { + showLearnMore() + } + + override fun updateDrawState(drawState: TextPaint) { + super.updateDrawState(drawState) + drawState.isUnderlineText = true + } + } + errorDescriptionSpannableString.setSpan( + clickableSpan, + errorDescription.length - learnMore.length, + errorDescription.length, + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE, ) + binding.titleDescription.text = errorDescriptionSpannableString + binding.titleDescription.movementMethod = LinkMovementMethod.getInstance() + binding.titleDescription.highlightColor = Color.TRANSPARENT + } + + private fun showLearnMore() { + //TODO("Not yet implemented") }
private fun openHome() { + Log.d(TAG, "openHome()") //This doesn't seem to be ever called findNavController().navigate(TorConnectionAssistFragmentDirections.actionStartupHome()) }
+ private fun openSettings(preferenceToScrollTo: String? = null) { + findNavController().navigate( + TorConnectionAssistFragmentDirections.actionTorConnectionAssistFragmentToSettingsFragment( + preferenceToScrollTo, + ), + ) + } + + private fun openTorNetworkSettings() { + findNavController().navigate( + TorConnectionAssistFragmentDirections.actionTorConnectionAssistFragmentToTorNetworkSettings(), + ) + } }
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/TorConnectionAssistViewModel.kt ===================================== @@ -26,24 +26,30 @@ class TorConnectionAssistViewModel( private val _torConnectState = MutableStateFlow(TorConnectState.Initial) internal val torConnectState: StateFlow<TorConnectState> = _torConnectState
- init { - _torController.registerTorListener(this) - } + private val _torError = MutableStateFlow(_torController.getLastErrorState()) + internal val torError: StateFlow<TorError?> = _torError
private val _progress = MutableLiveData(0) fun progress(): LiveData<Int> { return _progress }
- private val _quickconnectToggle = MutableLiveData(_torController.quickstart) - fun quickconnectToggle(): LiveData<Boolean> { - return _quickconnectToggle + private val _quickStartToggle = MutableLiveData<Boolean>() // don't initialize with quickstart off the bat + fun quickstartToggle(): LiveData<Boolean?> { + _quickStartToggle.value = _torController.quickstart // quickstart isn't ready until torSettings is ready + return _quickStartToggle + } + + init { + Log.d(TAG, "initiating TorConnectionAssistViewModel") + _torController.registerTorListener(this) }
fun handleConnect( withDebugLogging: Boolean = false, lifecycleScope: LifecycleCoroutineScope? = null, ) { + Log.d(TAG, "handleConnect initiatingTorBootstrap with lifecycleScope = $lifecycleScope") _torController.initiateTorBootstrap( withDebugLogging = withDebugLogging, lifecycleScope = lifecycleScope, @@ -52,6 +58,7 @@ class TorConnectionAssistViewModel(
fun handleQuickstartChecked(checked: Boolean) { _torController.quickstart = checked + _quickStartToggle.value = checked }
fun cancelTorBootstrap() { @@ -66,7 +73,6 @@ class TorConnectionAssistViewModel( override fun onTorConnected() { Log.d(TAG, "onTorConnected()") _torController.unregisterTorListener(this) - _torConnectState.value = _torController.lastKnownStatus }
override fun onTorStatusUpdate(entry: String?, status: String?, progress: Double?) { @@ -75,12 +81,32 @@ class TorConnectionAssistViewModel( _progress.value = progress.toInt() } _torConnectState.value = _torController.lastKnownStatus + _torError.value = _torController.getLastErrorState() }
override fun onTorStopped() { Log.d(TAG, "onTorStopped()") - _progress.value = 0 - _torConnectState.value = _torController.lastKnownStatus }
+ internal fun handleError(it: TorError?): ErrorScreen? { + // TODO(Only partly implemented) + if (it?.message == null){ + return null + } + return ErrorScreen.CantConnectToInternet + } + + fun tryABridge() { + // TODO("Try a bridge not enabled") + // connect to bridge based on country + // try connecting + } +} + +internal enum class ErrorScreen { + CantConnectToInternet, + CantConnectToTorDirectly, + WeCouldntFindYourLocation, + WereStillHavingTroubleConnecting, + WeWerentAbleToConnectAutomatically, }
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/TorController.kt ===================================== @@ -12,6 +12,10 @@ interface TorEvents { fun onTorStatusUpdate(entry: String?, status: String?, progress: Double? = 0.0) fun onTorStopped() } +class TorError( + var message: String, + var details: String +) { }
internal enum class TorStatus(val status: String) { OFF("OFF"), @@ -59,6 +63,8 @@ interface TorController: TorEvents { override fun onTorStatusUpdate(entry: String?, status: String?, progress: Double?) override fun onTorStopped()
+ fun getLastErrorState() : TorError? + fun registerTorListener(l: TorEvents) fun unregisterTorListener(l: TorEvents)
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerGV.kt ===================================== @@ -53,6 +53,7 @@ class TorControllerGV( private var torListeners = mutableListOf<TorEvents>()
internal var lastKnownStatus = TorConnectState.Initial + internal var lastKnownError: TorError? = null private var wasTorBootstrapped = false private var isTorRestarting = false
@@ -210,6 +211,7 @@ class TorControllerGV(
override fun setTorStopped() { lastKnownStatus = TorConnectState.Configuring + onTorStatusUpdate(null, lastKnownStatus.toString(), 0.0) onTorStopped() }
@@ -227,6 +229,10 @@ class TorControllerGV( } }
+ override fun getLastErrorState() : TorError? { + return lastKnownError + } + // TorEventsBootstrapStateChangeListener -> (lastKnowStatus, TorEvents) // Handle events from GeckoView TorAndroidIntegration and map to TorEvents based events // and state for firefox-android (designed for tor-android-service) @@ -263,7 +269,7 @@ class TorControllerGV( }
lastKnownStatus = newState - + onTorStatusUpdate(null, newStateVal, null) }
// TorEventsBootstrapStateChangeListener @@ -290,7 +296,7 @@ class TorControllerGV(
// TorEventsBootstrapStateChangeListener override fun onBootstrapError(message: String?, details: String?) { - lastKnownStatus = TorConnectState.Error + lastKnownError = TorError(message ?: "", details ?: "") onBootstrapStateChange(TorConnectState.Error.state) }
===================================== fenix/app/src/main/java/org/mozilla/fenix/tor/TorControllerTAS.kt ===================================== @@ -330,4 +330,10 @@ class TorControllerTAS (private val context: Context): TorController { companion object { const val torServiceResponseTimeout = 5000L } + + // Compat with TorControlGV Stubs + + override fun getLastErrorState() : TorError? { + return null; + } }
===================================== fenix/app/src/main/res/drawable/connect_broken.xml ===================================== @@ -0,0 +1,37 @@ +<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="M8.317,5.337C11.521,2.781 15.582,1.253 19.999,1.253C30.352,1.253 38.745,9.647 38.745,20C38.745,24.418 37.218,28.478 34.662,31.681L32.577,29.597C34.611,26.937 35.819,23.611 35.819,20C35.819,11.26 28.739,4.18 19.999,4.18C16.389,4.18 13.063,5.388 10.401,7.421L8.317,5.337Z" + android:fillColor="#FBFBFE"/> + <path + android:pathData="M5.89,7.656C3.002,10.954 1.252,15.273 1.252,20C1.252,28.967 7.545,36.46 15.959,38.307C16.839,38.5 17.732,38.633 18.652,38.693V24.373C16.785,23.8 15.425,22.06 15.425,20C15.425,19.19 15.635,18.43 16.004,17.771L13.887,15.653C13.013,16.88 12.499,18.38 12.499,20C12.499,22.653 13.879,24.987 15.959,26.32V35.293C9.179,33.513 4.179,27.347 4.179,20C4.179,16.08 5.603,12.493 7.963,9.73L5.89,7.656Z" + android:fillColor="#FBFBFE"/> + <path + android:pathData="M16.399,13.419L18.618,15.638C19.054,15.501 19.517,15.427 19.998,15.427C22.525,15.427 24.572,17.473 24.572,20C24.572,20.481 24.498,20.945 24.36,21.38L26.579,23.599C27.165,22.531 27.498,21.304 27.498,20C27.498,15.86 24.138,12.5 19.998,12.5C18.694,12.5 17.468,12.833 16.399,13.419Z" + android:fillColor="#FBFBFE"/> + <path + android:pathData="M24.349,26.112L22.232,23.995C21.954,24.151 21.658,24.278 21.349,24.373V38.693C22.269,38.633 23.162,38.5 24.042,38.307C27.176,37.619 30.015,36.147 32.345,34.109L30.271,32.034C28.492,33.552 26.372,34.681 24.042,35.293V26.32C24.146,26.253 24.249,26.184 24.349,26.112Z" + android:fillColor="#FBFBFE"/> + <path + android:pathData="M30.653,27.67C32.21,25.514 33.127,22.864 33.127,20C33.127,12.753 27.247,6.873 20,6.873C17.138,6.873 14.488,7.791 12.33,9.348L14.437,11.455C16.037,10.412 17.947,9.807 20,9.807C25.634,9.807 30.194,14.367 30.194,20C30.194,22.051 29.587,23.962 28.544,25.562L30.653,27.67Z" + android:fillColor="#FBFBFE"/> + <path + android:pathData="M26.272,28.037L28.357,30.121C27.095,31.163 25.635,31.973 24.041,32.487V29.36C24.844,29.014 25.593,28.568 26.272,28.037Z" + android:fillColor="#FBFBFE"/> + <path + android:pathData="M11.962,13.727L9.878,11.643C8.001,13.914 6.873,16.826 6.873,20C6.873,25.84 10.686,30.787 15.96,32.487V29.36C12.34,27.8 9.806,24.193 9.806,20C9.806,17.633 10.611,15.457 11.962,13.727Z" + android:fillColor="#FBFBFE"/> + <path + android:pathData="M17.922,19.688L20.311,22.077C20.21,22.092 20.105,22.1 19.999,22.1C18.84,22.1 17.899,21.16 17.899,20C17.899,19.894 17.907,19.79 17.922,19.688Z" + android:fillColor="#FBFBFE"/> + <path + android:pathData="M2.89,4.642L35.228,36.98C35.879,37.632 35.879,38.688 35.228,39.339L35.228,39.339C34.576,39.991 33.52,39.991 32.868,39.339L0.53,7.001C-0.121,6.35 -0.121,5.294 0.53,4.642C1.182,3.991 2.238,3.991 2.89,4.642Z" + android:fillColor="#FBFBFE"/> + </group> +</vector>
===================================== fenix/app/src/main/res/drawable/globe_broken.xml ===================================== @@ -0,0 +1,18 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="40dp" + android:height="40dp" + android:viewportWidth="40" + android:viewportHeight="40"> + <path + android:pathData="M4.209,1.999L37.355,35.145L35.145,37.355L1.999,4.209L4.209,1.999Z" + android:fillColor="#FBFBFE" + android:fillType="evenOdd"/> + <path + android:pathData="M7.869,5.703C3.82,9.142 1.25,14.271 1.25,20C1.25,30.03 9.126,38.221 19.031,38.725L19.041,38.733L19.047,38.726C19.363,38.742 19.681,38.75 20,38.75C20.32,38.75 20.638,38.742 20.954,38.726L20.96,38.733L20.97,38.725C26.306,38.453 31.053,35.951 34.297,32.132L32.079,29.913C30.228,32.166 27.759,33.891 24.931,34.831C26.854,32.438 28.243,29.75 29.097,26.931L26.534,24.368C25.642,28.517 23.465,32.438 20,35.474C15.763,31.76 13.451,26.722 13.063,21.563H23.728L20.603,18.438H13.063C13.22,16.35 13.692,14.282 14.479,12.313L12.102,9.936C10.844,12.632 10.12,15.52 9.93,18.438H4.453C4.872,14.209 6.978,10.477 10.087,7.922L7.869,5.703ZM15.069,34.831C11.952,30.951 10.239,26.295 9.93,21.563H4.453C5.07,27.779 9.331,32.924 15.069,34.831Z" + android:fillColor="#FBFBFE" + android:fillType="evenOdd"/> + <path + android:pathData="M13.678,7.093C14.106,6.433 14.569,5.791 15.069,5.169C14.263,5.437 13.486,5.769 12.744,6.159L10.448,3.863C12.985,2.358 15.907,1.434 19.031,1.275L19.041,1.267L19.047,1.274C19.363,1.258 19.681,1.25 20,1.25C20.32,1.25 20.638,1.258 20.954,1.274L20.96,1.267L20.97,1.275C30.875,1.779 38.75,9.97 38.75,20C38.75,23.489 37.798,26.755 36.138,29.553L33.842,27.257C34.752,25.525 35.346,23.601 35.548,21.563H30.071C30.033,22.146 29.974,22.728 29.893,23.308L25.023,18.438H26.938C26.55,13.278 24.238,8.24 20,4.526C18.361,5.963 17.01,7.598 15.947,9.361L13.678,7.093ZM30.071,18.438H35.548C34.931,12.221 30.67,7.076 24.931,5.169C28.049,9.049 29.762,13.705 30.071,18.438Z" + android:fillColor="#FBFBFE" + android:fillType="evenOdd"/> +</vector>
===================================== fenix/app/src/main/res/drawable/tor_bootstrap_background_gradient.xml ===================================== @@ -7,9 +7,9 @@ <shape> <gradient android:angle="225" - android:startColor="#FF7329A4" - android:centerColor="#FF3A3274" - android:endColor="#FF3A3274" + android:startColor="@color/backgroundGradientLight" + android:centerColor="@color/backgroundGradientDark" + android:endColor="@color/backgroundGradientDark" android:type="linear" /> </shape> </item>
===================================== fenix/app/src/main/res/layout/fragment_tor_connection_assist.xml ===================================== @@ -3,29 +3,63 @@ - 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"> + android:background="@drawable/tor_bootstrap_background_gradient" + android:paddingBottom="16dp">
<ProgressBar android:id="@+id/tor_bootstrap_progress_bar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="6dp" + android:visibility="invisible" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
- <ImageView + <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/settings_button" - android:layout_width="24dp" - android:layout_height="24dp" - android:layout_marginTop="26dp" - android:layout_marginEnd="20dp" - android:contentDescription="@string/settings" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="8dp" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:srcCompat="@drawable/mozac_ic_settings" /> + app:layout_constraintTop_toTopOf="parent"> + + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/settings" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/mozac_ic_settings" /> + </androidx.constraintlayout.widget.ConstraintLayout> + + <androidx.constraintlayout.widget.ConstraintLayout + android:id="@+id/back_button" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_marginStart="8dp" + android:layout_marginTop="8dp" + android:visibility="invisible" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/settings" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:srcCompat="@drawable/mozac_ic_back" /> + </androidx.constraintlayout.widget.ConstraintLayout> +
<ImageView android:id="@+id/tor_connect_image" @@ -45,99 +79,139 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="24dp" - android:layout_marginTop="24dp" android:layout_marginEnd="24dp" android:text="@string/connection_assist_tor_connect_title" android:textColor="#FBFBFE" - android:textFontWeight="400" android:textSize="22sp" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/tor_connect_image" /> + app:layout_constraintTop_toBottomOf="@id/tor_connect_image" + app:layout_constraintVertical_bias="0.03" />
<TextView - android:id="@+id/connect_to_tor_description" + android:id="@+id/title_description" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="24dp" - android:layout_marginTop="16dp" android:layout_marginEnd="24dp" + android:lineSpacingExtra="6dp" android:text="@string/preferences_tor_network_settings_explanation" android:textColor="#FBFBFE" - android:textFontWeight="400" android:textSize="14sp" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/title_large_text_view" /> + app:layout_constraintTop_toBottomOf="@id/title_large_text_view" + app:layout_constraintVertical_bias="0.03" /> +
<TextView - android:id="@+id/connect_automatically" - android:layout_width="wrap_content" + android:id="@+id/quick_start_description" + android:layout_width="230dp" android:layout_height="wrap_content" android:layout_marginStart="24dp" - android:layout_marginTop="24dp" android:text="@string/connection_assist_always_connect_automatically_toggle_description" - android:textColor="#80FBFBFE" + android:textColor="#FBFBFE" android:textSize="14sp" - app:layout_constraintBottom_toBottomOf="@+id/quickstart_switch" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="@+id/quickstart_switch" - app:layout_constraintVertical_bias="1.25" /> + app:layout_constraintTop_toBottomOf="@+id/title_description" + app:layout_constraintVertical_bias=".03" />
<androidx.appcompat.widget.SwitchCompat android:id="@+id/quickstart_switch" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="24dp" + android:layout_marginStart="100dp" android:layout_marginEnd="24dp" android:layout_marginBottom="24dp" - android:enabled="false" android:gravity="center" - app:thumbTint="#7D6298" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toBottomOf="@id/connect_to_tor_description" + app:layout_constraintHorizontal_bias="0" + app:layout_constraintStart_toEndOf="@+id/quick_start_description" + app:layout_constraintTop_toBottomOf="@id/title_description" + app:layout_constraintVertical_bias=".023" app:layout_goneMarginEnd="6dp" app:layout_goneMarginTop="9dp" />
- <Button - android:id="@+id/tor_bootstrap_connect_button" + <TextView + android:id="@+id/unblock_the_internet_in_country_description" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginTop="24dp" + android:layout_marginEnd="24dp" + android:text="@string/connection_assist_unblock_the_internet_in_country_or_region" + android:textColor="#FBFBFE" + android:visibility="invisible" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/title_description" /> + + <androidx.appcompat.widget.AppCompatSpinner + android:id="@+id/country_drop_down" + style="@style/Widget.AppCompat.Spinner.Underlined" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="24dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="24dp" + android:textColor="#FBFBFE" + android:tooltipText="@string/connection_assist_share_my_location_country_or_region" + android:visibility="invisible" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/unblock_the_internet_in_country_description" /> + + <ImageView + android:id="@+id/wordmarkLogo" + android:layout_width="160dp" + android:layout_height="160dp" + android:src="@mipmap/ic_launcher_round" + + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + android:contentDescription="" /> + + <Button + android:id="@+id/tor_bootstrap_button_1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" android:layout_marginEnd="24dp" android:layout_marginBottom="8dp" android:background="@drawable/rounded_corners" android:backgroundTint="@color/connect_button_purple" - android:maxWidth="312dp" + android:minWidth="360dp" android:text="@string/tor_bootstrap_connect" android:textAllCaps="false" android:textColor="#FBFBFE" - android:textFontWeight="500" android:textSize="14sp" android:textStyle="bold" - app:layout_constraintBottom_toTopOf="@id/tor_bootstrap_network_settings_button" + app:layout_constraintBottom_toTopOf="@id/tor_bootstrap_button_2" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/quickstart_switch" app:layout_constraintVertical_bias="1" />
- <Button - android:id="@+id/tor_bootstrap_network_settings_button" - android:layout_width="match_parent" + android:id="@+id/tor_bootstrap_button_2" + android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="24dp" android:layout_marginEnd="24dp" - android:layout_marginBottom="24dp" + android:layout_marginBottom="8dp" android:background="@drawable/rounded_corners" android:backgroundTint="@color/configure_connection_button_white" - android:maxWidth="312dp" + android:minWidth="360dp" android:text="@string/connection_assist_configure_connection_button" android:textAllCaps="false" android:textColor="#15141A" - android:textFontWeight="500" android:textSize="14sp" android:textStyle="bold" app:layout_constraintBottom_toBottomOf="parent"
===================================== fenix/app/src/main/res/values/colors.xml ===================================== @@ -273,6 +273,8 @@ <color name="sync_disconnected_background_private_theme">#5B5846</color> <color name="onboarding_illustration_deselected_private_theme">#99FBFBFE</color> <color name="prompt_login_edit_text_cursor_color_private_theme">@color/photonViolet50</color> + <color name="backgroundGradientDark">#FF3A3274</color> + <color name="backgroundGradientLight">#FF7329A4</color>
<!-- Normal theme colors for light mode --> <color name="accent_normal_theme">@color/photonInk20</color> @@ -344,5 +346,6 @@ <!-- Connection Assist --> <color name="connect_button_purple">#9059FF</color> <color name="configure_connection_button_white">#E1E0E7</color> + <color name="warning_yellow">#FFA436</color>
</resources>
===================================== fenix/app/src/main/res/values/styles.xml ===================================== @@ -12,7 +12,7 @@ <item name="android:windowAnimationStyle">@style/WindowAnimationTransition</item> <item name="android:progressBarStyleHorizontal">@style/progressBarStyleHorizontal</item> <item name="android:statusBarColor">@android:color/transparent</item> - <item name="android:windowBackground">@color/fx_mobile_layer_color_1</item> + <item name="android:windowBackground">@color/backgroundGradientDark</item> <item name="android:colorEdgeEffect">@color/accent_normal_theme</item> <item name="android:colorAccent">@color/fx_mobile_text_color_primary</item> <item name="android:textColorPrimary">@color/state_list_text_color</item>
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/compare/5ab...
tbb-commits@lists.torproject.org