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

[android] Implement Android-native Connection Assist UI

parent 75314fc9
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)
+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
@@ -45,4 +45,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
@@ -85,6 +86,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
@@ -172,13 +174,23 @@ import org.mozilla.fenix.tabhistory.TabHistoryDialogFragment
import org.mozilla.fenix.theme.DefaultThemeManager
import org.mozilla.fenix.theme.StatusBarColorManager
import org.mozilla.fenix.theme.ThemeManager
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:
@@ -377,6 +389,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {

    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.
@@ -825,8 +839,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() {
@@ -859,6 +875,16 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
            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,
@@ -923,15 +949,21 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
            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
        }
    }
@@ -1323,6 +1355,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(
@@ -1362,11 +1418,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {

    @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) {
@@ -1559,4 +1611,19 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {

        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)
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import org.mozilla.fenix.GleanMetrics.Events
import org.mozilla.fenix.GleanMetrics.ReaderMode
import org.mozilla.fenix.GleanMetrics.Toolbar
import org.mozilla.fenix.GleanMetrics.Translations
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserFragmentDirections
@@ -164,6 +165,7 @@ class DefaultBrowserToolbarMenuController(
            }
            is ToolbarMenu.Item.Quit -> {
                deleteAndQuit(fragment.requireActivity())
                (fragment.requireActivity() as HomeActivity).shutDown()
            }
            is ToolbarMenu.Item.CustomizeReaderView -> {
                readerModeController.showControls()
Loading