From 1e3f5e59339de0e0d690ad5fd8d263efea35f140 Mon Sep 17 00:00:00 2001 From: Naveen Singh <36371707+naveensingh@users.noreply.github.com> Date: Sun, 21 Dec 2025 14:51:54 +0530 Subject: [PATCH] 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 --- CHANGELOG.md | 3 + .../fossify/messages/extensions/Context.kt | 24 +-- .../fossify/messages/receivers/MmsReceiver.kt | 50 +++-- .../fossify/messages/receivers/SmsReceiver.kt | 180 ++++++++++-------- 4 files changed, 138 insertions(+), 119 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3860b889..1140cd06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed +- Fixed missing notifications in some cases ([#159]) ## [1.7.0] - 2025-12-16 ### Added @@ -188,6 +190,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#115]: https://github.com/FossifyOrg/Messages/issues/115 [#135]: https://github.com/FossifyOrg/Messages/issues/135 [#153]: https://github.com/FossifyOrg/Messages/issues/153 +[#159]: https://github.com/FossifyOrg/Messages/issues/159 [#165]: https://github.com/FossifyOrg/Messages/issues/165 [#177]: https://github.com/FossifyOrg/Messages/issues/177 [#180]: https://github.com/FossifyOrg/Messages/issues/180 diff --git a/app/src/main/kotlin/org/fossify/messages/extensions/Context.kt b/app/src/main/kotlin/org/fossify/messages/extensions/Context.kt index 24ac58e7..144e7ad6 100644 --- a/app/src/main/kotlin/org/fossify/messages/extensions/Context.kt +++ b/app/src/main/kotlin/org/fossify/messages/extensions/Context.kt @@ -1050,24 +1050,20 @@ fun Context.getThreadId(addresses: Set): 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 + ) } } diff --git a/app/src/main/kotlin/org/fossify/messages/receivers/MmsReceiver.kt b/app/src/main/kotlin/org/fossify/messages/receivers/MmsReceiver.kt index 59de89cc..04ad1e60 100644 --- a/app/src/main/kotlin/org/fossify/messages/receivers/MmsReceiver.kt +++ b/app/src/main/kotlin/org/fossify/messages/receivers/MmsReceiver.kt @@ -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() } } diff --git a/app/src/main/kotlin/org/fossify/messages/receivers/SmsReceiver.kt b/app/src/main/kotlin/org/fossify/messages/receivers/SmsReceiver.kt index 1c2f7eb5..e429634a 100644 --- a/app/src/main/kotlin/org/fossify/messages/receivers/SmsReceiver.kt +++ b/app/src/main/kotlin/org/fossify/messages/receivers/SmsReceiver.kt @@ -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 + ) } }