Show 2 checks when sms is delivered

- differentiate between sent sms and delivered sms by updating the SmsStatusSentReceiver which updates the type to Telephony.Sms.MESSAGE_TYPE_SENT or Telephony.Sms.MESSAGE_TYPE_FAILED depending on the outcome.
- rename ThreadSuccess to ThreadSent and add a boolean field for the delivery status
- SmsStatusSentReceiver updates the status of the message to Telephony.Sms.STATUS_COMPLETE.
- accommodate for the need to keep track of the status by adding Int field status to the Message class,
- add appropriate database migrations (3 to 4) for the new status field.
- add status to the query for sms in extension function Context.getMessages and Context.getMMS
- add extension function Context.updateMessageStatus to update the status of a message in the database
This commit is contained in:
Paul Akhamiogu 2021-08-25 16:57:07 +01:00
parent 84c1705078
commit 46f71c994f
13 changed files with 58 additions and 27 deletions

View File

@ -569,8 +569,8 @@ class ThreadActivity : SimpleActivity() {
conversationsDB.markRead(threadId) conversationsDB.markRead(threadId)
} }
if (i == cnt - 1 && message.type == Telephony.Sms.MESSAGE_TYPE_SENT) { if (i == cnt - 1 && (message.type == Telephony.Sms.MESSAGE_TYPE_SENT )) {
items.add(ThreadSuccess(message.id)) items.add(ThreadSent(message.id, delivered = message.status == Telephony.Sms.STATUS_COMPLETE))
} }
} }

View File

@ -99,7 +99,7 @@ class ThreadAdapter(
THREAD_DATE_TIME -> R.layout.item_thread_date_time THREAD_DATE_TIME -> R.layout.item_thread_date_time
THREAD_RECEIVED_MESSAGE -> R.layout.item_received_message THREAD_RECEIVED_MESSAGE -> R.layout.item_received_message
THREAD_SENT_MESSAGE_ERROR -> R.layout.item_thread_error THREAD_SENT_MESSAGE_ERROR -> R.layout.item_thread_error
THREAD_SENT_MESSAGE_SUCCESS -> R.layout.item_thread_success THREAD_SENT_MESSAGE_SENT -> R.layout.item_thread_success
THREAD_SENT_MESSAGE_SENDING -> R.layout.item_thread_sending THREAD_SENT_MESSAGE_SENDING -> R.layout.item_thread_sending
else -> R.layout.item_sent_message else -> R.layout.item_sent_message
} }
@ -113,7 +113,7 @@ class ThreadAdapter(
holder.bindView(item, isClickable, isLongClickable) { itemView, layoutPosition -> holder.bindView(item, isClickable, isLongClickable) { itemView, layoutPosition ->
when (item) { when (item) {
is ThreadDateTime -> setupDateTime(itemView, item) is ThreadDateTime -> setupDateTime(itemView, item)
is ThreadSuccess -> setupThreadSuccess(itemView) is ThreadSent -> setupThreadSuccess(itemView, item.delivered)
is ThreadError -> setupThreadError(itemView) is ThreadError -> setupThreadError(itemView)
is ThreadSending -> setupThreadSending(itemView) is ThreadSending -> setupThreadSending(itemView)
else -> setupView(itemView, item as Message) else -> setupView(itemView, item as Message)
@ -130,7 +130,7 @@ class ThreadAdapter(
item is ThreadDateTime -> THREAD_DATE_TIME item is ThreadDateTime -> THREAD_DATE_TIME
(messages[position] as? Message)?.isReceivedMessage() == true -> THREAD_RECEIVED_MESSAGE (messages[position] as? Message)?.isReceivedMessage() == true -> THREAD_RECEIVED_MESSAGE
item is ThreadError -> THREAD_SENT_MESSAGE_ERROR item is ThreadError -> THREAD_SENT_MESSAGE_ERROR
item is ThreadSuccess -> THREAD_SENT_MESSAGE_SUCCESS item is ThreadSent -> THREAD_SENT_MESSAGE_SENT
item is ThreadSending -> THREAD_SENT_MESSAGE_SENDING item is ThreadSending -> THREAD_SENT_MESSAGE_SENDING
else -> THREAD_SENT_MESSAGE else -> THREAD_SENT_MESSAGE
} }
@ -350,7 +350,8 @@ class ThreadAdapter(
} }
} }
private fun setupThreadSuccess(view: View) { private fun setupThreadSuccess(view: View, isDelivered: Boolean = false) {
view.thread_success.setImageResource(if (isDelivered) R.drawable.ic_check_double_vector else R.drawable.ic_check_vector)
view.thread_success.applyColorFilter(textColor) view.thread_success.applyColorFilter(textColor)
} }

View File

@ -17,7 +17,7 @@ import com.simplemobiletools.smsmessenger.models.Conversation
import com.simplemobiletools.smsmessenger.models.Message import com.simplemobiletools.smsmessenger.models.Message
import com.simplemobiletools.smsmessenger.models.MessageAttachment import com.simplemobiletools.smsmessenger.models.MessageAttachment
@Database(entities = [Conversation::class, Attachment::class, MessageAttachment::class, Message::class], version = 3) @Database(entities = [Conversation::class, Attachment::class, MessageAttachment::class, Message::class], version = 4)
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class MessagesDatabase : RoomDatabase() { abstract class MessagesDatabase : RoomDatabase() {
@ -40,6 +40,7 @@ abstract class MessagesDatabase : RoomDatabase() {
.fallbackToDestructiveMigration() .fallbackToDestructiveMigration()
.addMigrations(MIGRATION_1_2) .addMigrations(MIGRATION_1_2)
.addMigrations(MIGRATION_2_3) .addMigrations(MIGRATION_2_3)
.addMigrations(MIGRATION_3_4)
.build() .build()
} }
} }
@ -76,5 +77,13 @@ abstract class MessagesDatabase : RoomDatabase() {
} }
} }
} }
private val MIGRATION_3_4 = object : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
database.apply {
execSQL("ALTER TABLE messages ADD COLUMN status INTEGER NOT NULL DEFAULT -1")
}
}
}
} }
} }

