[tbb-commits] [Git][tpo/applications/firefox-android][firefox-android-115.2.1-13.5-1] 3 commits: fixup! Implement Android-native Connection Assist UI
Dan Ballard (@dan)
git at gitlab.torproject.org
Tue Mar 26 23:11:32 UTC 2024
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-view-is-clickable
+ */
+ 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/5ab6ae0ae3c863b8915547584a7fdbedb84745fb...99f95c3012970dce8d608fb683a41f4c4a8c242f
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/compare/5ab6ae0ae3c863b8915547584a7fdbedb84745fb...99f95c3012970dce8d608fb683a41f4c4a8c242f
You're receiving this email because of your account on gitlab.torproject.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tbb-commits/attachments/20240326/be243f3c/attachment-0001.htm>
More information about the tbb-commits
mailing list