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 ec845d6d..fc1f3945 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/MessagingUtils.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/MessagingUtils.kt @@ -3,9 +3,11 @@ package com.simplemobiletools.smsmessenger.messaging import android.app.Activity import android.content.ContentValues import android.content.Context +import android.content.Intent import android.net.Uri import android.provider.Telephony.Sms import android.telephony.SmsManager +import android.telephony.SmsMessage import android.widget.Toast import com.klinker.android.send_message.Message import com.klinker.android.send_message.Settings @@ -88,6 +90,12 @@ class MessagingUtils(val context: Context) { } } + fun getSmsMessageFromDeliveryReport(intent: Intent): SmsMessage? { + val pdu = intent.getByteArrayExtra("pdu") + val format = intent.getStringExtra("format") + return SmsMessage.createFromPdu(pdu, format) + } + @Deprecated("TODO: Move/rewrite MMS code into the app.") fun sendMmsMessage(text: String, addresses: List, attachments: List, settings: Settings) { val transaction = Transaction(context, settings) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/SmsSender.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/SmsSender.kt index 843ed05a..fa9b22b3 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/SmsSender.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/messaging/SmsSender.kt @@ -5,6 +5,7 @@ import android.app.PendingIntent import android.content.Intent import android.net.Uri import android.telephony.PhoneNumberUtils +import com.simplemobiletools.commons.helpers.isSPlus import com.simplemobiletools.smsmessenger.messaging.SmsException.Companion.EMPTY_DESTINATION_ADDRESS import com.simplemobiletools.smsmessenger.messaging.SmsException.Companion.ERROR_SENDING_MESSAGE import com.simplemobiletools.smsmessenger.receivers.SmsStatusDeliveredReceiver @@ -56,7 +57,10 @@ class SmsSender(val app: Application) { val deliveryIntents = ArrayList(messageCount) val sentIntents = ArrayList(messageCount) - val flags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + var flags = PendingIntent.FLAG_UPDATE_CURRENT + if (isSPlus()) { + flags = flags or PendingIntent.FLAG_MUTABLE + } for (i in 0 until messageCount) { // Make pending intents different for each message part diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusDeliveredReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusDeliveredReceiver.kt index 45542cb3..33c8cc7b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusDeliveredReceiver.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/receivers/SmsStatusDeliveredReceiver.kt @@ -1,99 +1,96 @@ package com.simplemobiletools.smsmessenger.receivers import android.annotation.SuppressLint -import android.app.Activity import android.content.ContentValues import android.content.Context import android.content.Intent import android.net.Uri -import android.os.Handler -import android.os.Looper import android.provider.Telephony.Sms import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.smsmessenger.extensions.messagesDB +import com.simplemobiletools.smsmessenger.extensions.messagingUtils import com.simplemobiletools.smsmessenger.helpers.refreshMessages import com.simplemobiletools.smsmessenger.messaging.SendStatusReceiver /** Handles updating databases and states when a sent SMS message is delivered. */ class SmsStatusDeliveredReceiver : SendStatusReceiver() { + private var status: Int = Sms.Sent.STATUS_NONE + override fun updateAndroidDatabase(context: Context, intent: Intent, receiverResultCode: Int) { - val uri: Uri? = intent.data - val resultCode = resultCode + val messageUri: Uri? = intent.data + val smsMessage = context.messagingUtils.getSmsMessageFromDeliveryReport(intent) ?: return try { - when (resultCode) { - Activity.RESULT_OK -> { - if (uri != null) { - val values = ContentValues().apply { - put(Sms.Sent.STATUS, Sms.Sent.STATUS_COMPLETE) - put(Sms.Sent.DATE_SENT, System.currentTimeMillis()) - put(Sms.Sent.READ, true) + val format = intent.getStringExtra("format") + status = smsMessage.status + // Simple matching up CDMA status with GSM status. + if ("3gpp2" == format) { + val errorClass = status shr 24 and 0x03 + val statusCode = status shr 16 and 0x3f + status = when (errorClass) { + 0 -> { + if (statusCode == 0x02 /*STATUS_DELIVERED*/) { + Sms.STATUS_COMPLETE + } else { + Sms.STATUS_PENDING } - context.contentResolver.update(uri, values, null, null) - } else { - updateLatestSmsStatus(context, status = Sms.Sent.STATUS_COMPLETE, read = true, date = System.currentTimeMillis()) } - } - Activity.RESULT_CANCELED -> { - if (uri != null) { - val values = ContentValues().apply { - put(Sms.Sent.STATUS, Sms.Sent.STATUS_FAILED) - put(Sms.Sent.DATE_SENT, System.currentTimeMillis()) - put(Sms.Sent.READ, true) - put(Sms.Sent.ERROR_CODE, resultCode) - } - context.contentResolver.update(uri, values, null, null) - } else { - updateLatestSmsStatus(context, status = Sms.Sent.STATUS_FAILED, read = true, errorCode = resultCode) + 2 -> { + // TODO: Need to check whether SC still trying to deliver the SMS to destination and will send the report again? + Sms.STATUS_PENDING + } + 3 -> { + Sms.STATUS_FAILED + } + else -> { + Sms.STATUS_PENDING } } } - } catch (e: Exception) { - e.printStackTrace() + } catch (e: NullPointerException) { + // Sometimes, SmsMessage.mWrappedSmsMessage is null causing NPE when we access + // the methods on it although the SmsMessage itself is not null. + return } + + updateSmsStatusAndDateSent(context, messageUri, System.currentTimeMillis()) } - @SuppressLint("Range") - private fun updateLatestSmsStatus(context: Context, status: Int, read: Boolean, date: Long = -1L, errorCode: Int = -1) { - val query = context.contentResolver.query(Sms.Sent.CONTENT_URI, null, null, null, "date desc") - - // mark message as delivered in database - if (query!!.moveToFirst()) { - val id = query.getString(query.getColumnIndex(Sms.Sent._ID)) - - val values = ContentValues().apply { + private fun updateSmsStatusAndDateSent(context: Context, messageUri: Uri?, timeSentInMillis: Long = -1L) { + val resolver = context.contentResolver + val values = ContentValues().apply { + if (status != Sms.Sent.STATUS_NONE) { put(Sms.Sent.STATUS, status) - put(Sms.Sent.READ, read) + } + put(Sms.Sent.DATE_SENT, timeSentInMillis) + } - if (date != -1L) { - put(Sms.Sent.DATE_SENT, date) - } - if (errorCode != -1) { - put(Sms.Sent.ERROR_CODE, errorCode) + if (messageUri != null) { + resolver.update(messageUri, values, null, null) + } else { + // mark latest sms as delivered, need to check if this is still necessary (or reliable) + val cursor = resolver.query(Sms.Sent.CONTENT_URI, null, null, null, "date desc") + cursor?.use { + if (cursor.moveToFirst()) { + @SuppressLint("Range") + val id = cursor.getString(cursor.getColumnIndex(Sms.Sent._ID)) + val selection = "${Sms._ID} = ?" + val selectionArgs = arrayOf(id.toString()) + resolver.update(Sms.Sent.CONTENT_URI, values, selection, selectionArgs) } } - - context.contentResolver.update(Sms.Sent.CONTENT_URI, values, "_id=$id", null) } - query.close() } override fun updateAppDatabase(context: Context, intent: Intent, receiverResultCode: Int) { - val uri = intent.data - if (uri != null) { - val messageId = uri.lastPathSegment?.toLong() ?: 0L + val messageUri: Uri? = intent.data + if (messageUri != null) { + val messageId = messageUri.lastPathSegment?.toLong() ?: 0L ensureBackgroundThread { - val status = Sms.Sent.STATUS_COMPLETE - val updated = context.messagesDB.updateStatus(messageId, status) - if (updated == 0) { - Handler(Looper.getMainLooper()).postDelayed({ - ensureBackgroundThread { - context.messagesDB.updateStatus(messageId, status) - } - }, 2000) + if (status != Sms.Sent.STATUS_NONE) { + context.messagesDB.updateStatus(messageId, status) } - refreshMessages() } }