Reworked how Persons are used + fixed timestamp issue in chat message notification + fixed chat room being marked as read when answering in the notification

This commit is contained in:
Sylvain Berfini 2023-01-12 16:53:52 +01:00
parent 8a09115623
commit 01c8735caf
3 changed files with 65 additions and 65 deletions

View file

@ -26,6 +26,7 @@ import android.content.ContentResolver
import android.content.ContentUris import android.content.ContentUris
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.provider.ContactsContract import android.provider.ContactsContract
@ -41,6 +42,7 @@ import org.linphone.R
import org.linphone.core.* import org.linphone.core.*
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
import org.linphone.utils.ImageUtils import org.linphone.utils.ImageUtils
import org.linphone.utils.LinphoneUtils
import org.linphone.utils.PermissionHelper import org.linphone.utils.PermissionHelper
interface ContactsUpdatedListener { interface ContactsUpdatedListener {
@ -70,6 +72,7 @@ class ContactsManager(private val context: Context) {
val contactAvatar: IconCompat val contactAvatar: IconCompat
val groupAvatar: IconCompat val groupAvatar: IconCompat
val groupBitmap: Bitmap
private val localFriends = arrayListOf<Friend>() private val localFriends = arrayListOf<Friend>()
@ -93,6 +96,7 @@ class ContactsManager(private val context: Context) {
contactAvatar = IconCompat.createWithResource(context, R.drawable.voip_single_contact_avatar_alt) contactAvatar = IconCompat.createWithResource(context, R.drawable.voip_single_contact_avatar_alt)
groupAvatar = IconCompat.createWithResource(context, R.drawable.voip_multiple_contacts_avatar_alt) groupAvatar = IconCompat.createWithResource(context, R.drawable.voip_multiple_contacts_avatar_alt)
groupBitmap = BitmapFactory.decodeResource(context.resources, R.drawable.voip_multiple_contacts_avatar_alt)
val core = coreContext.core val core = coreContext.core
for (list in core.friendsLists) { for (list in core.friendsLists) {
@ -120,7 +124,7 @@ class ContactsManager(private val context: Context) {
for (account in coreContext.core.accountList) { for (account in coreContext.core.accountList) {
val friend = coreContext.core.createFriend() val friend = coreContext.core.createFriend()
friend.name = account.params.identityAddress?.displayName ?: account.params.identityAddress?.username friend.name = LinphoneUtils.getDisplayName(account.params.identityAddress)
val address = account.params.identityAddress ?: continue val address = account.params.identityAddress ?: continue
friend.address = address friend.address = address
@ -137,6 +141,17 @@ class ContactsManager(private val context: Context) {
} }
} }
@Synchronized
fun getMePerson(localAddress: Address): Person {
val friend = localFriends.find { localFriend ->
localFriend.addresses.find { address ->
address.weakEqual(localAddress)
} != null
}
return friend?.getPerson()
?: Person.Builder().setName(LinphoneUtils.getDisplayName(localAddress)).build()
}
@Synchronized @Synchronized
fun getAndroidContactIdFromUri(uri: Uri): String? { fun getAndroidContactIdFromUri(uri: Uri): String? {
val projection = arrayOf(ContactsContract.Data.CONTACT_ID) val projection = arrayOf(ContactsContract.Data.CONTACT_ID)
@ -381,14 +396,13 @@ fun Friend.getPerson(): Person {
coreContext.context, coreContext.context,
getThumbnailUri() getThumbnailUri()
) )
val icon = personBuilder.setIcon(
if (bm == null) { if (bm == null) {
coreContext.contactsManager.contactAvatar coreContext.contactsManager.contactAvatar
} else IconCompat.createWithAdaptiveBitmap(bm) } else IconCompat.createWithAdaptiveBitmap(bm)
if (icon != null) { )
personBuilder.setIcon(icon)
}
personBuilder.setKey(refKey)
personBuilder.setUri(nativeUri) personBuilder.setUri(nativeUri)
personBuilder.setImportant(starred) personBuilder.setImportant(starred)
return personBuilder.build() return personBuilder.build()

View file

@ -76,7 +76,6 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
return return
} }
room.markAsRead()
if (intent.action == NotificationsManager.INTENT_REPLY_NOTIF_ACTION) { if (intent.action == NotificationsManager.INTENT_REPLY_NOTIF_ACTION) {
val reply = getMessageText(intent)?.toString() val reply = getMessageText(intent)?.toString()
if (reply == null) { if (reply == null) {
@ -90,6 +89,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
msg.send() msg.send()
Log.i("[Notification Broadcast Receiver] Reply sent for notif id $notificationId") Log.i("[Notification Broadcast Receiver] Reply sent for notif id $notificationId")
} else { } else {
room.markAsRead()
if (!coreContext.notificationsManager.dismissChatNotification(room)) { if (!coreContext.notificationsManager.dismissChatNotification(room)) {
Log.w("[Notification Broadcast Receiver] Notifications Manager failed to cancel notification") Log.w("[Notification Broadcast Receiver] Notifications Manager failed to cancel notification")
val notificationManager = context.getSystemService(NotificationManager::class.java) val notificationManager = context.getSystemService(NotificationManager::class.java)

View file

@ -480,19 +480,18 @@ class NotificationsManager(private val context: Context) {
} }
fun getPerson(friend: Friend?, displayName: String, picture: Bitmap?): Person { fun getPerson(friend: Friend?, displayName: String, picture: Bitmap?): Person {
return if (friend != null) { return friend?.getPerson()
friend.getPerson() ?: Person.Builder()
} else { .setName(displayName)
val builder = Person.Builder().setName(displayName) .setIcon(
val userIcon = if (picture != null) {
if (picture != null) { IconCompat.createWithAdaptiveBitmap(picture)
IconCompat.createWithAdaptiveBitmap(picture) } else {
} else { coreContext.contactsManager.contactAvatar
coreContext.contactsManager.contactAvatar }
} )
if (userIcon != null) builder.setIcon(userIcon) .setKey(displayName)
builder.build() .build()
}
} }
fun displayIncomingCallNotification(call: Call, useAsForeground: Boolean) { fun displayIncomingCallNotification(call: Call, useAsForeground: Boolean) {
@ -665,41 +664,18 @@ class NotificationsManager(private val context: Context) {
) )
val id = LinphoneUtils.getChatRoomId(room.localAddress, room.peerAddress) val id = LinphoneUtils.getChatRoomId(room.localAddress, room.peerAddress)
val notification = createMessageNotification(notifiable, pendingIntent, bubbleIntent, id) val me = coreContext.contactsManager.getMePerson(room.localAddress)
val notification = createMessageNotification(notifiable, pendingIntent, bubbleIntent, id, me)
notify(notifiable.notificationId, notification, CHAT_TAG) notify(notifiable.notificationId, notification, CHAT_TAG)
} }
private fun createChatNotifiable(room: ChatRoom, message: ChatMessage): Notifiable {
val notifiable = getNotifiableForRoom(room)
if (notifiable.messages.isNotEmpty() || room.unreadMessagesCount == 1) {
val friend = coreContext.contactsManager.findContactByAddress(message.fromAddress)
val notifiableMessage = getNotifiableMessage(message, friend)
notifiable.messages.add(notifiableMessage)
} else {
for (chatMessage in room.unreadHistory) {
val friend = coreContext.contactsManager.findContactByAddress(chatMessage.fromAddress)
val notifiableMessage = getNotifiableMessage(chatMessage, friend)
notifiable.messages.add(notifiableMessage)
}
}
if (room.hasCapability(ChatRoomCapabilities.OneToOne.toInt())) {
notifiable.isGroup = false
} else {
notifiable.isGroup = true
notifiable.groupTitle = room.subject
}
return notifiable
}
private fun createChatNotifiable(room: ChatRoom, messages: Array<out ChatMessage>): Notifiable { private fun createChatNotifiable(room: ChatRoom, messages: Array<out ChatMessage>): Notifiable {
val notifiable = getNotifiableForRoom(room) val notifiable = getNotifiableForRoom(room)
for (message in messages) { for (message in messages) {
if (message.isRead || message.isOutgoing) continue if (message.isRead || message.isOutgoing) continue
val friend = coreContext.contactsManager.findContactByAddress(message.fromAddress) val friend = coreContext.contactsManager.findContactByAddress(message.fromAddress)
val notifiableMessage = getNotifiableMessage(message, friend) val notifiableMessage = getNotifiableMessage(message, friend, notifiable)
notifiable.messages.add(notifiableMessage) notifiable.messages.add(notifiableMessage)
} }
@ -727,7 +703,7 @@ class NotificationsManager(private val context: Context) {
return notifiable return notifiable
} }
private fun getNotifiableMessage(message: ChatMessage, friend: Friend?): NotifiableMessage { private fun getNotifiableMessage(message: ChatMessage, friend: Friend?, notifiable: Notifiable): NotifiableMessage {
val roundPicture = ImageUtils.getRoundBitmapFromUri(context, friend?.getThumbnailUri()) val roundPicture = ImageUtils.getRoundBitmapFromUri(context, friend?.getThumbnailUri())
val displayName = friend?.name ?: LinphoneUtils.getDisplayName(message.fromAddress) val displayName = friend?.name ?: LinphoneUtils.getDisplayName(message.fromAddress)
var text = "" var text = ""
@ -752,7 +728,7 @@ class NotificationsManager(private val context: Context) {
text, text,
friend, friend,
displayName, displayName,
message.time, message.time * 1000, /* Linphone timestamps are in seconds */
senderAvatar = roundPicture, senderAvatar = roundPicture,
isOutgoing = message.isOutgoing isOutgoing = message.isOutgoing
) )
@ -784,10 +760,11 @@ class NotificationsManager(private val context: Context) {
Log.i("[Notifications Manager] Updating message notification with reply for notification ${notifiable.notificationId}") Log.i("[Notifications Manager] Updating message notification with reply for notification ${notifiable.notificationId}")
val text = message.contents.find { content -> content.isText }?.utf8Text ?: "" val text = message.contents.find { content -> content.isText }?.utf8Text ?: ""
val senderAddress = message.fromAddress
val reply = NotifiableMessage( val reply = NotifiableMessage(
text, text,
null, null,
notifiable.myself ?: LinphoneUtils.getDisplayName(message.fromAddress), notifiable.myself ?: LinphoneUtils.getDisplayName(senderAddress),
System.currentTimeMillis(), System.currentTimeMillis(),
isOutgoing = true isOutgoing = true
) )
@ -836,38 +813,43 @@ class NotificationsManager(private val context: Context) {
notifiable: Notifiable, notifiable: Notifiable,
pendingIntent: PendingIntent, pendingIntent: PendingIntent,
bubbleIntent: PendingIntent, bubbleIntent: PendingIntent,
id: String id: String,
me: Person
): Notification { ): Notification {
val me = Person.Builder().setName(notifiable.myself).build()
val style = NotificationCompat.MessagingStyle(me) val style = NotificationCompat.MessagingStyle(me)
val largeIcon: Bitmap? = notifiable.messages.lastOrNull()?.senderAvatar val allPersons = arrayListOf<Person>()
var lastPersonAvatar: Bitmap? = null
var lastPerson: Person? = null var lastPerson: Person? = null
for (message in notifiable.messages) { for (message in notifiable.messages) {
val friend = message.friend val friend = message.friend
val person = getPerson(friend, message.sender, message.senderAvatar) val person = if (message.isOutgoing)
me
else
getPerson(friend, message.sender, message.senderAvatar)
// We don't want to see our own avatar
if (!message.isOutgoing) { if (!message.isOutgoing) {
// We don't want to see our own avatar
lastPerson = person lastPerson = person
lastPersonAvatar = message.senderAvatar
if (allPersons.find { it.key == person.key } == null) {
allPersons.add(person)
}
} }
val msg = if (!corePreferences.hideChatMessageContentInNotification) { val msg = if (corePreferences.hideChatMessageContentInNotification) {
NotificationCompat.MessagingStyle.Message(message.message, message.time, person)
} else {
NotificationCompat.MessagingStyle.Message(AppUtils.getString(R.string.chat_message_notification_hidden_content), message.time, person) NotificationCompat.MessagingStyle.Message(AppUtils.getString(R.string.chat_message_notification_hidden_content), message.time, person)
} } else {
val tmp = NotificationCompat.MessagingStyle.Message(message.message, message.time, person)
if (message.filePath != null && !corePreferences.hideChatMessageContentInNotification) { if (message.filePath != null) tmp.setData(message.fileMime, message.filePath)
msg.setData(message.fileMime, message.filePath) tmp
} }
style.addMessage(msg) style.addMessage(msg)
} }
if (notifiable.isGroup) { style.conversationTitle = if (notifiable.isGroup) notifiable.groupTitle else lastPerson?.name
style.conversationTitle = notifiable.groupTitle
}
style.isGroupConversation = notifiable.isGroup style.isGroupConversation = notifiable.isGroup
val icon = lastPerson?.icon ?: coreContext.contactsManager.contactAvatar val icon = lastPerson?.icon ?: coreContext.contactsManager.contactAvatar
@ -875,11 +857,12 @@ class NotificationsManager(private val context: Context) {
.setDesiredHeightResId(R.dimen.chat_message_bubble_desired_height) .setDesiredHeightResId(R.dimen.chat_message_bubble_desired_height)
.build() .build()
val largeIcon = if (notifiable.isGroup) coreContext.contactsManager.groupBitmap else lastPersonAvatar
val notificationBuilder = NotificationCompat.Builder(context, context.getString(R.string.notification_channel_chat_id)) val notificationBuilder = NotificationCompat.Builder(context, context.getString(R.string.notification_channel_chat_id))
.addPerson(lastPerson)
.setSmallIcon(R.drawable.topbar_chat_notification) .setSmallIcon(R.drawable.topbar_chat_notification)
.setAutoCancel(true) .setAutoCancel(true)
.setLargeIcon(largeIcon) .setLargeIcon(largeIcon)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
.setCategory(NotificationCompat.CATEGORY_MESSAGE) .setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setGroup(CHAT_NOTIFICATIONS_GROUP) .setGroup(CHAT_NOTIFICATIONS_GROUP)
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE) .setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
@ -887,12 +870,15 @@ class NotificationsManager(private val context: Context) {
.setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis())
.setShowWhen(true) .setShowWhen(true)
.setStyle(style) .setStyle(style)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
.addAction(getReplyMessageAction(notifiable)) .addAction(getReplyMessageAction(notifiable))
.addAction(getMarkMessageAsReadAction(notifiable)) .addAction(getMarkMessageAsReadAction(notifiable))
.setShortcutId(id) .setShortcutId(id)
.setLocusId(LocusIdCompat(id)) .setLocusId(LocusIdCompat(id))
for (person in allPersons) {
notificationBuilder.addPerson(person)
}
if (!corePreferences.preventInterfaceFromShowingUp) { if (!corePreferences.preventInterfaceFromShowingUp) {
notificationBuilder.setContentIntent(pendingIntent) notificationBuilder.setContentIntent(pendingIntent)
} }