improve intent handling
This commit is contained in:
@@ -108,16 +108,6 @@
|
||||
<action android:name="es.antonborri.home_widget.action.LAUNCH" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.WEB_SEARCH" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Intent router: receives external VIEW/SEND intents and routes
|
||||
@@ -170,6 +160,17 @@
|
||||
<data android:mimeType="text/*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.WEB_SEARCH" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- PWA launch from home screen shortcut -->
|
||||
<intent-filter>
|
||||
<action android:name="mozilla.components.feature.pwa.VIEW_PWA" />
|
||||
|
||||
+2
-1
@@ -344,7 +344,8 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit
|
||||
val appLinksUseCases = components.useCases.appLinksUseCases
|
||||
val getRedirect = appLinksUseCases.appLinkRedirect
|
||||
val redirect = getRedirect.invoke(fallbackUrl)
|
||||
redirect.appIntent?.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
redirect.appIntent?.flags =
|
||||
Intent.FLAG_ACTIVITY_NEW_DOCUMENT or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
|
||||
appLinksUseCases.openAppLink.invoke(redirect.appIntent)
|
||||
}
|
||||
},
|
||||
|
||||
+3
@@ -295,6 +295,9 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), UserInteractionHandler
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_TEXT, tab.content.url)
|
||||
putExtra(Intent.EXTRA_SUBJECT, tab.content.title)
|
||||
// Use NEW_DOCUMENT + MULTIPLE_TASK so the receiving app opens
|
||||
// in its own task rather than inside WebLibre's recents entry.
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_DOCUMENT or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
|
||||
}
|
||||
startActivity(Intent.createChooser(shareIntent, null))
|
||||
}
|
||||
|
||||
+94
-2
@@ -33,11 +33,12 @@ import mozilla.components.browser.state.state.ExternalAppType
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Lightweight transparent activity that receives all ACTION_VIEW intents and routes them
|
||||
* Lightweight transparent activity that receives all external intents and routes them
|
||||
* to the appropriate activity:
|
||||
* - Custom Tab intents → [ExternalAppBrowserActivity]
|
||||
* - PWA launch intents → [ExternalAppBrowserActivity] (with profile/context tracking)
|
||||
* - Regular VIEW intents → MainActivity (Flutter)
|
||||
* - SHARE intents with a URL → [ExternalAppBrowserActivity] (separate recents entry)
|
||||
* - Regular VIEW / SEND / PROCESS_TEXT / WEB_SEARCH intents → MainActivity (Flutter)
|
||||
*
|
||||
* For PWA intents created by our custom installer, checks profile match and shows dialog
|
||||
* if the current profile differs from the installation profile.
|
||||
@@ -135,6 +136,23 @@ class IntentReceiverActivity : Activity() {
|
||||
val privateBrowsingMode = intent.getBooleanExtra(PRIVATE_BROWSING_MODE, false)
|
||||
intent.putExtra(PRIVATE_BROWSING_MODE, privateBrowsingMode)
|
||||
|
||||
// SHARE intents with a URL are routed to ExternalAppBrowserActivity so they
|
||||
// appear as a separate recents entry ("share as new task"), matching the
|
||||
// behaviour users expect when sharing content into the browser. SEND intents
|
||||
// without a URL (plain text, files) fall through to MainActivity for the
|
||||
// Flutter-side to handle (search, PDF display, etc.).
|
||||
if (intent.action == Intent.ACTION_SEND) {
|
||||
val shareUrl = extractShareUrl(intent)
|
||||
if (shareUrl != null) {
|
||||
Log.d(TAG, "SHARE intent with URL, routing to custom tab: $shareUrl")
|
||||
handleShareUrlAsCustomTab(intent, shareUrl, privateBrowsingMode)
|
||||
return
|
||||
}
|
||||
Log.d(TAG, "SHARE intent without URL, routing to MainActivity")
|
||||
handleRegularIntent(intent)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if this is our custom PWA intent with profile metadata
|
||||
val profileUuid = intent.getStringExtra(PwaConstants.EXTRA_PWA_PROFILE_UUID)
|
||||
val contextId = intent.getStringExtra(PwaConstants.EXTRA_PWA_CONTEXT_ID)
|
||||
@@ -493,6 +511,80 @@ class IntentReceiverActivity : Activity() {
|
||||
return tab.id
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a URL from a SEND intent.
|
||||
* First checks EXTRA_TEXT for a URL, then EXTRA_STREAM.
|
||||
* Returns null if no valid URL is found.
|
||||
*/
|
||||
private fun extractShareUrl(intent: Intent): String? {
|
||||
fun String?.toHttpUrl(): String? {
|
||||
val candidate = this?.trim().orEmpty()
|
||||
return candidate.takeIf {
|
||||
it.startsWith("http://") || it.startsWith("https://")
|
||||
}
|
||||
}
|
||||
|
||||
intent.getStringExtra(Intent.EXTRA_TEXT)?.toHttpUrl()?.let { return it }
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val streamUri: Uri? = intent.getParcelableExtra(Intent.EXTRA_STREAM)
|
||||
streamUri?.toString().toHttpUrl()?.let { return it }
|
||||
|
||||
intent.dataString.toHttpUrl()?.let { return it }
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a custom tab session for the shared URL and launches
|
||||
* [ExternalAppBrowserActivity], which appears as a separate recents entry
|
||||
* because it uses taskAffinity="" and documentLaunchMode="always".
|
||||
*/
|
||||
private fun handleShareUrlAsCustomTab(
|
||||
sourceIntent: Intent,
|
||||
url: String,
|
||||
privateBrowsingMode: Boolean,
|
||||
) {
|
||||
var components = GlobalComponents.components
|
||||
if (components == null) {
|
||||
if (!GlobalComponents.ensureExternalComponents(applicationContext)) {
|
||||
Log.w(TAG, "Components not initialized, falling back to MainActivity for SHARE")
|
||||
handleRegularIntent(sourceIntent)
|
||||
return
|
||||
}
|
||||
components = GlobalComponents.components
|
||||
}
|
||||
|
||||
if (components == null) {
|
||||
Log.e(TAG, "Components still null after init, falling back to MainActivity for SHARE")
|
||||
handleRegularIntent(sourceIntent)
|
||||
return
|
||||
}
|
||||
|
||||
val customTabConfig = mozilla.components.browser.state.state.CustomTabConfig()
|
||||
|
||||
val tab = mozilla.components.browser.state.state.createCustomTab(
|
||||
url = url,
|
||||
config = customTabConfig,
|
||||
source = mozilla.components.browser.state.state.SessionState.Source.Internal.CustomTab,
|
||||
private = privateBrowsingMode,
|
||||
)
|
||||
|
||||
components.core.store.dispatch(
|
||||
mozilla.components.browser.state.action.CustomTabListAction.AddCustomTabAction(tab)
|
||||
)
|
||||
|
||||
val loadUrlFlags = mozilla.components.concept.engine.EngineSession.LoadUrlFlags.external()
|
||||
components.useCases.sessionUseCases.loadUrl(url, tab.id, loadUrlFlags)
|
||||
|
||||
val externalIntent = ExternalAppBrowserActivity.createIntent(
|
||||
context = this,
|
||||
customTabSessionId = tab.id,
|
||||
)
|
||||
startActivity(externalIntent)
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun handleRegularIntent(intent: Intent) {
|
||||
val mainActivityIntent = Intent(intent).apply {
|
||||
setClassName(this@IntentReceiverActivity, "eu.weblibre.gecko.MainActivity")
|
||||
|
||||
+5
-3
@@ -54,9 +54,11 @@ class GeckoAppLinksApiImpl(
|
||||
return@launch
|
||||
}
|
||||
|
||||
// Set FLAG_ACTIVITY_NEW_TASK to launch in new task
|
||||
// This prevents issues with app task stacks
|
||||
redirect.appIntent?.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
// Use NEW_DOCUMENT + MULTIPLE_TASK so the target app opens in its own
|
||||
// task and doesn't get absorbed into WebLibre's recents entry.
|
||||
// This matches Fenix's ShareController behaviour.
|
||||
redirect.appIntent?.flags =
|
||||
Intent.FLAG_ACTIVITY_NEW_DOCUMENT or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
|
||||
|
||||
components.useCases.appLinksUseCases.openAppLink.invoke(redirect.appIntent)
|
||||
callback(Result.success(true))
|
||||
|
||||
Reference in New Issue
Block a user