Daggerization and cleanup of NotificationUtils

This commit is contained in:
Benoit Marty 2019-09-18 17:20:45 +02:00
parent 7da9cafcc2
commit f5020d0f63
7 changed files with 167 additions and 185 deletions

View File

@ -48,7 +48,6 @@ import im.vector.riotx.features.lifecycle.VectorActivityLifecycleCallbacks
import im.vector.riotx.features.notifications.NotificationDrawerManager import im.vector.riotx.features.notifications.NotificationDrawerManager
import im.vector.riotx.features.notifications.NotificationUtils import im.vector.riotx.features.notifications.NotificationUtils
import im.vector.riotx.features.notifications.PushRuleTriggerListener import im.vector.riotx.features.notifications.PushRuleTriggerListener
import im.vector.riotx.features.rageshake.VectorFileLogger
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
import im.vector.riotx.features.settings.VectorPreferences import im.vector.riotx.features.settings.VectorPreferences
import im.vector.riotx.features.version.VersionProvider import im.vector.riotx.features.version.VersionProvider
@ -73,6 +72,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
@Inject lateinit var pushRuleTriggerListener: PushRuleTriggerListener @Inject lateinit var pushRuleTriggerListener: PushRuleTriggerListener
@Inject lateinit var vectorPreferences: VectorPreferences @Inject lateinit var vectorPreferences: VectorPreferences
@Inject lateinit var versionProvider: VersionProvider @Inject lateinit var versionProvider: VersionProvider
@Inject lateinit var notificationUtils: NotificationUtils
lateinit var vectorComponent: VectorComponent lateinit var vectorComponent: VectorComponent
private var fontThreadHandler: Handler? = null private var fontThreadHandler: Handler? = null
@ -112,7 +112,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
emojiCompatWrapper.init(fontRequest) emojiCompatWrapper.init(fontRequest)
NotificationUtils.createNotificationChannels(applicationContext) notificationUtils.createNotificationChannels()
if (authenticator.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) { if (authenticator.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
val lastAuthenticatedSession = authenticator.getLastAuthenticatedSession()!! val lastAuthenticatedSession = authenticator.getLastAuthenticatedSession()!!
activeSessionHolder.setActiveSession(lastAuthenticatedSession) activeSessionHolder.setActiveSession(lastAuthenticatedSession)

View File

@ -36,10 +36,7 @@ import im.vector.riotx.features.home.HomeRoomListObservableStore
import im.vector.riotx.features.home.group.SelectedGroupStore import im.vector.riotx.features.home.group.SelectedGroupStore
import im.vector.riotx.features.html.EventHtmlRenderer import im.vector.riotx.features.html.EventHtmlRenderer
import im.vector.riotx.features.navigation.Navigator import im.vector.riotx.features.navigation.Navigator
import im.vector.riotx.features.notifications.NotifiableEventResolver import im.vector.riotx.features.notifications.*
import im.vector.riotx.features.notifications.NotificationBroadcastReceiver
import im.vector.riotx.features.notifications.NotificationDrawerManager
import im.vector.riotx.features.notifications.PushRuleTriggerListener
import im.vector.riotx.features.rageshake.BugReporter import im.vector.riotx.features.rageshake.BugReporter
import im.vector.riotx.features.rageshake.VectorFileLogger import im.vector.riotx.features.rageshake.VectorFileLogger
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
@ -58,6 +55,8 @@ interface VectorComponent {
fun currentSession(): Session fun currentSession(): Session
fun notificationUtils(): NotificationUtils
fun notificationDrawerManager(): NotificationDrawerManager fun notificationDrawerManager(): NotificationDrawerManager
fun appContext(): Context fun appContext(): Context
@ -72,7 +71,7 @@ interface VectorComponent {
fun emojiCompatFontProvider(): EmojiCompatFontProvider fun emojiCompatFontProvider(): EmojiCompatFontProvider
fun emojiCompatWrapper() : EmojiCompatWrapper fun emojiCompatWrapper(): EmojiCompatWrapper
fun eventHtmlRenderer(): EventHtmlRenderer fun eventHtmlRenderer(): EventHtmlRenderer

View File

@ -19,6 +19,7 @@ package im.vector.riotx.core.services
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import im.vector.riotx.core.extensions.vectorComponent
import im.vector.riotx.features.notifications.NotificationUtils import im.vector.riotx.features.notifications.NotificationUtils
import timber.log.Timber import timber.log.Timber
@ -32,11 +33,18 @@ class CallService : VectorService() {
*/ */
private var mCallIdInProgress: String? = null private var mCallIdInProgress: String? = null
private lateinit var notificationUtils: NotificationUtils
/** /**
* incoming (foreground notification) * incoming (foreground notification)
*/ */
private var mIncomingCallId: String? = null private var mIncomingCallId: String? = null
override fun onCreate() {
super.onCreate()
notificationUtils = vectorComponent().notificationUtils()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent == null) { if (intent == null) {
// Service started again by the system. // Service started again by the system.
@ -120,7 +128,7 @@ class CallService : VectorService() {
private fun displayCallInProgressNotification(intent: Intent) { private fun displayCallInProgressNotification(intent: Intent) {
val callId = intent.getStringExtra(EXTRA_CALL_ID) val callId = intent.getStringExtra(EXTRA_CALL_ID)
val notification = NotificationUtils.buildPendingCallNotification(applicationContext, val notification = notificationUtils.buildPendingCallNotification(
intent.getBooleanExtra(EXTRA_IS_VIDEO, false), intent.getBooleanExtra(EXTRA_IS_VIDEO, false),
intent.getStringExtra(EXTRA_ROOM_NAME), intent.getStringExtra(EXTRA_ROOM_NAME),
intent.getStringExtra(EXTRA_ROOM_ID), intent.getStringExtra(EXTRA_ROOM_ID),
@ -136,7 +144,7 @@ class CallService : VectorService() {
* Hide the permanent call notifications * Hide the permanent call notifications
*/ */
private fun hideCallNotifications() { private fun hideCallNotifications() {
val notification = NotificationUtils.buildCallEndedNotification(applicationContext) val notification = notificationUtils.buildCallEndedNotification()
// It's mandatory to startForeground to avoid crash // It's mandatory to startForeground to avoid crash
startForeground(NOTIFICATION_ID, notification) startForeground(NOTIFICATION_ID, notification)

View File

@ -18,11 +18,7 @@ package im.vector.riotx.core.utils
import android.annotation.TargetApi import android.annotation.TargetApi
import android.app.Activity import android.app.Activity
import android.content.ActivityNotFoundException import android.content.*
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.PowerManager import android.os.PowerManager
@ -32,7 +28,7 @@ import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.features.notifications.supportNotificationChannels import im.vector.riotx.features.notifications.NotificationUtils
import im.vector.riotx.features.settings.VectorLocale import im.vector.riotx.features.settings.VectorLocale
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -138,7 +134,7 @@ fun startNotificationSettingsIntent(activity: AppCompatActivity, requestCode: In
*/ */
@TargetApi(Build.VERSION_CODES.O) @TargetApi(Build.VERSION_CODES.O)
fun startNotificationChannelSettingsIntent(fragment: Fragment, channelID: String) { fun startNotificationChannelSettingsIntent(fragment: Fragment, channelID: String) {
if (!supportNotificationChannels()) return if (!NotificationUtils.supportNotificationChannels()) return
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply { val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply {
putExtra(Settings.EXTRA_APP_PACKAGE, fragment.context?.packageName) putExtra(Settings.EXTRA_APP_PACKAGE, fragment.context?.packageName)
putExtra(Settings.EXTRA_CHANNEL_ID, channelID) putExtra(Settings.EXTRA_CHANNEL_ID, channelID)

View File

@ -26,6 +26,7 @@ import im.vector.matrix.android.api.session.content.ContentUrlResolver
import im.vector.riotx.BuildConfig import im.vector.riotx.BuildConfig
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.settings.VectorPreferences import im.vector.riotx.features.settings.VectorPreferences
import me.gujun.android.span.span import me.gujun.android.span.span
import timber.log.Timber import timber.log.Timber
@ -42,7 +43,9 @@ import javax.inject.Singleton
*/ */
@Singleton @Singleton
class NotificationDrawerManager @Inject constructor(private val context: Context, class NotificationDrawerManager @Inject constructor(private val context: Context,
private val notificationUtils: NotificationUtils,
private val vectorPreferences: VectorPreferences, private val vectorPreferences: VectorPreferences,
private val stringProvider: StringProvider,
private val activeSessionHolder: ActiveSessionHolder, private val activeSessionHolder: ActiveSessionHolder,
private val iconLoader: IconLoader, private val iconLoader: IconLoader,
private val bitmapLoader: BitmapLoader, private val bitmapLoader: BitmapLoader,
@ -154,7 +157,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
e is NotifiableMessageEvent && e.roomId == roomId e is NotifiableMessageEvent && e.roomId == roomId
} }
} }
NotificationUtils.cancelNotificationMessage(context, roomId, ROOM_MESSAGES_NOTIFICATION_ID) notificationUtils.cancelNotificationMessage(roomId, ROOM_MESSAGES_NOTIFICATION_ID)
} }
refreshNotificationDrawer() refreshNotificationDrawer()
} }
@ -254,7 +257,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
if (events.isEmpty() || events.all { it.isRedacted }) { if (events.isEmpty() || events.all { it.isRedacted }) {
//Just clear this notification //Just clear this notification
Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER $roomId has no more events") Timber.v("%%%%%%%% REFRESH NOTIFICATION DRAWER $roomId has no more events")
NotificationUtils.cancelNotificationMessage(context, roomId, ROOM_MESSAGES_NOTIFICATION_ID) notificationUtils.cancelNotificationMessage(roomId, ROOM_MESSAGES_NOTIFICATION_ID)
continue continue
} }
@ -295,7 +298,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
.build() .build()
if (event.outGoingMessage && event.outGoingMessageFailed) { if (event.outGoingMessage && event.outGoingMessageFailed) {
style.addMessage(context.getString(R.string.notification_inline_reply_failed), event.timestamp, senderPerson) style.addMessage(stringProvider.getString(R.string.notification_inline_reply_failed), event.timestamp, senderPerson)
roomEventGroupInfo.hasSmartReplyError = true roomEventGroupInfo.hasSmartReplyError = true
} else { } else {
if (!event.isRedacted) { if (!event.isRedacted) {
@ -306,7 +309,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
//It is possible that this event was previously shown as an 'anonymous' simple notif. //It is possible that this event was previously shown as an 'anonymous' simple notif.
//And now it will be merged in a single MessageStyle notif, so we can clean to be sure //And now it will be merged in a single MessageStyle notif, so we can clean to be sure
NotificationUtils.cancelNotificationMessage(context, event.eventId, ROOM_EVENT_NOTIFICATION_ID) notificationUtils.cancelNotificationMessage(event.eventId, ROOM_EVENT_NOTIFICATION_ID)
} }
try { try {
@ -332,7 +335,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
summaryInboxStyle.addLine(line) summaryInboxStyle.addLine(line)
} }
} else { } else {
val summaryLine = context.resources.getQuantityString( val summaryLine = stringProvider.getQuantityString(
R.plurals.notification_compat_summary_line_for_room, events.size, roomName, events.size) R.plurals.notification_compat_summary_line_for_room, events.size, roomName, events.size)
summaryInboxStyle.addLine(summaryLine) summaryInboxStyle.addLine(summaryLine)
} }
@ -351,17 +354,16 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
globalLastMessageTimestamp = lastMessageTimestamp globalLastMessageTimestamp = lastMessageTimestamp
} }
NotificationUtils.buildMessagesListNotification(context, val notification = notificationUtils.buildMessagesListNotification(
vectorPreferences,
style, style,
roomEventGroupInfo, roomEventGroupInfo,
largeBitmap, largeBitmap,
lastMessageTimestamp, lastMessageTimestamp,
myUserDisplayName) myUserDisplayName)
?.let {
//is there an id for this room? //is there an id for this room?
NotificationUtils.showNotificationMessage(context, roomId, ROOM_MESSAGES_NOTIFICATION_ID, it) notificationUtils.showNotificationMessage(roomId, ROOM_MESSAGES_NOTIFICATION_ID, notification)
}
hasNewEvent = true hasNewEvent = true
summaryIsNoisy = summaryIsNoisy || roomEventGroupInfo.shouldBing summaryIsNoisy = summaryIsNoisy || roomEventGroupInfo.shouldBing
} else { } else {
@ -374,13 +376,12 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
for (event in simpleEvents) { for (event in simpleEvents) {
//We build a simple event //We build a simple event
if (firstTime || !event.hasBeenDisplayed) { if (firstTime || !event.hasBeenDisplayed) {
NotificationUtils.buildSimpleEventNotification(context, vectorPreferences, event, null, session.myUserId)?.let { val notification = notificationUtils.buildSimpleEventNotification(event, null, session.myUserId)
NotificationUtils.showNotificationMessage(context, event.eventId, ROOM_EVENT_NOTIFICATION_ID, it) notificationUtils.showNotificationMessage(event.eventId, ROOM_EVENT_NOTIFICATION_ID, notification)
event.hasBeenDisplayed = true //we can consider it as displayed event.hasBeenDisplayed = true //we can consider it as displayed
hasNewEvent = true hasNewEvent = true
summaryIsNoisy = summaryIsNoisy || event.noisy summaryIsNoisy = summaryIsNoisy || event.noisy
summaryInboxStyle.addLine(event.description) summaryInboxStyle.addLine(event.description)
}
} }
} }
@ -399,27 +400,21 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
// https://developer.android.com/training/notify-user/group // https://developer.android.com/training/notify-user/group
if (eventList.isEmpty() || eventList.all { it.isRedacted }) { if (eventList.isEmpty() || eventList.all { it.isRedacted }) {
NotificationUtils.cancelNotificationMessage(context, null, SUMMARY_NOTIFICATION_ID) notificationUtils.cancelNotificationMessage(null, SUMMARY_NOTIFICATION_ID)
} else { } else {
val nbEvents = roomIdToEventMap.size + simpleEvents.size val nbEvents = roomIdToEventMap.size + simpleEvents.size
val sumTitle = context.resources.getQuantityString( val sumTitle = stringProvider.getQuantityString(R.plurals.notification_compat_summary_title, nbEvents, nbEvents)
R.plurals.notification_compat_summary_title, nbEvents, nbEvents)
summaryInboxStyle.setBigContentTitle(sumTitle) summaryInboxStyle.setBigContentTitle(sumTitle)
//TODO get latest event? //TODO get latest event?
.setSummaryText( .setSummaryText(stringProvider.getQuantityString(R.plurals.notification_unread_notified_messages, nbEvents, nbEvents))
context.resources
.getQuantityString(R.plurals.notification_unread_notified_messages, nbEvents, nbEvents))
NotificationUtils.buildSummaryListNotification( val notification = notificationUtils.buildSummaryListNotification(
context,
vectorPreferences,
summaryInboxStyle, summaryInboxStyle,
sumTitle, sumTitle,
noisy = hasNewEvent && summaryIsNoisy, noisy = hasNewEvent && summaryIsNoisy,
lastMessageTimestamp = globalLastMessageTimestamp lastMessageTimestamp = globalLastMessageTimestamp)
)?.let {
NotificationUtils.showNotificationMessage(context, null, SUMMARY_NOTIFICATION_ID, it) notificationUtils.showNotificationMessage(null, SUMMARY_NOTIFICATION_ID, notification)
}
if (hasNewEvent && summaryIsNoisy) { if (hasNewEvent && summaryIsNoisy) {
try { try {
@ -462,7 +457,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
fun persistInfo() { fun persistInfo() {
synchronized(eventList) { synchronized(eventList) {
if (eventList.isEmpty()) { if (eventList.isEmpty()) {
deleteCachedRoomNotifications(context) deleteCachedRoomNotifications()
return return
} }
try { try {
@ -494,7 +489,7 @@ class NotificationDrawerManager @Inject constructor(private val context: Context
return ArrayList() return ArrayList()
} }
private fun deleteCachedRoomNotifications(context: Context) { private fun deleteCachedRoomNotifications() {
val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME) val file = File(context.applicationContext.cacheDir, ROOMS_NOTIFICATIONS_FILE_NAME)
if (file.exists()) { if (file.exists()) {
file.delete() file.delete()

View File

@ -27,7 +27,6 @@ import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.text.TextUtils
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
@ -37,6 +36,7 @@ import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import im.vector.riotx.BuildConfig import im.vector.riotx.BuildConfig
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.startNotificationChannelSettingsIntent import im.vector.riotx.core.utils.startNotificationChannelSettingsIntent
import im.vector.riotx.features.home.HomeActivity import im.vector.riotx.features.home.HomeActivity
import im.vector.riotx.features.home.room.detail.RoomDetailActivity import im.vector.riotx.features.home.room.detail.RoomDetailActivity
@ -44,51 +44,73 @@ import im.vector.riotx.features.home.room.detail.RoomDetailArgs
import im.vector.riotx.features.settings.VectorPreferences import im.vector.riotx.features.settings.VectorPreferences
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
fun supportNotificationChannels() = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
/** /**
* Util class for creating notifications. * Util class for creating notifications.
* Note: Cannot inject ColorProvider in the constructor, because it requires an Activity
*/ */
object NotificationUtils { @Singleton
class NotificationUtils @Inject constructor(private val context: Context,
private val stringProvider: StringProvider,
private val vectorPreferences: VectorPreferences) {
/* ========================================================================================== companion object {
* IDs for notifications /* ==========================================================================================
* ========================================================================================== */ * IDs for notifications
* ========================================================================================== */
/** /**
* Identifier of the foreground notification used to keep the application alive * Identifier of the foreground notification used to keep the application alive
* when it runs in background. * when it runs in background.
* This notification, which is not removable by the end user, displays what * This notification, which is not removable by the end user, displays what
* the application is doing while in background. * the application is doing while in background.
*/ */
const val NOTIFICATION_ID_FOREGROUND_SERVICE = 61 const val NOTIFICATION_ID_FOREGROUND_SERVICE = 61
/* ========================================================================================== /* ==========================================================================================
* IDs for actions * IDs for actions
* ========================================================================================== */ * ========================================================================================== */
const val JOIN_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.JOIN_ACTION" const val JOIN_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.JOIN_ACTION"
const val REJECT_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.REJECT_ACTION" const val REJECT_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.REJECT_ACTION"
private const val QUICK_LAUNCH_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.QUICK_LAUNCH_ACTION" private const val QUICK_LAUNCH_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.QUICK_LAUNCH_ACTION"
const val MARK_ROOM_READ_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.MARK_ROOM_READ_ACTION" const val MARK_ROOM_READ_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.MARK_ROOM_READ_ACTION"
const val SMART_REPLY_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.SMART_REPLY_ACTION" const val SMART_REPLY_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.SMART_REPLY_ACTION"
const val DISMISS_SUMMARY_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.DISMISS_SUMMARY_ACTION" const val DISMISS_SUMMARY_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.DISMISS_SUMMARY_ACTION"
const val DISMISS_ROOM_NOTIF_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.DISMISS_ROOM_NOTIF_ACTION" const val DISMISS_ROOM_NOTIF_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.DISMISS_ROOM_NOTIF_ACTION"
private const val TAP_TO_VIEW_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.TAP_TO_VIEW_ACTION" private const val TAP_TO_VIEW_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.TAP_TO_VIEW_ACTION"
/* ========================================================================================== /* ==========================================================================================
* IDs for channels * IDs for channels
* ========================================================================================== */ * ========================================================================================== */
// on devices >= android O, we need to define a channel for each notifications // on devices >= android O, we need to define a channel for each notifications
private const val LISTENING_FOR_EVENTS_NOTIFICATION_CHANNEL_ID = "LISTEN_FOR_EVENTS_NOTIFICATION_CHANNEL_ID" private const val LISTENING_FOR_EVENTS_NOTIFICATION_CHANNEL_ID = "LISTEN_FOR_EVENTS_NOTIFICATION_CHANNEL_ID"
private const val NOISY_NOTIFICATION_CHANNEL_ID = "DEFAULT_NOISY_NOTIFICATION_CHANNEL_ID" private const val NOISY_NOTIFICATION_CHANNEL_ID = "DEFAULT_NOISY_NOTIFICATION_CHANNEL_ID"
private const val SILENT_NOTIFICATION_CHANNEL_ID = "DEFAULT_SILENT_NOTIFICATION_CHANNEL_ID_V2" private const val SILENT_NOTIFICATION_CHANNEL_ID = "DEFAULT_SILENT_NOTIFICATION_CHANNEL_ID_V2"
private const val CALL_NOTIFICATION_CHANNEL_ID = "CALL_NOTIFICATION_CHANNEL_ID_V2" private const val CALL_NOTIFICATION_CHANNEL_ID = "CALL_NOTIFICATION_CHANNEL_ID_V2"
fun supportNotificationChannels() = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
fun openSystemSettingsForSilentCategory(fragment: Fragment) {
startNotificationChannelSettingsIntent(fragment, SILENT_NOTIFICATION_CHANNEL_ID)
}
fun openSystemSettingsForNoisyCategory(fragment: Fragment) {
startNotificationChannelSettingsIntent(fragment, NOISY_NOTIFICATION_CHANNEL_ID)
}
fun openSystemSettingsForCallCategory(fragment: Fragment) {
startNotificationChannelSettingsIntent(fragment, CALL_NOTIFICATION_CHANNEL_ID)
}
}
private val notificationManager = NotificationManagerCompat.from(context)
/* ========================================================================================== /* ==========================================================================================
* Channel names * Channel names
@ -96,17 +118,13 @@ object NotificationUtils {
/** /**
* Create notification channels. * Create notification channels.
*
* @param context the context
*/ */
@TargetApi(Build.VERSION_CODES.O) @TargetApi(Build.VERSION_CODES.O)
fun createNotificationChannels(context: Context) { fun createNotificationChannels() {
if (!supportNotificationChannels()) { if (!supportNotificationChannels()) {
return return
} }
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
//Migration - the noisy channel was deleted and recreated when sound preference was changed (id was DEFAULT_NOISY_NOTIFICATION_CHANNEL_ID_BASE //Migration - the noisy channel was deleted and recreated when sound preference was changed (id was DEFAULT_NOISY_NOTIFICATION_CHANNEL_ID_BASE
@ -132,10 +150,10 @@ object NotificationUtils {
* intrude. * intrude.
*/ */
notificationManager.createNotificationChannel(NotificationChannel(NOISY_NOTIFICATION_CHANNEL_ID, notificationManager.createNotificationChannel(NotificationChannel(NOISY_NOTIFICATION_CHANNEL_ID,
context.getString(R.string.notification_noisy_notifications), stringProvider.getString(R.string.notification_noisy_notifications),
NotificationManager.IMPORTANCE_DEFAULT) NotificationManager.IMPORTANCE_DEFAULT)
.apply { .apply {
description = context.getString(R.string.notification_noisy_notifications) description = stringProvider.getString(R.string.notification_noisy_notifications)
enableVibration(true) enableVibration(true)
enableLights(true) enableLights(true)
lightColor = accentColor lightColor = accentColor
@ -145,29 +163,29 @@ object NotificationUtils {
* Low notification importance: shows everywhere, but is not intrusive. * Low notification importance: shows everywhere, but is not intrusive.
*/ */
notificationManager.createNotificationChannel(NotificationChannel(SILENT_NOTIFICATION_CHANNEL_ID, notificationManager.createNotificationChannel(NotificationChannel(SILENT_NOTIFICATION_CHANNEL_ID,
context.getString(R.string.notification_silent_notifications), stringProvider.getString(R.string.notification_silent_notifications),
NotificationManager.IMPORTANCE_LOW) NotificationManager.IMPORTANCE_LOW)
.apply { .apply {
description = context.getString(R.string.notification_silent_notifications) description = stringProvider.getString(R.string.notification_silent_notifications)
setSound(null, null) setSound(null, null)
enableLights(true) enableLights(true)
lightColor = accentColor lightColor = accentColor
}) })
notificationManager.createNotificationChannel(NotificationChannel(LISTENING_FOR_EVENTS_NOTIFICATION_CHANNEL_ID, notificationManager.createNotificationChannel(NotificationChannel(LISTENING_FOR_EVENTS_NOTIFICATION_CHANNEL_ID,
context.getString(R.string.notification_listening_for_events), stringProvider.getString(R.string.notification_listening_for_events),
NotificationManager.IMPORTANCE_MIN) NotificationManager.IMPORTANCE_MIN)
.apply { .apply {
description = context.getString(R.string.notification_listening_for_events) description = stringProvider.getString(R.string.notification_listening_for_events)
setSound(null, null) setSound(null, null)
setShowBadge(false) setShowBadge(false)
}) })
notificationManager.createNotificationChannel(NotificationChannel(CALL_NOTIFICATION_CHANNEL_ID, notificationManager.createNotificationChannel(NotificationChannel(CALL_NOTIFICATION_CHANNEL_ID,
context.getString(R.string.call), stringProvider.getString(R.string.call),
NotificationManager.IMPORTANCE_HIGH) NotificationManager.IMPORTANCE_HIGH)
.apply { .apply {
description = context.getString(R.string.call) description = stringProvider.getString(R.string.call)
setSound(null, null) setSound(null, null)
enableLights(true) enableLights(true)
lightColor = accentColor lightColor = accentColor
@ -177,12 +195,11 @@ object NotificationUtils {
/** /**
* Build a polling thread listener notification * Build a polling thread listener notification
* *
* @param context Android context
* @param subTitleResId subtitle string resource Id of the notification * @param subTitleResId subtitle string resource Id of the notification
* @return the polling thread listener notification * @return the polling thread listener notification
*/ */
@SuppressLint("NewApi") @SuppressLint("NewApi")
fun buildForegroundServiceNotification(context: Context, @StringRes subTitleResId: Int, withProgress: Boolean = true): Notification { fun buildForegroundServiceNotification(@StringRes subTitleResId: Int, withProgress: Boolean = true): Notification {
// build the pending intent go to the home screen if this is clicked. // build the pending intent go to the home screen if this is clicked.
val i = Intent(context, HomeActivity::class.java) val i = Intent(context, HomeActivity::class.java)
i.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP i.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
@ -191,7 +208,7 @@ object NotificationUtils {
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
val builder = NotificationCompat.Builder(context, LISTENING_FOR_EVENTS_NOTIFICATION_CHANNEL_ID) val builder = NotificationCompat.Builder(context, LISTENING_FOR_EVENTS_NOTIFICATION_CHANNEL_ID)
.setContentTitle(context.getString(subTitleResId)) .setContentTitle(stringProvider.getString(subTitleResId))
.setSmallIcon(R.drawable.sync) .setSmallIcon(R.drawable.sync)
.setCategory(NotificationCompat.CATEGORY_SERVICE) .setCategory(NotificationCompat.CATEGORY_SERVICE)
.setColor(accentColor) .setColor(accentColor)
@ -225,7 +242,7 @@ object NotificationUtils {
CharSequence::class.java, CharSequence::class.java,
CharSequence::class.java, CharSequence::class.java,
PendingIntent::class.java) PendingIntent::class.java)
deprecatedMethod.invoke(notification, context, context.getString(R.string.app_name), context.getString(subTitleResId), pi) deprecatedMethod.invoke(notification, context, stringProvider.getString(R.string.app_name), stringProvider.getString(subTitleResId), pi)
} catch (ex: Exception) { } catch (ex: Exception) {
Timber.e(ex, "## buildNotification(): Exception - setLatestEventInfo() Msg=") Timber.e(ex, "## buildNotification(): Exception - setLatestEventInfo() Msg=")
} }
@ -238,7 +255,6 @@ object NotificationUtils {
* Build an incoming call notification. * Build an incoming call notification.
* This notification starts the VectorHomeActivity which is in charge of centralizing the incoming call flow. * This notification starts the VectorHomeActivity which is in charge of centralizing the incoming call flow.
* *
* @param context the context.
* @param isVideo true if this is a video call, false for voice call * @param isVideo true if this is a video call, false for voice call
* @param roomName the room name in which the call is pending. * @param roomName the room name in which the call is pending.
* @param matrixId the matrix id * @param matrixId the matrix id
@ -246,20 +262,19 @@ object NotificationUtils {
* @return the call notification. * @return the call notification.
*/ */
@SuppressLint("NewApi") @SuppressLint("NewApi")
fun buildIncomingCallNotification(context: Context, fun buildIncomingCallNotification(isVideo: Boolean,
isVideo: Boolean,
roomName: String, roomName: String,
matrixId: String, matrixId: String,
callId: String): Notification { callId: String): Notification {
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
val builder = NotificationCompat.Builder(context, CALL_NOTIFICATION_CHANNEL_ID) val builder = NotificationCompat.Builder(context, CALL_NOTIFICATION_CHANNEL_ID)
.setContentTitle(ensureTitleNotEmpty(context, roomName)) .setContentTitle(ensureTitleNotEmpty(roomName))
.apply { .apply {
if (isVideo) { if (isVideo) {
setContentText(context.getString(R.string.incoming_video_call)) setContentText(stringProvider.getString(R.string.incoming_video_call))
} else { } else {
setContentText(context.getString(R.string.incoming_voice_call)) setContentText(stringProvider.getString(R.string.incoming_voice_call))
} }
} }
.setSmallIcon(R.drawable.incoming_call_notification_transparent) .setSmallIcon(R.drawable.incoming_call_notification_transparent)
@ -295,7 +310,6 @@ object NotificationUtils {
/** /**
* Build a pending call notification * Build a pending call notification
* *
* @param context the context.
* @param isVideo true if this is a video call, false for voice call * @param isVideo true if this is a video call, false for voice call
* @param roomName the room name in which the call is pending. * @param roomName the room name in which the call is pending.
* @param roomId the room Id * @param roomId the room Id
@ -304,20 +318,19 @@ object NotificationUtils {
* @return the call notification. * @return the call notification.
*/ */
@SuppressLint("NewApi") @SuppressLint("NewApi")
fun buildPendingCallNotification(context: Context, fun buildPendingCallNotification(isVideo: Boolean,
isVideo: Boolean,
roomName: String, roomName: String,
roomId: String, roomId: String,
matrixId: String, matrixId: String,
callId: String): Notification { callId: String): Notification {
val builder = NotificationCompat.Builder(context, CALL_NOTIFICATION_CHANNEL_ID) val builder = NotificationCompat.Builder(context, CALL_NOTIFICATION_CHANNEL_ID)
.setContentTitle(ensureTitleNotEmpty(context, roomName)) .setContentTitle(ensureTitleNotEmpty(roomName))
.apply { .apply {
if (isVideo) { if (isVideo) {
setContentText(context.getString(R.string.video_call_in_progress)) setContentText(stringProvider.getString(R.string.video_call_in_progress))
} else { } else {
setContentText(context.getString(R.string.call_in_progress)) setContentText(stringProvider.getString(R.string.call_in_progress))
} }
} }
.setSmallIcon(R.drawable.incoming_call_notification_transparent) .setSmallIcon(R.drawable.incoming_call_notification_transparent)
@ -355,9 +368,9 @@ object NotificationUtils {
/** /**
* Build a temporary (because service will be stopped just after) notification for the CallService, when a call is ended * Build a temporary (because service will be stopped just after) notification for the CallService, when a call is ended
*/ */
fun buildCallEndedNotification(context: Context): Notification { fun buildCallEndedNotification(): Notification {
return NotificationCompat.Builder(context, CALL_NOTIFICATION_CHANNEL_ID) return NotificationCompat.Builder(context, CALL_NOTIFICATION_CHANNEL_ID)
.setContentTitle(context.getString(R.string.call_ended)) .setContentTitle(stringProvider.getString(R.string.call_ended))
.setSmallIcon(R.drawable.ic_material_call_end_grey) .setSmallIcon(R.drawable.ic_material_call_end_grey)
.setCategory(NotificationCompat.CATEGORY_CALL) .setCategory(NotificationCompat.CATEGORY_CALL)
.build() .build()
@ -366,17 +379,14 @@ object NotificationUtils {
/** /**
* Build a notification for a Room * Build a notification for a Room
*/ */
fun buildMessagesListNotification(context: Context, fun buildMessagesListNotification(messageStyle: NotificationCompat.MessagingStyle,
vectorPreferences: VectorPreferences,
messageStyle: NotificationCompat.MessagingStyle,
roomInfo: RoomEventGroupInfo, roomInfo: RoomEventGroupInfo,
largeIcon: Bitmap?, largeIcon: Bitmap?,
lastMessageTimestamp: Long, lastMessageTimestamp: Long,
senderDisplayNameForReplyCompat: String?): Notification? { senderDisplayNameForReplyCompat: String?): Notification {
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
// Build the pending intent for when the notification is clicked // Build the pending intent for when the notification is clicked
val openRoomIntent = buildOpenRoomIntent(context, roomInfo.roomId) val openRoomIntent = buildOpenRoomIntent(roomInfo.roomId)
val smallIcon = R.drawable.ic_status_bar val smallIcon = R.drawable.ic_status_bar
val channelID = if (roomInfo.shouldBing) NOISY_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID val channelID = if (roomInfo.shouldBing) NOISY_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID
@ -393,18 +403,15 @@ object NotificationUtils {
// Title for API < 16 devices. // Title for API < 16 devices.
.setContentTitle(roomInfo.roomDisplayName) .setContentTitle(roomInfo.roomDisplayName)
// Content for API < 16 devices. // Content for API < 16 devices.
.setContentText(context.getString(R.string.notification_new_messages)) .setContentText(stringProvider.getString(R.string.notification_new_messages))
// Number of new notifications for API <24 (M and below) devices. // Number of new notifications for API <24 (M and below) devices.
.setSubText(context .setSubText(stringProvider.getQuantityString(R.plurals.room_new_messages_notification, messageStyle.messages.size, messageStyle.messages.size))
.resources
.getQuantityString(R.plurals.room_new_messages_notification, messageStyle.messages.size, messageStyle.messages.size)
)
// Auto-bundling is enabled for 4 or more notifications on API 24+ (N+) // Auto-bundling is enabled for 4 or more notifications on API 24+ (N+)
// devices and all Wear devices. But we want a custom grouping, so we specify the groupID // devices and all Wear devices. But we want a custom grouping, so we specify the groupID
// TODO Group should be current user display name // TODO Group should be current user display name
.setGroup(context.getString(R.string.app_name)) .setGroup(stringProvider.getString(R.string.app_name))
//In order to avoid notification making sound twice (due to the summary notification) //In order to avoid notification making sound twice (due to the summary notification)
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY) .setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
@ -440,17 +447,17 @@ object NotificationUtils {
addAction(NotificationCompat.Action( addAction(NotificationCompat.Action(
R.drawable.ic_material_done_all_white, R.drawable.ic_material_done_all_white,
context.getString(R.string.action_mark_room_read), stringProvider.getString(R.string.action_mark_room_read),
markRoomReadPendingIntent)) markRoomReadPendingIntent))
// Quick reply // Quick reply
if (!roomInfo.hasSmartReplyError) { if (!roomInfo.hasSmartReplyError) {
buildQuickReplyIntent(context, roomInfo.roomId, senderDisplayNameForReplyCompat)?.let { replyPendingIntent -> buildQuickReplyIntent(roomInfo.roomId, senderDisplayNameForReplyCompat)?.let { replyPendingIntent ->
val remoteInput = RemoteInput.Builder(NotificationBroadcastReceiver.KEY_TEXT_REPLY) val remoteInput = RemoteInput.Builder(NotificationBroadcastReceiver.KEY_TEXT_REPLY)
.setLabel(context.getString(R.string.action_quick_reply)) .setLabel(stringProvider.getString(R.string.action_quick_reply))
.build() .build()
NotificationCompat.Action.Builder(R.drawable.vector_notification_quick_reply, NotificationCompat.Action.Builder(R.drawable.vector_notification_quick_reply,
context.getString(R.string.action_quick_reply), replyPendingIntent) stringProvider.getString(R.string.action_quick_reply), replyPendingIntent)
.addRemoteInput(remoteInput) .addRemoteInput(remoteInput)
.build()?.let { .build()?.let {
addAction(it) addAction(it)
@ -477,11 +484,9 @@ object NotificationUtils {
} }
fun buildSimpleEventNotification(context: Context, fun buildSimpleEventNotification(simpleNotifiableEvent: NotifiableEvent,
vectorPreferences: VectorPreferences,
simpleNotifiableEvent: NotifiableEvent,
largeIcon: Bitmap?, largeIcon: Bitmap?,
matrixId: String): Notification? { matrixId: String): Notification {
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
// Build the pending intent for when the notification is clicked // Build the pending intent for when the notification is clicked
val smallIcon = R.drawable.ic_status_bar val smallIcon = R.drawable.ic_status_bar
@ -489,9 +494,9 @@ object NotificationUtils {
val channelID = if (simpleNotifiableEvent.noisy) NOISY_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID val channelID = if (simpleNotifiableEvent.noisy) NOISY_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID
return NotificationCompat.Builder(context, channelID) return NotificationCompat.Builder(context, channelID)
.setContentTitle(context.getString(R.string.app_name)) .setContentTitle(stringProvider.getString(R.string.app_name))
.setContentText(simpleNotifiableEvent.description) .setContentText(simpleNotifiableEvent.description)
.setGroup(context.getString(R.string.app_name)) .setGroup(stringProvider.getString(R.string.app_name))
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY) .setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
.setSmallIcon(smallIcon) .setSmallIcon(smallIcon)
.setColor(accentColor) .setColor(accentColor)
@ -508,7 +513,7 @@ object NotificationUtils {
addAction( addAction(
R.drawable.vector_notification_reject_invitation, R.drawable.vector_notification_reject_invitation,
context.getString(R.string.reject), stringProvider.getString(R.string.reject),
rejectIntentPendingIntent) rejectIntentPendingIntent)
// offer to type a quick accept button // offer to type a quick accept button
@ -520,7 +525,7 @@ object NotificationUtils {
PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT)
addAction( addAction(
R.drawable.vector_notification_accept_invitation, R.drawable.vector_notification_accept_invitation,
context.getString(R.string.join), stringProvider.getString(R.string.join),
joinIntentPendingIntent) joinIntentPendingIntent)
} else { } else {
setAutoCancel(true) setAutoCancel(true)
@ -551,7 +556,7 @@ object NotificationUtils {
.build() .build()
} }
private fun buildOpenRoomIntent(context: Context, roomId: String): PendingIntent? { private fun buildOpenRoomIntent(roomId: String): PendingIntent? {
val roomIntentTap = RoomDetailActivity.newIntent(context, RoomDetailArgs(roomId)) val roomIntentTap = RoomDetailActivity.newIntent(context, RoomDetailArgs(roomId))
roomIntentTap.action = TAP_TO_VIEW_ACTION roomIntentTap.action = TAP_TO_VIEW_ACTION
//pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that //pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that
@ -564,7 +569,7 @@ object NotificationUtils {
.getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT) .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT)
} }
private fun buildOpenHomePendingIntentForSummary(context: Context): PendingIntent { private fun buildOpenHomePendingIntentForSummary(): PendingIntent {
val intent = HomeActivity.newIntent(context, clearNotification = true) val intent = HomeActivity.newIntent(context, clearNotification = true)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.data = Uri.parse("foobar://tapSummary") intent.data = Uri.parse("foobar://tapSummary")
@ -578,7 +583,7 @@ object NotificationUtils {
However, for Android devices running Marshmallow and below (API level 23 and below), However, for Android devices running Marshmallow and below (API level 23 and below),
it will be more appropriate to use an activity. Since you have to provide your own UI. it will be more appropriate to use an activity. Since you have to provide your own UI.
*/ */
private fun buildQuickReplyIntent(context: Context, roomId: String, senderName: String?): PendingIntent? { private fun buildQuickReplyIntent(roomId: String, senderName: String?): PendingIntent? {
val intent: Intent val intent: Intent
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent = Intent(context, NotificationBroadcastReceiver::class.java) intent = Intent(context, NotificationBroadcastReceiver::class.java)
@ -610,12 +615,10 @@ object NotificationUtils {
/** /**
* Build the summary notification * Build the summary notification
*/ */
fun buildSummaryListNotification(context: Context, fun buildSummaryListNotification(style: NotificationCompat.InboxStyle,
vectorPreferences: VectorPreferences,
style: NotificationCompat.InboxStyle,
compatSummary: String, compatSummary: String,
noisy: Boolean, noisy: Boolean,
lastMessageTimestamp: Long): Notification? { lastMessageTimestamp: Long): Notification {
val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color) val accentColor = ContextCompat.getColor(context, R.color.notification_accent_color)
val smallIcon = R.drawable.ic_status_bar val smallIcon = R.drawable.ic_status_bar
@ -623,12 +626,12 @@ object NotificationUtils {
// used in compat < N, after summary is built based on child notifications // used in compat < N, after summary is built based on child notifications
.setWhen(lastMessageTimestamp) .setWhen(lastMessageTimestamp)
.setStyle(style) .setStyle(style)
.setContentTitle(context.getString(R.string.app_name)) .setContentTitle(stringProvider.getString(R.string.app_name))
.setCategory(NotificationCompat.CATEGORY_MESSAGE) .setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setSmallIcon(smallIcon) .setSmallIcon(smallIcon)
//set content text to support devices running API level < 24 //set content text to support devices running API level < 24
.setContentText(compatSummary) .setContentText(compatSummary)
.setGroup(context.getString(R.string.app_name)) .setGroup(stringProvider.getString(R.string.app_name))
//set this notification as the summary for the group //set this notification as the summary for the group
.setGroupSummary(true) .setGroupSummary(true)
.setColor(accentColor) .setColor(accentColor)
@ -645,13 +648,12 @@ object NotificationUtils {
priority = NotificationCompat.PRIORITY_LOW priority = NotificationCompat.PRIORITY_LOW
} }
} }
.setContentIntent(buildOpenHomePendingIntentForSummary(context)) .setContentIntent(buildOpenHomePendingIntentForSummary())
.setDeleteIntent(getDismissSummaryPendingIntent(context)) .setDeleteIntent(getDismissSummaryPendingIntent())
.build() .build()
} }
private fun getDismissSummaryPendingIntent(context: Context): PendingIntent { private fun getDismissSummaryPendingIntent(): PendingIntent {
val intent = Intent(context, NotificationBroadcastReceiver::class.java) val intent = Intent(context, NotificationBroadcastReceiver::class.java)
intent.action = DISMISS_SUMMARY_ACTION intent.action = DISMISS_SUMMARY_ACTION
intent.data = Uri.parse("foobar://deleteSummary") intent.data = Uri.parse("foobar://deleteSummary")
@ -659,33 +661,28 @@ object NotificationUtils {
0, intent, PendingIntent.FLAG_UPDATE_CURRENT) 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
} }
fun showNotificationMessage(context: Context, tag: String?, id: Int, notification: Notification) { fun showNotificationMessage(tag: String?, id: Int, notification: Notification) {
with(NotificationManagerCompat.from(context)) { notificationManager.notify(tag, id, notification)
notify(tag, id, notification)
}
} }
fun cancelNotificationMessage(context: Context, tag: String?, id: Int) { fun cancelNotificationMessage(tag: String?, id: Int) {
NotificationManagerCompat.from(context) notificationManager.cancel(tag, id)
.cancel(tag, id)
} }
/** /**
* Cancel the foreground notification service * Cancel the foreground notification service
*/ */
fun cancelNotificationForegroundService(context: Context) { fun cancelNotificationForegroundService() {
NotificationManagerCompat.from(context) notificationManager.cancel(NOTIFICATION_ID_FOREGROUND_SERVICE)
.cancel(NOTIFICATION_ID_FOREGROUND_SERVICE)
} }
/** /**
* Cancel all the notification * Cancel all the notification
*/ */
fun cancelAllNotifications(context: Context) { fun cancelAllNotifications() {
// Keep this try catch (reported by GA) // Keep this try catch (reported by GA)
try { try {
NotificationManagerCompat.from(context) notificationManager.cancelAll()
.cancelAll()
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "## cancelAllNotifications() failed " + e.message) Timber.e(e, "## cancelAllNotifications() failed " + e.message)
} }
@ -694,7 +691,7 @@ object NotificationUtils {
/** /**
* Return true it the user has enabled the do not disturb mode * Return true it the user has enabled the do not disturb mode
*/ */
fun isDoNotDisturbModeOn(context: Context): Boolean { fun isDoNotDisturbModeOn(): Boolean {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return false return false
} }
@ -706,23 +703,11 @@ object NotificationUtils {
|| setting == NotificationManager.INTERRUPTION_FILTER_ALARMS || setting == NotificationManager.INTERRUPTION_FILTER_ALARMS
} }
private fun ensureTitleNotEmpty(context: Context, title: String?): CharSequence { private fun ensureTitleNotEmpty(title: String?): CharSequence {
if (TextUtils.isEmpty(title)) { if (title.isNullOrBlank()) {
return context.getString(R.string.app_name) return stringProvider.getString(R.string.app_name)
} }
return title!! return title
}
fun openSystemSettingsForSilentCategory(fragment: Fragment) {
startNotificationChannelSettingsIntent(fragment, SILENT_NOTIFICATION_CHANNEL_ID)
}
fun openSystemSettingsForNoisyCategory(fragment: Fragment) {
startNotificationChannelSettingsIntent(fragment, NOISY_NOTIFICATION_CHANNEL_ID)
}
fun openSystemSettingsForCallCategory(fragment: Fragment) {
startNotificationChannelSettingsIntent(fragment, CALL_NOTIFICATION_CHANNEL_ID)
} }
} }

View File

@ -29,7 +29,6 @@ import im.vector.riotx.core.extensions.withArgs
import im.vector.riotx.core.preference.BingRule import im.vector.riotx.core.preference.BingRule
import im.vector.riotx.core.preference.BingRulePreference import im.vector.riotx.core.preference.BingRulePreference
import im.vector.riotx.features.notifications.NotificationUtils import im.vector.riotx.features.notifications.NotificationUtils
import im.vector.riotx.features.notifications.supportNotificationChannels
import javax.inject.Inject import javax.inject.Inject
class VectorSettingsAdvancedNotificationPreferenceFragment : VectorSettingsBaseFragment() { class VectorSettingsAdvancedNotificationPreferenceFragment : VectorSettingsBaseFragment() {
@ -56,7 +55,7 @@ class VectorSettingsAdvancedNotificationPreferenceFragment : VectorSettingsBaseF
override fun bindPref() { override fun bindPref() {
val callNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_CALL_NOTIFICATION_PREFERENCE_KEY) val callNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_CALL_NOTIFICATION_PREFERENCE_KEY)
if (supportNotificationChannels()) { if (NotificationUtils.supportNotificationChannels()) {
callNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener { callNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener {
NotificationUtils.openSystemSettingsForCallCategory(this) NotificationUtils.openSystemSettingsForCallCategory(this)
false false
@ -66,7 +65,7 @@ class VectorSettingsAdvancedNotificationPreferenceFragment : VectorSettingsBaseF
} }
val noisyNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_NOISY_NOTIFICATION_PREFERENCE_KEY) val noisyNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_NOISY_NOTIFICATION_PREFERENCE_KEY)
if (supportNotificationChannels()) { if (NotificationUtils.supportNotificationChannels()) {
noisyNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener { noisyNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener {
NotificationUtils.openSystemSettingsForNoisyCategory(this) NotificationUtils.openSystemSettingsForNoisyCategory(this)
false false
@ -76,7 +75,7 @@ class VectorSettingsAdvancedNotificationPreferenceFragment : VectorSettingsBaseF
} }
val silentNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_SILENT_NOTIFICATION_PREFERENCE_KEY) val silentNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_SILENT_NOTIFICATION_PREFERENCE_KEY)
if (supportNotificationChannels()) { if (NotificationUtils.supportNotificationChannels()) {
silentNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener { silentNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener {
NotificationUtils.openSystemSettingsForSilentCategory(this) NotificationUtils.openSystemSettingsForSilentCategory(this)
false false
@ -89,7 +88,7 @@ class VectorSettingsAdvancedNotificationPreferenceFragment : VectorSettingsBaseF
// Ringtone // Ringtone
val ringtonePreference = findPreference(VectorPreferences.SETTINGS_NOTIFICATION_RINGTONE_SELECTION_PREFERENCE_KEY) val ringtonePreference = findPreference(VectorPreferences.SETTINGS_NOTIFICATION_RINGTONE_SELECTION_PREFERENCE_KEY)
if (supportNotificationChannels()) { if (NotificationUtils.supportNotificationChannels()) {
ringtonePreference.isVisible = false ringtonePreference.isVisible = false
} else { } else {
ringtonePreference.summary = vectorPreferences.getNotificationRingToneName() ringtonePreference.summary = vectorPreferences.getNotificationRingToneName()