View File

@ -35,9 +35,9 @@ import com.simplemobiletools.smsmessenger.interfaces.MessagesDao
import com.simplemobiletools.smsmessenger.models.* import com.simplemobiletools.smsmessenger.models.*
import com.simplemobiletools.smsmessenger.receivers.DirectReplyReceiver import com.simplemobiletools.smsmessenger.receivers.DirectReplyReceiver
import com.simplemobiletools.smsmessenger.receivers.MarkAsReadReceiver import com.simplemobiletools.smsmessenger.receivers.MarkAsReadReceiver
import me.leolin.shortcutbadger.ShortcutBadger
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import me.leolin.shortcutbadger.ShortcutBadger
val Context.config: Config get() = Config.newInstance(applicationContext) val Context.config: Config get() = Config.newInstance(applicationContext)
@ -61,7 +61,8 @@ fun Context.getMessages(threadId: Long): ArrayList<Message> {
Sms.DATE, Sms.DATE,
Sms.READ, Sms.READ,
Sms.THREAD_ID, Sms.THREAD_ID,
Sms.SUBSCRIPTION_ID Sms.SUBSCRIPTION_ID,
Sms.STATUS
) )
val selection = "${Sms.THREAD_ID} = ?" val selection = "${Sms.THREAD_ID} = ?"
@ -96,9 +97,10 @@ fun Context.getMessages(threadId: Long): ArrayList<Message> {
val read = cursor.getIntValue(Sms.READ) == 1 val read = cursor.getIntValue(Sms.READ) == 1
val thread = cursor.getLongValue(Sms.THREAD_ID) val thread = cursor.getLongValue(Sms.THREAD_ID)
val subscriptionId = cursor.getIntValue(Sms.SUBSCRIPTION_ID) val subscriptionId = cursor.getIntValue(Sms.SUBSCRIPTION_ID)
val status = cursor.getIntValue(Sms.STATUS)
val participant = SimpleContact(0, 0, senderName, photoUri, arrayListOf(senderNumber), ArrayList(), ArrayList()) val participant = SimpleContact(0, 0, senderName, photoUri, arrayListOf(senderNumber), ArrayList(), ArrayList())
val isMMS = false val isMMS = false
val message = Message(id, body, type, arrayListOf(participant), date, read, thread, isMMS, null, senderName, photoUri, subscriptionId) val message = Message(id, body, type, status, arrayListOf(participant), date, read, thread, isMMS, null, senderName, photoUri, subscriptionId)
messages.add(message) messages.add(message)
} }
@ -118,7 +120,8 @@ fun Context.getMMS(threadId: Long? = null, sortOrder: String? = null): ArrayList
Mms.READ, Mms.READ,
Mms.MESSAGE_BOX, Mms.MESSAGE_BOX,
Mms.THREAD_ID, Mms.THREAD_ID,
Mms.SUBSCRIPTION_ID Mms.SUBSCRIPTION_ID,
Mms.STATUS
) )
val selection = if (threadId == null) { val selection = if (threadId == null) {
@ -143,6 +146,7 @@ fun Context.getMMS(threadId: Long? = null, sortOrder: String? = null): ArrayList
val read = cursor.getIntValue(Mms.READ) == 1 val read = cursor.getIntValue(Mms.READ) == 1
val threadId = cursor.getLongValue(Mms.THREAD_ID) val threadId = cursor.getLongValue(Mms.THREAD_ID)
val subscriptionId = cursor.getIntValue(Mms.SUBSCRIPTION_ID) val subscriptionId = cursor.getIntValue(Mms.SUBSCRIPTION_ID)
val status = cursor.getIntValue(Mms.STATUS)
val participants = if (threadParticipants.containsKey(threadId)) { val participants = if (threadParticipants.containsKey(threadId)) {
threadParticipants[threadId]!! threadParticipants[threadId]!!
} else { } else {
@ -164,7 +168,7 @@ fun Context.getMMS(threadId: Long? = null, sortOrder: String? = null): ArrayList
senderPhotoUri = namePhoto.photoUri ?: "" senderPhotoUri = namePhoto.photoUri ?: ""
} }
val message = Message(mmsId, body, type, participants, date, read, threadId, isMMS, attachment, senderName, senderPhotoUri, subscriptionId) val message = Message(mmsId, body, type, status, participants, date, read, threadId, isMMS, attachment, senderName, senderPhotoUri, subscriptionId)
messages.add(message) messages.add(message)
participants.forEach { participants.forEach {
@ -580,10 +584,20 @@ fun Context.markThreadMessagesUnread(threadId: Long) {
} }
} }
fun Context.updateMessageType(id: Long, status: Int) { fun Context.updateMessageType(id: Long, type: Int) {
val uri = Sms.CONTENT_URI val uri = Sms.CONTENT_URI
val contentValues = ContentValues().apply { val contentValues = ContentValues().apply {
put(Sms.TYPE, status) put(Sms.TYPE, type)
}
val selection = "${Sms._ID} = ?"
val selectionArgs = arrayOf(id.toString())
contentResolver.update(uri, contentValues, selection, selectionArgs)
}
fun Context.updateMessageStatus(id: Long, status: Int) {
val uri = Sms.CONTENT_URI
val contentValues = ContentValues().apply {
put(Sms.STATUS, status)
} }
val selection = "${Sms._ID} = ?" val selection = "${Sms._ID} = ?"
val selectionArgs = arrayOf(id.toString()) val selectionArgs = arrayOf(id.toString())

View File

@ -24,7 +24,7 @@ const val THREAD_DATE_TIME = 1
const val THREAD_RECEIVED_MESSAGE = 2 const val THREAD_RECEIVED_MESSAGE = 2
const val THREAD_SENT_MESSAGE = 3 const val THREAD_SENT_MESSAGE = 3
const val THREAD_SENT_MESSAGE_ERROR = 4 const val THREAD_SENT_MESSAGE_ERROR = 4
const val THREAD_SENT_MESSAGE_SUCCESS = 5 const val THREAD_SENT_MESSAGE_SENT = 5
const val THREAD_SENT_MESSAGE_SENDING = 6 const val THREAD_SENT_MESSAGE_SENDING = 6
// lock screen visibility constants // lock screen visibility constants

View File

@ -35,6 +35,9 @@ interface MessagesDao {
@Query("UPDATE messages SET type = :type WHERE id = :id") @Query("UPDATE messages SET type = :type WHERE id = :id")
fun updateType(id: Long, type: Int): Int fun updateType(id: Long, type: Int): Int
@Query("UPDATE messages SET status = :status WHERE id = :id")
fun updateStatus(id: Long, status: Int): Int
@Query("DELETE FROM messages WHERE id = :id") @Query("DELETE FROM messages WHERE id = :id")
fun delete(id: Long) fun delete(id: Long)

View File

@ -11,6 +11,7 @@ data class Message(
@PrimaryKey val id: Long, @PrimaryKey val id: Long,
@ColumnInfo(name = "body") val body: String, @ColumnInfo(name = "body") val body: String,
@ColumnInfo(name = "type") val type: Int, @ColumnInfo(name = "type") val type: Int,
@ColumnInfo(name = "status") val status: Int,
@ColumnInfo(name = "participants") val participants: ArrayList<SimpleContact>, @ColumnInfo(name = "participants") val participants: ArrayList<SimpleContact>,
@ColumnInfo(name = "date") val date: Int, @ColumnInfo(name = "date") val date: Int,
@ColumnInfo(name = "read") val read: Boolean, @ColumnInfo(name = "read") val read: Boolean,

View File

@ -0,0 +1,5 @@
package com.simplemobiletools.smsmessenger.models
// show a check after the latest message, if it is a sent one and succeeded,
// show a double check if it is delivered
data class ThreadSent(val messageID: Long, val delivered: Boolean) : ThreadItem()

View File

@ -1,4 +0,0 @@
package com.simplemobiletools.smsmessenger.models
// show a check after the latest message, if it is a sent one and succeeded
data class ThreadSuccess(val messageID: Long) : ThreadItem()

View File

@ -21,6 +21,7 @@ class SmsReceiver : BroadcastReceiver() {
var subject = "" var subject = ""
var date = 0L var date = 0L
var threadId = 0L var threadId = 0L
var status = Telephony.Sms.STATUS_NONE
val type = Telephony.Sms.MESSAGE_TYPE_INBOX val type = Telephony.Sms.MESSAGE_TYPE_INBOX
val read = 0 val read = 0
val subscriptionId = intent.getIntExtra("subscription", -1) val subscriptionId = intent.getIntExtra("subscription", -1)
@ -29,6 +30,7 @@ class SmsReceiver : BroadcastReceiver() {
messages.forEach { messages.forEach {
address = it.originatingAddress ?: "" address = it.originatingAddress ?: ""
subject = it.pseudoSubject subject = it.pseudoSubject
status = it.status
body += it.messageBody body += it.messageBody
date = Math.min(it.timestampMillis, System.currentTimeMillis()) date = Math.min(it.timestampMillis, System.currentTimeMillis())
threadId = context.getThreadId(address) threadId = context.getThreadId(address)
@ -49,7 +51,7 @@ class SmsReceiver : BroadcastReceiver() {
val participant = SimpleContact(0, 0, address, "", arrayListOf(address), ArrayList(), ArrayList()) val participant = SimpleContact(0, 0, address, "", arrayListOf(address), ArrayList(), ArrayList())
val participants = arrayListOf(participant) val participants = arrayListOf(participant)
val messageDate = (date / 1000).toInt() val messageDate = (date / 1000).toInt()
val message = Message(newMessageId, body, type, participants, messageDate, false, threadId, false, null, address, "", subscriptionId) val message = Message(newMessageId, body, type, status, participants, messageDate, false, threadId, false, null, address, "", subscriptionId)
context.messagesDB.insertOrUpdate(message) context.messagesDB.insertOrUpdate(message)
refreshMessages() refreshMessages()
} }

View File

@ -9,7 +9,7 @@ import android.provider.Telephony
import com.klinker.android.send_message.DeliveredReceiver import com.klinker.android.send_message.DeliveredReceiver
import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.smsmessenger.extensions.messagesDB import com.simplemobiletools.smsmessenger.extensions.messagesDB
import com.simplemobiletools.smsmessenger.extensions.updateMessageType import com.simplemobiletools.smsmessenger.extensions.updateMessageStatus
import com.simplemobiletools.smsmessenger.helpers.refreshMessages import com.simplemobiletools.smsmessenger.helpers.refreshMessages
class SmsStatusDeliveredReceiver : DeliveredReceiver() { class SmsStatusDeliveredReceiver : DeliveredReceiver() {
@ -19,13 +19,13 @@ class SmsStatusDeliveredReceiver : DeliveredReceiver() {
val uri = Uri.parse(intent.getStringExtra("message_uri")) val uri = Uri.parse(intent.getStringExtra("message_uri"))
val messageId = uri?.lastPathSegment?.toLong() ?: 0L val messageId = uri?.lastPathSegment?.toLong() ?: 0L
ensureBackgroundThread { ensureBackgroundThread {
val type = Telephony.Sms.MESSAGE_TYPE_SENT val status = Telephony.Sms.STATUS_COMPLETE
context.updateMessageType(messageId, type) context.updateMessageStatus(messageId, status)
val updated = context.messagesDB.updateType(messageId, type) val updated = context.messagesDB.updateStatus(messageId, status)
if (updated == 0) { if (updated == 0) {
Handler(Looper.getMainLooper()).postDelayed({ Handler(Looper.getMainLooper()).postDelayed({
ensureBackgroundThread { ensureBackgroundThread {
context.messagesDB.updateType(messageId, type) context.messagesDB.updateStatus(messageId, status)
} }
}, 2000) }, 2000)
} }

View File

@ -39,7 +39,7 @@ class SmsStatusSentReceiver : SentReceiver() {
showSendingFailedNotification(context, messageId) showSendingFailedNotification(context, messageId)
Telephony.Sms.MESSAGE_TYPE_FAILED Telephony.Sms.MESSAGE_TYPE_FAILED
} else { } else {
Telephony.Sms.MESSAGE_TYPE_OUTBOX Telephony.Sms.MESSAGE_TYPE_SENT
} }
context.updateMessageType(messageId, type) context.updateMessageType(messageId, type)

View File

@ -46,7 +46,7 @@
<!-- Settings --> <!-- Settings -->
<string name="lock_screen_visibility">Meldingen op vergrendelscherm</string> <string name="lock_screen_visibility">Meldingen op vergrendelscherm</string>
<string name="sender_and_message">Afzender en bericht/string> <string name="sender_and_message">Afzender en bericht</string>
<string name="sender_only">Alleen afzender</string> <string name="sender_only">Alleen afzender</string>
<string name="enable_delivery_reports">Bezorgingsrapporten inschakelen</string> <string name="enable_delivery_reports">Bezorgingsrapporten inschakelen</string>