Skip to content
Snippets Groups Projects
Commit 50faa535 authored by Alex Catarineu's avatar Alex Catarineu Committed by Beatriz Rizental
Browse files

TB 34378: [android] Port external helper app prompting

Together with the corresponding fenix patch, this allows all `startActivity`
that may open external apps to be replaced by `TorUtils.startActivityPrompt`.

Originally, android-components#40007 and fenix#34378.
parent 90b6d9fa
Branches
Tags
1 merge request!1527Bug 43808: Rebase 128.10.1 onto 128.11
Showing
with 93 additions and 14 deletions
......@@ -46,6 +46,7 @@ dependencies {
implementation project(':ui-widgets')
implementation ComponentsDependencies.kotlin_coroutines
implementation project(path: ':support-utils')
testImplementation project(':support-test')
testImplementation project(':support-test-libstate')
......
......
......@@ -108,7 +108,7 @@ class AppLinksFeature(
}
@Suppress("ComplexCondition")
if (isSameCallerAndApp(tab, appIntent) || (!tab.content.private && !shouldPrompt()) ||
if (isSameCallerAndApp(tab, appIntent) || (true || !tab.content.private && !shouldPrompt()) ||
fragmentManager == null
) {
doOpenApp()
......
......
......@@ -26,6 +26,7 @@ import java.lang.Exception
import java.lang.NullPointerException
import java.lang.NumberFormatException
import java.net.URISyntaxException
import mozilla.components.support.utils.TorUtils
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal const val EXTRA_BROWSER_FALLBACK_URL = "browser_fallback_url"
......@@ -232,7 +233,7 @@ class AppLinksUseCases(
if (launchInNewTask) {
it.flags = it.flags or Intent.FLAG_ACTIVITY_NEW_TASK
}
context.startActivity(it)
TorUtils.startActivityPrompt(context, it)
} catch (e: Exception) {
when (e) {
is ActivityNotFoundException, is SecurityException, is NullPointerException -> {
......
......
......@@ -26,6 +26,7 @@ import mozilla.components.support.ktx.kotlin.stripMailToProtocol
import mozilla.components.support.ktx.kotlin.takeOrReplace
import mozilla.components.ui.widgets.DefaultSnackbarDelegate
import mozilla.components.ui.widgets.SnackbarDelegate
import mozilla.components.support.utils.TorUtils
/**
* A candidate for an item to be displayed in the context menu.
......@@ -491,7 +492,8 @@ data class ContextMenuCandidate(
flags = Intent.FLAG_ACTIVITY_NEW_TASK
putExtra(Intent.EXTRA_TEXT, hitResult.getLink())
}
context.startActivity(
TorUtils.startActivityPrompt(
context,
intent.createChooserExcludingCurrentApp(
context,
context.getString(R.string.mozac_feature_contextmenu_share_link),
......
......
......@@ -77,6 +77,7 @@ import mozilla.components.support.ktx.kotlinx.coroutines.throttleLatest
import mozilla.components.support.utils.DownloadUtils
import mozilla.components.support.utils.ext.registerReceiverCompat
import mozilla.components.support.utils.ext.stopForegroundCompat
import mozilla.components.support.utils.TorUtils
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
......@@ -984,7 +985,7 @@ abstract class AbstractFetchDownloadService : Service() {
val newIntent = createOpenFileIntent(applicationContext, download)
return try {
applicationContext.startActivity(newIntent)
TorUtils.startActivityPrompt(applicationContext, newIntent)
true
} catch (error: ActivityNotFoundException) {
false
......
......
......@@ -41,6 +41,7 @@ import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.ktx.R
import mozilla.components.support.ktx.android.content.res.resolveAttribute
import mozilla.components.support.utils.ext.getPackageInfoCompat
import mozilla.components.support.utils.TorUtils
import java.io.File
/**
......@@ -109,12 +110,11 @@ fun Context.share(text: String, subject: String = getString(R.string.mozac_suppo
flags = FLAG_ACTIVITY_NEW_TASK
}
startActivity(
intent.createChooserExcludingCurrentApp(
this,
getString(R.string.mozac_support_ktx_menu_share_with),
),
)
val shareIntent = intent.createChooserExcludingCurrentApp(this, getString(R.string.mozac_support_ktx_menu_share_with)).apply {
flags = FLAG_ACTIVITY_NEW_TASK
}
TorUtils.startActivityPrompt(this, shareIntent)
true
} catch (e: ActivityNotFoundException) {
Log.log(Log.Priority.WARN, message = "No activity to share to found", throwable = e, tag = "Reference-Browser")
......@@ -221,7 +221,7 @@ fun Context.email(
flags = FLAG_ACTIVITY_NEW_TASK
}
startActivity(emailIntent)
TorUtils.startActivityPrompt(this, emailIntent)
true
} catch (e: ActivityNotFoundException) {
Logger.warn("No activity found to handle email intent", throwable = e)
......@@ -252,7 +252,7 @@ fun Context.call(
flags = FLAG_ACTIVITY_NEW_TASK
}
startActivity(callIntent)
TorUtils.startActivityPrompt(this, callIntent)
true
} catch (e: ActivityNotFoundException) {
Logger.warn("No activity found to handle dial intent", throwable = e)
......@@ -280,7 +280,7 @@ fun Context.addContact(
addFlags(FLAG_ACTIVITY_NEW_TASK)
}
startActivity(intent)
TorUtils.startActivityPrompt(this, intent)
true
} catch (e: ActivityNotFoundException) {
Logger.warn("No activity found to handle dial intent", throwable = e)
......
......
/* 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 mozilla.components.support.utils
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import mozilla.components.support.utils.PendingIntentUtils
object TorUtils {
const val TORBROWSER_START_ACTIVITY_PROMPT = "torbrowser_start_activity_prompt"
// Delegates showing prompt and possibly starting the activity to the main app activity.
// Highly dependant on Fenix/Tor Browser for Android.
// One downside of this implementation is that it does not throw exceptions like the
// direct context.startActivity, so the UI will behave as if the startActivity call was
// done successfully, which may not always be the case.
fun startActivityPrompt(context: Context, intent: Intent) {
val intentContainer = Intent()
intentContainer.setPackage(context.applicationContext.packageName)
intentContainer.putExtra(TORBROWSER_START_ACTIVITY_PROMPT, PendingIntent.getActivity(context, 0, intent, PendingIntentUtils.defaultFlags))
intentContainer.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(intentContainer)
}
}
......@@ -5,6 +5,7 @@
package org.mozilla.fenix
import android.app.assist.AssistContent
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_MAIN
......@@ -56,6 +57,8 @@ import mozilla.components.browser.state.state.WebExtensionState
import mozilla.components.concept.engine.EngineSession
import mozilla.components.concept.engine.EngineView
import mozilla.components.concept.storage.HistoryMetadataKey
import mozilla.components.feature.app.links.RedirectDialogFragment
import mozilla.components.feature.app.links.SimpleRedirectDialogFragment
import mozilla.components.feature.contextmenu.DefaultSelectionActionDelegate
import mozilla.components.feature.media.ext.findActiveMediaTab
import mozilla.components.feature.privatemode.notification.PrivateNotificationFeature
......@@ -75,6 +78,7 @@ import mozilla.components.support.utils.BootUtils
import mozilla.components.support.utils.BrowsersCache
import mozilla.components.support.utils.ManufacturerCodes
import mozilla.components.support.utils.SafeIntent
import mozilla.components.support.utils.TorUtils
import mozilla.components.support.utils.toSafeIntent
import mozilla.components.support.webextensions.WebExtensionPopupObserver
import mozilla.telemetry.glean.private.NoExtras
......@@ -220,6 +224,8 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
private val startupPathProvider = StartupPathProvider()
private lateinit var startupTypeTelemetry: StartupTypeTelemetry
private var dialog: RedirectDialogFragment? = null
@Suppress("ComplexMethod")
final override fun onCreate(savedInstanceState: Bundle?) {
// DO NOT MOVE ANYTHING ABOVE THIS getProfilerTime CALL.
......@@ -642,6 +648,26 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
super.recreate()
}
// Copied from mozac AppLinksFeature.kt
internal fun getOrCreateDialog(): RedirectDialogFragment {
val existingDialog = dialog
if (existingDialog != null) {
return existingDialog
}
SimpleRedirectDialogFragment.newInstance().also {
dialog = it
return it
}
}
private fun isAlreadyADialogCreated(): Boolean {
return findPreviousDialogFragment() != null
}
private fun findPreviousDialogFragment(): RedirectDialogFragment? {
return supportFragmentManager.findFragmentByTag(RedirectDialogFragment.FRAGMENT_TAG) as? RedirectDialogFragment
}
/**
* Handles intents received when the activity is open.
*/
......@@ -659,6 +685,26 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
return
}
val startIntent = intent.getParcelableExtraCompat(TorUtils.TORBROWSER_START_ACTIVITY_PROMPT, PendingIntent::class.java)
if (startIntent != null) {
if (startIntent.creatorPackage == applicationContext.packageName) {
val dialog = getOrCreateDialog()
dialog.onConfirmRedirect = {
@Suppress("EmptyCatchBlock")
try {
startIntent.send()
} catch (error: PendingIntent.CanceledException) {
}
}
dialog.onCancelRedirect = {}
if (!isAlreadyADialogCreated()) {
dialog.showNow(supportFragmentManager, RedirectDialogFragment.FRAGMENT_TAG)
}
}
return
}
// Diagnostic breadcrumb for "Display already aquired" crash:
// https://github.com/mozilla-mobile/android-components/issues/7960
breadcrumb(
......
......
......@@ -36,6 +36,7 @@ import mozilla.components.service.glean.private.NoExtras
import mozilla.components.support.ktx.kotlin.isExtensionUrl
import org.mozilla.fenix.GleanMetrics.Events
import org.mozilla.fenix.GleanMetrics.SyncAccount
import mozilla.components.support.utils.TorUtils
import org.mozilla.fenix.R
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.accounts.FenixFxAEntryPoint
......@@ -140,7 +141,7 @@ class DefaultShareController(
@Suppress("TooGenericExceptionCaught")
val result = try {
context.startActivity(intent)
TorUtils.startActivityPrompt(context, intent)
ShareController.Result.SUCCESS
} catch (e: Exception) {
when (e) {
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment