[tbb-commits] [Git][tpo/applications/firefox-android][firefox-android-115.2.1-13.0-1] 3 commits: fixup! Add Tor integration and UI
Dan Ballard (@dan)
git at gitlab.torproject.org
Tue Sep 12 15:53:33 UTC 2023
Dan Ballard pushed to branch firefox-android-115.2.1-13.0-1 at The Tor Project / Applications / firefox-android
Commits:
a09967fd by Dan Ballard at 2023-09-12T08:52:55-07:00
fixup! Add Tor integration and UI
Bug 41878: Remove bootstrap from `Add Tor integration and UI`
- - - - -
40bf5511 by Dan Ballard at 2023-09-12T08:52:55-07:00
fixup! Add Tor integration and UI
Bug 41878: Remove rest of onboarding from `Add Tor integration and UI`
- - - - -
d2a7dfa6 by Dan Ballard at 2023-09-12T08:52:55-07:00
Bug 41878: Add standalone Tor Bootstrap
- - - - -
25 changed files:
- fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
- fenix/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
- fenix/app/src/main/java/org/mozilla/fenix/home/Mode.kt
- fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt
- fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt
- fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt
- fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt
- − fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/TorOnboardingDonateViewHolder.kt
- − fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/TorOnboardingSecurityLevelViewHolder.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapFragment.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapStatus.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/controller/TorBootstrapController.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/interactor/TorBootstrapInteractor.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapAdapter.kt
- fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TorBootstrapConnectViewHolder.kt → fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapConnectViewHolder.kt
- fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TorBootstrapLoggerViewHolder.kt → fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapLoggerViewHolder.kt
- fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/torbootstrap/BootstrapPagerAdapter.kt → fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapPagerAdapter.kt
- fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TorBootstrapPagerViewHolder.kt → fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapPagerViewHolder.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapView.kt
- − fenix/app/src/main/res/drawable/tor_onboarding_donate_gradient.xml
- − fenix/app/src/main/res/drawable/tor_onboarding_donate_rounded_corners.xml
- − fenix/app/src/main/res/layout/tor_onboarding_donate.xml
- − fenix/app/src/main/res/layout/tor_onboarding_security_level.xml
- fenix/app/src/main/res/navigation/nav_graph.xml
- fenix/app/src/main/res/values/styles.xml
Changes:
=====================================
fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
=====================================
@@ -34,6 +34,7 @@ import androidx.annotation.VisibleForTesting.Companion.PROTECTED
import androidx.appcompat.app.ActionBar
import androidx.appcompat.widget.Toolbar
import androidx.core.app.NotificationManagerCompat
+import androidx.core.content.ContentProviderCompat.requireContext
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavDestination
import androidx.navigation.NavDirections
@@ -285,6 +286,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
it.start()
}
+ /*
if (settings().shouldShowJunoOnboarding(
hasUserBeenOnboarded = components.fenixOnboarding.userHasBeenOnboarded(),
isLauncherIntent = intent.toSafeIntent().isLauncherIntent,
@@ -295,6 +297,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
navHost.navController.navigate(NavGraphDirections.actionGlobalJunoOnboarding())
}
} else {
+ */
lifecycleScope.launch(IO) {
// showFullscreenMessageIfNeeded(applicationContext)
}
@@ -315,7 +318,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
}
showNotificationPermissionPromptIfRequired()
*/
- }
+ //}
Performance.processIntentIfPerformanceTest(intent, this)
@@ -1158,13 +1161,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
}
open fun navigateToHome() {
- // if (components.fenixOnboarding.userHasBeenOnboarded()) {
- navHost.navController.navigate(NavGraphDirections.actionStartupHome())
- /*
- } else {
- navHost.navController.navigate(NavGraphDirections.actionStartupOnboarding())
- }
- */
+ navHost.navController.navigate(NavGraphDirections.actionStartupTorbootstrap())
}
override fun attachBaseContext(base: Context) {
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
=====================================
@@ -113,6 +113,8 @@ import org.mozilla.fenix.perf.runBlockingIncrement
import org.mozilla.fenix.search.toolbar.DefaultSearchSelectorController
import org.mozilla.fenix.search.toolbar.SearchSelectorMenu
import org.mozilla.fenix.tabstray.TabsTrayAccessPoint
+import org.mozilla.fenix.tor.TorBootstrapFragmentDirections
+import org.mozilla.fenix.tor.TorBootstrapStatus
import org.mozilla.fenix.tor.bootstrap.TorQuickStart
import org.mozilla.fenix.utils.Settings.Companion.TOP_SITES_PROVIDER_MAX_THRESHOLD
import org.mozilla.fenix.utils.allowUndo
@@ -200,9 +202,9 @@ class HomeFragment : Fragment() {
private val recentBookmarksFeature = ViewBoundFeatureWrapper<RecentBookmarksFeature>()
private val historyMetadataFeature = ViewBoundFeatureWrapper<RecentVisitsFeature>()
private val searchSelectorBinding = ViewBoundFeatureWrapper<SearchSelectorBinding>()
- private val searchSelectorMenuBinding = ViewBoundFeatureWrapper<SearchSelectorMenuBinding>()
private val torQuickStart by lazy { TorQuickStart(requireContext()) }
- private lateinit var currentMode: CurrentMode
+ private val searchSelectorMenuBinding = ViewBoundFeatureWrapper<SearchSelectorMenuBinding>()
+ private lateinit var torBootstrapStatus: TorBootstrapStatus
override fun onCreate(savedInstanceState: Bundle?) {
// DO NOT ADD ANYTHING ABOVE THIS getProfilerTime CALL!
@@ -233,29 +235,27 @@ class HomeFragment : Fragment() {
val activity = activity as HomeActivity
val components = requireComponents
- val currentWallpaperName = requireContext().settings().currentWallpaperName
- applyWallpaper(wallpaperName = currentWallpaperName, orientationChange = false)
-
- currentMode = CurrentMode(
- requireContext(),
+ torBootstrapStatus = TorBootstrapStatus(
torQuickStart,
!BuildConfig.DISABLE_TOR,
components.torController,
- browsingModeManager,
::dispatchModeChanges
)
+ val currentWallpaperName = requireContext().settings().currentWallpaperName
+ applyWallpaper(wallpaperName = currentWallpaperName, orientationChange = false)
+
// Splits by full stops or commas and puts the parts in different lines.
// Ignoring separators at the end of the string, it is expected
// that there are at most two parts (e.g. "Explore. Privately.").
- val localBinding = binding;
+ val localBinding = binding
binding.exploreprivately.text = localBinding
.exploreprivately
.text
?.replace(" *([.,。।]) *".toRegex(), "$1\n")
?.trim()
- components.appStore.dispatch(AppAction.ModeChange(currentMode.getCurrentMode()))
+ components.appStore.dispatch(AppAction.ModeChange(Mode.fromBrowsingMode(browsingModeManager.mode)))
lifecycleScope.launch(IO) {
if (requireContext().settings().showPocketRecommendationsFeature) {
@@ -378,10 +378,6 @@ class HomeFragment : Fragment() {
registerCollectionStorageObserver = ::registerCollectionStorageObserver,
removeCollectionWithUndo = ::removeCollectionWithUndo,
showTabTray = ::openTabsTray,
- handleTorBootstrapConnect = ::handleTorBootstrapConnect,
- cancelTorBootstrap = ::cancelTorBootstrap,
- initiateTorBootstrap = ::initiateTorBootstrap,
- openTorNetworkSettings = ::openTorNetworkSettings
),
recentTabController = DefaultRecentTabsController(
selectTabUseCase = components.useCases.tabsUseCases.selectTab,
@@ -447,9 +443,6 @@ class HomeFragment : Fragment() {
FxNimbus.features.homescreen.recordExposure()
- adjustHomeFragmentView(currentMode.getCurrentMode())
- showSessionControlView()
-
// DO NOT MOVE ANYTHING BELOW THIS addMarker CALL!
requireComponents.core.engine.profiler?.addMarker(
MarkersFragmentLifecycleCallbacks.MARKER_NAME,
@@ -530,111 +523,6 @@ class HomeFragment : Fragment() {
binding.homeAppBar.setExpanded(true)
}
- // This function should be paired with showSessionControlView()
- @SuppressWarnings("ComplexMethod", "NestedBlockDepth", "LongMethod")
- private fun adjustHomeFragmentView(mode: Mode) {
- binding.sessionControlRecyclerView.apply {
- visibility = View.INVISIBLE
- }
-
- if (mode == Mode.Bootstrap) {
- binding.sessionControlRecyclerView.apply {
- setPadding(0, 0, 0, 0)
- (layoutParams as ViewGroup.MarginLayoutParams).setMargins(0, 0, 0, 0)
- }
- binding.homeAppBar.apply {
- visibility = View.GONE
-
- // Reset this as SCROLL in case it was previously set as NO_SCROLL after bootstrap
- children.forEach {
- (it.layoutParams as AppBarLayout.LayoutParams).scrollFlags =
- AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
- }
- }
- binding.onionPatternImage.apply {
- visibility = View.GONE
- }
- binding.toolbarLayout.apply {
- visibility = View.GONE
- }
- } else {
- // Keep synchronized with xml layout (somehow).
- binding.sessionControlRecyclerView.apply {
- setPadding(
- SESSION_CONTROL_VIEW_PADDING,
- SESSION_CONTROL_VIEW_PADDING,
- SESSION_CONTROL_VIEW_PADDING,
- SESSION_CONTROL_VIEW_PADDING
- )
- // Default margin until it is re-set below (either set immediately or after Layout)
- (layoutParams as ViewGroup.MarginLayoutParams).setMargins(
- 0,
- 0,
- 0,
- DEFAULT_ONBOARDING_FINISH_MARGIN
- )
- }
- binding.toolbarLayout.apply {
- visibility = View.VISIBLE
- // If the Layout rendering pass was completed, then we have a |height| value,
- // if it wasn't completed then we have 0.
- if (height == 0) {
- // Set the bottom margin after the toolbar height is defined during Layout
- doOnLayout {
- val toolbarLayoutHeight = binding.toolbarLayout.height
- binding.sessionControlRecyclerView.apply {
- (layoutParams as ViewGroup.MarginLayoutParams).setMargins(
- 0,
- 0,
- 0,
- toolbarLayoutHeight - SESSION_CONTROL_VIEW_PADDING
- )
- }
- }
- } else {
- binding.sessionControlRecyclerView.apply {
- (layoutParams as ViewGroup.MarginLayoutParams).setMargins(
- 0,
- 0,
- 0,
- height - SESSION_CONTROL_VIEW_PADDING
- )
- }
- }
- }
- // Hide the onion pattern during Onboarding, too.
- // With new onboarding HomeFragment is only reached once onboarding is complete
- binding.onionPatternImage.apply {
- visibility = if (currentMode.getCurrentMode() != Mode.Bootstrap) {
- View.VISIBLE
- } else {
- View.GONE
- }
-
- }
- binding.homeAppBar.apply {
- visibility = View.VISIBLE
-
- children.forEach {
- (it.layoutParams as AppBarLayout.LayoutParams).scrollFlags =
- if (currentMode.getCurrentMode() != Mode.Bootstrap) {
- AppBarLayout.LayoutParams.SCROLL_FLAG_NO_SCROLL
- } else {
- AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
- }
-
- }
- }
- }
- }
-
- // This function should be paired with adjustHomeFragmentView()
- private fun showSessionControlView() {
- binding.sessionControlRecyclerView.apply {
- visibility = View.VISIBLE
- }
- }
-
@Suppress("LongMethod", "ComplexMethod")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// DO NOT ADD ANYTHING ABOVE THIS getProfilerTime CALL!
@@ -880,13 +768,14 @@ class HomeFragment : Fragment() {
requireComponents.reviewPromptController.promptReview(requireActivity())
}
}
-
- private fun dispatchModeChanges(mode: Mode) {
- requireComponents.appStore.dispatch(AppAction.ModeChange(mode))
- adjustHomeFragmentView(mode)
- updateSessionControlView()
- showSessionControlView()
+ private fun dispatchModeChanges(isBootstrapping: Boolean) {
+ if (isBootstrapping) {
+ val directions =
+ TorBootstrapFragmentDirections
+ .actionStartupTorbootstrap()
+ findNavController().navigate(directions)
+ }
}
@VisibleForTesting
@@ -912,21 +801,16 @@ class HomeFragment : Fragment() {
override fun onStop() {
super.onStop()
- currentMode.unregisterTorListener()
+ torBootstrapStatus.unregisterTorListener()
}
override fun onResume() {
super.onResume()
+ torBootstrapStatus.registerTorListener()
if (browsingModeManager.mode == BrowsingMode.Private) {
activity?.window?.setBackgroundDrawableResource(R.drawable.private_home_background_gradient)
}
- // fenix#40176: Ensure the Home fragment is rendered correctly when we resume.
- val mode = currentMode.getCurrentMode()
- adjustHomeFragmentView(mode)
- updateSessionControlView()
- showSessionControlView()
-
hideToolbar()
// Whenever a tab is selected its last access timestamp is automatically updated by A-C.
@@ -1113,25 +997,6 @@ class HomeFragment : Fragment() {
}
}
- private fun handleTorBootstrapConnect() {
- requireComponents.torController.onTorConnecting()
- }
-
- private fun cancelTorBootstrap() {
- requireComponents.torController.stopTor()
- }
-
- private fun initiateTorBootstrap(withDebugLogging: Boolean = false) {
- requireComponents.torController.initiateTorBootstrap(lifecycleScope, withDebugLogging)
- }
-
- private fun openTorNetworkSettings() {
- val directions =
- HomeFragmentDirections
- .actionHomeFragmentToTorNetworkSettingsFragment()
- findNavController().navigate(directions)
- }
-
companion object {
const val ALL_NORMAL_TABS = "all_normal"
const val ALL_PRIVATE_TABS = "all_private"
@@ -1153,9 +1018,5 @@ class HomeFragment : Fragment() {
// Elevation for undo toasts
internal const val TOAST_ELEVATION = 80f
-
- // Layout
- private const val DEFAULT_ONBOARDING_FINISH_MARGIN = 60
- private const val SESSION_CONTROL_VIEW_PADDING = 16
}
}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/Mode.kt
=====================================
@@ -4,12 +4,7 @@
package org.mozilla.fenix.home
-import android.content.Context
-import org.mozilla.fenix.tor.TorController
-import org.mozilla.fenix.tor.TorEvents
-import org.mozilla.fenix.tor.bootstrap.TorQuickStart
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
-import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
/**
* Describes various states of the home fragment UI.
@@ -17,7 +12,6 @@ import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
sealed class Mode {
object Normal : Mode()
object Private : Mode()
- object Bootstrap : Mode()
companion object {
fun fromBrowsingMode(browsingMode: BrowsingMode) = when (browsingMode) {
@@ -26,48 +20,3 @@ sealed class Mode {
}
}
}
-
- at SuppressWarnings("LongParameterList", "TooManyFunctions")
-class CurrentMode(
- private val context: Context,
- private val torQuickStart: TorQuickStart,
- private val shouldStartTor: Boolean,
- private val torController: TorController,
- private val browsingModeManager: BrowsingModeManager,
- private val dispatchModeChanges: (mode: Mode) -> Unit
-) : TorEvents {
-
- init {
- torController.registerTorListener(this)
- }
-
- fun getCurrentMode() = if (shouldStartTor && (!torQuickStart.quickStartTor() && !torController.isBootstrapped)) {
- Mode.Bootstrap
- } else {
- Mode.fromBrowsingMode(browsingModeManager.mode)
- }
-
- fun emitModeChanges() {
- dispatchModeChanges(getCurrentMode())
- }
-
- @SuppressWarnings("EmptyFunctionBlock")
- override fun onTorConnecting() {
- }
-
- override fun onTorConnected() {
- dispatchModeChanges(getCurrentMode())
- }
-
- override fun onTorStopped() {
- dispatchModeChanges(getCurrentMode())
- }
-
- @SuppressWarnings("EmptyFunctionBlock")
- override fun onTorStatusUpdate(entry: String?, status: String?) {
- }
-
- fun unregisterTorListener() {
- torController.unregisterTorListener(this)
- }
-}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt
=====================================
@@ -34,10 +34,7 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHol
import org.mozilla.fenix.home.sessioncontrol.viewholders.CustomizeHomeButtonViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionsMessageViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
-import org.mozilla.fenix.home.sessioncontrol.viewholders.TorBootstrapPagerViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.MessageCardViewHolder
-import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.TorOnboardingSecurityLevelViewHolder
-import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.TorOnboardingDonateViewHolder
import org.mozilla.fenix.home.topsites.TopSitePagerViewHolder
import mozilla.components.feature.tab.collections.Tab as ComponentTab
@@ -102,8 +99,6 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {
object PrivateBrowsingDescription : AdapterItem(PrivateBrowsingDescriptionViewHolder.LAYOUT_ID)
object NoCollectionsMessage : AdapterItem(NoCollectionsMessageViewHolder.LAYOUT_ID)
- object TorBootstrap : AdapterItem(TorBootstrapPagerViewHolder.LAYOUT_ID)
-
object CollectionHeader : AdapterItem(CollectionHeaderViewHolder.LAYOUT_ID)
data class CollectionItem(
val collection: TabCollection,
@@ -143,9 +138,6 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {
object CustomizeHomeButton : AdapterItem(CustomizeHomeButtonViewHolder.LAYOUT_ID)
- object TorOnboardingSecurityLevel : AdapterItem(TorOnboardingSecurityLevelViewHolder.LAYOUT_ID)
- object TorOnboardingDonate : AdapterItem(TorOnboardingDonateViewHolder.LAYOUT_ID)
-
object RecentTabsHeader : AdapterItem(RecentTabsHeaderViewHolder.LAYOUT_ID)
object RecentTabItem : AdapterItem(RecentTabViewHolder.LAYOUT_ID)
@@ -293,11 +285,6 @@ class SessionControlAdapter(
viewLifecycleOwner = viewLifecycleOwner,
interactor = interactor,
)
- TorBootstrapPagerViewHolder.LAYOUT_ID -> TorBootstrapPagerViewHolder(
- view,
- components,
- interactor
- )
NoCollectionsMessageViewHolder.LAYOUT_ID ->
NoCollectionsMessageViewHolder(
view,
@@ -307,15 +294,6 @@ class SessionControlAdapter(
interactor,
)
BottomSpacerViewHolder.LAYOUT_ID -> BottomSpacerViewHolder(view)
-
- TorOnboardingSecurityLevelViewHolder.LAYOUT_ID -> TorOnboardingSecurityLevelViewHolder(
- view,
- interactor
- )
- TorOnboardingDonateViewHolder.LAYOUT_ID -> TorOnboardingDonateViewHolder(
- view,
- interactor
- )
else -> throw IllegalStateException()
}
}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt
=====================================
@@ -134,21 +134,6 @@ interface SessionControlController {
*/
fun handleTopSiteLongClicked(topSite: TopSite)
- /**
- * @see [OnboardingInteractor.onOpenSettingsClicked]
- */
- fun handleOpenSettingsClicked()
-
- /**
- * @see [OnboardingInteractor.onOpenSecurityLevelSettingsClicked]
- */
- fun handleOpenSecurityLevelSettingsClicked()
-
- /**
- * @see [OnboardingInteractor.onDonateClicked]
- */
- fun handleDonateClicked()
-
/**
* @see [CollectionInteractor.onToggleCollectionExpanded]
*/
@@ -188,31 +173,6 @@ interface SessionControlController {
* @see [SessionControlInteractor.reportSessionMetrics]
*/
fun handleReportSessionMetrics(state: AppState)
-
- /**
- * @see [TorBootstrapInteractor.onTorBootstrapConnectClicked]
- */
- fun handleTorBootstrapConnectClicked()
-
- /**
- * @see [TorBootstrapInteractor.onTorStopBootstrapping]
- */
- fun handleTorStopBootstrapping()
-
- /**
- * @see [TorBootstrapInteractor.onTorStartBootstrapping]
- */
- fun handleTorStartBootstrapping()
-
- /**
- * @see [TorBootstrapInteractor.onTorStartDebugBootstrapping]
- */
- fun handleTorStartDebugBootstrapping()
-
- /**
- * @see [TorBootstrapInteractor.onTorBootstrapNetworkSettingsClicked]
- */
- fun handleTorNetworkSettingsClicked()
}
@Suppress("TooManyFunctions", "LargeClass", "LongParameterList")
@@ -233,10 +193,6 @@ class DefaultSessionControlController(
private val registerCollectionStorageObserver: () -> Unit,
private val removeCollectionWithUndo: (tabCollection: TabCollection) -> Unit,
private val showTabTray: () -> Unit,
- private val handleTorBootstrapConnect: () -> Unit,
- private val initiateTorBootstrap: (Boolean) -> Unit,
- private val cancelTorBootstrap: () -> Unit,
- private val openTorNetworkSettings: () -> Unit
) : SessionControlController {
override fun handleCollectionAddTabTapped(collection: TabCollection) {
@@ -511,25 +467,6 @@ class DefaultSessionControlController(
}
}
}
-
- override fun handleOpenSettingsClicked() {
- val directions = HomeFragmentDirections.actionGlobalPrivateBrowsingFragment()
- navController.nav(R.id.homeFragment, directions)
- }
-
- override fun handleOpenSecurityLevelSettingsClicked() {
- val directions = HomeFragmentDirections.actionGlobalTorSecurityLevelFragment()
- navController.nav(R.id.homeFragment, directions)
- }
-
- override fun handleDonateClicked() {
- activity.openToBrowserAndLoad(
- searchTermOrURL = SupportUtils.DONATE_URL,
- newTab = true,
- from = BrowserDirection.FromHome
- )
- }
-
override fun handleToggleCollectionExpanded(collection: TabCollection, expand: Boolean) {
appStore.dispatch(AppAction.CollectionExpanded(collection, expand))
}
@@ -601,24 +538,4 @@ class DefaultSessionControlController(
RecentBookmarks.recentBookmarksCount.set(state.recentBookmarks.size.toLong())
}
-
- override fun handleTorBootstrapConnectClicked() {
- handleTorBootstrapConnect()
- }
-
- override fun handleTorStopBootstrapping() {
- cancelTorBootstrap()
- }
-
- override fun handleTorStartBootstrapping() {
- initiateTorBootstrap(false)
- }
-
- override fun handleTorStartDebugBootstrapping() {
- initiateTorBootstrap(true)
- }
-
- override fun handleTorNetworkSettingsClicked() {
- openTorNetworkSettings()
- }
}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt
=====================================
@@ -129,26 +129,6 @@ interface CollectionInteractor {
fun onRemoveCollectionsPlaceholder()
}
-/**
- * Interface for onboarding related actions in the [SessionControlInteractor].
- */
-interface OnboardingInteractor {
- /**
- * Hides the onboarding and navigates to Search. Called when a user clicks on the "Start Browsing" button.
- */
- fun onStartBrowsingClicked()
-
- /**
- * Hides the onboarding and navigates to Settings. Called when a user clicks on the "Open settings" button.
- */
- fun onOpenSettingsClicked()
-
- /**
- * Opens a custom tab to privacy notice url. Called when a user clicks on the "read our privacy notice" button.
- */
- fun onDonateClicked()
-}
-
interface CustomizeHomeIteractor {
/**
* Opens the customize home settings page.
@@ -156,34 +136,6 @@ interface CustomizeHomeIteractor {
fun openCustomizeHomePage()
}
-interface TorBootstrapInteractor {
- /**
- * Initiates Tor bootstrapping. Called when a user clicks on the "Connect" button.
- */
- fun onTorBootstrapConnectClicked()
-
- /**
- * Initiates Tor bootstrapping. Called when a user clicks on the "Connect" button.
- */
- fun onTorStartBootstrapping()
-
- /**
- * Stop Tor bootstrapping. Called when a user clicks on the "settings" cog/button.
- */
- fun onTorStopBootstrapping()
-
- /**
- * Initiates Tor bootstrapping with debug logging. Called when bootstrapping fails with
- * the control.txt file not existing.
- */
- fun onTorStartDebugBootstrapping()
-
- /**
- * Open Tor Network Settings preference screen
- */
- fun onTorBootstrapNetworkSettingsClicked()
-}
-
/**
* Interface for top site related actions in the [SessionControlInteractor].
*/
@@ -295,7 +247,6 @@ class SessionControlInteractor(
PocketStoriesInteractor,
PrivateBrowsingInteractor,
SearchSelectorInteractor,
- TorBootstrapInteractor,
WallpaperInteractor {
override fun onCollectionAddTabTapped(collection: TabCollection) {
@@ -358,15 +309,6 @@ class SessionControlInteractor(
return controller.handleShowWallpapersOnboardingDialog(state)
}
- // TODO: Do these still work, if not overrides, cus parent class dropped, are they wired in still?
- fun onOpenSettingsClicked() {
- controller.handleOpenSettingsClicked()
- }
-
- fun onDonateClicked() {
- controller.handleDonateClicked()
- }
-
override fun onToggleCollectionExpanded(collection: TabCollection, expand: Boolean) {
controller.handleToggleCollectionExpanded(collection, expand)
}
@@ -500,24 +442,4 @@ class SessionControlInteractor(
override fun onMenuItemTapped(item: SearchSelectorMenu.Item) {
searchSelectorController.handleMenuItemTapped(item)
}
-
- override fun onTorBootstrapConnectClicked() {
- controller.handleTorBootstrapConnectClicked()
- }
-
- override fun onTorStopBootstrapping() {
- controller.handleTorStopBootstrapping()
- }
-
- override fun onTorStartBootstrapping() {
- controller.handleTorStartBootstrapping()
- }
-
- override fun onTorStartDebugBootstrapping() {
- controller.handleTorStartDebugBootstrapping()
- }
-
- override fun onTorBootstrapNetworkSettingsClicked() {
- controller.handleTorNetworkSettingsClicked()
- }
}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt
=====================================
@@ -126,15 +126,6 @@ private fun showCollections(
private fun privateModeAdapterItems() = listOf(AdapterItem.PrivateBrowsingDescription)
-private fun bootstrapAdapterItems() = listOf(AdapterItem.TorBootstrap)
-
-private fun torOnboardingAdapterItems() =
- listOf(
- AdapterItem.TorOnboardingSecurityLevel,
- AdapterItem.TorOnboardingDonate,
- // AdapterItem.OnboardingFinish
- )
-
private fun AppState.toAdapterList(settings: Settings): List<AdapterItem> = when (mode) {
is Mode.Normal -> normalModeAdapterItems(
settings,
@@ -151,7 +142,6 @@ private fun AppState.toAdapterList(settings: Settings): List<AdapterItem> = when
firstFrameDrawn,
)
is Mode.Private -> privateModeAdapterItems()
- is Mode.Bootstrap -> bootstrapAdapterItems()
}
private fun collectionTabItems(collection: TabCollection) =
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/TorOnboardingDonateViewHolder.kt deleted
=====================================
@@ -1,28 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
-
-import android.view.View
-import androidx.recyclerview.widget.RecyclerView
-import org.mozilla.fenix.R
-import org.mozilla.fenix.databinding.TorOnboardingDonateBinding
-import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
-
-class TorOnboardingDonateViewHolder(
- view: View,
- private val interactor: SessionControlInteractor
-) : RecyclerView.ViewHolder(view) {
-
- init {
- val binding = TorOnboardingDonateBinding.bind(view)
- binding.donateNowButton.setOnClickListener {
- interactor.onDonateClicked()
- }
- }
-
- companion object {
- const val LAYOUT_ID = R.layout.tor_onboarding_donate
- }
-}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/TorOnboardingSecurityLevelViewHolder.kt deleted
=====================================
@@ -1,95 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
-
-import android.view.View
-import androidx.recyclerview.widget.RecyclerView
-import org.mozilla.fenix.R
-import org.mozilla.fenix.databinding.TorOnboardingSecurityLevelBinding
-import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
-import org.mozilla.fenix.ext.components
-import org.mozilla.fenix.onboarding.OnboardingRadioButton
-import org.mozilla.fenix.tor.SecurityLevel
-import org.mozilla.fenix.tor.SecurityLevelUtil
-import org.mozilla.fenix.utils.view.addToRadioGroup
-
-class TorOnboardingSecurityLevelViewHolder(
- view: View,
- private val interactor: SessionControlInteractor
-) : RecyclerView.ViewHolder(view) {
-
- private var _binding: TorOnboardingSecurityLevelBinding? = null
- private val binding get() = _binding!!
-
- private var standardSecurityLevel: OnboardingRadioButton
- private var saferSecurityLevel: OnboardingRadioButton
- private var safestSecurityLevel: OnboardingRadioButton
-
- init {
- _binding = TorOnboardingSecurityLevelBinding.bind(view)
- binding.headerText.setOnboardingIcon(R.drawable.ic_onboarding_tracking_protection)
-
- standardSecurityLevel = binding.securityLevelStandardOption
- saferSecurityLevel = binding.securityLevelSaferOption
- safestSecurityLevel = binding.securityLevelSafestOption
-
- binding.descriptionText.text = view.context.getString(
- R.string.tor_onboarding_security_level_description
- )
-
- setupRadioGroup(view)
-
- }
-
- private fun setupRadioGroup(view: View) {
-
- addToRadioGroup(standardSecurityLevel, saferSecurityLevel, safestSecurityLevel)
-
- val securityLevel = try {
- SecurityLevelUtil.getSecurityLevelFromInt(
- view.context.components.core.engine.settings.torSecurityLevel
- )
- } catch (e: IllegalStateException) {
- SecurityLevel.STANDARD
- }
-
- standardSecurityLevel.isChecked = securityLevel == SecurityLevel.STANDARD
- safestSecurityLevel.isChecked = securityLevel == SecurityLevel.SAFEST
- saferSecurityLevel.isChecked = securityLevel == SecurityLevel.SAFER
-
- standardSecurityLevel.onClickListener {
- updateSecurityLevel(SecurityLevel.STANDARD, view)
- }
-
- saferSecurityLevel.onClickListener {
- updateSecurityLevel(SecurityLevel.SAFER, view)
- }
-
- safestSecurityLevel.onClickListener {
- updateSecurityLevel(SecurityLevel.SAFEST, view)
- }
-
- updateSecurityLevel(securityLevel, view)
- }
-
- private fun updateSecurityLevel(newLevel: SecurityLevel, view: View) {
- val resources = view.context.resources
- val securityLevel = when (newLevel) {
- SecurityLevel.STANDARD -> resources.getString(R.string.tor_security_level_standard_option)
- SecurityLevel.SAFER -> resources.getString(R.string.tor_security_level_safer_option)
- SecurityLevel.SAFEST -> resources.getString(R.string.tor_security_level_safest_option)
- }
- binding.currentLevel.text = resources.getString(
- R.string.tor_onboarding_chosen_security_level_label, securityLevel
- )
- view.context.components.let {
- it.core.engine.settings.torSecurityLevel = newLevel.intRepresentation
- }
- }
-
- companion object {
- const val LAYOUT_ID = R.layout.tor_onboarding_security_level
- }
-}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapFragment.kt
=====================================
@@ -0,0 +1,195 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.tor
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.VisibleForTesting
+import androidx.core.view.children
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import org.mozilla.fenix.BuildConfig
+import org.mozilla.fenix.databinding.FragmentHomeBinding
+import org.mozilla.fenix.ext.requireComponents
+import org.mozilla.fenix.tor.bootstrap.TorQuickStart
+import org.mozilla.fenix.tor.interactor.DefaultTorBootstrapInteractor
+import org.mozilla.fenix.tor.interactor.TorBootstrapInteractor
+import androidx.navigation.fragment.findNavController
+import com.google.android.material.appbar.AppBarLayout
+import org.mozilla.fenix.ext.components
+import org.mozilla.fenix.ext.hideToolbar
+import org.mozilla.fenix.tor.controller.DefaultTorBootstrapController
+import org.mozilla.fenix.tor.view.TorBootstrapView
+
+
+ at Suppress("TooManyFunctions", "LargeClass")
+class TorBootstrapFragment : Fragment() {
+ private val torQuickStart by lazy { TorQuickStart(requireContext()) }
+
+ internal var _binding: FragmentHomeBinding? = null
+ private val binding get() = _binding!!
+
+
+ private var torBootstrapView: TorBootstrapView? = null
+
+ private var _torBootstrapInteractor: TorBootstrapInteractor? = null
+ private val torBootstrapInteractor: TorBootstrapInteractor
+ get() = _torBootstrapInteractor!!
+
+ private lateinit var torBootstrapStatus: TorBootstrapStatus
+
+
+ @Suppress("LongMethod")
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?,
+ ): View {
+ _binding = FragmentHomeBinding.inflate(inflater, container, false)
+ val components = requireComponents
+
+ torBootstrapStatus = TorBootstrapStatus(
+ torQuickStart,
+ !BuildConfig.DISABLE_TOR,
+ components.torController,
+ ::dispatchModeChanges
+ )
+
+ if (!torBootstrapStatus.isBootstrapping()) {
+ openHome()
+ }
+
+ // Was _sessionControlInteractor
+ _torBootstrapInteractor = DefaultTorBootstrapInteractor(
+ controller = DefaultTorBootstrapController(
+ handleTorBootstrapConnect = ::handleTorBootstrapConnect,
+ cancelTorBootstrap = ::cancelTorBootstrap,
+ initiateTorBootstrap = ::initiateTorBootstrap,
+ openTorNetworkSettings = ::openTorNetworkSettings
+ ),
+ )
+
+ torBootstrapView = TorBootstrapView(
+ containerView = binding.sessionControlRecyclerView,
+ viewLifecycleOwner = viewLifecycleOwner,
+ interactor = torBootstrapInteractor,
+ )
+
+ adjustHomeFragmentView()
+ updateSessionControlView()
+ showSessionControlView()
+
+ return binding.root
+ }
+
+ private fun updateSessionControlView() {
+ torBootstrapView?.update(requireContext().components.appStore.state)
+ }
+
+ // This function should be paired with showSessionControlView()
+ private fun adjustHomeFragmentView() {
+ binding.sessionControlRecyclerView.apply {
+ visibility = View.INVISIBLE
+ }
+
+ binding.sessionControlRecyclerView.apply {
+ setPadding(0, 0, 0, 0)
+ (layoutParams as ViewGroup.MarginLayoutParams).setMargins(0, 0, 0, 0)
+ }
+
+ binding.homeAppBar.apply {
+ visibility = View.GONE
+
+ // Reset this as SCROLL in case it was previously set as NO_SCROLL after bootstrap
+ children.forEach {
+ (it.layoutParams as AppBarLayout.LayoutParams).scrollFlags =
+ AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
+ }
+ }
+ binding.onionPatternImage.apply {
+ visibility = View.GONE
+ }
+ binding.toolbarLayout.apply {
+ visibility = View.GONE
+ }
+ }
+
+ // This function should be paired with adjustHomeFragmentView()
+ private fun showSessionControlView() {
+ binding.sessionControlRecyclerView.apply {
+ visibility = View.VISIBLE
+ }
+ }
+
+ private fun dispatchModeChanges(isBootstrapping: Boolean) {
+ //requireComponents.appStore.dispatch(AppAction.ModeChange(mode))
+ if (!isBootstrapping) {
+ openHome()
+ } else {
+ adjustHomeFragmentView()
+ updateSessionControlView()
+ showSessionControlView()
+ }
+ }
+
+ override fun onStop() {
+ super.onStop()
+ torBootstrapStatus.unregisterTorListener()
+ }
+
+ override fun onResume() {
+ super.onResume()
+
+ torBootstrapStatus.registerTorListener()
+
+ // fenix#40176: Ensure the Home fragment is rendered correctly when we resume.
+ val isBootstraping = torBootstrapStatus.isBootstrapping()
+
+ if (!isBootstraping) {
+ openHome()
+ }
+
+ adjustHomeFragmentView()
+ updateSessionControlView()
+ showSessionControlView()
+
+ hideToolbar()
+
+ // Whenever a tab is selected its last access timestamp is automatically updated by A-C.
+ // However, in the case of resuming the app to the home fragment, we already have an
+ // existing selected tab, but its last access timestamp is outdated. No action is
+ // triggered to cause an automatic update on warm start (no tab selection occurs). So we
+ // update it manually here.
+ requireComponents.useCases.sessionUseCases.updateLastAccess()
+ }
+
+ private fun handleTorBootstrapConnect() {
+ requireComponents.torController.onTorConnecting()
+ }
+
+ private fun cancelTorBootstrap() {
+ requireComponents.torController.stopTor()
+ }
+
+ private fun initiateTorBootstrap(withDebugLogging: Boolean = false) {
+ requireComponents.torController.initiateTorBootstrap(lifecycleScope, withDebugLogging)
+ }
+
+ private fun openTorNetworkSettings() {
+ val directions =
+ TorBootstrapFragmentDirections.actionTorbootstrapFragmentToTorNetworkSettingsFragment()
+ findNavController().navigate(directions)
+ }
+
+ private fun openHome() {
+ val directions =
+ TorBootstrapFragmentDirections
+ .actionStartupHome()
+ findNavController().navigate(directions)
+ }
+
+}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapStatus.kt
=====================================
@@ -0,0 +1,48 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.tor
+
+import org.mozilla.fenix.tor.bootstrap.TorQuickStart
+
+ at SuppressWarnings("LongParameterList", "TooManyFunctions")
+class TorBootstrapStatus(
+ private val torQuickStart: TorQuickStart,
+ private val shouldStartTor: Boolean,
+ private val torController: TorController,
+ private val dispatchModeChanges: (isShouldBootstrap: Boolean) -> Unit
+ ) : TorEvents {
+
+ init {
+ torController.registerTorListener(this)
+ }
+
+ fun isBootstrapping() = (shouldStartTor && (!torQuickStart.quickStartTor() && !torController.isBootstrapped))
+
+
+ @SuppressWarnings("EmptyFunctionBlock")
+ override fun onTorConnecting() {
+ }
+
+ override fun onTorConnected() {
+ dispatchModeChanges(isBootstrapping())
+ }
+
+ override fun onTorStopped() {
+ dispatchModeChanges(isBootstrapping())
+ }
+
+ @SuppressWarnings("EmptyFunctionBlock")
+ override fun onTorStatusUpdate(entry: String?, status: String?) {
+ }
+
+ fun unregisterTorListener() {
+ torController.unregisterTorListener(this)
+ }
+
+ fun registerTorListener() {
+ torController.registerTorListener(this)
+ }
+
+}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/controller/TorBootstrapController.kt
=====================================
@@ -0,0 +1,63 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.tor.controller
+
+import org.mozilla.fenix.tor.interactor.TorBootstrapInteractor
+
+interface TorBootstrapController {
+ /**
+ * @see [TorBootstrapInteractor.onTorBootstrapConnectClicked]
+ */
+ fun handleTorBootstrapConnectClicked()
+
+ /**
+ * @see [TorBootstrapInteractor.onTorStopBootstrapping]
+ */
+ fun handleTorStopBootstrapping()
+
+ /**
+ * @see [TorBootstrapInteractor.onTorStartBootstrapping]
+ */
+ fun handleTorStartBootstrapping()
+
+ /**
+ * @see [TorBootstrapInteractor.onTorStartDebugBootstrapping]
+ */
+ fun handleTorStartDebugBootstrapping()
+
+ /**
+ * @see [TorBootstrapInteractor.onTorBootstrapNetworkSettingsClicked]
+ */
+ fun handleTorNetworkSettingsClicked()
+
+
+}
+
+class DefaultTorBootstrapController(
+ private val handleTorBootstrapConnect: () -> Unit,
+ private val initiateTorBootstrap: (Boolean) -> Unit,
+ private val cancelTorBootstrap: () -> Unit,
+ private val openTorNetworkSettings: () -> Unit
+) : TorBootstrapController {
+ override fun handleTorBootstrapConnectClicked() {
+ handleTorBootstrapConnect()
+ }
+
+ override fun handleTorStopBootstrapping() {
+ cancelTorBootstrap()
+ }
+
+ override fun handleTorStartBootstrapping() {
+ initiateTorBootstrap(false)
+ }
+
+ override fun handleTorStartDebugBootstrapping() {
+ initiateTorBootstrap(true)
+ }
+
+ override fun handleTorNetworkSettingsClicked() {
+ openTorNetworkSettings()
+ }
+}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/interactor/TorBootstrapInteractor.kt
=====================================
@@ -0,0 +1,60 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.tor.interactor
+
+import org.mozilla.fenix.tor.controller.TorBootstrapController
+
+interface TorBootstrapInteractor {
+ /**
+ * Initiates Tor bootstrapping. Called when a user clicks on the "Connect" button.
+ */
+ fun onTorBootstrapConnectClicked()
+
+ /**
+ * Initiates Tor bootstrapping. Called when a user clicks on the "Connect" button.
+ */
+ fun onTorStartBootstrapping()
+
+ /**
+ * Stop Tor bootstrapping. Called when a user clicks on the "settings" cog/button.
+ */
+ fun onTorStopBootstrapping()
+
+ /**
+ * Initiates Tor bootstrapping with debug logging. Called when bootstrapping fails with
+ * the control.txt file not existing.
+ */
+ fun onTorStartDebugBootstrapping()
+
+ /**
+ * Open Tor Network Settings preference screen
+ */
+ fun onTorBootstrapNetworkSettingsClicked()
+}
+
+class DefaultTorBootstrapInteractor(
+ private val controller: TorBootstrapController,
+) : TorBootstrapInteractor {
+
+ override fun onTorBootstrapConnectClicked() {
+ controller.handleTorBootstrapConnectClicked()
+ }
+
+ override fun onTorStopBootstrapping() {
+ controller.handleTorStopBootstrapping()
+ }
+
+ override fun onTorStartBootstrapping() {
+ controller.handleTorStartBootstrapping()
+ }
+
+ override fun onTorStartDebugBootstrapping() {
+ controller.handleTorStartDebugBootstrapping()
+ }
+
+ override fun onTorBootstrapNetworkSettingsClicked() {
+ controller.handleTorNetworkSettingsClicked()
+ }
+}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapAdapter.kt
=====================================
@@ -0,0 +1,83 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.tor.view
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.lifecycle.LifecycleOwner
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.ListAdapter
+import androidx.recyclerview.widget.RecyclerView
+import org.mozilla.fenix.components.Components
+import org.mozilla.fenix.home.topsites.TopSitePagerViewHolder
+import org.mozilla.fenix.tor.interactor.TorBootstrapInteractor
+
+sealed class AdapterItem(@LayoutRes val viewType: Int) {
+ object TorBootstrap : AdapterItem(TorBootstrapPagerViewHolder.LAYOUT_ID)
+
+
+ open fun sameAs(other: AdapterItem) = this::class == other::class
+ open fun getChangePayload(newItem: AdapterItem): Any? = null
+ open fun contentsSameAs(other: AdapterItem) = this::class == other::class
+
+}
+
+class AdapterItemDiffCallback : DiffUtil.ItemCallback<AdapterItem>() {
+ override fun areItemsTheSame(oldItem: AdapterItem, newItem: AdapterItem) =
+ oldItem.sameAs(newItem)
+
+ @Suppress("DiffUtilEquals")
+ override fun areContentsTheSame(oldItem: AdapterItem, newItem: AdapterItem) =
+ oldItem.contentsSameAs(newItem)
+
+ override fun getChangePayload(oldItem: AdapterItem, newItem: AdapterItem): Any? {
+ return oldItem.getChangePayload(newItem) ?: return super.getChangePayload(oldItem, newItem)
+ }
+}
+
+
+
+class TorBootstrapAdapter(
+ private val interactor: TorBootstrapInteractor,
+ private val viewLifecycleOwner: LifecycleOwner,
+ private val components: Components,
+) : ListAdapter<AdapterItem, RecyclerView.ViewHolder>(AdapterItemDiffCallback()) {
+
+ // This method triggers the ComplexMethod lint error when in fact it's quite simple.
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
+ return when (viewType) {
+ TorBootstrapPagerViewHolder.LAYOUT_ID -> TorBootstrapPagerViewHolder(
+ view,
+ components,
+ interactor
+ )
+ else -> throw IllegalStateException()
+ }
+ }
+
+ override fun getItemViewType(position: Int) = getItem(position).viewType
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int, payloads: MutableList<Any>) {
+ if (payloads.isEmpty()) {
+ onBindViewHolder(holder, position)
+ } else {
+ when (holder) {
+ is TopSitePagerViewHolder -> {
+ if (payloads[0] is org.mozilla.fenix.home.sessioncontrol.AdapterItem.TopSitePagerPayload) {
+ val payload = payloads[0] as org.mozilla.fenix.home.sessioncontrol.AdapterItem.TopSitePagerPayload
+ holder.update(payload)
+ }
+ }
+ }
+ }
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ // no-op. This ViewHolder receives the HomeStore as argument and will observe that
+ // without the need for us to manually update from here the data to be displayed.
+ }
+}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TorBootstrapConnectViewHolder.kt → fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapConnectViewHolder.kt
=====================================
@@ -2,17 +2,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-package org.mozilla.fenix.home.sessioncontrol.viewholders
+package org.mozilla.fenix.tor.view
import android.view.View
-import androidx.appcompat.widget.SwitchCompat
import androidx.recyclerview.widget.RecyclerView
import org.mozilla.fenix.R
+import org.mozilla.fenix.components.Components
import org.mozilla.fenix.databinding.TorBootstrapConnectBinding
import org.mozilla.fenix.tor.TorEvents
import org.mozilla.fenix.tor.bootstrap.TorQuickStart
-import org.mozilla.fenix.components.Components
-import org.mozilla.fenix.home.sessioncontrol.TorBootstrapInteractor
+import org.mozilla.fenix.tor.interactor.TorBootstrapInteractor
class TorBootstrapConnectViewHolder(
private val view: View,
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TorBootstrapLoggerViewHolder.kt → fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapLoggerViewHolder.kt
=====================================
@@ -2,20 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-package org.mozilla.fenix.home.sessioncontrol.viewholders
+package org.mozilla.fenix.tor.view
import android.text.method.ScrollingMovementMethod
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import org.mozilla.fenix.R
+import org.mozilla.fenix.components.Components
import org.mozilla.fenix.databinding.TorBootstrapLoggerBinding
import org.mozilla.fenix.tor.TorEvents
-import org.mozilla.fenix.components.Components
class TorBootstrapLoggerViewHolder(
- private val view: View,
- private val components: Components
-) : RecyclerView.ViewHolder(view), TorEvents {
+ private val view: View,
+ private val components: Components
+ ) : RecyclerView.ViewHolder(view), TorEvents {
private var entries = mutableListOf<String>()
private var binding: TorBootstrapLoggerBinding
@@ -25,10 +25,10 @@ class TorBootstrapLoggerViewHolder(
components.torController.registerTorListener(this)
val currentEntries = components.torController.logEntries
- .filter { it.first != null }
- .filter { !(it.first!!.startsWith("Circuit") && it.second == "ON") }
- // Keep synchronized with format in onTorStatusUpdate
- .flatMap { listOf("(${it.second}) '${it.first}'") }
+ .filter { it.first != null }
+ .filter { !(it.first!!.startsWith("Circuit") && it.second == "ON") }
+ // Keep synchronized with format in onTorStatusUpdate
+ .flatMap { listOf("(${it.second}) '${it.first}'") }
val entriesLen = currentEntries.size
val subListOffset = if (entriesLen > MAX_NEW_ENTRIES) MAX_NEW_ENTRIES else entriesLen
entries = currentEntries.subList((entriesLen - subListOffset), entriesLen) as MutableList<String>
@@ -72,4 +72,5 @@ class TorBootstrapLoggerViewHolder(
const val MAX_NEW_ENTRIES = 24
const val MAX_LINES = 25
}
+
}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/torbootstrap/BootstrapPagerAdapter.kt → fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapPagerAdapter.kt
=====================================
@@ -2,18 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-package org.mozilla.fenix.home.sessioncontrol.viewholders.torbootstrap
+package org.mozilla.fenix.tor.view
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
-import androidx.recyclerview.widget.RecyclerView.ViewHolder
import org.mozilla.fenix.components.Components
-import org.mozilla.fenix.home.sessioncontrol.TorBootstrapInteractor
-import org.mozilla.fenix.home.sessioncontrol.viewholders.TorBootstrapConnectViewHolder
-import org.mozilla.fenix.home.sessioncontrol.viewholders.TorBootstrapLoggerViewHolder
+import org.mozilla.fenix.tor.interactor.TorBootstrapInteractor
-class BootstrapPagerAdapter(
+class TorBootstrapPagerAdapter(
private val components: Components,
private val interactor: TorBootstrapInteractor
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
=====================================
fenix/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TorBootstrapPagerViewHolder.kt → fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapPagerViewHolder.kt
=====================================
@@ -2,23 +2,22 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-package org.mozilla.fenix.home.sessioncontrol.viewholders
+package org.mozilla.fenix.tor.view
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import org.mozilla.fenix.R
-import org.mozilla.fenix.databinding.TorBootstrapPagerBinding
import org.mozilla.fenix.components.Components
-import org.mozilla.fenix.home.sessioncontrol.TorBootstrapInteractor
-import org.mozilla.fenix.home.sessioncontrol.viewholders.torbootstrap.BootstrapPagerAdapter
+import org.mozilla.fenix.databinding.TorBootstrapPagerBinding
+import org.mozilla.fenix.tor.interactor.TorBootstrapInteractor
class TorBootstrapPagerViewHolder(
- view: View,
- components: Components,
- interactor: TorBootstrapInteractor
-) : RecyclerView.ViewHolder(view) {
+ view: View,
+ components: Components,
+ interactor: TorBootstrapInteractor
+ ) : RecyclerView.ViewHolder(view) {
- private val bootstrapPagerAdapter = BootstrapPagerAdapter(components, interactor)
+ private val bootstrapPagerAdapter = TorBootstrapPagerAdapter(components, interactor)
init {
val binding = TorBootstrapPagerBinding.bind(view)
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/view/TorBootstrapView.kt
=====================================
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.tor.view
+
+import androidx.lifecycle.LifecycleOwner
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import org.mozilla.fenix.components.appstate.AppState
+import org.mozilla.fenix.ext.components
+import org.mozilla.fenix.tor.interactor.TorBootstrapInteractor
+
+
+class TorBootstrapView(
+ containerView: RecyclerView,
+ viewLifecycleOwner: LifecycleOwner,
+ interactor: TorBootstrapInteractor,
+) {
+
+ val view: RecyclerView = containerView //as RecyclerView
+
+ private fun bootstrapAdapterItems() = listOf(AdapterItem.TorBootstrap)
+
+ private val torBootstrapAdapter = TorBootstrapAdapter(
+ interactor,
+ viewLifecycleOwner,
+ containerView.context.components,
+ )
+
+ //private val torBootstrapAdapter =
+ // TorBootstrapAdapter(interactor, containerView.context.components)
+ //private val torBootstrapAdapter = TorBootstrapPagerAdapter(containerView.context.components, interactor)
+
+ init {
+ containerView.apply {
+ adapter = torBootstrapAdapter
+ layoutManager = LinearLayoutManager(containerView.context)
+ }
+ }
+
+ private fun AppState.toAdapterList(): List<AdapterItem> {
+ return bootstrapAdapterItems()
+ }
+
+ fun update(state: AppState) {
+ torBootstrapAdapter.submitList(state.toAdapterList())
+ }
+}
=====================================
fenix/app/src/main/res/drawable/tor_onboarding_donate_gradient.xml deleted
=====================================
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
- - License, v. 2.0. If a copy of the MPL was not distributed with this
- - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <shape>
- <gradient
- android:angle="45"
- android:startColor="#07d1db"
- android:endColor="#b240f5"
- android:type="linear" />
- </shape>
- </item>
-</selector>
=====================================
fenix/app/src/main/res/drawable/tor_onboarding_donate_rounded_corners.xml deleted
=====================================
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
- - License, v. 2.0. If a copy of the MPL was not distributed with this
- - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-
-<!-- Used for rounding the corners of a button -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="#70efde" />
- <corners android:radius="10dp" />
-</shape>
=====================================
fenix/app/src/main/res/layout/tor_onboarding_donate.xml deleted
=====================================
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
- - License, v. 2.0. If a copy of the MPL was not distributed with this
- - 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:id="@+id/onboarding_card"
- style="@style/TorOnboardingDonateCardLightWithPadding"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/header_text"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:text="@string/tor_onboarding_donate_header"
- android:textAppearance="@style/TorHeaderTextStyle"
- android:gravity="center_vertical"
- android:lines="1"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintEnd_toEndOf="parent" />
- <TextView
- android:id="@+id/description_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="@style/TorBody16TextStyle"
- android:layout_marginTop="14dp"
- android:text="@string/tor_onboarding_donate_description"
- app:layout_constraintTop_toBottomOf="@id/header_text"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent" />
-
- <Button
- style="@style/TorDonateOnboardingButton"
- android:id="@+id/donate_now_button"
- android:text="@string/tor_onboarding_donate_button"
- android:layout_marginTop="10dp"
- android:textAppearance="@style/TorHeaderTextStyle"
- android:background="@drawable/tor_onboarding_donate_rounded_corners"
- app:layout_constraintTop_toBottomOf="@id/description_text"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"/>
-</androidx.constraintlayout.widget.ConstraintLayout>
=====================================
fenix/app/src/main/res/layout/tor_onboarding_security_level.xml deleted
=====================================
@@ -1,123 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!-- This Source Code Form is subject to the terms of the Mozilla Public
- - License, v. 2.0. If a copy of the MPL was not distributed with this
- - 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:id="@+id/onboarding_card"
- style="@style/OnboardingCardLightWithPadding"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:clipToPadding="false">
-
- <TextView
- android:id="@+id/header_text"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:drawablePadding="12dp"
- android:gravity="center_vertical"
- android:lines="1"
- android:text="@string/tor_onboarding_security_level"
- android:textAppearance="@style/HeaderTextStyle"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- tools:drawableStart="@drawable/ic_onboarding_tracking_protection" />
-
- <TextView
- android:id="@+id/description_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:textAppearance="@style/Body14TextStyle"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/current_level"
- tools:text="@string/tor_onboarding_security_level_description" />
-
- <TextView
- android:id="@+id/current_level"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/header_text"
- tools:text="@string/tor_onboarding_chosen_security_level_label" />
-
- <org.mozilla.fenix.onboarding.OnboardingRadioButton
- android:id="@+id/security_level_standard_option"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="16dp"
- android:background="@android:color/transparent"
- android:checked="true"
- android:foreground="@drawable/rounded_ripple"
- android:gravity="top"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:theme="@style/Checkable.Colored"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/description_text"
- app:onboardingKey="@string/pref_key_tor_security_level_standard_option"
- app:onboardingKeyDescription="@string/tor_security_level_standard_description"
- app:onboardingKeyTitle="@string/tor_security_level_standard_option"
- tools:text="Standard" />
-
- <org.mozilla.fenix.onboarding.OnboardingRadioButton
- android:id="@+id/security_level_safer_option"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="16dp"
- android:background="@android:color/transparent"
- android:checked="false"
- android:foreground="@drawable/rounded_ripple"
- android:gravity="top"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:textColor="@color/primary_state_list_text_color"
- android:theme="@style/Checkable.Colored"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/security_level_standard_option"
- app:onboardingKey="@string/pref_key_tor_security_level_safer_option"
- app:onboardingKeyDescription="@string/tor_security_level_safer_description"
- app:onboardingKeyTitle="@string/tor_security_level_safer_option"
- tools:text="Safer" />
-
- <org.mozilla.fenix.onboarding.OnboardingRadioButton
- android:id="@+id/security_level_safest_option"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_marginTop="16dp"
- android:layout_marginBottom="16dp"
- android:background="@android:color/transparent"
- android:checked="false"
- android:foreground="@drawable/rounded_ripple"
- android:gravity="top"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:textColor="@color/primary_state_list_text_color"
- android:theme="@style/Checkable.Colored"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/security_level_safer_option"
- app:onboardingKey="@string/pref_key_tor_security_level_safest_option"
- app:onboardingKeyDescription="@string/tor_security_level_safest_description"
- app:onboardingKeyTitle="@string/tor_security_level_safest_option"
- tools:text="Safest" />
-
- <Button
- android:id="@+id/open_settings_button"
- style="@style/NeutralOnboardingButton"
- android:layout_marginTop="16dp"
- android:text="@string/tor_onboarding_security_settings_button"
- app:layout_constraintTop_toBottomOf="@id/security_level_safest_option"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"/>
-
-</androidx.constraintlayout.widget.ConstraintLayout>
=====================================
fenix/app/src/main/res/navigation/nav_graph.xml
=====================================
@@ -21,6 +21,12 @@
app:popUpTo="@id/startupFragment"
app:popUpToInclusive="true" />
+ <action
+ android:id="@+id/action_startup_torbootstrap"
+ app:destination="@id/torbootstrapFragment"
+ app:popUpTo="@id/startupFragment"
+ app:popUpToInclusive="true" />
+
<action
android:id="@+id/action_global_home"
app:destination="@id/homeFragment"
@@ -247,6 +253,24 @@
app:popUpToInclusive="true" />
</fragment>
+ <fragment
+ android:id="@+id/torbootstrapFragment"
+ android:name="org.mozilla.fenix.tor.TorBootstrapFragment"
+ tools:layout="@layout/fragment_home">
+ <action
+ android:id="@+id/action_home"
+ app:destination="@id/homeFragment"
+ app:popUpTo="@id/torbootstrapFragment"
+ app:popUpToInclusive="true" />
+ <action
+ android:id="@+id/action_torbootstrapFragment_to_torNetworkSettingsFragment"
+ app:destination="@id/torNetworkSettingsFragment"
+ app:enterAnim="@anim/slide_in_right"
+ app:exitAnim="@anim/slide_out_left"
+ app:popEnterAnim="@anim/slide_in_left"
+ app:popExitAnim="@anim/slide_out_right" />
+ </fragment>
+
<dialog
android:id="@+id/homeOnboardingDialogFragment"
android:name="org.mozilla.fenix.onboarding.HomeOnboardingDialogFragment" />
=====================================
fenix/app/src/main/res/values/styles.xml
=====================================
@@ -375,13 +375,6 @@
<item name="android:textColor">?attr/textPrimary</item>
</style>
- <!-- Ideally we should consolidate this with NeutralButton in the future -->
- <style name="TorDonateOnboardingButton" parent="NeutralButton">
- <item name="android:background">@drawable/tor_onboarding_donate_rounded_corners</item>
- <item name="backgroundTint">#70efde</item>
- <item name="android:textColor">#000000</item>
- </style>
-
<style name="DestructiveButton" parent="NeutralButton">
<item name="iconTint">@color/fx_mobile_icon_color_warning_button</item>
<item name="android:textColor">@color/fx_mobile_text_color_warning_button</item>
@@ -582,10 +575,6 @@
<item name="android:elevation">0dp</item>
</style>
- <style name="TorOnboardingDonateCardLightWithPadding" parent="OnboardingCardDark">
- <item name="android:background">@drawable/tor_onboarding_donate_gradient</item>
- </style>
-
<style name="SearchClipboardStyle">
<item name="android:ellipsize">end</item>
<item name="android:maxLines">1</item>
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/compare/d19b676f148dade33eea6dd64cf54df7d4f52c3c...d2a7dfa603c2b5dec1607be715275e56dc3c04a2
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/compare/d19b676f148dade33eea6dd64cf54df7d4f52c3c...d2a7dfa603c2b5dec1607be715275e56dc3c04a2
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/20230912/7d1d2248/attachment-0001.htm>
More information about the tbb-commits
mailing list