From d2757cf67e8a800f29ed4d38bea5b5e5683cd29d Mon Sep 17 00:00:00 2001 From: t-p-white Date: Thu, 28 Mar 2024 11:18:30 +0000 Subject: [PATCH] Bug 1886792 - Handle install_search_widget deeplink r=android-reviewers,amejiamarmol Differential Revision: https://phabricator.services.mozilla.com/D205477 --- .../intent/HomeDeepLinkIntentProcessor.kt | 7 ++++ .../fenix/onboarding/OnboardingFragment.kt | 24 +++---------- .../fenix/utils/AddSearchWidgetPrompt.kt | 35 +++++++++++++++++++ .../intent/HomeDeepLinkIntentProcessorTest.kt | 23 +++++++++--- 4 files changed, 65 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/utils/AddSearchWidgetPrompt.kt diff --git a/app/src/main/java/org/mozilla/fenix/home/intent/HomeDeepLinkIntentProcessor.kt b/app/src/main/java/org/mozilla/fenix/home/intent/HomeDeepLinkIntentProcessor.kt index 8900a0a9d..85a854be3 100644 --- a/app/src/main/java/org/mozilla/fenix/home/intent/HomeDeepLinkIntentProcessor.kt +++ b/app/src/main/java/org/mozilla/fenix/home/intent/HomeDeepLinkIntentProcessor.kt @@ -4,6 +4,7 @@ package org.mozilla.fenix.home.intent +import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri @@ -20,12 +21,14 @@ import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.ext.alreadyOnDestination import org.mozilla.fenix.ext.openSetDefaultBrowserOption +import org.mozilla.fenix.utils.showAddSearchWidgetPrompt /** * Deep links in the form of `fenix://host` open different parts of the app. */ class HomeDeepLinkIntentProcessor( private val activity: HomeActivity, + private val showAddSearchWidgetPrompt: (Activity) -> Unit = ::showAddSearchWidgetPrompt, ) : HomeIntentProcessor { private val logger = Logger("DeepLinkIntentProcessor") @@ -102,6 +105,10 @@ class HomeDeepLinkIntentProcessor( val intent = notificationSettings(activity) activity.startActivity(intent) } + "install_search_widget" -> { + showAddSearchWidgetPrompt(activity) + return + } } } diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingFragment.kt b/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingFragment.kt index 97d87682e..487e46b7d 100644 --- a/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingFragment.kt @@ -5,8 +5,6 @@ package org.mozilla.fenix.onboarding import android.annotation.SuppressLint -import android.appwidget.AppWidgetManager -import android.content.ComponentName import android.content.Context import android.content.IntentFilter import android.content.pm.ActivityInfo @@ -43,7 +41,8 @@ import org.mozilla.fenix.onboarding.view.telemetrySequenceId import org.mozilla.fenix.onboarding.view.toPageUiData import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.theme.FirefoxTheme -import org.mozilla.gecko.search.SearchWidgetProvider +import org.mozilla.fenix.utils.canShowAddSearchWidgetPrompt +import org.mozilla.fenix.utils.showAddSearchWidgetPrompt /** * Fragment displaying the onboarding flow. @@ -54,7 +53,7 @@ class OnboardingFragment : Fragment() { pagesToDisplay( isNotDefaultBrowser(requireContext()), canShowNotificationPage(requireContext()), - canShowAddWidgetCard(), + canShowAddSearchWidgetPrompt(), ) } private val telemetryRecorder by lazy { OnboardingTelemetryRecorder() } @@ -162,7 +161,7 @@ class OnboardingFragment : Fragment() { pagesToDisplay.telemetrySequenceId(), pagesToDisplay.sequencePosition(OnboardingPageUiData.Type.ADD_SEARCH_WIDGET), ) - showAddSearchWidgetDialog() + showAddSearchWidgetPrompt(requireActivity()) }, onSkipFirefoxWidgetClick = { telemetryRecorder.onSkipAddWidgetClick( @@ -183,19 +182,6 @@ class OnboardingFragment : Fragment() { ) } - private fun showAddSearchWidgetDialog() { - // Requesting to pin app widget is only available for Android 8.0 and above - if (canShowAddWidgetCard()) { - val appWidgetManager = AppWidgetManager.getInstance(activity) - val searchWidgetProvider = - ComponentName(requireActivity(), SearchWidgetProvider::class.java) - if (appWidgetManager.isRequestPinAppWidgetSupported) { - val successCallback = WidgetPinnedReceiver.getPendingIntent(requireContext()) - appWidgetManager.requestPinAppWidget(searchWidgetProvider, null, successCallback) - } - } - } - private fun onFinish(onboardingPageUiData: OnboardingPageUiData?) { /* onboarding page UI data can be null if there was no pages to display */ if (onboardingPageUiData != null) { @@ -222,8 +208,6 @@ class OnboardingFragment : Fragment() { !NotificationManagerCompat.from(context.applicationContext) .areNotificationsEnabledSafe() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU - private fun canShowAddWidgetCard() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O - private fun isNotATablet() = !resources.getBoolean(R.bool.tablet) private fun pagesToDisplay( diff --git a/app/src/main/java/org/mozilla/fenix/utils/AddSearchWidgetPrompt.kt b/app/src/main/java/org/mozilla/fenix/utils/AddSearchWidgetPrompt.kt new file mode 100644 index 000000000..a3eafbc73 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/utils/AddSearchWidgetPrompt.kt @@ -0,0 +1,35 @@ +/* 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 org.mozilla.fenix.utils + +import android.app.Activity +import android.appwidget.AppWidgetManager +import android.content.ComponentName +import android.os.Build +import org.mozilla.fenix.onboarding.WidgetPinnedReceiver +import org.mozilla.gecko.search.SearchWidgetProvider + +/** + * Displays the "add search widget" prompt for capable devices. + * + * @param activity the parent [Activity]. + */ +fun showAddSearchWidgetPrompt(activity: Activity) { + // Requesting to pin app widget is only available for Android 8.0 and above + if (canShowAddSearchWidgetPrompt()) { + val appWidgetManager = AppWidgetManager.getInstance(activity) + val searchWidgetProvider = + ComponentName(activity, SearchWidgetProvider::class.java) + if (appWidgetManager.isRequestPinAppWidgetSupported) { + val successCallback = WidgetPinnedReceiver.getPendingIntent(activity) + appWidgetManager.requestPinAppWidget(searchWidgetProvider, null, successCallback) + } + } +} + +/** + * Checks whether the device is capable of displaying the "add search widget" prompt. + */ +fun canShowAddSearchWidgetPrompt() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O 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 d3be5f12d..1827f5eb1 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 @@ -4,6 +4,7 @@ package org.mozilla.fenix.home.intent +import android.app.Activity import android.content.Intent import android.content.pm.PackageInfo import android.content.pm.PackageManager @@ -43,7 +44,7 @@ class HomeDeepLinkIntentProcessorTest { activity = mockk(relaxed = true) navController = mockk(relaxed = true) out = mockk() - processorHome = HomeDeepLinkIntentProcessor(activity) + processorHome = HomeDeepLinkIntentProcessor(activity, ::showAddSearchWidgetPrompt) } @Test @@ -257,9 +258,10 @@ class HomeDeepLinkIntentProcessorTest { assertTrue(processorHome.process(testIntent("make_default_browser"), navController, out)) - val searchTermOrURL = SupportUtils.getGenericSumoURLForTopic( - topic = SupportUtils.SumoTopic.SET_AS_DEFAULT_BROWSER, - ) + val searchTermOrURL = + SupportUtils.getGenericSumoURLForTopic( + topic = SupportUtils.SumoTopic.SET_AS_DEFAULT_BROWSER, + ) verify { activity.openToBrowserAndLoad( @@ -291,5 +293,18 @@ class HomeDeepLinkIntentProcessorTest { verify { out wasNot Called } } + @Test + fun `process install_search_widget deep link`() { + assertTrue(processorHome.process(testIntent("install_search_widget"), navController, out)) + + verify { showAddSearchWidgetPrompt(activity) } + verify { navController wasNot Called } + verify { out wasNot Called } + } + private fun testIntent(uri: String) = Intent("", "$DEEP_LINK_SCHEME://$uri".toUri()) + + private fun showAddSearchWidgetPrompt(activity: Activity) { + println("$activity add search widget prompt was shown ") + } }