diff --git a/app/src/main/kotlin/org/fossify/messages/activities/SettingsActivity.kt b/app/src/main/kotlin/org/fossify/messages/activities/SettingsActivity.kt index 1c12634d..24f576c7 100644 --- a/app/src/main/kotlin/org/fossify/messages/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/org/fossify/messages/activities/SettingsActivity.kt @@ -5,9 +5,10 @@ import android.content.Intent import android.net.Uri import android.os.Build import android.os.Bundle +import android.provider.DocumentsContract import androidx.activity.result.contract.ActivityResultContracts -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToStream import org.fossify.commons.activities.ManageBlockedNumbersActivity import org.fossify.commons.dialogs.ChangeDateTimeFormatDialog import org.fossify.commons.dialogs.ConfirmationDialog @@ -170,8 +171,10 @@ class SettingsActivity : SimpleActivity() { } } + @OptIn(kotlinx.serialization.ExperimentalSerializationApi::class) private fun exportMessages(uri: Uri) { ensureBackgroundThread { + var success = false try { MessagesReader(this).getMessagesToExport( config.exportSms, @@ -182,16 +185,23 @@ class SettingsActivity : SimpleActivity() { return@getMessagesToExport } val json = Json { encodeDefaults = true } - val jsonString = json.encodeToString(messagesToExport) - val outputStream = contentResolver.openOutputStream(uri)!! - - outputStream.use { - it.write(jsonString.toByteArray()) + contentResolver.openOutputStream(uri)!!.buffered().use { outputStream -> + json.encodeToStream(messagesToExport, outputStream) } + success = true toast(org.fossify.commons.R.string.exporting_successful) } - } catch (e: Exception) { - showErrorToast(e) + } catch (e: Throwable) { // also catch OutOfMemoryError etc. + showErrorToast(e.toString()) + } finally { + if (!success) { + // delete the file to avoid leaving behind an empty/corrupt file + try { + DocumentsContract.deleteDocument(contentResolver, uri) + } catch (ignored: Exception) { + // ignored because we don't want to overwhelm the user with two error messages + } + } } } } diff --git a/app/src/main/kotlin/org/fossify/messages/helpers/MessagesImporter.kt b/app/src/main/kotlin/org/fossify/messages/helpers/MessagesImporter.kt index 9faa06a6..476c2b80 100644 --- a/app/src/main/kotlin/org/fossify/messages/helpers/MessagesImporter.kt +++ b/app/src/main/kotlin/org/fossify/messages/helpers/MessagesImporter.kt @@ -4,6 +4,7 @@ import android.net.Uri import android.util.Xml import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream import org.fossify.commons.extensions.showErrorToast import org.fossify.commons.extensions.toast import org.fossify.commons.helpers.ensureBackgroundThread @@ -32,18 +33,17 @@ class MessagesImporter(private val activity: SimpleActivity) { } else { importJson(uri) } - } catch (e: Exception) { - activity.showErrorToast(e) + } catch (e: Throwable) { // also catch OutOfMemoryError etc. + activity.showErrorToast(e.toString()) } } + @OptIn(kotlinx.serialization.ExperimentalSerializationApi::class) private fun importJson(uri: Uri) { try { - val jsonString = activity.contentResolver.openInputStream(uri)!!.use { inputStream -> - inputStream.bufferedReader().readText() + val deserializedList = activity.contentResolver.openInputStream(uri)!!.buffered().use { inputStream -> + Json.decodeFromStream>(inputStream) } - - val deserializedList = Json.decodeFromString>(jsonString) if (deserializedList.isEmpty()) { activity.toast(org.fossify.commons.R.string.no_entries_for_importing) return