fix: improve sms receiver handling (#642)

* fix: improve sms receiver handling
* docs: add comment regarding multiple messages
* fix: catch errors when inserting conversation

Refs: https://github.com/FossifyOrg/Messages/issues/159
This commit is contained in:
Naveen Singh 2025-12-21 14:51:54 +05:30 committed by GitHub
parent ed2aedd915
commit 1e3f5e5933
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 138 additions and 119 deletions

View file

@ -1050,24 +1050,20 @@ fun Context.getThreadId(addresses: Set<String>): Long {
fun Context.showReceivedMessageNotification(
messageId: Long,
address: String,
senderName: String,
body: String,
threadId: Long,
bitmap: Bitmap?,
) {
val privateCursor = getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true)
ensureBackgroundThread {
val senderName = getNameFromAddress(address, privateCursor)
Handler(Looper.getMainLooper()).post {
notificationHelper.showMessageNotification(
messageId = messageId,
address = address,
body = body,
threadId = threadId,
bitmap = bitmap,
sender = senderName
)
}
Handler(Looper.getMainLooper()).post {
notificationHelper.showMessageNotification(
messageId = messageId,
address = address,
body = body,
threadId = threadId,
bitmap = bitmap,
sender = senderName
)
}
}

View file

@ -2,8 +2,6 @@ package org.fossify.messages.receivers
import android.content.Context
import android.net.Uri
import android.os.Handler
import android.os.Looper
import com.bumptech.glide.Glide
import com.klinker.android.send_message.MmsReceivedReceiver
import org.fossify.commons.extensions.baseConfig
@ -16,6 +14,7 @@ import org.fossify.commons.helpers.ensureBackgroundThread
import org.fossify.messages.R
import org.fossify.messages.extensions.getConversations
import org.fossify.messages.extensions.getLatestMMS
import org.fossify.messages.extensions.getNameFromAddress
import org.fossify.messages.extensions.insertOrUpdateConversation
import org.fossify.messages.extensions.shouldUnarchive
import org.fossify.messages.extensions.showReceivedMessageNotification
@ -31,12 +30,10 @@ class MmsReceiver : MmsReceivedReceiver() {
val normalizedAddress = address.normalizePhoneNumber()
if (context.isNumberBlocked(normalizedAddress)) return true
if (context.baseConfig.blockUnknownNumbers) {
val privateCursor = context.getMyContactsCursor(
favoritesOnly = false,
withPhoneNumbersOnly = true
)
val isKnownContact = SimpleContactsHelper(context).existsSync(address, privateCursor)
return !isKnownContact
context.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true).use {
val isKnownContact = SimpleContactsHelper(context).existsSync(address, it)
return !isKnownContact
}
}
return false
@ -76,25 +73,26 @@ class MmsReceiver : MmsReceivedReceiver() {
null
}
Handler(Looper.getMainLooper()).post {
context.showReceivedMessageNotification(
messageId = mms.id,
address = address,
body = mms.body,
threadId = mms.threadId,
bitmap = glideBitmap
)
ensureBackgroundThread {
val conversation = context.getConversations(mms.threadId).firstOrNull()
?: return@ensureBackgroundThread
context.insertOrUpdateConversation(conversation)
if (context.shouldUnarchive()) {
context.updateConversationArchivedStatus(mms.threadId, false)
}
refreshMessages()
refreshConversations()
}
val senderName = context.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true).use {
context.getNameFromAddress(address, it)
}
context.showReceivedMessageNotification(
messageId = mms.id,
address = address,
senderName = senderName,
body = mms.body,
threadId = mms.threadId,
bitmap = glideBitmap
)
val conversation = context.getConversations(mms.threadId).firstOrNull() ?: return
runCatching { context.insertOrUpdateConversation(conversation) }
if (context.shouldUnarchive()) {
context.updateConversationArchivedStatus(mms.threadId, false)
}
refreshMessages()
refreshConversations()
}
}

View file

@ -3,8 +3,6 @@ package org.fossify.messages.receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.provider.Telephony
import org.fossify.commons.extensions.baseConfig
import org.fossify.commons.extensions.getMyContactsCursor
@ -29,104 +27,128 @@ import org.fossify.messages.helpers.refreshMessages
import org.fossify.messages.models.Message
class SmsReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val messages = Telephony.Sms.Intents.getMessagesFromIntent(intent)
var address = ""
var body = ""
var subject = ""
var date = 0L
var threadId = 0L
var status = Telephony.Sms.STATUS_NONE
val type = Telephony.Sms.MESSAGE_TYPE_INBOX
val read = 0
val subscriptionId = intent.getIntExtra("subscription", -1)
val privateCursor = context.getMyContactsCursor(false, true)
override fun onReceive(context: Context, intent: Intent) {
val pending = goAsync()
val appContext = context.applicationContext
ensureBackgroundThread {
messages.forEach {
address = it.originatingAddress ?: ""
subject = it.pseudoSubject
status = it.status
body += it.messageBody
date = System.currentTimeMillis()
threadId = context.getThreadId(address)
}
if (context.baseConfig.blockUnknownNumbers) {
val simpleContactsHelper = SimpleContactsHelper(context)
// Maybe switch to existsSync()? No?
simpleContactsHelper.exists(address, privateCursor) { exists ->
if (exists) {
handleMessage(context, address, subject, body, date, read, threadId, type, subscriptionId, status)
try {
val parts = Telephony.Sms.Intents.getMessagesFromIntent(intent)
if (parts.isEmpty()) return@ensureBackgroundThread
// this is how it has always worked, but need to revisit this.
val address = parts.last().originatingAddress.orEmpty()
if (address.isBlank()) return@ensureBackgroundThread
val subject = parts.last().pseudoSubject.orEmpty()
val status = parts.last().status
val body = buildString { parts.forEach { append(it.messageBody.orEmpty()) } }
if (isMessageFilteredOut(appContext, body)) return@ensureBackgroundThread
if (appContext.isNumberBlocked(address)) return@ensureBackgroundThread
if (appContext.baseConfig.blockUnknownNumbers) {
appContext.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true).use {
val isKnownContact = SimpleContactsHelper(appContext).existsSync(address, it)
if (!isKnownContact) return@ensureBackgroundThread
}
}
} else {
handleMessage(context, address, subject, body, date, read, threadId, type, subscriptionId, status)
val date = System.currentTimeMillis()
val threadId = appContext.getThreadId(address)
val subscriptionId = intent.getIntExtra("subscription", -1)
handleMessageSync(
context = appContext,
address = address,
subject = subject,
body = body,
date = date,
threadId = threadId,
subscriptionId = subscriptionId,
status = status
)
} finally {
pending.finish()
}
}
}
private fun handleMessage(
private fun handleMessageSync(
context: Context,
address: String,
subject: String,
body: String,
date: Long,
read: Int,
read: Int = 0,
threadId: Long,
type: Int,
type: Int = Telephony.Sms.MESSAGE_TYPE_INBOX,
subscriptionId: Int,
status: Int
) {
if (isMessageFilteredOut(context, body)) {
return
}
val photoUri = SimpleContactsHelper(context).getPhotoUriFromPhoneNumber(address)
val bitmap = context.getNotificationBitmap(photoUri)
Handler(Looper.getMainLooper()).post {
if (!context.isNumberBlocked(address)) {
val privateCursor = context.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true)
ensureBackgroundThread {
val newMessageId = context.insertNewSMS(address, subject, body, date, read, threadId, type, subscriptionId)
val conversation = context.getConversations(threadId).firstOrNull() ?: return@ensureBackgroundThread
try {
context.insertOrUpdateConversation(conversation)
} catch (ignored: Exception) {
}
val newMessageId = context.insertNewSMS(
address = address,
subject = subject,
body = body,
date = date,
read = read,
threadId = threadId,
type = type,
subscriptionId = subscriptionId
)
val senderName = context.getNameFromAddress(address, privateCursor)
val phoneNumber = PhoneNumber(address, 0, "", address)
val participant = SimpleContact(0, 0, senderName, photoUri, arrayListOf(phoneNumber), ArrayList(), ArrayList())
val participants = arrayListOf(participant)
val messageDate = (date / 1000).toInt()
val message =
Message(
newMessageId,
body,
type,
status,
participants,
messageDate,
false,
threadId,
false,
null,
address,
senderName,
photoUri,
subscriptionId
)
context.messagesDB.insertOrUpdate(message)
if (context.shouldUnarchive()) {
context.updateConversationArchivedStatus(threadId, false)
}
refreshMessages()
refreshConversations()
context.showReceivedMessageNotification(newMessageId, address, body, threadId, bitmap)
}
}
context.getConversations(threadId).firstOrNull()?.let { conv ->
runCatching { context.insertOrUpdateConversation(conv) }
}
val senderName = context.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true).use {
context.getNameFromAddress(address, it)
}
val participant = SimpleContact(
rawId = 0,
contactId = 0,
name = senderName,
photoUri = photoUri,
phoneNumbers = arrayListOf(PhoneNumber(value = address, type = 0, label = "", normalizedNumber = address)),
birthdays = ArrayList(),
anniversaries = ArrayList()
)
val message = Message(
id = newMessageId,
body = body,
type = type,
status = status,
participants = arrayListOf(participant),
date = (date / 1000).toInt(),
read = false,
threadId = threadId,
isMMS = false,
attachment = null,
senderPhoneNumber = address,
senderName = senderName,
senderPhotoUri = photoUri,
subscriptionId = subscriptionId
)
context.messagesDB.insertOrUpdate(message)
if (context.shouldUnarchive()) {
context.updateConversationArchivedStatus(threadId, false)
}
refreshMessages()
refreshConversations()
context.showReceivedMessageNotification(
messageId = newMessageId,
address = address,
senderName = senderName,
body = body,
threadId = threadId,
bitmap = bitmap
)
}
}