From 72fcb6121fd94f0e8ce92030f91819f0de5e01f0 Mon Sep 17 00:00:00 2001 From: rahulsainani Date: Mon, 24 Apr 2023 13:33:58 +0200 Subject: [PATCH] Bug 1829619 - Fix external ActivityNotFoundException for default browser settings (cherry picked from commit 825b3aafeccdbfd6306521b68bb405f68f45d287) --- .../java/org/mozilla/fenix/ext/Activity.kt | 96 +++++++++++++------ .../intent/HomeDeepLinkIntentProcessorTest.kt | 12 --- 2 files changed, 68 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/ext/Activity.kt b/app/src/main/java/org/mozilla/fenix/ext/Activity.kt index 6562b31628..6626f36b5c 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/Activity.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/Activity.kt @@ -12,6 +12,7 @@ import android.provider.Settings import android.view.View import android.view.WindowManager import androidx.annotation.DrawableRes +import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity import androidx.core.os.bundleOf import mozilla.components.concept.base.crash.Breadcrumb @@ -88,48 +89,87 @@ fun Activity.openSetDefaultBrowserOption( REQUEST_CODE_BROWSER_ROLE, ) } else { - navigateToDefaultBrowserAppsSettings() + navigateToDefaultBrowserAppsSettings( + useCustomTab = useCustomTab, + from = from, + flags = flags, + ) } } } Build.VERSION.SDK_INT >= Build.VERSION_CODES.N -> { - navigateToDefaultBrowserAppsSettings() + navigateToDefaultBrowserAppsSettings( + useCustomTab = useCustomTab, + from = from, + flags = flags, + ) } else -> { - val sumoDefaultBrowserUrl = SupportUtils.getGenericSumoURLForTopic( - topic = SupportUtils.SumoTopic.SET_AS_DEFAULT_BROWSER, - ) - if (useCustomTab) { - startActivity( - SupportUtils.createSandboxCustomTabIntent( - context = this, - url = sumoDefaultBrowserUrl, - ), - ) - } else { - (this as HomeActivity).openToBrowserAndLoad( - searchTermOrURL = sumoDefaultBrowserUrl, - newTab = true, - from = from, - flags = flags, - ) - } + openDefaultBrowserSumoPage(useCustomTab, from, flags) } } } -private fun Activity.navigateToDefaultBrowserAppsSettings() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - val intent = Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) - intent.putExtra( - SETTINGS_SELECT_OPTION_KEY, - DEFAULT_BROWSER_APP_OPTION, - ) - intent.putExtra( +@RequiresApi(Build.VERSION_CODES.N) +private fun Activity.navigateToDefaultBrowserAppsSettings( + from: BrowserDirection, + flags: EngineSession.LoadUrlFlags, + useCustomTab: Boolean, +) { + val intent = Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS).apply { + putExtra(SETTINGS_SELECT_OPTION_KEY, DEFAULT_BROWSER_APP_OPTION) + putExtra( SETTINGS_SHOW_FRAGMENT_ARGS, bundleOf(SETTINGS_SELECT_OPTION_KEY to DEFAULT_BROWSER_APP_OPTION), ) + } + startExternalActivitySafe( + intent = intent, + onActivityNotPresent = { + openDefaultBrowserSumoPage(useCustomTab = useCustomTab, from = from, flags = flags) + }, + ) +} + +private fun Activity.openDefaultBrowserSumoPage( + useCustomTab: Boolean, + from: BrowserDirection, + flags: EngineSession.LoadUrlFlags, +) { + val sumoDefaultBrowserUrl = SupportUtils.getGenericSumoURLForTopic( + topic = SupportUtils.SumoTopic.SET_AS_DEFAULT_BROWSER, + ) + if (useCustomTab) { + startActivity( + SupportUtils.createSandboxCustomTabIntent( + context = this, + url = sumoDefaultBrowserUrl, + ), + ) + } else { + (this as HomeActivity).openToBrowserAndLoad( + searchTermOrURL = sumoDefaultBrowserUrl, + newTab = true, + from = from, + flags = flags, + ) + } +} + +/** + * Checks for the presence of an activity before starting it. In case it's not present, + * [onActivityNotPresent] is invoked, preventing ActivityNotFoundException from being thrown. + * This is useful when navigating to external activities like device permission settings, + * notification settings, default app settings, etc. + * + * @param intent The Intent of the activity to resolve and start. + * @param onActivityNotPresent Invoked when the activity to handle the intent is not present. + */ +inline fun Activity.startExternalActivitySafe(intent: Intent, onActivityNotPresent: () -> Unit) { + if (intent.resolveActivity(packageManager) != null) { startActivity(intent) + } else { + onActivityNotPresent() } } diff --git a/app/src/test/java/org/mozilla/fenix/home/intent/HomeDeepLinkIntentProcessorTest.kt b/app/src/test/java/org/mozilla/fenix/home/intent/HomeDeepLinkIntentProcessorTest.kt index 3387a8ea24..d77e6d5027 100644 --- a/app/src/test/java/org/mozilla/fenix/home/intent/HomeDeepLinkIntentProcessorTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/intent/HomeDeepLinkIntentProcessorTest.kt @@ -8,8 +8,6 @@ import android.content.Intent import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.os.Build.VERSION_CODES.M -import android.os.Build.VERSION_CODES.N -import android.os.Build.VERSION_CODES.P import androidx.core.net.toUri import androidx.navigation.NavController import io.mockk.Called @@ -238,16 +236,6 @@ class HomeDeepLinkIntentProcessorTest { verify { out wasNot Called } } - @Test - @Config(minSdk = N, maxSdk = P) - fun `process make_default_browser deep link for above API 23`() { - assertTrue(processorHome.process(testIntent("make_default_browser"), navController, out)) - - verify { activity.startActivity(any()) } - verify { navController wasNot Called } - verify { out wasNot Called } - } - @Test @Config(maxSdk = M) fun `process make_default_browser deep link for API 23 and below`() {