Commit 4d96eb68 authored by Matthew Finkel's avatar Matthew Finkel
Browse files

Bug 40028: Integrate Tor Controller into HomeFragment

parent b4d323b9
...@@ -49,6 +49,7 @@ import org.mozilla.fenix.push.WebPushEngineIntegration ...@@ -49,6 +49,7 @@ import org.mozilla.fenix.push.WebPushEngineIntegration
import org.mozilla.fenix.session.PerformanceActivityLifecycleCallbacks import org.mozilla.fenix.session.PerformanceActivityLifecycleCallbacks
import org.mozilla.fenix.session.VisibilityLifecycleCallback import org.mozilla.fenix.session.VisibilityLifecycleCallback
import org.mozilla.fenix.utils.BrowsersCache import org.mozilla.fenix.utils.BrowsersCache
import org.torproject.android.service.util.Prefs
/** /**
*The main application class for Fenix. Records data to measure initialization performance. *The main application class for Fenix. Records data to measure initialization performance.
...@@ -62,6 +63,8 @@ open class FenixApplication : LocaleAwareApplication(), Provider { ...@@ -62,6 +63,8 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
private val logger = Logger("FenixApplication") private val logger = Logger("FenixApplication")
var terminating = false
open val components by lazy { Components(this) } open val components by lazy { Components(this) }
var visibilityLifecycleCallback: VisibilityLifecycleCallback? = null var visibilityLifecycleCallback: VisibilityLifecycleCallback? = null
...@@ -91,6 +94,21 @@ open class FenixApplication : LocaleAwareApplication(), Provider { ...@@ -91,6 +94,21 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
setupInMainProcessOnly() setupInMainProcessOnly()
} }
fun isTerminating() = terminating
fun terminate() {
onTerminate()
System.exit(0)
}
override fun onTerminate() {
terminating = true
super.onTerminate()
components.torController.stop()
components.torController.stopTor()
}
protected open fun initializeGlean() { protected open fun initializeGlean() {
val telemetryEnabled = settings().isTelemetryEnabled val telemetryEnabled = settings().isTelemetryEnabled
...@@ -139,6 +157,11 @@ open class FenixApplication : LocaleAwareApplication(), Provider { ...@@ -139,6 +157,11 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
if (!megazordSetup.isCompleted) { if (!megazordSetup.isCompleted) {
runBlocking { megazordSetup.await(); } runBlocking { megazordSetup.await(); }
} }
GlobalScope.launch(Dispatchers.IO) {
// Give TAS the base Context
Prefs.setContext(applicationContext)
}
} }
setupLeakCanary() setupLeakCanary()
...@@ -157,6 +180,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { ...@@ -157,6 +180,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
initVisualCompletenessQueueAndQueueTasks() initVisualCompletenessQueueAndQueueTasks()
components.appStartupTelemetry.onFenixApplicationOnCreate() components.appStartupTelemetry.onFenixApplicationOnCreate()
components.torController.start()
} }
private fun restoreDownloads() { private fun restoreDownloads() {
......
...@@ -4,10 +4,9 @@ ...@@ -4,10 +4,9 @@
package org.mozilla.fenix package org.mozilla.fenix
import android.content.BroadcastReceiver import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
...@@ -26,7 +25,6 @@ import androidx.annotation.VisibleForTesting.PROTECTED ...@@ -26,7 +25,6 @@ import androidx.annotation.VisibleForTesting.PROTECTED
import androidx.appcompat.app.ActionBar import androidx.appcompat.app.ActionBar
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.navigation.NavDestination import androidx.navigation.NavDestination
import androidx.navigation.NavDirections import androidx.navigation.NavDirections
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
...@@ -104,9 +102,6 @@ import org.mozilla.fenix.tabtray.TabTrayDialogFragmentDirections ...@@ -104,9 +102,6 @@ import org.mozilla.fenix.tabtray.TabTrayDialogFragmentDirections
import org.mozilla.fenix.theme.DefaultThemeManager import org.mozilla.fenix.theme.DefaultThemeManager
import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.utils.BrowsersCache import org.mozilla.fenix.utils.BrowsersCache
import org.torproject.android.service.TorService
import org.torproject.android.service.TorServiceConstants
import org.torproject.android.service.util.Prefs
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
/** /**
...@@ -135,6 +130,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { ...@@ -135,6 +130,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
private var isToolbarInflated = false private var isToolbarInflated = false
private var isBeingRecreated = false
private val webExtensionPopupFeature by lazy { private val webExtensionPopupFeature by lazy {
WebExtensionPopupFeature(components.core.store, ::openPopup) WebExtensionPopupFeature(components.core.store, ::openPopup)
} }
...@@ -159,9 +156,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { ...@@ -159,9 +156,6 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
private lateinit var navigationToolbar: Toolbar private lateinit var navigationToolbar: Toolbar
final override fun onCreate(savedInstanceState: Bundle?) { final override fun onCreate(savedInstanceState: Bundle?) {
// Give Orbot the base Context
Prefs.setContext(applicationContext)
components.strictMode.attachListenerToDisablePenaltyDeath(supportFragmentManager) components.strictMode.attachListenerToDisablePenaltyDeath(supportFragmentManager)
// There is disk read violations on some devices such as samsung and pixel for android 9/10 // There is disk read violations on some devices such as samsung and pixel for android 9/10
...@@ -380,6 +374,14 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { ...@@ -380,6 +374,14 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
) )
privateNotificationObserver?.stop() privateNotificationObserver?.stop()
if (!isBeingRecreated && !(application as FenixApplication).isTerminating()) {
// We assume the Activity is being destroyed because the user
// swiped away the app on the Recent screen. When this happens,
// we assume the user expects the entire Application is destroyed
// and not only the top Activity/Task. Therefore we kill the
// underlying Application, as well.
(application as FenixApplication).terminate()
}
} }
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
...@@ -399,6 +401,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { ...@@ -399,6 +401,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
message = "recreate()" message = "recreate()"
) )
isBeingRecreated = true
super.recreate() super.recreate()
} }
......
...@@ -22,6 +22,7 @@ import org.mozilla.fenix.HomeActivity ...@@ -22,6 +22,7 @@ import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.StrictModeManager import org.mozilla.fenix.StrictModeManager
import org.mozilla.fenix.components.metrics.AppStartupTelemetry import org.mozilla.fenix.components.metrics.AppStartupTelemetry
import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.tor.TorController
import org.mozilla.fenix.utils.ClipboardHandler import org.mozilla.fenix.utils.ClipboardHandler
import org.mozilla.fenix.utils.Mockable import org.mozilla.fenix.utils.Mockable
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
...@@ -142,4 +143,6 @@ class Components(private val context: Context) { ...@@ -142,4 +143,6 @@ class Components(private val context: Context) {
FenixReviewSettings(settings) FenixReviewSettings(settings)
) )
} }
val torController by lazy { TorController(context) }
} }
...@@ -72,6 +72,7 @@ import mozilla.components.lib.state.ext.consumeFrom ...@@ -72,6 +72,7 @@ import mozilla.components.lib.state.ext.consumeFrom
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import mozilla.components.support.ktx.android.content.res.resolveAttribute import mozilla.components.support.ktx.android.content.res.resolveAttribute
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserAnimator.Companion.getToolbarNavOptions import org.mozilla.fenix.browser.BrowserAnimator.Companion.getToolbarNavOptions
...@@ -101,6 +102,8 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.DefaultTopSite ...@@ -101,6 +102,8 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.DefaultTopSite
import org.mozilla.fenix.onboarding.FenixOnboarding import org.mozilla.fenix.onboarding.FenixOnboarding
import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit
import org.mozilla.fenix.tor.TorEvents
import org.mozilla.fenix.tor.bootstrap.TorQuickStart
import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.utils.FragmentPreDrawManager import org.mozilla.fenix.utils.FragmentPreDrawManager
import org.mozilla.fenix.utils.ToolbarPopupWindow import org.mozilla.fenix.utils.ToolbarPopupWindow
...@@ -164,6 +167,7 @@ class HomeFragment : Fragment() { ...@@ -164,6 +167,7 @@ class HomeFragment : Fragment() {
private lateinit var currentMode: CurrentMode private lateinit var currentMode: CurrentMode
private val topSitesFeature = ViewBoundFeatureWrapper<TopSitesFeature>() private val topSitesFeature = ViewBoundFeatureWrapper<TopSitesFeature>()
private val torQuickStart by lazy { TorQuickStart(requireContext()) }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
...@@ -189,6 +193,9 @@ class HomeFragment : Fragment() { ...@@ -189,6 +193,9 @@ class HomeFragment : Fragment() {
currentMode = CurrentMode( currentMode = CurrentMode(
view.context, view.context,
onboarding, onboarding,
torQuickStart,
!BuildConfig.DISABLE_TOR,
components.torController,
browsingModeManager, browsingModeManager,
::dispatchModeChanges ::dispatchModeChanges
) )
...@@ -242,7 +249,10 @@ class HomeFragment : Fragment() { ...@@ -242,7 +249,10 @@ class HomeFragment : Fragment() {
registerCollectionStorageObserver = ::registerCollectionStorageObserver, registerCollectionStorageObserver = ::registerCollectionStorageObserver,
showDeleteCollectionPrompt = ::showDeleteCollectionPrompt, showDeleteCollectionPrompt = ::showDeleteCollectionPrompt,
showTabTray = ::openTabTray, showTabTray = ::openTabTray,
handleSwipedItemDeletionCancel = ::handleSwipedItemDeletionCancel handleSwipedItemDeletionCancel = ::handleSwipedItemDeletionCancel,
handleTorBootstrapConnect = ::handleTorBootstrapConnect,
cancelTorBootstrap = ::cancelTorBootstrap,
initiateTorBootstrap = ::initiateTorBootstrap
) )
) )
...@@ -257,6 +267,9 @@ class HomeFragment : Fragment() { ...@@ -257,6 +267,9 @@ class HomeFragment : Fragment() {
updateSessionControlView(view) updateSessionControlView(view)
activity.themeManager.applyStatusBarTheme(activity) activity.themeManager.applyStatusBarTheme(activity)
adjustHomeFragmentView(currentMode.getCurrentMode(), view)
return view return view
} }
...@@ -328,6 +341,44 @@ class HomeFragment : Fragment() { ...@@ -328,6 +341,44 @@ class HomeFragment : Fragment() {
} }
} }
private fun adjustHomeFragmentView(mode: Mode, view: View?) {
if (mode == Mode.Bootstrap) {
view?.sessionControlRecyclerView?.apply {
setPadding(0, 0, 0, 0)
(getLayoutParams() as ViewGroup.MarginLayoutParams).setMargins(0, 0, 0, 0)
}
view?.homeAppBar?.apply {
visibility = View.GONE
}
view?.toolbarLayout?.apply {
visibility = View.GONE
}
} else {
// Keep synchronized with xml layout (somehow).
view?.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)
(getLayoutParams() as ViewGroup.MarginLayoutParams).setMargins(
0,
0,
0,
DEFAULT_ONBOARDING_FINISH_MARGIN
)
}
view?.homeAppBar?.apply {
visibility = View.VISIBLE
}
view?.toolbarLayout?.apply {
visibility = View.VISIBLE
}
}
}
@Suppress("LongMethod", "ComplexMethod") @Suppress("LongMethod", "ComplexMethod")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
...@@ -604,8 +655,12 @@ class HomeFragment : Fragment() { ...@@ -604,8 +655,12 @@ class HomeFragment : Fragment() {
} }
private fun dispatchModeChanges(mode: Mode) { private fun dispatchModeChanges(mode: Mode) {
if (mode != Mode.fromBrowsingMode(browsingModeManager.mode)) { homeFragmentStore.dispatch(HomeFragmentAction.ModeChange(mode))
homeFragmentStore.dispatch(HomeFragmentAction.ModeChange(mode))
val localView = view
adjustHomeFragmentView(mode, view)
if (localView != null) {
updateSessionControlView(localView)
} }
} }
...@@ -646,6 +701,8 @@ class HomeFragment : Fragment() { ...@@ -646,6 +701,8 @@ class HomeFragment : Fragment() {
} }
homeViewModel.layoutManagerState = homeViewModel.layoutManagerState =
sessionControlView!!.view.layoutManager?.onSaveInstanceState() sessionControlView!!.view.layoutManager?.onSaveInstanceState()
currentMode.unregisterTorListener()
} }
override fun onResume() { override fun onResume() {
...@@ -973,6 +1030,18 @@ class HomeFragment : Fragment() { ...@@ -973,6 +1030,18 @@ class HomeFragment : Fragment() {
view?.sessionControlRecyclerView?.adapter?.notifyDataSetChanged() view?.sessionControlRecyclerView?.adapter?.notifyDataSetChanged()
} }
private fun handleTorBootstrapConnect() {
requireComponents.torController.onTorConnecting()
}
private fun cancelTorBootstrap() {
requireComponents.torController.stopTor()
}
private fun initiateTorBootstrap(withDebugLogging: Boolean = false) {
requireComponents.torController.initiateTorBootstrap(lifecycleScope, withDebugLogging)
}
companion object { companion object {
const val ALL_NORMAL_TABS = "all_normal" const val ALL_NORMAL_TABS = "all_normal"
const val ALL_PRIVATE_TABS = "all_private" const val ALL_PRIVATE_TABS = "all_private"
...@@ -987,5 +1056,9 @@ class HomeFragment : Fragment() { ...@@ -987,5 +1056,9 @@ class HomeFragment : Fragment() {
private const val ANIM_SNACKBAR_DELAY = 100L private const val ANIM_SNACKBAR_DELAY = 100L
private const val CFR_WIDTH_DIVIDER = 1.7 private const val CFR_WIDTH_DIVIDER = 1.7
private const val CFR_Y_OFFSET = -20 private const val CFR_Y_OFFSET = -20
// Layout
private const val DEFAULT_ONBOARDING_FINISH_MARGIN = 60
private const val SESSION_CONTROL_VIEW_PADDING = 16
} }
} }
...@@ -10,6 +10,9 @@ import mozilla.components.concept.sync.AuthType ...@@ -10,6 +10,9 @@ import mozilla.components.concept.sync.AuthType
import mozilla.components.concept.sync.OAuthAccount import mozilla.components.concept.sync.OAuthAccount
import mozilla.components.concept.sync.Profile import mozilla.components.concept.sync.Profile
import mozilla.components.service.fxa.sharing.ShareableAccount import mozilla.components.service.fxa.sharing.ShareableAccount
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.BrowsingMode
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
...@@ -22,6 +25,7 @@ sealed class Mode { ...@@ -22,6 +25,7 @@ sealed class Mode {
object Normal : Mode() object Normal : Mode()
object Private : Mode() object Private : Mode()
data class Onboarding(val state: OnboardingState) : Mode() data class Onboarding(val state: OnboardingState) : Mode()
object Bootstrap : Mode()
companion object { companion object {
fun fromBrowsingMode(browsingMode: BrowsingMode) = when (browsingMode) { fun fromBrowsingMode(browsingMode: BrowsingMode) = when (browsingMode) {
...@@ -43,16 +47,26 @@ sealed class OnboardingState { ...@@ -43,16 +47,26 @@ sealed class OnboardingState {
object SignedIn : OnboardingState() object SignedIn : OnboardingState()
} }
@SuppressWarnings("LongParameterList", "TooManyFunctions")
class CurrentMode( class CurrentMode(
private val context: Context, private val context: Context,
private val onboarding: FenixOnboarding, private val onboarding: FenixOnboarding,
private val torQuickStart: TorQuickStart,
private val shouldStartTor: Boolean,
private val torController: TorController,
private val browsingModeManager: BrowsingModeManager, private val browsingModeManager: BrowsingModeManager,
private val dispatchModeChanges: (mode: Mode) -> Unit private val dispatchModeChanges: (mode: Mode) -> Unit
) : AccountObserver { ) : AccountObserver, TorEvents {
private val accountManager by lazy { context.components.backgroundServices.accountManager } private val accountManager by lazy { context.components.backgroundServices.accountManager }
fun getCurrentMode() = if (onboarding.userHasBeenOnboarded()) { init {
torController.registerTorListener(this)
}
fun getCurrentMode() = if (shouldStartTor && (!torQuickStart.quickStartTor() && !torController.isBootstrapped)) {
Mode.Bootstrap
} else if (onboarding.userHasBeenOnboarded()) {
Mode.fromBrowsingMode(browsingModeManager.mode) Mode.fromBrowsingMode(browsingModeManager.mode)
} else { } else {
val account = accountManager.authenticatedAccount() val account = accountManager.authenticatedAccount()
...@@ -72,6 +86,26 @@ class CurrentMode( ...@@ -72,6 +86,26 @@ class CurrentMode(
dispatchModeChanges(getCurrentMode()) 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)
}
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) = emitModeChanges() override fun onAuthenticated(account: OAuthAccount, authType: AuthType) = emitModeChanges()
override fun onAuthenticationProblems() = emitModeChanges() override fun onAuthenticationProblems() = emitModeChanges()
override fun onLoggedOut() = emitModeChanges() override fun onLoggedOut() = emitModeChanges()
......
...@@ -149,6 +149,26 @@ interface SessionControlController { ...@@ -149,6 +149,26 @@ interface SessionControlController {
* @see [CollectionInteractor.onRemoveCollectionsPlaceholder] * @see [CollectionInteractor.onRemoveCollectionsPlaceholder]
*/ */
fun handleRemoveCollectionsPlaceholder() fun handleRemoveCollectionsPlaceholder()
/**
* @see [TorBootstrapInteractor.onTorBootstrapConnectClicked]
*/
fun handleTorBootstrapConnectClicked()
/**
* @see [TorBootstrapInteractor.onTorBootstrapConnectingClicked]
*/
fun handleTorBootstrapConnectingClicked()
/**
* @see [TorBootstrapInteractor.onTorStartBootstrapping]
*/
fun handleTorStartBootstrapping()
/**
* @see [TorBootstrapInteractor.onTorStartDebugBootstrapping]
*/
fun handleTorStartDebugBootstrapping()
} }
@Suppress("TooManyFunctions", "LargeClass") @Suppress("TooManyFunctions", "LargeClass")
...@@ -173,7 +193,10 @@ class DefaultSessionControlController( ...@@ -173,7 +193,10 @@ class DefaultSessionControlController(
handleSwipedItemDeletionCancel: () -> Unit handleSwipedItemDeletionCancel: () -> Unit
) -> Unit, ) -> Unit,
private val showTabTray: () -> Unit, private val showTabTray: () -> Unit,
private val handleSwipedItemDeletionCancel: () -> Unit private val handleSwipedItemDeletionCancel: () -> Unit,
private val handleTorBootstrapConnect: () -> Unit,
private val initiateTorBootstrap: (Boolean) -> Unit,
private val cancelTorBootstrap: () -> Unit
) : SessionControlController { ) : SessionControlController {
override fun handleCollectionAddTabTapped(collection: TabCollection) { override fun handleCollectionAddTabTapped(collection: TabCollection) {
...@@ -434,4 +457,20 @@ class DefaultSessionControlController( ...@@ -434,4 +457,20 @@ class DefaultSessionControlController(
) )
navController.nav(R.id.homeFragment, directions) navController.nav(R.id.homeFragment, directions)
} }
override fun handleTorBootstrapConnectClicked() {
handleTorBootstrapConnect()
}
override fun handleTorBootstrapConnectingClicked() {
cancelTorBootstrap()
}
override fun handleTorStartBootstrapping() {
initiateTorBootstrap(false)
}
override fun handleTorStartDebugBootstrapping() {
initiateTorBootstrap(true)
}
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment