Added additional types for txt or xml and moved import logic to Importer

This commit is contained in:
merkost
2023-07-18 17:17:52 +10:00
parent 321e4f11ff
commit db5decfcd8
3 changed files with 158 additions and 33 deletions

View File

@@ -28,6 +28,7 @@ import kotlin.system.exitProcess
class SettingsActivity : SimpleActivity() {
private var blockedNumbersAtPause = -1
private val messagesFileType = "application/json"
private val messageImportFileType = "application/json, application/xml, text/plain"
override fun onCreate(savedInstanceState: Bundle?) {
isMaterialActivity = true
@@ -83,7 +84,13 @@ class SettingsActivity : SimpleActivity() {
private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri != null) {
toast(R.string.importing)
importMessages(uri)
MessagesImporter(this).importMessages(uri) { deserializedList ->
if (deserializedList.isEmpty()) {
toast(R.string.no_entries_for_importing)
} else {
ImportMessagesDialog(this, deserializedList)
}
}
}
}
@@ -104,7 +111,7 @@ class SettingsActivity : SimpleActivity() {
private fun setupMessagesImport() {
settings_import_messages_holder.setOnClickListener {
getContent.launch(messagesFileType)
getContent.launch(messageImportFileType)
}
}
@@ -131,27 +138,6 @@ class SettingsActivity : SimpleActivity() {
}
}
private fun importMessages(uri: Uri) {
try {
val jsonString = contentResolver.openInputStream(uri)!!.use { inputStream ->
inputStream.bufferedReader().readText()
}
val deserializedList = Json.decodeFromString<List<MessagesBackup>>(jsonString)
if (deserializedList.isEmpty()) {
toast(R.string.no_entries_for_importing)
return
}
ImportMessagesDialog(this, deserializedList)
} catch (e: SerializationException) {
toast(R.string.invalid_file_format)
} catch (e: IllegalArgumentException) {
toast(R.string.invalid_file_format)
} catch (e: Exception) {
showErrorToast(e)
}
}
override fun onPause() {
super.onPause()
blockedNumbersAtPause = getBlockedNumbers().hashCode()

View File

@@ -48,7 +48,7 @@ class ImportMessagesDialog(
config.importSms = view.import_sms_checkbox.isChecked
config.importMms = view.import_mms_checkbox.isChecked
ensureBackgroundThread {
MessagesImporter(activity).importMessages(messages) {
MessagesImporter(activity).restoreMessages(messages) {
handleParseResult(it)
alertDialog.dismiss()
}

View File

@@ -1,20 +1,68 @@
package com.simplemobiletools.smsmessenger.helpers
import android.content.Context
import android.net.Uri
import android.util.Xml
import com.simplemobiletools.commons.extensions.showErrorToast
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.smsmessenger.R
import com.simplemobiletools.smsmessenger.activities.SimpleActivity
import com.simplemobiletools.smsmessenger.dialogs.ImportMessagesDialog
import com.simplemobiletools.smsmessenger.extensions.config
import com.simplemobiletools.smsmessenger.models.*
import kotlinx.serialization.SerializationException
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.xmlpull.v1.XmlPullParser
import java.io.InputStream
class MessagesImporter(private val context: Context) {
class MessagesImporter(private val activity: SimpleActivity) {
private val messageWriter = MessagesWriter(context)
private val config = context.config
private val messageWriter = MessagesWriter(activity)
private val config = activity.config
private var messagesImported = 0
private var messagesFailed = 0
fun importMessages(messagesBackup: List<MessagesBackup>, callback: (result: ImportResult) -> Unit) {
fun importMessages(uri: Uri) {
try {
val fileType = activity.contentResolver.getType(uri).orEmpty()
val isXml = isXmlMimeType(fileType) || (uri.path?.endsWith("txt") == true && isFileXml(uri))
if (isXml) {
getInputStreamFromUri(uri)!!.importXml()
} else {
importJson(uri)
}
} catch (e: Exception) {
activity.showErrorToast(e)
}
}
private fun importJson(uri: Uri) {
try {
val jsonString = activity.contentResolver.openInputStream(uri)!!.use { inputStream ->
inputStream.bufferedReader().readText()
}
val deserializedList = Json.decodeFromString<List<MessagesBackup>>(jsonString)
if (deserializedList.isEmpty()) {
activity.toast(R.string.no_entries_for_importing)
return
}
ImportMessagesDialog(activity, deserializedList)
} catch (e: SerializationException) {
activity.toast(R.string.invalid_file_format)
} catch (e: IllegalArgumentException) {
activity.toast(R.string.invalid_file_format)
} catch (e: Exception) {
activity.showErrorToast(e)
}
}
fun restoreMessages(messagesBackup: List<MessagesBackup>, callback: (ImportResult) -> Unit) {
ensureBackgroundThread {
try {
messagesBackup.forEach { message ->
@@ -23,17 +71,16 @@ class MessagesImporter(private val context: Context) {
messageWriter.writeSmsMessage(message as SmsBackup)
} else if (message.backupType == BackupType.MMS && config.importMms) {
messageWriter.writeMmsMessage(message as MmsBackup)
}
else return@forEach
} else return@forEach
messagesImported++
} catch (e: Exception) {
context.showErrorToast(e)
activity.showErrorToast(e)
messagesFailed++
}
}
refreshMessages()
} catch (e: Exception) {
context.showErrorToast(e)
activity.showErrorToast(e)
}
callback.invoke(
@@ -46,4 +93,96 @@ class MessagesImporter(private val context: Context) {
)
}
}
private fun InputStream.importXml() {
bufferedReader().use { reader ->
val xmlParser = Xml.newPullParser().apply {
setInput(reader)
}
xmlParser.nextTag()
xmlParser.require(XmlPullParser.START_TAG, null, "smses")
var depth = 1
while (depth != 0) {
when (xmlParser.next()) {
XmlPullParser.END_TAG -> depth--
XmlPullParser.START_TAG -> depth++
}
if (xmlParser.eventType != XmlPullParser.START_TAG) {
continue
}
try {
if (xmlParser.name == "sms") {
if (config.importSms) {
val message = xmlParser.readSms()
messageWriter.writeSmsMessage(message)
messagesImported++
} else {
xmlParser.skip()
}
} else {
xmlParser.skip()
}
} catch (e: Exception) {
activity.showErrorToast(e)
messagesFailed++
}
}
refreshMessages()
}
// TODO: Add result to xml import
}
private fun XmlPullParser.readSms(): SmsBackup {
require(XmlPullParser.START_TAG, null, "sms")
return SmsBackup(
subscriptionId = 0,
address = getAttributeValue(null, "address"),
body = getAttributeValue(null, "body"),
date = getAttributeValue(null, "date").toLong(),
dateSent = getAttributeValue(null, "date").toLong(),
locked = getAttributeValue(null, "locked").toInt(),
protocol = getAttributeValue(null, "protocol"),
read = getAttributeValue(null, "read").toInt(),
status = getAttributeValue(null, "status").toInt(),
type = getAttributeValue(null, "type").toInt(),
serviceCenter = getAttributeValue(null, "service_center")
)
}
private fun XmlPullParser.skip() {
if (eventType != XmlPullParser.START_TAG) {
throw IllegalStateException()
}
var depth = 1
while (depth != 0) {
when (next()) {
XmlPullParser.END_TAG -> depth--
XmlPullParser.START_TAG -> depth++
}
}
}
private fun getInputStreamFromUri(uri: Uri): InputStream? {
return try {
activity.contentResolver.openInputStream(uri)
} catch (e: Exception) {
null
}
}
private fun isFileXml(uri: Uri): Boolean {
val inputStream = getInputStreamFromUri(uri)
return inputStream?.bufferedReader()?.use { reader ->
reader.readLine()?.startsWith("<?xml") ?: false
} ?: false
}
private fun isXmlMimeType(mimeType: String): Boolean {
return mimeType.equals("application/xml", ignoreCase = true)
}
}