Commit ba46d6a8 authored by clairehurst's avatar clairehurst 🌱 Committed by Pier Angelo Vendrame
Browse files

[android] Implement Android-native Connection Assist UI

parent e363ef7d
Loading
Loading
Loading
Loading
+2 −12
Original line number Diff line number Diff line
@@ -76,12 +76,7 @@ class SearchUseCases(
            flags: EngineSession.LoadUrlFlags = EngineSession.LoadUrlFlags.none(),
            additionalHeaders: Map<String, String>? = null,
        ) {
            var securityLevel: Int
            try {
                securityLevel = settings?.torSecurityLevel ?: 0
            } catch (e: UnsupportedSettingException) {
                securityLevel = 0
            }
            val securityLevel : Int = settings!!.torSecurityLevel
            val searchUrl = searchEngine?.let {
                searchEngine.buildSearchUrl(searchTerms, securityLevel)
            } ?: store.state.search.selectedOrDefaultSearchEngine?.buildSearchUrl(searchTerms, securityLevel)
@@ -172,12 +167,7 @@ class SearchUseCases(
            flags: EngineSession.LoadUrlFlags = EngineSession.LoadUrlFlags.none(),
            additionalHeaders: Map<String, String>? = null,
        ) {
            var securityLevel: Int
            try {
                securityLevel = settings?.torSecurityLevel ?: 0
            } catch (e: UnsupportedSettingException) {
                securityLevel = 0
            }
            val securityLevel : Int = settings!!.torSecurityLevel
            val searchUrl = searchEngine?.let {
                searchEngine.buildSearchUrl(searchTerms, securityLevel)
            } ?: store.state.search.selectedOrDefaultSearchEngine?.buildSearchUrl(searchTerms, securityLevel)
+1 −0
Original line number Diff line number Diff line
@@ -44,4 +44,5 @@ enum class BrowserDirection(@IdRes val fragmentId: Int) {
    FromMenuDialogFragment(R.id.menuDialogFragment),
    FromWebCompatReporterFragment(R.id.webCompatReporterFragment),
    FromGleanDebugToolsFragment(R.id.gleanDebugToolsFragment),
    FromTorConnectionAssistFragment(R.id.torConnectionAssistFragment),
}
+86 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.view.ViewConfiguration
import android.view.ViewGroup
import android.view.WindowManager.LayoutParams.FLAG_SECURE
import androidx.activity.BackEventCompat
import androidx.activity.viewModels
import androidx.annotation.CallSuper
import androidx.annotation.IdRes
import androidx.annotation.RequiresApi
@@ -37,7 +38,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.core.app.NotificationManagerCompat
import androidx.core.net.toUri
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.content.ContentProviderCompat.requireContext
import androidx.core.text.layoutDirection
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
@@ -85,6 +85,7 @@ import mozilla.components.support.utils.BrowsersCache
import mozilla.components.support.utils.BuildManufacturerChecker
import mozilla.components.support.utils.SafeIntent
import mozilla.components.support.utils.TorUtils
import mozilla.components.support.utils.ext.getParcelableExtraCompat
import mozilla.components.support.utils.toSafeIntent
import mozilla.components.support.webextensions.WebExtensionPopupObserver
import mozilla.telemetry.glean.private.NoExtras
@@ -165,12 +166,23 @@ import org.mozilla.fenix.tabstray.TabsTrayFragment
import org.mozilla.fenix.theme.DefaultThemeManager
import org.mozilla.fenix.theme.StatusBarColorManager
import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.tor.TorConnectionAssistFragmentDirections
import org.mozilla.fenix.tor.TorEvents
import org.mozilla.fenix.utils.Settings
import org.mozilla.fenix.utils.changeAppLauncherIcon
import java.lang.ref.WeakReference
import java.util.Locale

import androidx.compose.material.SnackbarDuration
import mozilla.components.browser.engine.gecko.GeckoEngine
import org.mozilla.fenix.compose.core.Action
import org.mozilla.fenix.compose.snackbar.SnackbarState
import org.mozilla.fenix.compose.snackbar.Snackbar
import org.mozilla.fenix.tor.UrlQuickLoadViewModel
import org.mozilla.geckoview.TorAndroidIntegration
import org.mozilla.geckoview.TorConnectStage
import kotlin.system.exitProcess

/**
 * The main activity of the application. The application is primarily a single Activity (this one)
 * with fragments switching out to display different views. The most important views shown here are the:
@@ -178,7 +190,7 @@ import java.util.Locale
 * - browser screen
 */
@SuppressWarnings("TooManyFunctions", "LargeClass", "LongMethod")
open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorAndroidIntegration.BootstrapStateChangeListener {
    @VisibleForTesting
    internal lateinit var binding: ActivityHomeBinding
    lateinit var themeManager: ThemeManager
@@ -314,6 +326,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {

    private var dialog: RedirectDialogFragment? = null

    private val urlQuickLoadViewModel: UrlQuickLoadViewModel by viewModels()

    @Suppress("ComplexMethod")
    final override fun onCreate(savedInstanceState: Bundle?) {
        // DO NOT MOVE ANYTHING ABOVE THIS getProfilerTime CALL.
@@ -603,6 +617,14 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
            onBackPressedCallback = onBackPressedCallback,
        )

        if (settings().useHtmlConnectionUi) {
            val engine = components.core.engine
            if (engine is GeckoEngine) {
                val torIntegration = engine.getTorIntegrationController()
                torIntegration.registerBootstrapStateChangeListener(this)
            }
        }

        StartupTimeline.onActivityCreateEndHome(this) // DO NOT MOVE ANYTHING BELOW HERE.
    }

@@ -791,8 +813,10 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
    override fun onProvideAssistContent(outContent: AssistContent?) {
        super.onProvideAssistContent(outContent)
        val currentTabUrl = components.core.store.state.selectedTab?.content?.url
        if (components.core.store.state.selectedTab?.content?.private == false) {
            outContent?.webUri = currentTabUrl?.let { it.toUri() }
        }
    }

    @CallSuper
    override fun onDestroy() {
@@ -1294,6 +1318,30 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
        historyMetadata: HistoryMetadataKey? = null,
        additionalHeaders: Map<String, String>? = null,
    ) {
        if (!components.torController.isBootstrapped && !searchTermOrURL.startsWith("about:")) {
            Snackbar.make(
                snackBarParentView = binding.root,
                snackbarState = SnackbarState(
                    message = getString(R.string.connection_assist_connect_to_tor_before_opening_links),
                    duration = SnackbarState.Duration.Preset.Long,
                    action = Action(
                        label = getString(R.string.connection_assist_connect_to_tor_before_opening_links_confirmation),
                        onClick = {
                            urlQuickLoadViewModel.urlToLoadAfterConnecting.value = searchTermOrURL
                            urlQuickLoadViewModel.maybeBeginBootstrap()
                            if (navHost.navController.previousBackStackEntry?.destination?.id == R.id.torConnectionAssistFragment) {
                                supportFragmentManager.popBackStack()
                            } else {
                                navHost.navController.navigate(
                                    TorConnectionAssistFragmentDirections.actionConnectToTorBeforeOpeningLinks(),
                                )
                            }
                        },
                    ),
                ),
            ).show()
            return
        }
        openToBrowser(from, customTabSessionId)

        components.useCases.fenixBrowserUseCases.loadUrlOrSearch(
@@ -1337,7 +1385,16 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
        //     return
        // }

        navHost.navController.navigate(NavGraphDirections.actionStartupTorbootstrap())
        if (!settings().useHtmlConnectionUi) {
            navController.navigate(NavGraphDirections.actionStartupTorConnectionAssist())
        } else {
            navController.navigate(NavGraphDirections.actionStartupHome())
            openToBrowserAndLoad(
                searchTermOrURL = "about:torconnect",
                newTab = true,
                from = BrowserDirection.FromHome,
            )
        }
    }

    final override fun attachBaseContext(base: Context) {
@@ -1528,4 +1585,29 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
        // telemetry purposes.
        private const val PWA_RECENTLY_USED_THRESHOLD = DateUtils.DAY_IN_MILLIS * 30L
    }

    fun restartApplication() {
        startActivity(
            Intent(applicationContext, HomeActivity::class.java).addFlags(
                Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK,
            ),
        )
        shutDown()
    }

    fun shutDown() : Nothing {
        finishAndRemoveTask()
        exitProcess(0)
    }

    override fun onBootstrapStateChange(state: String) = Unit
    override fun onBootstrapStageChange(stage: TorConnectStage) = Unit
    override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) = Unit
    override fun onBootstrapComplete() {
        if (settings().useHtmlConnectionUi) {
            components.useCases.tabsUseCases.removeAllTabs()
            navHost.navController.navigate(NavGraphDirections.actionStartupHome())
        }
    }
    override fun onBootstrapError(code: String?, message: String?, phase: String?, reason: String?) = Unit
}
+22 −0
Original line number Diff line number Diff line
@@ -1865,6 +1865,10 @@ abstract class BaseBrowserFragment :
                resumeDownloadDialogState(selectedTab.id, context.components.core.store, context)
                @Suppress("DEPRECATION")
                it.announceForAccessibility(selectedTab.toDisplayTitle())
                if (getCurrentTab()?.content?.url == "about:torconnect") {
                    // FIXME: view is not available anymore.
                    // browserToolbarView.view.visibility = View.GONE
                }
            }
        } else {
            view?.let { view -> initializeUI(view) }
@@ -1889,6 +1893,24 @@ abstract class BaseBrowserFragment :
            true
        BiometricAuthenticationManager.biometricAuthenticationNeededInfo.authenticationStatus =
            AuthenticationStatus.NOT_AUTHENTICATED

        handleBetaHtmlTorConnect()
    }

    private fun handleBetaHtmlTorConnect() {
        val currentTab = getCurrentTab() ?: return
        if (currentTab.content.url == "about:torconnect") {
            if (!requireActivity().settings().useHtmlConnectionUi) {
                requireContext().components.useCases.tabsUseCases.removeTab(currentTab.id)
                (requireActivity() as HomeActivity).navigateToHome(findNavController())
            } else {
                // This just makes it not flash (be visible for a split second) before handleTabSelected() hides it again
                // FIXME: view is not available anymore.
                // browserToolbarView.view.visibility = View.GONE
            }
        } else if (currentTab.content.url == "about:tor") {
            requireContext().components.useCases.tabsUseCases.removeTab(currentTab.id)
        }
    }

    private fun evaluateMessagesForMicrosurvey(components: Components) =
+1 −0
Original line number Diff line number Diff line
@@ -160,6 +160,7 @@ class DefaultBrowserToolbarMenuController(
            }
            is ToolbarMenu.Item.Quit -> {
                deleteAndQuit(activity, activity.lifecycleScope)
                activity.shutDown()
            }
            is ToolbarMenu.Item.CustomizeReaderView -> {
                readerModeController.showControls()
Loading