From 679236e3fa8c9503bdf5cb5c65fd36e7e4c4e736 Mon Sep 17 00:00:00 2001 From: merkost Date: Tue, 18 Jul 2023 16:23:46 +1000 Subject: [PATCH] MessagesImporter and MessagesReader refactoring --- .../smsmessenger/helpers/MessagesImporter.kt | 92 ++------- .../smsmessenger/helpers/MessagesReader.kt | 178 ++++++++++-------- 2 files changed, 114 insertions(+), 156 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt index 7377d057..c5020e31 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt @@ -1,102 +1,46 @@ package com.simplemobiletools.smsmessenger.helpers import android.content.Context -import android.util.JsonToken -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken import com.simplemobiletools.commons.extensions.showErrorToast import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.smsmessenger.extensions.config -import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_FAIL -import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_NOTHING_NEW -import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_OK -import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_PARTIAL -import com.simplemobiletools.smsmessenger.models.MmsBackup -import com.simplemobiletools.smsmessenger.models.SmsBackup -import java.io.File +import com.simplemobiletools.smsmessenger.models.* class MessagesImporter(private val context: Context) { - enum class ImportResult { - IMPORT_FAIL, IMPORT_OK, IMPORT_PARTIAL, IMPORT_NOTHING_NEW - } - private val gson = Gson() private val messageWriter = MessagesWriter(context) private val config = context.config private var messagesImported = 0 private var messagesFailed = 0 - fun importMessages(path: String, onProgress: (total: Int, current: Int) -> Unit = { _, _ -> }, callback: (result: ImportResult) -> Unit) { + fun importMessages(messagesBackup: List, callback: (result: ImportResult) -> Unit) { ensureBackgroundThread { try { - val inputStream = if (path.contains("/")) { - File(path).inputStream() - } else { - context.assets.open(path) - } - - inputStream.bufferedReader().use { reader -> - val jsonReader = gson.newJsonReader(reader) - val smsMessageType = object : TypeToken() {}.type - val mmsMessageType = object : TypeToken() {}.type - - jsonReader.beginArray() - while (jsonReader.hasNext()) { - jsonReader.beginObject() - while (jsonReader.hasNext()) { - val nextToken = jsonReader.peek() - if (nextToken.ordinal == JsonToken.NAME.ordinal) { - val msgType = jsonReader.nextName() - - if ((!msgType.equals("sms") && !msgType.equals("mms")) || - (msgType.equals("sms") && !config.importSms) || - (msgType.equals("mms") && !config.importMms) - ) { - jsonReader.skipValue() - continue - } - - jsonReader.beginArray() - while (jsonReader.hasNext()) { - try { - if (msgType.equals("sms")) { - val message = gson.fromJson(jsonReader, smsMessageType) - messageWriter.writeSmsMessage(message) - } else { - val message = gson.fromJson(jsonReader, mmsMessageType) - messageWriter.writeMmsMessage(message) - } - - messagesImported++ - } catch (e: Exception) { - context.showErrorToast(e) - messagesFailed++ - - } - } - jsonReader.endArray() - } else { - jsonReader.skipValue() - } + messagesBackup.forEach { message -> + try { + if (message.backupType == BackupType.SMS && config.importSms) { + messageWriter.writeSmsMessage(message as SmsBackup) + } else if (message.backupType == BackupType.MMS && config.importMms) { + messageWriter.writeMmsMessage(message as MmsBackup) } - - jsonReader.endObject() - refreshMessages() + else return@forEach + messagesImported++ + } catch (e: Exception) { + context.showErrorToast(e) + messagesFailed++ } - - jsonReader.endArray() } + refreshMessages() } catch (e: Exception) { context.showErrorToast(e) - messagesFailed++ } callback.invoke( when { - messagesImported == 0 && messagesFailed == 0 -> IMPORT_NOTHING_NEW - messagesFailed > 0 && messagesImported > 0 -> IMPORT_PARTIAL - messagesFailed > 0 -> IMPORT_FAIL - else -> IMPORT_OK + messagesImported == 0 && messagesFailed == 0 -> ImportResult.IMPORT_NOTHING_NEW + messagesFailed > 0 && messagesImported > 0 -> ImportResult.IMPORT_PARTIAL + messagesFailed > 0 -> ImportResult.IMPORT_FAIL + else -> ImportResult.IMPORT_OK } ) } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt index 175ad735..fbf164c5 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt @@ -9,49 +9,60 @@ import android.util.Base64 import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.isQPlus import com.simplemobiletools.commons.helpers.isRPlus -import com.simplemobiletools.smsmessenger.models.MmsAddress -import com.simplemobiletools.smsmessenger.models.MmsBackup -import com.simplemobiletools.smsmessenger.models.MmsPart -import com.simplemobiletools.smsmessenger.models.SmsBackup +import com.simplemobiletools.smsmessenger.extensions.getConversationIds +import com.simplemobiletools.smsmessenger.models.* import java.io.IOException import java.io.InputStream class MessagesReader(private val context: Context) { - fun forEachSms(threadId: Long, block: (SmsBackup) -> Unit) { + + fun getMessagesToExport( + getSms: Boolean, + getMms: Boolean, + callback: (messages: List) -> Unit + ) { + val conversationIds = context.getConversationIds() + var smsMessages = listOf() + var mmsMessages = listOf() + + if (getSms) { + smsMessages = getSmsMessages(conversationIds) + } + if (getMms) { + mmsMessages = getMmsMessages(conversationIds) + } + callback(smsMessages + mmsMessages) + } + + private fun getSmsMessages(threadIds: List): List { val projection = arrayOf( - Sms.SUBSCRIPTION_ID, - Sms.ADDRESS, - Sms.BODY, - Sms.DATE, - Sms.DATE_SENT, - Sms.LOCKED, - Sms.PROTOCOL, - Sms.READ, - Sms.STATUS, - Sms.TYPE, - Sms.SERVICE_CENTER + Sms.SUBSCRIPTION_ID, Sms.ADDRESS, Sms.BODY, Sms.DATE, Sms.DATE_SENT, Sms.LOCKED, Sms.PROTOCOL, Sms.READ, Sms.STATUS, Sms.TYPE, Sms.SERVICE_CENTER ) val selection = "${Sms.THREAD_ID} = ?" - val selectionArgs = arrayOf(threadId.toString()) - context.queryCursor(Sms.CONTENT_URI, projection, selection, selectionArgs) { cursor -> - val subscriptionId = cursor.getLongValue(Sms.SUBSCRIPTION_ID) - val address = cursor.getStringValue(Sms.ADDRESS) - val body = cursor.getStringValueOrNull(Sms.BODY) - val date = cursor.getLongValue(Sms.DATE) - val dateSent = cursor.getLongValue(Sms.DATE_SENT) - val locked = cursor.getIntValue(Sms.DATE_SENT) - val protocol = cursor.getStringValueOrNull(Sms.PROTOCOL) - val read = cursor.getIntValue(Sms.READ) - val status = cursor.getIntValue(Sms.STATUS) - val type = cursor.getIntValue(Sms.TYPE) - val serviceCenter = cursor.getStringValueOrNull(Sms.SERVICE_CENTER) - block(SmsBackup(subscriptionId, address, body, date, dateSent, locked, protocol, read, status, type, serviceCenter)) + val smsList = mutableListOf() + + threadIds.map { it.toString() }.forEach { threadId -> + context.queryCursor(Sms.CONTENT_URI, projection, selection, arrayOf(threadId)) { cursor -> + val subscriptionId = cursor.getLongValue(Sms.SUBSCRIPTION_ID) + val address = cursor.getStringValue(Sms.ADDRESS) + val body = cursor.getStringValueOrNull(Sms.BODY) + val date = cursor.getLongValue(Sms.DATE) + val dateSent = cursor.getLongValue(Sms.DATE_SENT) + val locked = cursor.getIntValue(Sms.DATE_SENT) + val protocol = cursor.getStringValueOrNull(Sms.PROTOCOL) + val read = cursor.getIntValue(Sms.READ) + val status = cursor.getIntValue(Sms.STATUS) + val type = cursor.getIntValue(Sms.TYPE) + val serviceCenter = cursor.getStringValueOrNull(Sms.SERVICE_CENTER) + smsList.add(SmsBackup(subscriptionId, address, body, date, dateSent, locked, protocol, read, status, type, serviceCenter)) + } } + + return smsList } - // all mms from simple sms are non-text messages - fun forEachMms(threadId: Long, includeTextOnlyAttachment: Boolean = false, block: (MmsBackup) -> Unit) { + private fun getMmsMessages(threadIds: List, includeTextOnlyAttachment: Boolean = false): List { val projection = arrayOf( Mms._ID, Mms.CREATOR, @@ -71,65 +82,67 @@ class MessagesReader(private val context: Context) { Mms.SUBSCRIPTION_ID, Mms.TRANSACTION_ID ) - val selection = if (includeTextOnlyAttachment) { "${Mms.THREAD_ID} = ? AND ${Mms.TEXT_ONLY} = ?" } else { "${Mms.THREAD_ID} = ?" } + val mmsList = mutableListOf() - val selectionArgs = if (includeTextOnlyAttachment) { - arrayOf(threadId.toString(), "1") - } else { - arrayOf(threadId.toString()) - } + threadIds.map { it.toString() }.forEach { threadId -> + val selectionArgs = if (includeTextOnlyAttachment) { + arrayOf(threadId, "1") + } else { + arrayOf(threadId) + } + context.queryCursor(Mms.CONTENT_URI, projection, selection, selectionArgs) { cursor -> + val mmsId = cursor.getLongValue(Mms._ID) + val creator = cursor.getStringValueOrNull(Mms.CREATOR) + val contentType = cursor.getStringValueOrNull(Mms.CONTENT_TYPE) + val deliveryReport = cursor.getIntValue(Mms.DELIVERY_REPORT) + val date = cursor.getLongValue(Mms.DATE) + val dateSent = cursor.getLongValue(Mms.DATE_SENT) + val locked = cursor.getIntValue(Mms.LOCKED) + val messageType = cursor.getIntValue(Mms.MESSAGE_TYPE) + val messageBox = cursor.getIntValue(Mms.MESSAGE_BOX) + val read = cursor.getIntValue(Mms.READ) + val readReport = cursor.getIntValue(Mms.READ_REPORT) + val seen = cursor.getIntValue(Mms.SEEN) + val textOnly = cursor.getIntValue(Mms.TEXT_ONLY) + val status = cursor.getStringValueOrNull(Mms.STATUS) + val subject = cursor.getStringValueOrNull(Mms.SUBJECT) + val subjectCharSet = cursor.getStringValueOrNull(Mms.SUBJECT_CHARSET) + val subscriptionId = cursor.getLongValue(Mms.SUBSCRIPTION_ID) + val transactionId = cursor.getStringValueOrNull(Mms.TRANSACTION_ID) - context.queryCursor(Mms.CONTENT_URI, projection, selection, selectionArgs) { cursor -> - val mmsId = cursor.getLongValue(Mms._ID) - val creator = cursor.getStringValueOrNull(Mms.CREATOR) - val contentType = cursor.getStringValueOrNull(Mms.CONTENT_TYPE) - val deliveryReport = cursor.getIntValue(Mms.DELIVERY_REPORT) - val date = cursor.getLongValue(Mms.DATE) - val dateSent = cursor.getLongValue(Mms.DATE_SENT) - val locked = cursor.getIntValue(Mms.LOCKED) - val messageType = cursor.getIntValue(Mms.MESSAGE_TYPE) - val messageBox = cursor.getIntValue(Mms.MESSAGE_BOX) - val read = cursor.getIntValue(Mms.READ) - val readReport = cursor.getIntValue(Mms.READ_REPORT) - val seen = cursor.getIntValue(Mms.SEEN) - val textOnly = cursor.getIntValue(Mms.TEXT_ONLY) - val status = cursor.getStringValueOrNull(Mms.STATUS) - val subject = cursor.getStringValueOrNull(Mms.SUBJECT) - val subjectCharSet = cursor.getStringValueOrNull(Mms.SUBJECT_CHARSET) - val subscriptionId = cursor.getLongValue(Mms.SUBSCRIPTION_ID) - val transactionId = cursor.getStringValueOrNull(Mms.TRANSACTION_ID) - - val parts = getParts(mmsId) - val addresses = getMmsAddresses(mmsId) - block( - MmsBackup( - creator, - contentType, - deliveryReport, - date, - dateSent, - locked, - messageType, - messageBox, - read, - readReport, - seen, - textOnly, - status, - subject, - subjectCharSet, - subscriptionId, - transactionId, - addresses, - parts + val parts = getParts(mmsId) + val addresses = getMmsAddresses(mmsId) + mmsList.add( + MmsBackup( + creator, + contentType, + deliveryReport, + date, + dateSent, + locked, + messageType, + messageBox, + read, + readReport, + seen, + textOnly, + status, + subject, + subjectCharSet, + subscriptionId, + transactionId, + addresses, + parts + ) ) - ) + } } + return mmsList } @SuppressLint("NewApi") @@ -172,6 +185,7 @@ class MessagesReader(private val context: Context) { stream.readBytes().toString(Charsets.UTF_8) } } + else -> { usePart(partId) { stream -> Base64.encodeToString(stream.readBytes(), Base64.DEFAULT)