diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml index 47d209f998..c76a534fcd 100644 --- a/app/lint-baseline.xml +++ b/app/lint-baseline.xml @@ -1031,72 +1031,6 @@ column="10"/> - - - - - - - - - - - - - - - - - - - - - - - - = Build.VERSION_CODES.S) { + PendingIntent.FLAG_MUTABLE + } else { + 0 // No flags. Default behavior. + } val pendingIntent = PendingIntent.getActivity( context, 0, intent, - 0 + crashReportingIntentFlags ) CrashReporter( diff --git a/app/src/main/java/org/mozilla/fenix/components/NotificationManager.kt b/app/src/main/java/org/mozilla/fenix/components/NotificationManager.kt index 24d3034f55..c4a68e2b73 100644 --- a/app/src/main/java/org/mozilla/fenix/components/NotificationManager.kt +++ b/app/src/main/java/org/mozilla/fenix/components/NotificationManager.kt @@ -21,6 +21,7 @@ import mozilla.components.concept.sync.Device import mozilla.components.concept.sync.TabData import mozilla.components.support.base.log.logger.Logger import org.mozilla.fenix.R +import org.mozilla.fenix.utils.IntentUtils /** * Manages notification channels and allows displaying different types of notifications. @@ -54,11 +55,12 @@ class NotificationManager(private val context: Context) { // For now, a single notification per tab received will suffice. logger.debug("Showing ${tabs.size} tab(s) received from deviceID=${device?.id}") tabs.forEach { tab -> + val showReceivedTabsIntentFlags = IntentUtils.defaultIntentPendingFlags or PendingIntent.FLAG_ONE_SHOT val intent = Intent(Intent.ACTION_VIEW, Uri.parse(tab.url)) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK intent.putExtra(RECEIVE_TABS_TAG, true) val pendingIntent: PendingIntent = - PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT) + PendingIntent.getActivity(context, 0, intent, showReceivedTabsIntentFlags) val builder = NotificationCompat.Builder(context, RECEIVE_TABS_CHANNEL_ID) .setSmallIcon(R.drawable.ic_status_logo) diff --git a/app/src/main/java/org/mozilla/fenix/components/PrivateShortcutCreateManager.kt b/app/src/main/java/org/mozilla/fenix/components/PrivateShortcutCreateManager.kt index 9aa3d6364d..6d37991e6f 100644 --- a/app/src/main/java/org/mozilla/fenix/components/PrivateShortcutCreateManager.kt +++ b/app/src/main/java/org/mozilla/fenix/components/PrivateShortcutCreateManager.kt @@ -13,6 +13,7 @@ import androidx.core.graphics.drawable.IconCompat import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.home.intent.StartSearchIntentProcessor +import org.mozilla.fenix.utils.IntentUtils import java.util.UUID /** @@ -50,11 +51,13 @@ object PrivateShortcutCreateManager { } ) .build() + val createPrivateShortcutIntentFlags = IntentUtils.defaultIntentPendingFlags or + PendingIntent.FLAG_UPDATE_CURRENT val homeScreenIntent = Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) val intentSender = PendingIntent - .getActivity(context, 0, homeScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT) + .getActivity(context, 0, homeScreenIntent, createPrivateShortcutIntentFlags) .intentSender ShortcutManagerCompat.requestPinShortcut(context, shortcut, intentSender) } diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/DefaultBrowserNotificationWorker.kt b/app/src/main/java/org/mozilla/fenix/onboarding/DefaultBrowserNotificationWorker.kt index 479fb090b4..de967d9a96 100644 --- a/app/src/main/java/org/mozilla/fenix/onboarding/DefaultBrowserNotificationWorker.kt +++ b/app/src/main/java/org/mozilla/fenix/onboarding/DefaultBrowserNotificationWorker.kt @@ -24,6 +24,7 @@ import mozilla.components.support.base.ids.SharedIdsHelper import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.utils.IntentUtils import org.mozilla.fenix.utils.Settings class DefaultBrowserNotificationWorker( @@ -54,7 +55,7 @@ class DefaultBrowserNotificationWorker( applicationContext, SharedIdsHelper.getNextIdForTag(applicationContext, NOTIFICATION_PENDING_INTENT_TAG), intent, - 0 + IntentUtils.defaultIntentPendingFlags ) with(applicationContext) { diff --git a/app/src/main/java/org/mozilla/fenix/utils/IntentUtils.kt b/app/src/main/java/org/mozilla/fenix/utils/IntentUtils.kt new file mode 100644 index 0000000000..0715e3dca5 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/utils/IntentUtils.kt @@ -0,0 +1,23 @@ +/* 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.PendingIntent +import android.os.Build + +object IntentUtils { + + /** + * Since Android 12 we need to set PendingIntent mutability explicitly, but Android 6 can be the minimum version + * This additional requirement improves your app's security. + * FLAG_IMMUTABLE -> Flag indicating that the created PendingIntent should be immutable. + */ + val defaultIntentPendingFlags + get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + PendingIntent.FLAG_IMMUTABLE + } else { + 0 // No flags. Default behavior. + } +} diff --git a/app/src/main/java/org/mozilla/gecko/search/SearchWidgetProvider.kt b/app/src/main/java/org/mozilla/gecko/search/SearchWidgetProvider.kt index c657c80c79..2f35ea8a77 100644 --- a/app/src/main/java/org/mozilla/gecko/search/SearchWidgetProvider.kt +++ b/app/src/main/java/org/mozilla/gecko/search/SearchWidgetProvider.kt @@ -28,6 +28,7 @@ import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.metrics import org.mozilla.fenix.ext.settings import org.mozilla.fenix.home.intent.StartSearchIntentProcessor +import org.mozilla.fenix.utils.IntentUtils import org.mozilla.fenix.widget.VoiceSearchActivity import org.mozilla.fenix.widget.VoiceSearchActivity.Companion.SPEECH_PROCESSING @@ -89,11 +90,13 @@ class SearchWidgetProvider : AppWidgetProvider() { private fun createTextSearchIntent(context: Context): PendingIntent { return Intent(context, IntentReceiverActivity::class.java) .let { intent -> + val createTextSearchIntentFlags = IntentUtils.defaultIntentPendingFlags or + PendingIntent.FLAG_UPDATE_CURRENT intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK intent.putExtra(HomeActivity.OPEN_TO_SEARCH, StartSearchIntentProcessor.SEARCH_WIDGET) PendingIntent.getActivity( context, - REQUEST_CODE_NEW_TAB, intent, PendingIntent.FLAG_UPDATE_CURRENT + REQUEST_CODE_NEW_TAB, intent, createTextSearchIntentFlags ) } } @@ -117,7 +120,7 @@ class SearchWidgetProvider : AppWidgetProvider() { return intentSpeech.resolveActivity(context.packageManager)?.let { PendingIntent.getActivity( context, - REQUEST_CODE_VOICE, voiceIntent, 0 + REQUEST_CODE_VOICE, voiceIntent, IntentUtils.defaultIntentPendingFlags ) } } diff --git a/app/src/test/java/org/mozilla/fenix/components/PrivateShortcutCreateManagerTest.kt b/app/src/test/java/org/mozilla/fenix/components/PrivateShortcutCreateManagerTest.kt index 5c55d5e401..c4772e7377 100644 --- a/app/src/test/java/org/mozilla/fenix/components/PrivateShortcutCreateManagerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/PrivateShortcutCreateManagerTest.kt @@ -24,6 +24,7 @@ import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.home.intent.StartSearchIntentProcessor +import org.mozilla.fenix.utils.IntentUtils @RunWith(FenixRobolectricTestRunner::class) class PrivateShortcutCreateManagerTest { @@ -59,7 +60,7 @@ class PrivateShortcutCreateManagerTest { PrivateShortcutCreateManager.createPrivateShortcut(testContext) - verify { PendingIntent.getActivity(testContext, 0, capture(intent), PendingIntent.FLAG_UPDATE_CURRENT) } + verify { PendingIntent.getActivity(testContext, 0, capture(intent), IntentUtils.defaultIntentPendingFlags or PendingIntent.FLAG_UPDATE_CURRENT) } verify { ShortcutManagerCompat.requestPinShortcut(testContext, capture(shortcut), capture(intentSender)) } `assert shortcutInfoCompat is build correctly`(shortcut.captured) `assert homeScreenIntent is built correctly`(intent.captured)