Daggerization and cleanup of NotificationUtils
This commit is contained in:
parent
7da9cafcc2
commit
f5020d0f63
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue