diff --git a/app-tracking-protection/vpn-impl/src/main/AndroidManifest.xml b/app-tracking-protection/vpn-impl/src/main/AndroidManifest.xml index 789ad0ef9338..c7239be1ca5c 100644 --- a/app-tracking-protection/vpn-impl/src/main/AndroidManifest.xml +++ b/app-tracking-protection/vpn-impl/src/main/AndroidManifest.xml @@ -3,6 +3,9 @@ + + + diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/apps/NewAppBroadcastReceiver.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/apps/NewAppBroadcastReceiver.kt index 92a6a706e805..9f9149b85630 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/apps/NewAppBroadcastReceiver.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/apps/NewAppBroadcastReceiver.kt @@ -23,6 +23,7 @@ import android.content.IntentFilter import androidx.annotation.MainThread import androidx.annotation.WorkerThread import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.extensions.registerExportedReceiver import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.vpn.AppTpVpnFeature @@ -81,7 +82,7 @@ class NewAppBroadcastReceiver @Inject constructor( addAction(Intent.ACTION_PACKAGE_ADDED) addDataScheme("package") }.run { - applicationContext.registerReceiver(this@NewAppBroadcastReceiver, this) + applicationContext.registerExportedReceiver(this@NewAppBroadcastReceiver, this) } } diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/debug/DeviceShieldNotificationsDebugReceiver.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/debug/DeviceShieldNotificationsDebugReceiver.kt index 56dc167dcc90..ce9e8bae6d18 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/debug/DeviceShieldNotificationsDebugReceiver.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/debug/DeviceShieldNotificationsDebugReceiver.kt @@ -26,6 +26,8 @@ import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver import com.duckduckgo.appbuildconfig.api.AppBuildConfig import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.mobile.android.vpn.ui.notification.* import com.squareup.anvil.annotations.ContributesMultibinding @@ -49,7 +51,7 @@ class DeviceShieldNotificationsDebugReceiver( ) : BroadcastReceiver() { init { - context.registerReceiver(this, IntentFilter(intentAction)) + context.registerNotExportedReceiver(this, IntentFilter(intentAction)) } override fun onReceive( @@ -116,7 +118,7 @@ class DeviceShieldNotificationsDebugReceiverRegister @Inject constructor( } notification?.let { - notificationManagerCompat.notify(DeviceShieldNotificationScheduler.VPN_WEEKLY_NOTIFICATION_ID, it) + notificationManagerCompat.checkPermissionAndNotify(context, DeviceShieldNotificationScheduler.VPN_WEEKLY_NOTIFICATION_ID, it) } } } diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/debug/SendTrackerDebugReceiver.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/debug/SendTrackerDebugReceiver.kt index 76cefe11cc4e..e108cd292870 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/debug/SendTrackerDebugReceiver.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/debug/SendTrackerDebugReceiver.kt @@ -22,6 +22,7 @@ import android.content.Intent import android.content.IntentFilter import com.duckduckgo.appbuildconfig.api.AppBuildConfig import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver import com.duckduckgo.common.utils.formatters.time.DatabaseDateFormatter import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.vpn.model.TrackingApp @@ -66,7 +67,7 @@ class SendTrackerDebugReceiver @Inject constructor( } logcat { "Debug receiver SendTrackerDebugReceiver registered" } - context.registerReceiver(this, IntentFilter(INTENT_ACTION)) + context.registerNotExportedReceiver(this, IntentFilter(INTENT_ACTION)) } private fun unregister() { diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/RestartReceiver.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/RestartReceiver.kt index 1bb0c9ba754a..2a71939bede8 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/RestartReceiver.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/RestartReceiver.kt @@ -24,6 +24,7 @@ import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.appbuildconfig.api.AppBuildConfig import com.duckduckgo.appbuildconfig.api.isInternalBuild import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor import com.squareup.anvil.annotations.ContributesMultibinding @@ -56,7 +57,7 @@ class RestartReceiver @Inject constructor( if (appBuildConfig.isInternalBuild()) { logcat { "Starting vpn-service receiver" } unregister() - context.registerReceiver(this, IntentFilter("vpn-service")) + context.registerNotExportedReceiver(this, IntentFilter("vpn-service")) } } diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/VpnReminderReceiverManager.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/VpnReminderReceiverManager.kt index 23a79e3f2a6c..292cccbdb3ac 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/VpnReminderReceiverManager.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/VpnReminderReceiverManager.kt @@ -16,8 +16,11 @@ package com.duckduckgo.mobile.android.vpn.service +import android.Manifest.permission import android.content.Context import android.content.SharedPreferences +import android.content.pm.PackageManager +import androidx.core.app.ActivityCompat import androidx.core.app.NotificationManagerCompat import androidx.core.content.edit import com.duckduckgo.common.utils.plugins.PluginPoint @@ -50,18 +53,20 @@ class AndroidVpnReminderReceiverManager @Inject constructor( logcat { "Vpn is already running, nothing to show" } } else { logcat { "Vpn is not running, showing reminder notification" } - val notification = vpnReminderNotificationContentPluginPoint.getHighestPriorityPluginForType(DISABLED)?.getContent()?.let { content -> - val actualContent = if (wasReminderNotificationShown()) { - content.copy(true) - } else { - notificationWasShown() - content.copy(false) + if (ActivityCompat.checkSelfPermission(context, permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { + val notification = vpnReminderNotificationContentPluginPoint.getHighestPriorityPluginForType(DISABLED)?.getContent()?.let { content -> + val actualContent = if (wasReminderNotificationShown()) { + content.copy(true) + } else { + notificationWasShown() + content.copy(false) + } + vpnReminderNotificationBuilder.buildReminderNotification(actualContent) + } + if (notification != null) { + deviceShieldPixels.didShowReminderNotification() + notificationManager.notify(TrackerBlockingVpnService.VPN_REMINDER_NOTIFICATION_ID, notification) } - vpnReminderNotificationBuilder.buildReminderNotification(actualContent) - } - if (notification != null) { - deviceShieldPixels.didShowReminderNotification() - notificationManager.notify(TrackerBlockingVpnService.VPN_REMINDER_NOTIFICATION_ID, notification) } } } diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/VpnTrackerNotificationUpdates.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/VpnTrackerNotificationUpdates.kt index 8b01315bcd13..23ca9d65fde5 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/VpnTrackerNotificationUpdates.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/service/VpnTrackerNotificationUpdates.kt @@ -20,6 +20,7 @@ import android.content.Context import androidx.core.app.NotificationManagerCompat import com.duckduckgo.common.utils.ConflatedJob import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.common.utils.plugins.PluginPoint import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason @@ -71,6 +72,6 @@ class VpnTrackerNotificationUpdates @Inject constructor( vpnNotification: VpnEnabledNotificationContentPlugin.VpnEnabledNotificationContent, ) { val notification = VpnEnabledNotificationBuilder.buildVpnEnabledUpdateNotification(context, vpnNotification) - notificationManager.notify(TrackerBlockingVpnService.VPN_FOREGROUND_SERVICE_ID, notification) + notificationManager.checkPermissionAndNotify(context, TrackerBlockingVpnService.VPN_FOREGROUND_SERVICE_ID, notification) } } diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/alwayson/AlwaysOnLockDownDetector.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/alwayson/AlwaysOnLockDownDetector.kt index 200333b75728..9aa5de8eef0d 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/alwayson/AlwaysOnLockDownDetector.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/alwayson/AlwaysOnLockDownDetector.kt @@ -22,6 +22,7 @@ import android.text.SpannableStringBuilder import androidx.core.app.NotificationManagerCompat import com.duckduckgo.common.utils.ConflatedJob import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.app.tracking.AppTrackingProtection import com.duckduckgo.mobile.android.app.tracking.ui.AppTrackingProtectionScreens.AppTrackerActivityWithEmptyParams @@ -95,7 +96,7 @@ class AlwaysOnLockDownDetector @Inject constructor( notification, intent, ).also { - notificationManagerCompat.notify(notificationId, it) + notificationManagerCompat.checkPermissionAndNotify(context, notificationId, it) } } diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/notification/AppTPReminderNotificationScheduler.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/notification/AppTPReminderNotificationScheduler.kt index 9e5dd969ddd5..945373478826 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/notification/AppTPReminderNotificationScheduler.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/notification/AppTPReminderNotificationScheduler.kt @@ -26,6 +26,7 @@ import androidx.work.OneTimeWorkRequestBuilder import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.common.utils.plugins.PluginPoint import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.app.tracking.AppTrackingProtection @@ -179,7 +180,8 @@ class AppTPReminderNotificationScheduler @Inject constructor( vpnReminderNotificationContentPluginPoint.getHighestPriorityPluginForType(DISABLED)?.let { it.getContent()?.let { content -> logcat { "Showing disabled notification from $it" } - notificationManager.notify( + notificationManager.checkPermissionAndNotify( + context, TrackerBlockingVpnService.VPN_REMINDER_NOTIFICATION_ID, vpnReminderNotificationBuilder.buildReminderNotification(content), ) @@ -191,7 +193,8 @@ class AppTPReminderNotificationScheduler @Inject constructor( vpnReminderNotificationContentPluginPoint.getHighestPriorityPluginForType(REVOKED)?.let { it.getContent()?.let { content -> logcat { "Showing revoked notification from $it" } - notificationManager.notify( + notificationManager.checkPermissionAndNotify( + context, TrackerBlockingVpnService.VPN_REMINDER_NOTIFICATION_ID, vpnReminderNotificationBuilder.buildReminderNotification(content), ) diff --git a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/notification/DeviceShieldNotificationScheduler.kt b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/notification/DeviceShieldNotificationScheduler.kt index efa48e109449..10a2c4da4ec2 100644 --- a/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/notification/DeviceShieldNotificationScheduler.kt +++ b/app-tracking-protection/vpn-impl/src/main/java/com/duckduckgo/mobile/android/vpn/ui/notification/DeviceShieldNotificationScheduler.kt @@ -16,7 +16,10 @@ package com.duckduckgo.mobile.android.vpn.ui.notification +import android.Manifest.permission import android.content.Context +import android.content.pm.PackageManager +import androidx.core.app.ActivityCompat import androidx.core.app.NotificationManagerCompat import androidx.lifecycle.LifecycleOwner import androidx.work.* @@ -185,18 +188,20 @@ class DeviceShieldDailyNotificationWorker( } private suspend fun showNotification() { - val deviceShieldNotification = deviceShieldNotificationFactory.createDailyDeviceShieldNotification().also { - notificationPressedHandler.notificationVariant = it.notificationVariant - } + if (ActivityCompat.checkSelfPermission(context, permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { + val deviceShieldNotification = deviceShieldNotificationFactory.createDailyDeviceShieldNotification().also { + notificationPressedHandler.notificationVariant = it.notificationVariant + } - if (!deviceShieldNotification.hidden) { - val notification = - deviceShieldAlertNotificationBuilder.buildStatusNotification(context, deviceShieldNotification, notificationPressedHandler) - deviceShieldPixels.didShowDailyNotification(deviceShieldNotification.notificationVariant) - notificationManager.notify(DeviceShieldNotificationScheduler.VPN_DAILY_NOTIFICATION_ID, notification) - logcat { "Vpn Daily notification is now shown" } - } else { - logcat { "Vpn Daily notification won't be shown because there is no data to show" } + if (!deviceShieldNotification.hidden) { + val notification = + deviceShieldAlertNotificationBuilder.buildStatusNotification(context, deviceShieldNotification, notificationPressedHandler) + deviceShieldPixels.didShowDailyNotification(deviceShieldNotification.notificationVariant) + notificationManager.notify(DeviceShieldNotificationScheduler.VPN_DAILY_NOTIFICATION_ID, notification) + logcat { "Vpn Daily notification is now shown" } + } else { + logcat { "Vpn Daily notification won't be shown because there is no data to show" } + } } } } @@ -223,20 +228,21 @@ class DeviceShieldWeeklyNotificationWorker( override suspend fun doWork(): Result { logcat { "Vpn Weekly notification worker is now awake" } + if (ActivityCompat.checkSelfPermission(context, permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { + val deviceShieldNotification = deviceShieldNotificationFactory.createWeeklyDeviceShieldNotification().also { + notificationPressedHandler.notificationVariant = it.notificationVariant + } - val deviceShieldNotification = deviceShieldNotificationFactory.createWeeklyDeviceShieldNotification().also { - notificationPressedHandler.notificationVariant = it.notificationVariant - } - - if (!deviceShieldNotification.hidden) { - logcat { "Vpn Daily notification won't be shown because there is no data to show" } - val notification = deviceShieldAlertNotificationBuilder.buildStatusNotification( - context, - deviceShieldNotification, - notificationPressedHandler, - ) - deviceShieldPixels.didShowWeeklyNotification(deviceShieldNotification.notificationVariant) - notificationManager.notify(Companion.VPN_WEEKLY_NOTIFICATION_ID, notification) + if (!deviceShieldNotification.hidden) { + logcat { "Vpn Daily notification won't be shown because there is no data to show" } + val notification = deviceShieldAlertNotificationBuilder.buildStatusNotification( + context, + deviceShieldNotification, + notificationPressedHandler, + ) + deviceShieldPixels.didShowWeeklyNotification(deviceShieldNotification.notificationVariant) + notificationManager.notify(Companion.VPN_WEEKLY_NOTIFICATION_ID, notification) + } } return Result.success() diff --git a/app-tracking-protection/vpn-impl/src/test/java/com/duckduckgo/mobile/android/vpn/service/RestartReceiverTest.kt b/app-tracking-protection/vpn-impl/src/test/java/com/duckduckgo/mobile/android/vpn/service/RestartReceiverTest.kt index 328ff2738714..23590a281847 100644 --- a/app-tracking-protection/vpn-impl/src/test/java/com/duckduckgo/mobile/android/vpn/service/RestartReceiverTest.kt +++ b/app-tracking-protection/vpn-impl/src/test/java/com/duckduckgo/mobile/android/vpn/service/RestartReceiverTest.kt @@ -56,7 +56,7 @@ class RestartReceiverTest { receiver.onVpnStarted(coroutineRule.testScope) verify(context).unregisterReceiver(any()) - verify(context).registerReceiver(any(), any()) + verify(context).registerReceiver(any(), any(), isNull(), isNull(), any()) } @Test @@ -66,7 +66,7 @@ class RestartReceiverTest { receiver.onVpnStarted(coroutineRule.testScope) verify(context, never()).unregisterReceiver(any()) - verify(context, never()).registerReceiver(any(), any()) + verify(context, never()).registerReceiver(any(), any(), isNull(), isNull(), any()) } @Test @@ -76,7 +76,7 @@ class RestartReceiverTest { receiver.onVpnStopped(coroutineRule.testScope, VpnStateMonitor.VpnStopReason.SELF_STOP()) verify(context).unregisterReceiver(any()) - verify(context, never()).registerReceiver(any(), any()) + verify(context, never()).registerReceiver(any(), any(), isNull(), isNull(), any()) } @Test @@ -86,6 +86,6 @@ class RestartReceiverTest { receiver.onVpnStopped(coroutineRule.testScope, VpnStateMonitor.VpnStopReason.SELF_STOP()) verify(context).unregisterReceiver(any()) - verify(context, never()).registerReceiver(any(), any()) + verify(context, never()).registerReceiver(any(), any(), isNull(), isNull(), any()) } } diff --git a/app-tracking-protection/vpn-internal/src/main/java/com/duckduckgo/vpn/internal/feature/InternalFeatureReceiver.kt b/app-tracking-protection/vpn-internal/src/main/java/com/duckduckgo/vpn/internal/feature/InternalFeatureReceiver.kt index 1ff72fb6803a..7f32fdf7231c 100644 --- a/app-tracking-protection/vpn-internal/src/main/java/com/duckduckgo/vpn/internal/feature/InternalFeatureReceiver.kt +++ b/app-tracking-protection/vpn-internal/src/main/java/com/duckduckgo/vpn/internal/feature/InternalFeatureReceiver.kt @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver /** * Abstract class to create generic receivers for internal features accessible through @@ -44,7 +45,7 @@ abstract class InternalFeatureReceiver( fun register() { unregister() - context.registerReceiver(this, IntentFilter(intentAction())) + context.registerNotExportedReceiver(this, IntentFilter(intentAction())) } fun unregister() { diff --git a/app-tracking-protection/vpn-internal/src/main/java/com/duckduckgo/vpn/internal/feature/rules/ExceptionRulesDebugReceiver.kt b/app-tracking-protection/vpn-internal/src/main/java/com/duckduckgo/vpn/internal/feature/rules/ExceptionRulesDebugReceiver.kt index aa6347101253..bee5be79081c 100644 --- a/app-tracking-protection/vpn-internal/src/main/java/com/duckduckgo/vpn/internal/feature/rules/ExceptionRulesDebugReceiver.kt +++ b/app-tracking-protection/vpn-internal/src/main/java/com/duckduckgo/vpn/internal/feature/rules/ExceptionRulesDebugReceiver.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason @@ -48,7 +49,7 @@ class ExceptionRulesDebugReceiver( init { kotlin.runCatching { context.unregisterReceiver(this) } - context.registerReceiver(this, IntentFilter(intentAction)) + context.registerNotExportedReceiver(this, IntentFilter(intentAction)) } override fun onReceive( diff --git a/app/src/internal/java/com/duckduckgo/app/dev/settings/privacy/TrackerDataDevReceiver.kt b/app/src/internal/java/com/duckduckgo/app/dev/settings/privacy/TrackerDataDevReceiver.kt index 560d06f2be25..268c762046bc 100644 --- a/app/src/internal/java/com/duckduckgo/app/dev/settings/privacy/TrackerDataDevReceiver.kt +++ b/app/src/internal/java/com/duckduckgo/app/dev/settings/privacy/TrackerDataDevReceiver.kt @@ -26,6 +26,7 @@ import androidx.lifecycle.LifecycleOwner import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver import com.duckduckgo.app.trackerdetection.api.TrackerDataDownloader import com.duckduckgo.appbuildconfig.api.AppBuildConfig +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesMultibinding import io.reactivex.android.schedulers.AndroidSchedulers @@ -39,7 +40,7 @@ class TrackerDataDevReceiver( private val receiver: (Intent) -> Unit, ) : BroadcastReceiver() { init { - context.registerReceiver(this, IntentFilter(intentAction)) + context.registerNotExportedReceiver(this, IntentFilter(intentAction)) } override fun onReceive( diff --git a/app/src/main/java/com/duckduckgo/app/notification/AppNotificationSender.kt b/app/src/main/java/com/duckduckgo/app/notification/AppNotificationSender.kt index da067b82346c..6b8caefe42d7 100644 --- a/app/src/main/java/com/duckduckgo/app/notification/AppNotificationSender.kt +++ b/app/src/main/java/com/duckduckgo/app/notification/AppNotificationSender.kt @@ -22,6 +22,7 @@ import com.duckduckgo.app.notification.db.NotificationDao import com.duckduckgo.app.notification.model.Notification import com.duckduckgo.app.notification.model.SchedulableNotification import com.duckduckgo.app.notification.model.SchedulableNotificationPlugin +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.common.utils.plugins.PluginPoint import timber.log.Timber @@ -54,7 +55,7 @@ class AppNotificationSender( val cancelIntent = NotificationHandlerService.pendingCancelNotificationHandlerIntent(context, notification.javaClass) val systemNotification = factory.createNotification(specification, launchIntent, cancelIntent) notificationDao.insert(Notification(notification.id)) - manager.notify(specification.systemId, systemNotification) + manager.checkPermissionAndNotify(context, specification.systemId, systemNotification) notificationPlugin.onNotificationShown() } diff --git a/app/src/main/java/com/duckduckgo/app/widget/WidgetAddedReceiver.kt b/app/src/main/java/com/duckduckgo/app/widget/WidgetAddedReceiver.kt index 1070a1314c98..3ea7aee196df 100644 --- a/app/src/main/java/com/duckduckgo/app/widget/WidgetAddedReceiver.kt +++ b/app/src/main/java/com/duckduckgo/app/widget/WidgetAddedReceiver.kt @@ -26,6 +26,7 @@ import androidx.lifecycle.LifecycleOwner import com.duckduckgo.app.browser.R import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver import com.duckduckgo.app.widget.AppWidgetManagerAddWidgetLauncher.Companion.ACTION_ADD_WIDGET +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver import com.duckduckgo.di.scopes.AppScope import com.squareup.anvil.annotations.ContributesMultibinding import dagger.SingleInstanceIn @@ -46,7 +47,7 @@ class WidgetAddedReceiver @Inject constructor( override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) - context.registerReceiver(this, IntentFilter(ACTION_ADD_WIDGET)) + context.registerNotExportedReceiver(this, IntentFilter(ACTION_ADD_WIDGET)) } override fun onDestroy(owner: LifecycleOwner) { diff --git a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/sync/CredentialsSyncFeatureListener.kt b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/sync/CredentialsSyncFeatureListener.kt index 5d36ad165bbe..8694138316a3 100644 --- a/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/sync/CredentialsSyncFeatureListener.kt +++ b/autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/sync/CredentialsSyncFeatureListener.kt @@ -18,6 +18,7 @@ package com.duckduckgo.autofill.sync import android.content.Context import androidx.core.app.NotificationManagerCompat +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.sync.api.engine.FeatureSyncError import com.duckduckgo.sync.api.engine.FeatureSyncError.COLLECTION_LIMIT_REACHED @@ -65,7 +66,8 @@ class AppCredentialsSyncFeatureListener @Inject constructor( } private fun triggerNotification() { - notificationManager.notify( + notificationManager.checkPermissionAndNotify( + context, SYNC_PAUSED_CREDENTIALS_NOTIFICATION_ID, notificationBuilder.buildRateLimitNotification(context), ) diff --git a/build.gradle b/build.gradle index 3b38c25c0c43..2acf28e1fd16 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { ksp_version = '1.9.20-1.0.14' gradle_plugin = '8.1.2' min_sdk = 23 - target_sdk = 33 + target_sdk = 34 compile_sdk = 34 fladle_version = '0.17.4' kotlinter_version = '3.12.0' diff --git a/common/common-utils/src/main/AndroidManifest.xml b/common/common-utils/src/main/AndroidManifest.xml index e74ca12e7141..efb7d866ea9d 100644 --- a/common/common-utils/src/main/AndroidManifest.xml +++ b/common/common-utils/src/main/AndroidManifest.xml @@ -22,5 +22,6 @@ android:targetPackage="com.duckduckgo.common.utils" android:label="Test for common" /> + \ No newline at end of file diff --git a/common/common-utils/src/main/java/com/duckduckgo/common/utils/extensions/ContextExtensions.kt b/common/common-utils/src/main/java/com/duckduckgo/common/utils/extensions/ContextExtensions.kt index 871171847f9b..bf2ccd135d35 100644 --- a/common/common-utils/src/main/java/com/duckduckgo/common/utils/extensions/ContextExtensions.kt +++ b/common/common-utils/src/main/java/com/duckduckgo/common/utils/extensions/ContextExtensions.kt @@ -16,9 +16,12 @@ package com.duckduckgo.common.utils.extensions +import android.content.BroadcastReceiver import android.content.Context +import android.content.IntentFilter import android.os.PowerManager import android.provider.Settings +import androidx.core.content.ContextCompat import timber.log.Timber fun Context.isPrivateDnsActive(): Boolean { @@ -46,3 +49,17 @@ fun Context.isIgnoringBatteryOptimizations(): Boolean { } ?: false }.getOrDefault(false) } + +fun Context.registerNotExportedReceiver( + receiver: BroadcastReceiver, + intentFilter: IntentFilter, +) { + ContextCompat.registerReceiver(this, receiver, intentFilter, ContextCompat.RECEIVER_NOT_EXPORTED) +} + +fun Context.registerExportedReceiver( + receiver: BroadcastReceiver, + intentFilter: IntentFilter, +) { + ContextCompat.registerReceiver(this, receiver, intentFilter, ContextCompat.RECEIVER_EXPORTED) +} diff --git a/common/common-utils/src/main/java/com/duckduckgo/common/utils/notification/NotificationUtils.kt b/common/common-utils/src/main/java/com/duckduckgo/common/utils/notification/NotificationUtils.kt new file mode 100644 index 000000000000..1a54e5ae056c --- /dev/null +++ b/common/common-utils/src/main/java/com/duckduckgo/common/utils/notification/NotificationUtils.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.common.utils.notification + +import android.Manifest.permission.POST_NOTIFICATIONS +import android.app.Notification +import android.content.Context +import android.content.pm.PackageManager.PERMISSION_GRANTED +import androidx.core.app.ActivityCompat +import androidx.core.app.NotificationManagerCompat + +fun NotificationManagerCompat.checkPermissionAndNotify( + context: Context, + id: Int, + notification: Notification, +) { + if (ActivityCompat.checkSelfPermission(context, POST_NOTIFICATIONS) == PERMISSION_GRANTED) { + notify(id, notification) + } +} diff --git a/downloads/downloads-impl/src/main/java/com/duckduckgo/downloads/impl/DefaultFileDownloadNotificationManager.kt b/downloads/downloads-impl/src/main/java/com/duckduckgo/downloads/impl/DefaultFileDownloadNotificationManager.kt index 6d36a9a4a743..f02668c9e35a 100644 --- a/downloads/downloads-impl/src/main/java/com/duckduckgo/downloads/impl/DefaultFileDownloadNotificationManager.kt +++ b/downloads/downloads-impl/src/main/java/com/duckduckgo/downloads/impl/DefaultFileDownloadNotificationManager.kt @@ -28,6 +28,7 @@ import androidx.core.app.NotificationManagerCompat import androidx.core.content.FileProvider import com.duckduckgo.appbuildconfig.api.AppBuildConfig import com.duckduckgo.browser.api.BrowserLifecycleObserver +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.downloads.api.FileDownloadNotificationManager import com.squareup.anvil.annotations.ContributesBinding @@ -100,8 +101,8 @@ class DefaultFileDownloadNotificationManager @Inject constructor( } notificationManager.apply { - notify(downloadId.toInt(), notification) - notify(SUMMARY_ID, summary) + checkPermissionAndNotify(applicationContext, downloadId.toInt(), notification) + checkPermissionAndNotify(applicationContext, SUMMARY_ID, summary) groupNotificationsCounter.atomicUpdateAndGet { it.plus(downloadId to filename) } } } @@ -128,7 +129,7 @@ class DefaultFileDownloadNotificationManager @Inject constructor( // we don't want to post any notification while the DDG application is closing if (applicationClosing.get()) return - notificationManager.notify(downloadId.toInt(), notification) + notificationManager.checkPermissionAndNotify(applicationContext, downloadId.toInt(), notification) } @AnyThread @@ -158,7 +159,7 @@ class DefaultFileDownloadNotificationManager @Inject constructor( // we don't want to post any notification while the DDG application is closing if (applicationClosing.get()) return - notificationManager.notify(downloadId.toInt(), notification) + notificationManager.checkPermissionAndNotify(applicationContext, downloadId.toInt(), notification) } @AnyThread diff --git a/downloads/downloads-impl/src/main/java/com/duckduckgo/downloads/impl/FileDownloadNotificationActionReceiver.kt b/downloads/downloads-impl/src/main/java/com/duckduckgo/downloads/impl/FileDownloadNotificationActionReceiver.kt index dce2ec71137f..64206f89639e 100644 --- a/downloads/downloads-impl/src/main/java/com/duckduckgo/downloads/impl/FileDownloadNotificationActionReceiver.kt +++ b/downloads/downloads-impl/src/main/java/com/duckduckgo/downloads/impl/FileDownloadNotificationActionReceiver.kt @@ -26,6 +26,7 @@ import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver import com.duckduckgo.app.statistics.pixels.Pixel import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.downloads.api.* import com.duckduckgo.downloads.impl.pixels.DownloadsPixelName @@ -55,7 +56,7 @@ class FileDownloadNotificationActionReceiver @Inject constructor( override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) Timber.v("Registering file download notification action receiver") - context.registerReceiver(this, IntentFilter(INTENT_DOWNLOADS_NOTIFICATION_ACTION)) + context.registerNotExportedReceiver(this, IntentFilter(INTENT_DOWNLOADS_NOTIFICATION_ACTION)) // When the app process is killed and restarted, this onCreate method is called and we take the opportunity // to clean up the pending downloads that were in progress and will be no longer downloading. diff --git a/network-protection/network-protection-impl/src/main/java/com/duckduckgo/networkprotection/impl/notification/NetPDisabledNotificationScheduler.kt b/network-protection/network-protection-impl/src/main/java/com/duckduckgo/networkprotection/impl/notification/NetPDisabledNotificationScheduler.kt index 12694ef64104..72394551ea2d 100644 --- a/network-protection/network-protection-impl/src/main/java/com/duckduckgo/networkprotection/impl/notification/NetPDisabledNotificationScheduler.kt +++ b/network-protection/network-protection-impl/src/main/java/com/duckduckgo/networkprotection/impl/notification/NetPDisabledNotificationScheduler.kt @@ -22,6 +22,7 @@ import android.content.pm.PackageManager import androidx.core.app.NotificationManagerCompat import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason @@ -108,7 +109,8 @@ class NetPDisabledNotificationScheduler @Inject constructor( coroutineScope.launch(dispatcherProvider.io()) { if (triggerAtMillis != 0L) { if (!netPSettingsLocalConfig.vpnNotificationAlerts().isEnabled()) return@launch - notificationManager.notify( + notificationManager.checkPermissionAndNotify( + context, NETP_REMINDER_NOTIFICATION_ID, netPDisabledNotificationBuilder.buildSnoozeNotification(context, triggerAtMillis), ) @@ -122,7 +124,8 @@ class NetPDisabledNotificationScheduler @Inject constructor( coroutineScope.launch(dispatcherProvider.io()) { logcat { "Showing disabled notification for NetP" } if (!netPSettingsLocalConfig.vpnNotificationAlerts().isEnabled()) return@launch - notificationManager.notify( + notificationManager.checkPermissionAndNotify( + context, NETP_REMINDER_NOTIFICATION_ID, netPDisabledNotificationBuilder.buildDisabledNotification(context), ) @@ -141,7 +144,8 @@ class NetPDisabledNotificationScheduler @Inject constructor( coroutineScope.launch(dispatcherProvider.io()) { logcat { "Showing disabled by vpn notification for NetP" } if (!netPSettingsLocalConfig.vpnNotificationAlerts().isEnabled()) return@launch - notificationManager.notify( + notificationManager.checkPermissionAndNotify( + context, NETP_REMINDER_NOTIFICATION_ID, netPDisabledNotificationBuilder.buildDisabledByVpnNotification(context), ) diff --git a/network-protection/network-protection-impl/src/main/java/com/duckduckgo/networkprotection/impl/timezone/NetPTimezoneMonitor.kt b/network-protection/network-protection-impl/src/main/java/com/duckduckgo/networkprotection/impl/timezone/NetPTimezoneMonitor.kt index 1086926d1a4f..4637bb3db267 100644 --- a/network-protection/network-protection-impl/src/main/java/com/duckduckgo/networkprotection/impl/timezone/NetPTimezoneMonitor.kt +++ b/network-protection/network-protection-impl/src/main/java/com/duckduckgo/networkprotection/impl/timezone/NetPTimezoneMonitor.kt @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.vpn.VpnFeaturesRegistry import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks @@ -76,7 +77,7 @@ class NetPTimezoneMonitor @Inject constructor( IntentFilter().apply { addAction(Intent.ACTION_TIMEZONE_CHANGED) }.run { - context.registerReceiver(this@NetPTimezoneMonitor, this) + context.registerNotExportedReceiver(this@NetPTimezoneMonitor, this) } } diff --git a/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/feature/InternalFeatureReceiver.kt b/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/feature/InternalFeatureReceiver.kt index da8e597bddb6..391112ac52ec 100644 --- a/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/feature/InternalFeatureReceiver.kt +++ b/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/feature/InternalFeatureReceiver.kt @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver /** * Abstract class to create generic receivers for internal features accessible through @@ -44,7 +45,7 @@ abstract class InternalFeatureReceiver( fun register() { unregister() - context.registerReceiver(this, IntentFilter(intentAction())) + context.registerNotExportedReceiver(this, IntentFilter(intentAction())) } fun unregister() { diff --git a/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/feature/snooze/VpnCallStateReceiver.kt b/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/feature/snooze/VpnCallStateReceiver.kt index a740c1d73f98..91b7ee115567 100644 --- a/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/feature/snooze/VpnCallStateReceiver.kt +++ b/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/feature/snooze/VpnCallStateReceiver.kt @@ -27,6 +27,7 @@ import com.duckduckgo.app.di.AppCoroutineScope import com.duckduckgo.app.di.ProcessName import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.di.scopes.ReceiverScope import com.duckduckgo.mobile.android.vpn.Vpn @@ -75,7 +76,10 @@ class VpnCallStateReceiver @Inject constructor( private val _listener: PhoneStateListener = object : PhoneStateListener() { @Deprecated("Deprecated in Java") - override fun onCallStateChanged(state: Int, phoneNumber: String?) { + override fun onCallStateChanged( + state: Int, + phoneNumber: String?, + ) { appCoroutineScope.launch(dispatcherProvider.io()) { logcat { "Call state: $state" } if (state == TelephonyManager.CALL_STATE_IDLE) { @@ -128,12 +132,14 @@ class VpnCallStateReceiver @Inject constructor( registerListener() } } + ACTION_UNREGISTER_STATE_CALL_LISTENER -> { logcat { "ACTION_UNREGISTER_STATE_CALL_LISTENER" } goAsync(pendingResult) { unregisterListener() } } + else -> { logcat { "Unknown action ${intent.action}" } } @@ -155,7 +161,7 @@ class VpnCallStateReceiver @Inject constructor( private fun register() { unregister() logcat { "Registering vpn call state receiver" } - context.registerReceiver( + context.registerNotExportedReceiver( this, IntentFilter().apply { addAction(ACTION_REGISTER_STATE_CALL_LISTENER) diff --git a/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/rekey/DebugRekeyReceiver.kt b/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/rekey/DebugRekeyReceiver.kt index cc24e5972347..62c411aa7e70 100644 --- a/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/rekey/DebugRekeyReceiver.kt +++ b/network-protection/network-protection-internal/src/main/java/com/duckduckgo/networkprotection/internal/rekey/DebugRekeyReceiver.kt @@ -23,6 +23,7 @@ import android.content.Intent import android.content.IntentFilter import com.duckduckgo.anvil.annotations.InjectWith import com.duckduckgo.app.di.ProcessName +import com.duckduckgo.common.utils.extensions.registerNotExportedReceiver import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor @@ -61,6 +62,7 @@ class DebugRekeyReceiver @Inject constructor( rekeyer.forceRekey() } } + else -> { logcat(LogPriority.WARN) { "Unknown action" } pendingResult?.finish() @@ -72,7 +74,10 @@ class DebugRekeyReceiver @Inject constructor( register() } - override fun onVpnStopped(coroutineScope: CoroutineScope, vpnStopReason: VpnStateMonitor.VpnStopReason) { + override fun onVpnStopped( + coroutineScope: CoroutineScope, + vpnStopReason: VpnStateMonitor.VpnStopReason, + ) { logcat { "Unregistering debug re-keying receiver" } unregister() } @@ -81,7 +86,7 @@ class DebugRekeyReceiver @Inject constructor( private fun register() { unregister() logcat { "Registering debug re-keying receiver" } - context.registerReceiver( + context.registerNotExportedReceiver( this, IntentFilter().apply { addAction(ACTION_FORCE_REKEY) diff --git a/network-protection/network-protection-subscription-internal/src/main/java/com/duckduckgo/networkprotection/subscription/notification/NetpAccessRevokedNotificationScheduler.kt b/network-protection/network-protection-subscription-internal/src/main/java/com/duckduckgo/networkprotection/subscription/notification/NetpAccessRevokedNotificationScheduler.kt index f6af67db886a..058c4e1f8f4e 100644 --- a/network-protection/network-protection-subscription-internal/src/main/java/com/duckduckgo/networkprotection/subscription/notification/NetpAccessRevokedNotificationScheduler.kt +++ b/network-protection/network-protection-subscription-internal/src/main/java/com/duckduckgo/networkprotection/subscription/notification/NetpAccessRevokedNotificationScheduler.kt @@ -19,6 +19,7 @@ package com.duckduckgo.networkprotection.subscription.notification import android.content.Context import androidx.core.app.NotificationManagerCompat import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.di.scopes.VpnScope import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason @@ -49,7 +50,8 @@ class NetpAccessRevokedNotificationScheduler @Inject constructor( override fun onVpnStartFailed(coroutineScope: CoroutineScope) { if (networkProtectionRepository.vpnAccessRevoked) { - notificationManager.notify( + notificationManager.checkPermissionAndNotify( + context, NetPDisabledNotificationScheduler.NETP_REMINDER_NOTIFICATION_ID, netpAccessRevokedNotificationBuilder.buildVpnAccessRevokedNotification(context), ) diff --git a/saved-sites/saved-sites-impl/src/main/java/com/duckduckgo/savedsites/impl/sync/SavedSitesSyncFeatureListener.kt b/saved-sites/saved-sites-impl/src/main/java/com/duckduckgo/savedsites/impl/sync/SavedSitesSyncFeatureListener.kt index 971387214dca..5223d32b71e4 100644 --- a/saved-sites/saved-sites-impl/src/main/java/com/duckduckgo/savedsites/impl/sync/SavedSitesSyncFeatureListener.kt +++ b/saved-sites/saved-sites-impl/src/main/java/com/duckduckgo/savedsites/impl/sync/SavedSitesSyncFeatureListener.kt @@ -18,6 +18,7 @@ package com.duckduckgo.savedsites.impl.sync import android.content.Context import androidx.core.app.NotificationManagerCompat +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.sync.api.engine.FeatureSyncError import com.duckduckgo.sync.api.engine.FeatureSyncError.COLLECTION_LIMIT_REACHED @@ -65,7 +66,8 @@ class AppSavedSitesSyncFeatureListener @Inject constructor( } private fun triggerNotification() { - notificationManager.notify( + notificationManager.checkPermissionAndNotify( + context, SYNC_PAUSED_SAVED_SITES_NOTIFICATION_ID, notificationBuilder.buildRateLimitNotification(context), ) diff --git a/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeatureToggle.kt b/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeatureToggle.kt index dcbf3e3cf170..f3c8533f69d8 100644 --- a/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeatureToggle.kt +++ b/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeatureToggle.kt @@ -23,6 +23,7 @@ import com.duckduckgo.appbuildconfig.api.AppBuildConfig import com.duckduckgo.appbuildconfig.api.isInternalBuild import com.duckduckgo.common.utils.DefaultDispatcherProvider import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.notification.checkPermissionAndNotify import com.duckduckgo.di.scopes.AppScope import com.duckduckgo.feature.toggles.api.Toggle import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin @@ -135,7 +136,8 @@ class SyncRemoteFeatureToggle @Inject constructor( private fun triggerNotification() { val showSync = showSync() - notificationManager.notify( + notificationManager.checkPermissionAndNotify( + context, SYNC_PAUSED_NOTIFICATION_ID, syncNotificationBuilder.buildSyncPausedNotification(context, addNavigationIntent = showSync), ) diff --git a/versions.properties b/versions.properties index 0ff7a4230e76..ce854160dfe6 100644 --- a/versions.properties +++ b/versions.properties @@ -23,7 +23,7 @@ version.androidx.localbroadcastmanager=1.1.0 version.androidx.recyclerview=1.3.2 -version.androidx.core=1.8.0 +version.androidx.core=1.12.0 version.androidx.fragment=1.5.2