From 312f5bd0a82e4b69c6291779dbb662eb7b3859b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Mon, 24 Jul 2023 11:03:48 +0200 Subject: [PATCH] Prevent duplication of messages on resend This prevents duplication by ensuring that message is just updated in case of SMS, instead of creating a new entry. In case of MMS, due to the way it is sent internally, we delete original message once we get result of the new one. This closes #554 --- .../smsmessenger/activities/ThreadActivity.kt | 10 +++++-- .../smsmessenger/messaging/Messaging.kt | 10 +++---- .../smsmessenger/messaging/MessagingUtils.kt | 26 ++++++++++++++----- .../smsmessenger/receivers/MmsSentReceiver.kt | 8 ++++++ 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt index 82e2003a..c5194b56 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt @@ -107,6 +107,7 @@ class ThreadActivity : SimpleActivity() { private var wasProtectionHandled = false private var isScheduledMessage: Boolean = false + private var messageToResend: Long? = null private var scheduledMessage: Message? = null private lateinit var scheduledDateTime: DateTime @@ -291,6 +292,7 @@ class ThreadActivity : SimpleActivity() { super.onActivityResult(requestCode, resultCode, resultData) if (resultCode != Activity.RESULT_OK) return val data = resultData?.data + messageToResend = null if (requestCode == CAPTURE_PHOTO_INTENT && capturedImageUri != null) { addAttachment(capturedImageUri!!) @@ -492,7 +494,10 @@ class ThreadActivity : SimpleActivity() { private fun handleItemClick(any: Any) { when { any is Message && any.isScheduled -> showScheduledMessageInfo(any) - any is ThreadError -> thread_type_message.setText(any.messageText) + any is ThreadError -> { + thread_type_message.setText(any.messageText) + messageToResend = any.messageId + } } } @@ -635,6 +640,7 @@ class ThreadActivity : SimpleActivity() { thread_send_message.isClickable = false thread_type_message.onTextChangeListener { + messageToResend = null checkSendMessageAvailability() val messageString = if (config.useSimpleCharacters) { it.normalizeString() @@ -1334,7 +1340,7 @@ class ThreadActivity : SimpleActivity() { try { refreshedSinceSent = false - sendMessageCompat(text, addresses, subscriptionId, attachments) + sendMessageCompat(text, addresses, subscriptionId, attachments, messageToResend) ensureBackgroundThread { val messageIds = messages.map { it.id } val messages = getMessages(threadId, getImageResolutions = true, limit = maxOf(1, attachments.size)) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/Messaging.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/Messaging.kt index e02a1a6c..9a391395 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/Messaging.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/Messaging.kt @@ -32,7 +32,7 @@ fun Context.isLongMmsMessage(text: String, settings: Settings = getSendMessageSe } /** Sends the message using the in-app SmsManager API wrappers if it's an SMS or using android-smsmms for MMS. */ -fun Context.sendMessageCompat(text: String, addresses: List, subId: Int?, attachments: List) { +fun Context.sendMessageCompat(text: String, addresses: List, subId: Int?, attachments: List, messageId: Long? = null) { val settings = getSendMessageSettings() if (subId != null) { settings.subscriptionId = subId @@ -47,18 +47,18 @@ fun Context.sendMessageCompat(text: String, addresses: List, subId: Int? if (attachments.size > 1) { for (i in 0 until lastIndex) { val attachment = attachments[i] - messagingUtils.sendMmsMessage("", addresses, attachment, settings) + messagingUtils.sendMmsMessage("", addresses, attachment, settings, messageId) } } val lastAttachment = attachments[lastIndex] - messagingUtils.sendMmsMessage(text, addresses, lastAttachment, settings) + messagingUtils.sendMmsMessage(text, addresses, lastAttachment, settings, messageId) } else { - messagingUtils.sendMmsMessage(text, addresses, null, settings) + messagingUtils.sendMmsMessage(text, addresses, null, settings, messageId) } } else { try { - messagingUtils.sendSmsMessage(text, addresses.toSet(), settings.subscriptionId, settings.deliveryReports) + messagingUtils.sendSmsMessage(text, addresses.toSet(), settings.subscriptionId, settings.deliveryReports, messageId) } catch (e: SmsException) { when (e.errorCode) { EMPTY_DESTINATION_ADDRESS -> toast(id = R.string.empty_destination_address, length = LENGTH_LONG) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/MessagingUtils.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/MessagingUtils.kt index 8d79ea7d..211efadf 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/MessagingUtils.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/MessagingUtils.kt @@ -31,7 +31,7 @@ class MessagingUtils(val context: Context) { */ private fun insertSmsMessage( subId: Int, dest: String, text: String, timestamp: Long, threadId: Long, - status: Int = Sms.STATUS_NONE, type: Int = Sms.MESSAGE_TYPE_OUTBOX + status: Int = Sms.STATUS_NONE, type: Int = Sms.MESSAGE_TYPE_OUTBOX, messageId: Long? = null ): Uri { val response: Uri? val values = ContentValues().apply { @@ -58,7 +58,18 @@ class MessagingUtils(val context: Context) { } try { - response = context.contentResolver.insert(Sms.CONTENT_URI, values) + if (messageId != null) { + val selection = "${Sms._ID} = ?" + val selectionArgs = arrayOf(messageId.toString()) + val count = context.contentResolver.update(Sms.CONTENT_URI, values, selection, selectionArgs) + if (count > 0) { + response = Uri.parse("${Sms.CONTENT_URI}/${messageId}") + } else { + response = null + } + } else { + response = context.contentResolver.insert(Sms.CONTENT_URI, values) + } } catch (e: Exception) { throw SmsException(ERROR_PERSISTING_MESSAGE, e) } @@ -67,7 +78,7 @@ class MessagingUtils(val context: Context) { /** Send an SMS message given [text] and [addresses]. A [SmsException] is thrown in case any errors occur. */ fun sendSmsMessage( - text: String, addresses: Set, subId: Int, requireDeliveryReport: Boolean + text: String, addresses: Set, subId: Int, requireDeliveryReport: Boolean, messageId: Long? = null ) { if (addresses.size > 1) { // insert a dummy message for this thread if it is a group message @@ -76,7 +87,8 @@ class MessagingUtils(val context: Context) { insertSmsMessage( subId = subId, dest = mergedAddresses, text = text, timestamp = System.currentTimeMillis(), threadId = broadCastThreadId, - status = Sms.Sent.STATUS_COMPLETE, type = Sms.Sent.MESSAGE_TYPE_SENT + status = Sms.Sent.STATUS_COMPLETE, type = Sms.Sent.MESSAGE_TYPE_SENT, + messageId = messageId ) } @@ -84,7 +96,8 @@ class MessagingUtils(val context: Context) { val threadId = context.getThreadId(address) val messageUri = insertSmsMessage( subId = subId, dest = address, text = text, - timestamp = System.currentTimeMillis(), threadId = threadId + timestamp = System.currentTimeMillis(), threadId = threadId, + messageId = messageId ) try { context.smsSender.sendMessage( @@ -133,7 +146,7 @@ class MessagingUtils(val context: Context) { } @Deprecated("TODO: Move/rewrite MMS code into the app.") - fun sendMmsMessage(text: String, addresses: List, attachment: Attachment?, settings: Settings) { + fun sendMmsMessage(text: String, addresses: List, attachment: Attachment?, settings: Settings, messageId: Long? = null) { val transaction = Transaction(context, settings) val message = Message(text, addresses.toTypedArray()) @@ -158,6 +171,7 @@ class MessagingUtils(val context: Context) { } val mmsSentIntent = Intent(context, MmsSentReceiver::class.java) + mmsSentIntent.putExtra(MmsSentReceiver.EXTRA_ORIGINAL_RESENT_MESSAGE_ID, messageId) transaction.setExplicitBroadcastForSentMms(mmsSentIntent) try { diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsSentReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsSentReceiver.kt index e3c92eef..b2650622 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsSentReceiver.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/MmsSentReceiver.kt @@ -11,6 +11,7 @@ import android.widget.Toast import com.simplemobiletools.commons.extensions.showErrorToast import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.smsmessenger.R +import com.simplemobiletools.smsmessenger.extensions.deleteMessage import com.simplemobiletools.smsmessenger.helpers.refreshMessages import java.io.File @@ -19,6 +20,7 @@ class MmsSentReceiver : SendStatusReceiver() { override fun updateAndroidDatabase(context: Context, intent: Intent, receiverResultCode: Int) { val uri = Uri.parse(intent.getStringExtra(EXTRA_CONTENT_URI)) + val originalResentMessageId = intent.getLongExtra(EXTRA_ORIGINAL_RESENT_MESSAGE_ID, -1L) val messageBox = if (receiverResultCode == Activity.RESULT_OK) { Telephony.Mms.MESSAGE_BOX_SENT } else { @@ -37,6 +39,11 @@ class MmsSentReceiver : SendStatusReceiver() { context.showErrorToast(e) } + // In case of resent message, delete original to prevent duplication + if (originalResentMessageId != -1L) { + context.deleteMessage(originalResentMessageId, true) + } + val filePath = intent.getStringExtra(EXTRA_FILE_PATH) if (filePath != null) { File(filePath).delete() @@ -50,5 +57,6 @@ class MmsSentReceiver : SendStatusReceiver() { companion object { private const val EXTRA_CONTENT_URI = "content_uri" private const val EXTRA_FILE_PATH = "file_path" + const val EXTRA_ORIGINAL_RESENT_MESSAGE_ID = "original_message_id" } }