Improve message sync speed & reliability

This commit is contained in:
Moez Bhatti
2021-02-14 00:19:30 -05:00
parent bc6c19e080
commit ca1e7b7c7a
7 changed files with 81 additions and 45 deletions
@@ -124,8 +124,6 @@ class CursorToMessageImpl @Inject constructor(
?.let { EncodedStringValue(subjectCharset, it).string } ?: ""
textContentType = ""
attachmentType = Message.AttachmentType.NOT_LOADED
parts.addAll(cursorToPart.getPartsCursor(contentId)?.map { cursorToPart.map(it) } ?: listOf())
}
}
}
@@ -35,6 +35,7 @@ class CursorToPartImpl @Inject constructor(private val context: Context) : Curso
override fun map(from: Cursor) = MmsPart().apply {
id = from.getLong(from.getColumnIndexOrThrow(Telephony.Mms.Part._ID))
messageId = from.getLong(from.getColumnIndexOrThrow(Telephony.Mms.Part.MSG_ID))
type = from.getStringOrNull(from.getColumnIndexOrThrow(Telephony.Mms.Part.CONTENT_TYPE)) ?: "*/*"
seq = from.getIntOrNull(from.getColumnIndexOrThrow(Telephony.Mms.Part.SEQ)) ?: -1
name = from.getStringOrNull(from.getColumnIndexOrThrow(Telephony.Mms.Part.NAME))
@@ -43,9 +44,8 @@ class CursorToPartImpl @Inject constructor(private val context: Context) : Curso
text = from.getStringOrNull(from.getColumnIndexOrThrow(Telephony.Mms.Part.TEXT))
}
override fun getPartsCursor(messageId: Long): Cursor? {
return context.contentResolver.query(CONTENT_URI, null,
"${Telephony.Mms.Part.MSG_ID} = ?", arrayOf(messageId.toString()), null)
override fun getPartsCursor(): Cursor? {
return context.contentResolver.query(CONTENT_URI, null, null, null, null)
}
}
}
@@ -36,7 +36,7 @@ class QkRealmMigration @Inject constructor(
) : RealmMigration {
companion object {
const val SchemaVersion: Long = 10
const val SchemaVersion: Long = 11
}
@SuppressLint("ApplySharedPref")
@@ -223,6 +223,17 @@ class QkRealmMigration @Inject constructor(
version++
}
if (version == 10L) {
realm.schema.get("MmsPart")
?.addField("messageId", Long::class.java, FieldAttribute.INDEXED, FieldAttribute.REQUIRED)
?.transform { part ->
val messageId = part.linkingObjects("Message", "parts").firstOrNull()?.getLong("contentId") ?: 0
part.setLong("messageId", messageId)
}
version++
}
check(version >= newVersion) { "Migration missing from v$oldVersion to v$newVersion" }
}
@@ -23,6 +23,7 @@ import android.content.ContentUris
import android.net.Uri
import android.provider.Telephony
import com.f2prateek.rx.preferences2.RxSharedPreferences
import com.moez.QKSMS.extensions.forEach
import com.moez.QKSMS.extensions.insertOrUpdate
import com.moez.QKSMS.extensions.map
import com.moez.QKSMS.manager.KeyManager
@@ -31,6 +32,7 @@ import com.moez.QKSMS.mapper.CursorToContactGroup
import com.moez.QKSMS.mapper.CursorToContactGroupMember
import com.moez.QKSMS.mapper.CursorToConversation
import com.moez.QKSMS.mapper.CursorToMessage
import com.moez.QKSMS.mapper.CursorToPart
import com.moez.QKSMS.mapper.CursorToRecipient
import com.moez.QKSMS.model.Contact
import com.moez.QKSMS.model.ContactGroup
@@ -45,6 +47,7 @@ import com.moez.QKSMS.util.tryOrNull
import io.reactivex.subjects.BehaviorSubject
import io.reactivex.subjects.Subject
import io.realm.Realm
import io.realm.RealmList
import io.realm.Sort
import javax.inject.Inject
import javax.inject.Singleton
@@ -55,6 +58,7 @@ class SyncRepositoryImpl @Inject constructor(
private val conversationRepo: ConversationRepository,
private val cursorToConversation: CursorToConversation,
private val cursorToMessage: CursorToMessage,
private val cursorToPart: CursorToPart,
private val cursorToRecipient: CursorToRecipient,
private val cursorToContact: CursorToContact,
private val cursorToContactGroup: CursorToContactGroup,
@@ -103,25 +107,48 @@ class SyncRepositoryImpl @Inject constructor(
keys.reset()
val partsCursor = cursorToPart.getPartsCursor()
val messageCursor = cursorToMessage.getMessagesCursor()
val conversationCursor = cursorToConversation.getConversationsCursor()
val recipientCursor = cursorToRecipient.getRecipientCursor()
val max = (messageCursor?.count ?: 0) +
val max = (partsCursor?.count ?: 0) +
(messageCursor?.count ?: 0) +
(conversationCursor?.count ?: 0) +
(recipientCursor?.count ?: 0)
var progress = 0
// Sync message parts
partsCursor?.use {
partsCursor.forEach {
tryOrNull {
progress++
val part = cursorToPart.map(partsCursor)
realm.insertOrUpdate(part)
}
}
}
// Sync messages
messageCursor?.use {
val messageColumns = CursorToMessage.MessageColumns(messageCursor)
val messages = messageCursor.map { cursor ->
progress++
syncProgress.onNext(SyncRepository.SyncProgress.Running(max, progress, false))
cursorToMessage.map(Pair(cursor, messageColumns))
messageCursor.forEach { cursor ->
tryOrNull {
progress++
syncProgress.onNext(SyncRepository.SyncProgress.Running(max, progress, false))
val message = cursorToMessage.map(Pair(cursor, messageColumns)).apply {
if (isMms()) {
parts = RealmList<MmsPart>().apply {
addAll(realm.where(MmsPart::class.java)
.equalTo("messageId", contentId)
.findAll())
}
}
}
realm.insertOrUpdate(message)
}
}
realm.insertOrUpdate(messages)
}
// Migrate blocked conversations from 2.7.3
@@ -133,46 +160,44 @@ class SyncRepositoryImpl @Inject constructor(
// Sync conversations
conversationCursor?.use {
val conversations = conversationCursor.map { cursor ->
progress++
syncProgress.onNext(SyncRepository.SyncProgress.Running(max, progress, false))
cursorToConversation.map(cursor).apply {
persistedData[id]?.let { persistedConversation ->
archived = persistedConversation.archived
blocked = persistedConversation.blocked
pinned = persistedConversation.pinned
name = persistedConversation.name
blockingClient = persistedConversation.blockingClient
blockReason = persistedConversation.blockReason
conversationCursor.forEach { cursor ->
tryOrNull {
progress++
syncProgress.onNext(SyncRepository.SyncProgress.Running(max, progress, false))
val conversation = cursorToConversation.map(cursor).apply {
persistedData[id]?.let { persistedConversation ->
archived = persistedConversation.archived
blocked = persistedConversation.blocked
pinned = persistedConversation.pinned
name = persistedConversation.name
blockingClient = persistedConversation.blockingClient
blockReason = persistedConversation.blockReason
}
lastMessage = realm.where(Message::class.java)
.sort("date", Sort.DESCENDING)
.equalTo("threadId", id)
.findFirst()
}
realm.insertOrUpdate(conversation)
}
}
realm.where(Message::class.java)
.sort("date", Sort.DESCENDING)
.distinct("threadId")
.findAll()
.forEach { message ->
val conversation = conversations.find { conversation -> conversation.id == message.threadId }
conversation?.lastMessage = message
}
realm.insertOrUpdate(conversations)
}
// Sync recipients
recipientCursor?.use {
val contacts = realm.copyToRealmOrUpdate(getContacts())
val recipients = recipientCursor.map { cursor ->
progress++
syncProgress.onNext(SyncRepository.SyncProgress.Running(max, progress, false))
cursorToRecipient.map(cursor).apply {
contact = contacts.firstOrNull { contact ->
contact.numbers.any { phoneNumberUtils.compare(address, it.address) }
recipientCursor.forEach { cursor ->
tryOrNull {
progress++
syncProgress.onNext(SyncRepository.SyncProgress.Running(max, progress, false))
val recipient = cursorToRecipient.map(cursor).apply {
contact = contacts.firstOrNull { contact ->
contact.numbers.any { phoneNumberUtils.compare(address, it.address) }
}
}
realm.insertOrUpdate(recipient)
}
}
realm.insertOrUpdate(recipients)
}
syncProgress.onNext(SyncRepository.SyncProgress.Running(0, 0, true))