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

@ -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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]
### Fixed
- Fixed missing notifications in some cases ([#159])
## [1.7.0] - 2025-12-16 ## [1.7.0] - 2025-12-16
### Added ### 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 [#115]: https://github.com/FossifyOrg/Messages/issues/115
[#135]: https://github.com/FossifyOrg/Messages/issues/135 [#135]: https://github.com/FossifyOrg/Messages/issues/135
[#153]: https://github.com/FossifyOrg/Messages/issues/153 [#153]: https://github.com/FossifyOrg/Messages/issues/153
[#159]: https://github.com/FossifyOrg/Messages/issues/159
[#165]: https://github.com/FossifyOrg/Messages/issues/165 [#165]: https://github.com/FossifyOrg/Messages/issues/165
[#177]: https://github.com/FossifyOrg/Messages/issues/177 [#177]: https://github.com/FossifyOrg/Messages/issues/177
[#180]: https://github.com/FossifyOrg/Messages/issues/180 [#180]: https://github.com/FossifyOrg/Messages/issues/180

View file

@ -1050,24 +1050,20 @@ fun Context.getThreadId(addresses: Set<String>): Long {
fun Context.showReceivedMessageNotification( fun Context.showReceivedMessageNotification(
messageId: Long, messageId: Long,
address: String, address: String,
senderName: String,
body: String, body: String,
threadId: Long, threadId: Long,
bitmap: Bitmap?, bitmap: Bitmap?,
) { ) {
val privateCursor = getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true) Handler(Looper.getMainLooper()).post {
ensureBackgroundThread { notificationHelper.showMessageNotification(
val senderName = getNameFromAddress(address, privateCursor) messageId = messageId,
address = address,
Handler(Looper.getMainLooper()).post { body = body,
notificationHelper.showMessageNotification( threadId = threadId,
messageId = messageId, bitmap = bitmap,
address = address, sender = senderName
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.content.Context
import android.net.Uri import android.net.Uri
import android.os.Handler
import android.os.Looper
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.klinker.android.send_message.MmsReceivedReceiver import com.klinker.android.send_message.MmsReceivedReceiver
import org.fossify.commons.extensions.baseConfig 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.R
import org.fossify.messages.extensions.getConversations import org.fossify.messages.extensions.getConversations
import org.fossify.messages.extensions.getLatestMMS import org.fossify.messages.extensions.getLatestMMS
import org.fossify.messages.extensions.getNameFromAddress
import org.fossify.messages.extensions.insertOrUpdateConversation import org.fossify.messages.extensions.insertOrUpdateConversation
import org.fossify.messages.extensions.shouldUnarchive import org.fossify.messages.extensions.shouldUnarchive
import org.fossify.messages.extensions.showReceivedMessageNotification import org.fossify.messages.extensions.showReceivedMessageNotification
@ -31,12 +30,10 @@ class MmsReceiver : MmsReceivedReceiver() {
val normalizedAddress = address.normalizePhoneNumber() val normalizedAddress = address.normalizePhoneNumber()
if (context.isNumberBlocked(normalizedAddress)) return true if (context.isNumberBlocked(normalizedAddress)) return true
if (context.baseConfig.blockUnknownNumbers) { if (context.baseConfig.blockUnknownNumbers) {
val privateCursor = context.getMyContactsCursor( context.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true).use {
favoritesOnly = false, val isKnownContact = SimpleContactsHelper(context).existsSync(address, it)
withPhoneNumbersOnly = true return !isKnownContact
) }
val isKnownContact = SimpleContactsHelper(context).existsSync(address, privateCursor)
return !isKnownContact
} }
return false return false
@ -76,25 +73,26 @@ class MmsReceiver : MmsReceivedReceiver() {
null null
} }
Handler(Looper.getMainLooper()).post {
context.showReceivedMessageNotification(
messageId = mms.id,
address = address,
body = mms.body,
threadId = mms.threadId,
bitmap = glideBitmap
)
ensureBackgroundThread { val senderName = context.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true).use {
val conversation = context.getConversations(mms.threadId).firstOrNull() context.getNameFromAddress(address, it)
?: return@ensureBackgroundThread
context.insertOrUpdateConversation(conversation)
if (context.shouldUnarchive()) {
context.updateConversationArchivedStatus(mms.threadId, false)
}
refreshMessages()
refreshConversations()
}
} }
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.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.provider.Telephony import android.provider.Telephony
import org.fossify.commons.extensions.baseConfig import org.fossify.commons.extensions.baseConfig
import org.fossify.commons.extensions.getMyContactsCursor import org.fossify.commons.extensions.getMyContactsCursor
@ -29,104 +27,128 @@ import org.fossify.messages.helpers.refreshMessages
import org.fossify.messages.models.Message import org.fossify.messages.models.Message
class SmsReceiver : BroadcastReceiver() { 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 { ensureBackgroundThread {
messages.forEach { try {
address = it.originatingAddress ?: "" val parts = Telephony.Sms.Intents.getMessagesFromIntent(intent)
subject = it.pseudoSubject if (parts.isEmpty()) return@ensureBackgroundThread
status = it.status
body += it.messageBody // this is how it has always worked, but need to revisit this.
date = System.currentTimeMillis() val address = parts.last().originatingAddress.orEmpty()
threadId = context.getThreadId(address) if (address.isBlank()) return@ensureBackgroundThread
} val subject = parts.last().pseudoSubject.orEmpty()
if (context.baseConfig.blockUnknownNumbers) { val status = parts.last().status
val simpleContactsHelper = SimpleContactsHelper(context) val body = buildString { parts.forEach { append(it.messageBody.orEmpty()) } }
// Maybe switch to existsSync()? No?
simpleContactsHelper.exists(address, privateCursor) { exists -> if (isMessageFilteredOut(appContext, body)) return@ensureBackgroundThread
if (exists) { if (appContext.isNumberBlocked(address)) return@ensureBackgroundThread
handleMessage(context, address, subject, body, date, read, threadId, type, subscriptionId, status) 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, context: Context,
address: String, address: String,
subject: String, subject: String,
body: String, body: String,
date: Long, date: Long,
read: Int, read: Int = 0,
threadId: Long, threadId: Long,
type: Int, type: Int = Telephony.Sms.MESSAGE_TYPE_INBOX,
subscriptionId: Int, subscriptionId: Int,
status: Int status: Int
) { ) {
if (isMessageFilteredOut(context, body)) {
return
}
val photoUri = SimpleContactsHelper(context).getPhotoUriFromPhoneNumber(address) val photoUri = SimpleContactsHelper(context).getPhotoUriFromPhoneNumber(address)
val bitmap = context.getNotificationBitmap(photoUri) 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 val newMessageId = context.insertNewSMS(
try { address = address,
context.insertOrUpdateConversation(conversation) subject = subject,
} catch (ignored: Exception) { body = body,
} date = date,
read = read,
threadId = threadId,
type = type,
subscriptionId = subscriptionId
)
val senderName = context.getNameFromAddress(address, privateCursor) context.getConversations(threadId).firstOrNull()?.let { conv ->
val phoneNumber = PhoneNumber(address, 0, "", address) runCatching { context.insertOrUpdateConversation(conv) }
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)
}
}
} }
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
)
} }
} }