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

[android] Implement Android-native Connection Assist UI

parent 0dc757c4
Loading
Loading
Loading
Loading
+2 −12
Original line number Diff line number Diff line
@@ -81,12 +81,7 @@ class SearchUseCases(
                store.state.findTab(it)?.content?.private
            } ?: false
            val resolvedEngine = searchEngine ?: store.state.search.selectedOrDefaultSearchEngine(isTabPrivate)
            var securityLevel: Int
            try {
                securityLevel = settings?.torSecurityLevel ?: 0
            } catch (e: UnsupportedSettingException) {
                securityLevel = 0
            }
            val securityLevel : Int = settings!!.torSecurityLevel
            val searchUrl = resolvedEngine?.buildSearchUrl(searchTerms, securityLevel)

            if (searchUrl == null) {
@@ -176,12 +171,7 @@ class SearchUseCases(
            additionalHeaders: Map<String, String>? = null,
        ) {
            val resolvedEngine = searchEngine ?: store.state.search.selectedOrDefaultSearchEngine(isPrivate)
            var securityLevel: Int
            try {
                securityLevel = settings?.torSecurityLevel ?: 0
            } catch (e: UnsupportedSettingException) {
                securityLevel = 0
            }
            val securityLevel : Int = settings!!.torSecurityLevel
            val searchUrl = resolvedEngine?.buildSearchUrl(searchTerms, securityLevel)

            if (searchUrl == null) {
+9 −0
Original line number Diff line number Diff line
@@ -33,6 +33,15 @@ class NotificationsDelegate(
    var isRequestingPermission: Boolean = false
        private set

    /**
     * Defaults to true, normal behavior is to destroy the app when OnDestroy is called with isFinishing set to true
     *
     * A value of false indicates that the notification was just swiped away and the app should not shut down on it's behalf
     *
     * Workaround to make swiping the notification away not shutdown the app
     */
    var shouldShutDownWithOnDestroyWhenIsFinishing: Boolean = true

    @VisibleForTesting
    internal var permissionRequestsCount: Int = 0

+1 −0
Original line number Diff line number Diff line
@@ -44,4 +44,5 @@ enum class BrowserDirection(
    FromMenuDialogFragment(R.id.menuDialogFragment),
    FromWebCompatReporterFragment(R.id.webCompatReporterFragment),
    FromGleanDebugToolsFragment(R.id.gleanDebugToolsFragment),
    FromTorConnectionAssistFragment(R.id.torConnectionAssistFragment),
}
+82 −15
Original line number Diff line number Diff line
@@ -28,6 +28,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.VisibleForTesting
@@ -88,6 +89,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
@@ -187,13 +189,23 @@ import org.mozilla.fenix.theme.StatusBarColorManager
import org.mozilla.fenix.theme.ThemeManager
import org.mozilla.fenix.translations.TranslationsAIControllableFeatureRegistrar
import org.mozilla.fenix.translations.TranslationsEnabledSettings
import org.mozilla.fenix.tor.TorEvents
import org.mozilla.fenix.tor.TorConnectionAssistFragmentDirections
import org.mozilla.fenix.utils.AccessibilityUtils.announcePrivateModeForAccessibility
import org.mozilla.fenix.utils.Settings
import org.mozilla.fenix.utils.changeAppLauncherIcon
import java.util.Locale
import mozilla.components.ui.icons.R as iconsR

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.TorController
import org.mozilla.fenix.tor.UrlQuickLoadViewModel
import org.mozilla.geckoview.TorAndroidIntegration.BootstrapStateChangeListener
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:
@@ -432,6 +444,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash

    private var dialog: RedirectDialogFragment? = null

    private val urlQuickLoadViewModel: UrlQuickLoadViewModel by viewModels()

    @Suppress("CognitiveComplexMethod", "CyclomaticComplexMethod")
    final override fun onCreate(savedInstanceState: Bundle?) {
        // DO NOT MOVE ANYTHING ABOVE THIS getProfilerTime CALL.
@@ -881,8 +895,10 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash
    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() {
@@ -914,6 +930,16 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash
            stopMediaSession()
        }

        if (applicationContext.components.notificationsDelegate.shouldShutDownWithOnDestroyWhenIsFinishing) {
            if (isFinishing) {
                shutDown()
            }
        } else {
            // We only want to not shut down when the notification is swiped away,
            // if we do not reset this value
            applicationContext.components.notificationsDelegate.shouldShutDownWithOnDestroyWhenIsFinishing = true
        }

        components.core.engine.profiler?.addMarker(
            MarkersActivityLifecycleCallbacks.MARKER_NAME,
            startTimeProfiler,
@@ -978,15 +1004,21 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash
            onNewIntentInternal(intent)
        } else {
            // Wait until Tor is connected to handle intents from external apps for links, search, etc.
            components.torController.registerTorListener(object : TorEvents {
                override fun onTorConnected() {
                    components.torController.unregisterTorListener(this)
            val torIntegration = (components.core.engine as GeckoEngine).getTorIntegrationController()
            torIntegration.registerBootstrapStateChangeListener(
                object : BootstrapStateChangeListener {

                    override fun onBootstrapStageChange(stage: TorConnectStage) {
                        if (stage.isBootstrapped) {
                            torIntegration.unregisterBootstrapStateChangeListener(this)
                            onNewIntentInternal(intent)
                        }
                override fun onTorConnecting() { /* no-op */ }
                override fun onTorStopped() { /* no-op */ }
                override fun onTorStatusUpdate(entry: String?, status: String?, progress: Double?) { /* no-op */ }
            })
                    }

                    override fun onBootstrapProgress(progress: Double, hasWarnings: Boolean) {}
                }
            )

            return
        }
    }
@@ -1428,6 +1460,30 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash
        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(
@@ -1467,11 +1523,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash

    @VisibleForTesting
    internal fun navigateToHome(navController: NavController) {
        // if (this is ExternalAppBrowserActivity) {
        //     return
        // }

        navController.navigate(NavGraphDirections.actionStartupTorbootstrap())
        navController.navigate(NavGraphDirections.actionStartupTorConnectionAssist())
    }

    final override fun attachBaseContext(base: Context) {
@@ -1665,4 +1717,19 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, Crash

        private const val REQUEST_CODE_CAMERA_PERMISSIONS = 1
    }

    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()
        components.torController.shutdown()
        exitProcess(0)
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import org.mozilla.fenix.settings.studies.StudiesFragmentDirections
import org.mozilla.fenix.settings.wallpaper.WallpaperSettingsFragmentDirections
import org.mozilla.fenix.share.AddNewDeviceFragmentDirections
import org.mozilla.fenix.tabstray.ui.TabManagementFragmentDirections
import org.mozilla.fenix.tor.TorConnectionAssistFragmentDirections
import org.mozilla.fenix.trackingprotection.TrackingProtectionPanelDialogFragmentDirections
import org.mozilla.fenix.translations.TranslationsDialogFragmentDirections
import org.mozilla.fenix.translations.preferences.downloadlanguages.DownloadLanguagesPreferenceFragmentDirections
@@ -342,6 +343,9 @@ private fun getHomeNavDirections(

    BrowserDirection.FromWebCompatReporterFragment ->
        WebCompatReporterFragmentDirections.actionGlobalBrowser()

    BrowserDirection.FromTorConnectionAssistFragment ->
        TorConnectionAssistFragmentDirections.actionGlobalBrowser()
}

const val REQUEST_CODE_BROWSER_ROLE = 1
Loading