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,14 +1050,11 @@ 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)
ensureBackgroundThread {
val senderName = getNameFromAddress(address, privateCursor)
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
notificationHelper.showMessageNotification( notificationHelper.showMessageNotification(
messageId = messageId, messageId = messageId,
@ -1069,7 +1066,6 @@ fun Context.showReceivedMessageNotification(
) )
} }
} }
}
fun Context.getNameFromAddress(address: String, privateCursor: Cursor?): String { fun Context.getNameFromAddress(address: String, privateCursor: Cursor?): String {
var sender = getNameAndPhotoFromPhoneNumber(address).name var sender = getNameAndPhotoFromPhoneNumber(address).name

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,13 +30,11 @@ 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
)
val isKnownContact = SimpleContactsHelper(context).existsSync(address, privateCursor)
return !isKnownContact return !isKnownContact
} }
}
return false return false
} }
@ -76,19 +73,22 @@ class MmsReceiver : MmsReceivedReceiver() {
null null
} }
Handler(Looper.getMainLooper()).post {
val senderName = context.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true).use {
context.getNameFromAddress(address, it)
}
context.showReceivedMessageNotification( context.showReceivedMessageNotification(
messageId = mms.id, messageId = mms.id,
address = address, address = address,
senderName = senderName,
body = mms.body, body = mms.body,
threadId = mms.threadId, threadId = mms.threadId,
bitmap = glideBitmap bitmap = glideBitmap
) )
ensureBackgroundThread { val conversation = context.getConversations(mms.threadId).firstOrNull() ?: return
val conversation = context.getConversations(mms.threadId).firstOrNull() runCatching { context.insertOrUpdateConversation(conversation) }
?: return@ensureBackgroundThread
context.insertOrUpdateConversation(conversation)
if (context.shouldUnarchive()) { if (context.shouldUnarchive()) {
context.updateConversationArchivedStatus(mms.threadId, false) context.updateConversationArchivedStatus(mms.threadId, false)
} }
@ -96,5 +96,3 @@ class MmsReceiver : MmsReceivedReceiver() {
refreshConversations() 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) { override fun onReceive(context: Context, intent: Intent) {
val messages = Telephony.Sms.Intents.getMessagesFromIntent(intent) val pending = goAsync()
var address = "" val appContext = context.applicationContext
var body = ""
var subject = "" ensureBackgroundThread {
var date = 0L try {
var threadId = 0L val parts = Telephony.Sms.Intents.getMessagesFromIntent(intent)
var status = Telephony.Sms.STATUS_NONE if (parts.isEmpty()) return@ensureBackgroundThread
val type = Telephony.Sms.MESSAGE_TYPE_INBOX
val read = 0 // 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
}
}
val date = System.currentTimeMillis()
val threadId = appContext.getThreadId(address)
val subscriptionId = intent.getIntExtra("subscription", -1) val subscriptionId = intent.getIntExtra("subscription", -1)
val privateCursor = context.getMyContactsCursor(false, true) handleMessageSync(
ensureBackgroundThread { context = appContext,
messages.forEach { address = address,
address = it.originatingAddress ?: "" subject = subject,
subject = it.pseudoSubject body = body,
status = it.status date = date,
body += it.messageBody threadId = threadId,
date = System.currentTimeMillis() subscriptionId = subscriptionId,
threadId = context.getThreadId(address) status = status
} )
if (context.baseConfig.blockUnknownNumbers) { } finally {
val simpleContactsHelper = SimpleContactsHelper(context) pending.finish()
// Maybe switch to existsSync()? No?
simpleContactsHelper.exists(address, privateCursor) { exists ->
if (exists) {
handleMessage(context, address, subject, body, date, read, threadId, type, subscriptionId, status)
}
}
} else {
handleMessage(context, address, subject, body, date, read, threadId, type, subscriptionId, status)
} }
} }
} }
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
)
context.getConversations(threadId).firstOrNull()?.let { conv ->
runCatching { context.insertOrUpdateConversation(conv) }
} }
val senderName = context.getNameFromAddress(address, privateCursor) val senderName = context.getMyContactsCursor(favoritesOnly = false, withPhoneNumbersOnly = true).use {
val phoneNumber = PhoneNumber(address, 0, "", address) context.getNameFromAddress(address, it)
val participant = SimpleContact(0, 0, senderName, photoUri, arrayListOf(phoneNumber), ArrayList(), ArrayList()) }
val participants = arrayListOf(participant)
val messageDate = (date / 1000).toInt()
val message = val participant = SimpleContact(
Message( rawId = 0,
newMessageId, contactId = 0,
body, name = senderName,
type, photoUri = photoUri,
status, phoneNumbers = arrayListOf(PhoneNumber(value = address, type = 0, label = "", normalizedNumber = address)),
participants, birthdays = ArrayList(),
messageDate, anniversaries = ArrayList()
false,
threadId,
false,
null,
address,
senderName,
photoUri,
subscriptionId
) )
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) context.messagesDB.insertOrUpdate(message)
if (context.shouldUnarchive()) { if (context.shouldUnarchive()) {
context.updateConversationArchivedStatus(threadId, false) context.updateConversationArchivedStatus(threadId, false)
} }
refreshMessages() refreshMessages()
refreshConversations() refreshConversations()
context.showReceivedMessageNotification(newMessageId, address, body, threadId, bitmap) context.showReceivedMessageNotification(
} messageId = newMessageId,
} address = address,
} senderName = senderName,
body = body,
threadId = threadId,
bitmap = bitmap
)
} }
} }