|
|
|
@@ -10,8 +10,8 @@ import androidx.core.app.NotificationCompat
|
|
|
|
|
import androidx.core.app.NotificationManagerCompat
|
|
|
|
|
import chat.simplex.app.*
|
|
|
|
|
import chat.simplex.app.views.call.*
|
|
|
|
|
import chat.simplex.app.views.helpers.base64ToBitmap
|
|
|
|
|
import chat.simplex.app.views.helpers.generalGetString
|
|
|
|
|
import chat.simplex.app.views.chatlist.acceptContactRequest
|
|
|
|
|
import chat.simplex.app.views.helpers.*
|
|
|
|
|
import chat.simplex.app.views.usersettings.NotificationPreviewMode
|
|
|
|
|
import kotlinx.datetime.Clock
|
|
|
|
|
|
|
|
|
@@ -27,6 +27,8 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
|
|
|
|
|
const val LockScreenCallChannel: String = "chat.simplex.app.LOCK_SCREEN_CALL_NOTIFICATION"
|
|
|
|
|
const val AcceptCallAction: String = "chat.simplex.app.ACCEPT_CALL"
|
|
|
|
|
const val CallNotificationId: Int = -1
|
|
|
|
|
|
|
|
|
|
private const val ChatIdKey: String = "chatId"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private val manager: NotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
|
|
@@ -39,6 +41,10 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
|
|
|
|
|
manager.createNotificationChannel(callNotificationChannel())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum class NotificationAction {
|
|
|
|
|
ACCEPT_CONTACT_REQUEST
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun callNotificationChannel(): NotificationChannel {
|
|
|
|
|
val callChannel = NotificationChannel(CallChannel, generalGetString(R.string.ntf_channel_calls), NotificationManager.IMPORTANCE_HIGH)
|
|
|
|
|
val attrs = AudioAttributes.Builder()
|
|
|
|
@@ -64,13 +70,31 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun notifyContactRequestReceived(cInfo: ChatInfo.ContactRequest) {
|
|
|
|
|
notifyMessageReceived(
|
|
|
|
|
chatId = cInfo.id,
|
|
|
|
|
displayName = cInfo.displayName,
|
|
|
|
|
msgText = generalGetString(R.string.notification_new_contact_request),
|
|
|
|
|
image = cInfo.image,
|
|
|
|
|
listOf(NotificationAction.ACCEPT_CONTACT_REQUEST)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun notifyContactConnected(contact: Contact) {
|
|
|
|
|
notifyMessageReceived(
|
|
|
|
|
chatId = contact.id,
|
|
|
|
|
displayName = contact.displayName,
|
|
|
|
|
msgText = generalGetString(R.string.notification_contact_connected)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun notifyMessageReceived(cInfo: ChatInfo, cItem: ChatItem) {
|
|
|
|
|
if (!cInfo.ntfsEnabled) return
|
|
|
|
|
|
|
|
|
|
notifyMessageReceived(chatId = cInfo.id, displayName = cInfo.displayName, msgText = hideSecrets(cItem))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun notifyMessageReceived(chatId: String, displayName: String, msgText: String) {
|
|
|
|
|
fun notifyMessageReceived(chatId: String, displayName: String, msgText: String, image: String? = null, actions: List<NotificationAction> = emptyList()) {
|
|
|
|
|
Log.d(TAG, "notifyMessageReceived $chatId")
|
|
|
|
|
val now = Clock.System.now().toEpochMilliseconds()
|
|
|
|
|
val recentNotification = (now - prevNtfTime.getOrDefault(chatId, 0) < msgNtfTimeoutMs)
|
|
|
|
@@ -79,18 +103,36 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
|
|
|
|
|
val previewMode = appPreferences.notificationPreviewMode.get()
|
|
|
|
|
val title = if (previewMode == NotificationPreviewMode.HIDDEN.name) generalGetString(R.string.notification_preview_somebody) else displayName
|
|
|
|
|
val content = if (previewMode != NotificationPreviewMode.MESSAGE.name) generalGetString(R.string.notification_preview_new_message) else msgText
|
|
|
|
|
val notification = NotificationCompat.Builder(context, MessageChannel)
|
|
|
|
|
val largeIcon = when {
|
|
|
|
|
actions.isEmpty() -> null
|
|
|
|
|
image == null || previewMode == NotificationPreviewMode.HIDDEN.name -> BitmapFactory.decodeResource(context.resources, R.drawable.icon)
|
|
|
|
|
else -> base64ToBitmap(image)
|
|
|
|
|
}
|
|
|
|
|
val builder = NotificationCompat.Builder(context, MessageChannel)
|
|
|
|
|
.setContentTitle(title)
|
|
|
|
|
.setContentText(content)
|
|
|
|
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
|
|
|
.setGroup(MessageGroup)
|
|
|
|
|
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN)
|
|
|
|
|
.setSmallIcon(R.drawable.ntf_icon)
|
|
|
|
|
.setLargeIcon(largeIcon)
|
|
|
|
|
.setColor(0x88FFFF)
|
|
|
|
|
.setAutoCancel(true)
|
|
|
|
|
.setVibrate(if (actions.isEmpty()) null else longArrayOf(0, 250, 250, 250))
|
|
|
|
|
.setContentIntent(chatPendingIntent(OpenChatAction, chatId))
|
|
|
|
|
.setSilent(recentNotification)
|
|
|
|
|
.build()
|
|
|
|
|
.setSilent(if (actions.isEmpty()) recentNotification else false)
|
|
|
|
|
|
|
|
|
|
for (action in actions) {
|
|
|
|
|
val flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
|
|
|
|
val actionIntent = Intent(SimplexApp.context, NtfActionReceiver::class.java)
|
|
|
|
|
actionIntent.action = action.name
|
|
|
|
|
actionIntent.putExtra(ChatIdKey, chatId)
|
|
|
|
|
val actionPendingIntent: PendingIntent = PendingIntent.getBroadcast(SimplexApp.context, 0, actionIntent, flags)
|
|
|
|
|
val actionButton = when (action) {
|
|
|
|
|
NotificationAction.ACCEPT_CONTACT_REQUEST -> generalGetString(R.string.accept)
|
|
|
|
|
}
|
|
|
|
|
builder.addAction(0, actionButton, actionPendingIntent)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val summary = NotificationCompat.Builder(context, MessageChannel)
|
|
|
|
|
.setSmallIcon(R.drawable.ntf_icon)
|
|
|
|
@@ -103,7 +145,7 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
|
|
|
|
|
|
|
|
|
|
with(NotificationManagerCompat.from(context)) {
|
|
|
|
|
// using cInfo.id only shows one notification per chat and updates it when the message arrives
|
|
|
|
|
notify(chatId.hashCode(), notification)
|
|
|
|
|
notify(chatId.hashCode(), builder.build())
|
|
|
|
|
notify(0, summary)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -141,6 +183,10 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
|
|
|
|
|
generalGetString(R.string.notification_preview_somebody)
|
|
|
|
|
else
|
|
|
|
|
invitation.contact.displayName
|
|
|
|
|
val largeIcon = if (image == null || previewMode == NotificationPreviewMode.HIDDEN.name)
|
|
|
|
|
BitmapFactory.decodeResource(context.resources, R.drawable.icon)
|
|
|
|
|
else
|
|
|
|
|
base64ToBitmap(image)
|
|
|
|
|
|
|
|
|
|
ntfBuilder = ntfBuilder
|
|
|
|
|
.setContentTitle(title)
|
|
|
|
@@ -148,7 +194,7 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
|
|
|
|
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
|
|
|
.setCategory(NotificationCompat.CATEGORY_CALL)
|
|
|
|
|
.setSmallIcon(R.drawable.ntf_icon)
|
|
|
|
|
.setLargeIcon(if (image == null) BitmapFactory.decodeResource(context.resources, R.drawable.icon) else base64ToBitmap(image))
|
|
|
|
|
.setLargeIcon(largeIcon)
|
|
|
|
|
.setColor(0x88FFFF)
|
|
|
|
|
.setAutoCancel(true)
|
|
|
|
|
with(NotificationManagerCompat.from(context)) {
|
|
|
|
@@ -183,10 +229,31 @@ class NtfManager(val context: Context, private val appPreferences: AppPreference
|
|
|
|
|
var intent = Intent(context, MainActivity::class.java)
|
|
|
|
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
|
|
|
.setAction(intentAction)
|
|
|
|
|
if (chatId != null) intent = intent.putExtra("chatId", chatId)
|
|
|
|
|
if (chatId != null) intent = intent.putExtra(ChatIdKey, chatId)
|
|
|
|
|
return TaskStackBuilder.create(context).run {
|
|
|
|
|
addNextIntentWithParentStack(intent)
|
|
|
|
|
getPendingIntent(uniqueInt, PendingIntent.FLAG_IMMUTABLE)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Processes every action specified by [NotificationCompat.Builder.addAction] that comes with [NotificationAction]
|
|
|
|
|
* and [ChatInfo.id] as [ChatIdKey] in extra
|
|
|
|
|
* */
|
|
|
|
|
class NtfActionReceiver: BroadcastReceiver() {
|
|
|
|
|
override fun onReceive(context: Context?, intent: Intent?) {
|
|
|
|
|
val chatId = intent?.getStringExtra(ChatIdKey) ?: return
|
|
|
|
|
val cInfo = SimplexApp.context.chatModel.getChat(chatId)?.chatInfo
|
|
|
|
|
when (intent.action) {
|
|
|
|
|
NotificationAction.ACCEPT_CONTACT_REQUEST.name -> {
|
|
|
|
|
if (cInfo !is ChatInfo.ContactRequest) return
|
|
|
|
|
acceptContactRequest(cInfo, SimplexApp.context.chatModel)
|
|
|
|
|
SimplexApp.context.chatModel.controller.ntfManager.cancelNotificationsForChat(chatId)
|
|
|
|
|
}
|
|
|
|
|
else -> {
|
|
|
|
|
Log.e(TAG, "Unknown action. Make sure you provide action from NotificationAction enum")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|