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 { } } } - -@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 + + +@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 + +@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/d19...