Fix infinite export loop and improve general error handling.
This commit is contained in:
parent
0d715d2c18
commit
7fccbd44c0
18 changed files with 155 additions and 30 deletions
|
@ -65,6 +65,7 @@ import org.thoughtcrime.securesms.video.EncryptedMediaDataSource;
|
|||
import org.whispersystems.signalservice.internal.util.JsonUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
@ -204,7 +205,13 @@ public class AttachmentDatabase extends Database {
|
|||
public @NonNull InputStream getAttachmentStream(AttachmentId attachmentId, long offset)
|
||||
throws IOException
|
||||
{
|
||||
InputStream dataStream = getDataStream(attachmentId, DATA, offset);
|
||||
InputStream dataStream;
|
||||
|
||||
try {
|
||||
dataStream = getDataStream(attachmentId, DATA, offset);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new IOException("No stream for: " + attachmentId, e);
|
||||
}
|
||||
|
||||
if (dataStream == null) throw new IOException("No stream for: " + attachmentId);
|
||||
else return dataStream;
|
||||
|
@ -1019,8 +1026,8 @@ public class AttachmentDatabase extends Database {
|
|||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
@VisibleForTesting
|
||||
protected @Nullable InputStream getDataStream(AttachmentId attachmentId, String dataType, long offset)
|
||||
private @Nullable InputStream getDataStream(AttachmentId attachmentId, String dataType, long offset)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
DataInfo dataInfo = getAttachmentDataFileInfo(attachmentId, dataType);
|
||||
|
||||
|
@ -1042,6 +1049,9 @@ public class AttachmentDatabase extends Database {
|
|||
|
||||
return stream;
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w(TAG, e);
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return null;
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.database.documents.Document;
|
|||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchSet;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.model.MessageExportStatus;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.ParentStoryId;
|
||||
|
@ -398,7 +399,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns,
|
|||
}
|
||||
|
||||
public int getUnexportedInsecureMessagesCount(long threadId) {
|
||||
try (Cursor cursor = getWritableDatabase().query(getTableName(), SqlUtil.COUNT, getInsecureMessageClause(threadId) + " AND NOT " + EXPORTED, null, null, null, null)) {
|
||||
try (Cursor cursor = getWritableDatabase().query(getTableName(), SqlUtil.COUNT, getInsecureMessageClause(threadId) + " AND " + EXPORTED + " < ?", SqlUtil.buildArgs(MessageExportStatus.EXPORTED), null, null, null)) {
|
||||
if (cursor.moveToFirst()) {
|
||||
return cursor.getInt(0);
|
||||
}
|
||||
|
@ -407,6 +408,19 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the exported status (not state) to the default for clearing errors.
|
||||
*/
|
||||
public void clearInsecureMessageExportedErrorStatus() {
|
||||
ContentValues values = new ContentValues(1);
|
||||
values.put(EXPORTED, MessageExportStatus.UNEXPORTED.getCode());
|
||||
|
||||
SQLiteDatabaseExtensionsKt.update(getWritableDatabase(), getTableName())
|
||||
.values(values)
|
||||
.where(EXPORTED + " < ?", MessageExportStatus.UNEXPORTED.getCode())
|
||||
.run();
|
||||
}
|
||||
|
||||
public void setReactionsSeen(long threadId, long sinceTimestamp) {
|
||||
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
|||
import org.thoughtcrime.securesms.database.documents.NetworkFailureSet;
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.Mention;
|
||||
import org.thoughtcrime.securesms.database.model.MessageExportStatus;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
||||
|
@ -205,7 +206,8 @@ public class MmsDatabase extends MessageDatabase {
|
|||
"CREATE INDEX IF NOT EXISTS mms_is_story_index ON " + TABLE_NAME + " (" + STORY_TYPE + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_parent_story_id_index ON " + TABLE_NAME + " (" + PARENT_STORY_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_thread_story_parent_story_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + "," + STORY_TYPE + "," + PARENT_STORY_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_quote_id_quote_author_index ON " + TABLE_NAME + "(" + QUOTE_ID + ", " + QUOTE_AUTHOR + ");"
|
||||
"CREATE INDEX IF NOT EXISTS mms_quote_id_quote_author_index ON " + TABLE_NAME + "(" + QUOTE_ID + ", " + QUOTE_AUTHOR + ");",
|
||||
"CREATE INDEX IF NOT EXISTS mms_exported_index ON " + TABLE_NAME + " (" + EXPORTED + ");"
|
||||
};
|
||||
|
||||
private static final String[] MMS_PROJECTION = new String[] {
|
||||
|
@ -2466,13 +2468,13 @@ public class MmsDatabase extends MessageDatabase {
|
|||
beginTransaction();
|
||||
try {
|
||||
List<Long> threadsToUpdate = new LinkedList<>();
|
||||
try (Cursor cursor = getReadableDatabase().query(TABLE_NAME, THREAD_ID_PROJECTION, EXPORTED + " = ?", SqlUtil.buildArgs(1), THREAD_ID, null, null, null)) {
|
||||
try (Cursor cursor = getReadableDatabase().query(TABLE_NAME, THREAD_ID_PROJECTION, EXPORTED + " = ?", SqlUtil.buildArgs(MessageExportStatus.EXPORTED), THREAD_ID, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
threadsToUpdate.add(CursorUtil.requireLong(cursor, THREAD_ID));
|
||||
}
|
||||
}
|
||||
|
||||
getWritableDatabase().delete(TABLE_NAME, EXPORTED + " = ?", SqlUtil.buildArgs(1));
|
||||
getWritableDatabase().delete(TABLE_NAME, EXPORTED + " = ?", SqlUtil.buildArgs(MessageExportStatus.EXPORTED));
|
||||
|
||||
for (final long threadId : threadsToUpdate) {
|
||||
SignalDatabase.threads().update(threadId, false);
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.signal.core.util.logging.Log;
|
|||
import org.signal.libsignal.protocol.util.Pair;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase.MessageUpdate;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageExportStatus;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExportState;
|
||||
|
@ -671,7 +672,16 @@ public class MmsSmsDatabase extends Database {
|
|||
String table = messageId.isMms() ? MmsDatabase.TABLE_NAME : SmsDatabase.TABLE_NAME;
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
|
||||
contentValues.put(MmsSmsColumns.EXPORTED, 1);
|
||||
contentValues.put(MmsSmsColumns.EXPORTED, MessageExportStatus.EXPORTED.getCode());
|
||||
|
||||
getWritableDatabase().update(table, contentValues, ID_WHERE, SqlUtil.buildArgs(messageId.getId()));
|
||||
}
|
||||
|
||||
public void markMessageExportFailed(@NonNull MessageId messageId) {
|
||||
String table = messageId.isMms() ? MmsDatabase.TABLE_NAME : SmsDatabase.TABLE_NAME;
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
|
||||
contentValues.put(MmsSmsColumns.EXPORTED, MessageExportStatus.ERROR.getCode());
|
||||
|
||||
getWritableDatabase().update(table, contentValues, ID_WHERE, SqlUtil.buildArgs(messageId.getId()));
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
|||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatchSet;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil;
|
||||
import org.thoughtcrime.securesms.database.model.MessageExportStatus;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.ParentStoryId;
|
||||
|
@ -146,7 +147,8 @@ public class SmsDatabase extends MessageDatabase {
|
|||
"CREATE INDEX IF NOT EXISTS sms_date_sent_index ON " + TABLE_NAME + " (" + DATE_SENT + ", " + RECIPIENT_ID + ", " + THREAD_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_date_server_index ON " + TABLE_NAME + " (" + DATE_SERVER + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_thread_date_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_reactions_unread_index ON " + TABLE_NAME + " (" + REACTIONS_UNREAD + ");"
|
||||
"CREATE INDEX IF NOT EXISTS sms_reactions_unread_index ON " + TABLE_NAME + " (" + REACTIONS_UNREAD + ");",
|
||||
"CREATE INDEX IF NOT EXISTS sms_exported_index ON " + TABLE_NAME + " (" + EXPORTED + ");"
|
||||
};
|
||||
|
||||
private static final String[] MESSAGE_PROJECTION = new String[] {
|
||||
|
@ -924,13 +926,13 @@ public class SmsDatabase extends MessageDatabase {
|
|||
beginTransaction();
|
||||
try {
|
||||
List<Long> threadsToUpdate = new LinkedList<>();
|
||||
try (Cursor cursor = getReadableDatabase().query(TABLE_NAME, THREAD_ID_PROJECTION, EXPORTED + " = ?", SqlUtil.buildArgs(1), THREAD_ID, null, null, null)) {
|
||||
try (Cursor cursor = getReadableDatabase().query(TABLE_NAME, THREAD_ID_PROJECTION, EXPORTED + " = ?", SqlUtil.buildArgs(MessageExportStatus.EXPORTED), THREAD_ID, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
threadsToUpdate.add(CursorUtil.requireLong(cursor, THREAD_ID));
|
||||
}
|
||||
}
|
||||
|
||||
getWritableDatabase().delete(TABLE_NAME, EXPORTED + " = ?", SqlUtil.buildArgs(1));
|
||||
getWritableDatabase().delete(TABLE_NAME, EXPORTED + " = ?", SqlUtil.buildArgs(MessageExportStatus.EXPORTED));
|
||||
|
||||
for (final long threadId : threadsToUpdate) {
|
||||
SignalDatabase.threads().update(threadId, false);
|
||||
|
|
|
@ -14,13 +14,14 @@ import org.thoughtcrime.securesms.database.helpers.migration.V156_RecipientUnreg
|
|||
import org.thoughtcrime.securesms.database.helpers.migration.V157_RecipeintHiddenMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V158_GroupsLastForceUpdateTimestampMigration
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V159_ThreadUnreadSelfMentionCount
|
||||
import org.thoughtcrime.securesms.database.helpers.migration.V160_SmsMmsExportedIndexMigration
|
||||
|
||||
/**
|
||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||
*/
|
||||
object SignalDatabaseMigrations {
|
||||
|
||||
const val DATABASE_VERSION = 159
|
||||
const val DATABASE_VERSION = 160
|
||||
|
||||
@JvmStatic
|
||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
|
@ -67,6 +68,10 @@ object SignalDatabaseMigrations {
|
|||
if (oldVersion < 159) {
|
||||
V159_ThreadUnreadSelfMentionCount.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
|
||||
if (oldVersion < 160) {
|
||||
V160_SmsMmsExportedIndexMigration.migrate(context, db, oldVersion, newVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package org.thoughtcrime.securesms.database.helpers.migration
|
||||
|
||||
import android.app.Application
|
||||
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||
|
||||
object V160_SmsMmsExportedIndexMigration : SignalDatabaseMigration {
|
||||
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS sms_exported_index ON sms (exported)")
|
||||
db.execSQL("CREATE INDEX IF NOT EXISTS mms_exported_index ON mms (exported)")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package org.thoughtcrime.securesms.database.model
|
||||
|
||||
import org.signal.core.util.DatabaseId
|
||||
import org.signal.core.util.IntSerializer
|
||||
|
||||
/**
|
||||
* Export status for a message.
|
||||
*/
|
||||
enum class MessageExportStatus(val code: Int) : DatabaseId {
|
||||
UNEXPORTED(0),
|
||||
EXPORTED(1),
|
||||
ERROR(-1);
|
||||
|
||||
override fun serialize(): String {
|
||||
return Serializer.serialize(this).toString()
|
||||
}
|
||||
|
||||
companion object Serializer : IntSerializer<MessageExportStatus> {
|
||||
override fun serialize(data: MessageExportStatus): Int {
|
||||
return data.code
|
||||
}
|
||||
|
||||
override fun deserialize(data: Int): MessageExportStatus {
|
||||
return when (data) {
|
||||
UNEXPORTED.code -> UNEXPORTED
|
||||
EXPORTED.code -> EXPORTED
|
||||
ERROR.code -> ERROR
|
||||
else -> throw AssertionError("Unknown message export status: $data")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels
|
|||
import org.thoughtcrime.securesms.notifications.NotificationIds
|
||||
import org.thoughtcrime.securesms.notifications.v2.NotificationPendingIntentHelper
|
||||
import org.thoughtcrime.securesms.util.JsonUtils
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
|
||||
/**
|
||||
|
@ -79,6 +80,11 @@ class SignalSmsExportService : SmsExportService() {
|
|||
)
|
||||
}
|
||||
|
||||
override fun prepareForExport() {
|
||||
SignalDatabase.sms.clearInsecureMessageExportedErrorStatus()
|
||||
SignalDatabase.mms.clearInsecureMessageExportedErrorStatus()
|
||||
}
|
||||
|
||||
override fun getUnexportedMessageCount(): Int {
|
||||
ensureReader()
|
||||
return reader!!.getCount()
|
||||
|
@ -107,6 +113,8 @@ class SignalSmsExportService : SmsExportService() {
|
|||
SignalDatabase.mmsSms.updateMessageExportState(exportableMessage.getMessageId()) {
|
||||
it.toBuilder().setProgress(MessageExportState.Progress.INIT).build()
|
||||
}
|
||||
|
||||
SignalDatabase.mmsSms.markMessageExportFailed(exportableMessage.getMessageId())
|
||||
}
|
||||
|
||||
override fun onMessageIdCreated(exportableMessage: ExportableMessage, messageId: Long) {
|
||||
|
@ -153,6 +161,7 @@ class SignalSmsExportService : SmsExportService() {
|
|||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun getInputStream(part: ExportableMessage.Mms.Part): InputStream {
|
||||
return SignalDatabase.attachments.getAttachmentStream(JsonUtils.fromJson(part.contentId, AttachmentId::class.java), 0)
|
||||
}
|
||||
|
|
|
@ -14,12 +14,13 @@ import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
|||
*/
|
||||
class ExportSmsCompleteFragment : Fragment(R.layout.export_sms_complete_fragment) {
|
||||
|
||||
val args: ExportSmsCompleteFragmentArgs by navArgs()
|
||||
private val args: ExportSmsCompleteFragmentArgs by navArgs()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val binding = ExportSmsCompleteFragmentBinding.bind(view)
|
||||
val exportSuccessCount = args.exportMessageCount - args.exportMessageFailureCount
|
||||
|
||||
val binding = ExportSmsCompleteFragmentBinding.bind(view)
|
||||
binding.exportCompleteNext.setOnClickListener { findNavController().safeNavigate(ExportSmsCompleteFragmentDirections.actionExportingSmsMessagesFragmentToChooseANewDefaultSmsAppFragment()) }
|
||||
binding.exportCompleteStatus.text = resources.getQuantityString(R.plurals.ExportSmsCompleteFragment__d_of_d_messages_exported, args.exportMessageCount, args.exportMessageCount, args.exportMessageCount)
|
||||
binding.exportCompleteStatus.text = resources.getQuantityString(R.plurals.ExportSmsCompleteFragment__d_of_d_messages_exported, args.exportMessageCount, exportSuccessCount, args.exportMessageCount)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ class ExportYourSmsMessagesFragment : Fragment(R.layout.export_your_sms_messages
|
|||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
if (it is SmsExportProgress.Done) {
|
||||
findNavController().safeNavigate(SmsExportDirections.actionDirectToExportSmsCompleteFragment(it.progress))
|
||||
findNavController().safeNavigate(SmsExportDirections.actionDirectToExportSmsCompleteFragment(it.errorCount, it.total))
|
||||
} else if (it is SmsExportProgress.InProgress) {
|
||||
findNavController().safeNavigate(ExportYourSmsMessagesFragmentDirections.actionExportYourSmsMessagesFragmentToExportingSmsMessagesFragment())
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ class ExportingSmsMessagesFragment : Fragment(R.layout.exporting_sms_messages_fr
|
|||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
if (it is SmsExportProgress.Done) {
|
||||
findNavController().safeNavigate(ExportingSmsMessagesFragmentDirections.actionExportingSmsMessagesFragmentToExportSmsCompleteFragment(it.progress))
|
||||
findNavController().safeNavigate(ExportingSmsMessagesFragmentDirections.actionExportingSmsMessagesFragmentToExportSmsCompleteFragment(it.total, it.errorCount))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
app:popExitAnim="@anim/fragment_close_exit" />
|
||||
<action
|
||||
android:id="@+id/action_exportYourSmsMessagesFragment_to_setSignalAsDefaultSmsAppFragment"
|
||||
app:destination="@id/setSignalAsDefaultSmsAppFragment" />
|
||||
app:destination="@id/setSignalAsDefaultSmsAppFragment"
|
||||
app:enterAnim="@anim/fragment_open_enter"
|
||||
app:exitAnim="@anim/fragment_open_exit"
|
||||
app:popEnterAnim="@anim/fragment_close_enter"
|
||||
app:popExitAnim="@anim/fragment_close_exit" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
@ -58,7 +62,12 @@
|
|||
android:name="org.thoughtcrime.securesms.exporter.flow.ExportSmsCompleteFragment"
|
||||
tools:layout="@layout/export_sms_complete_fragment">
|
||||
|
||||
<argument android:name="export_message_count"
|
||||
<argument
|
||||
android:name="export_message_count"
|
||||
app:argType="integer" />
|
||||
|
||||
<argument
|
||||
android:name="export_message_failure_count"
|
||||
app:argType="integer" />
|
||||
|
||||
<action
|
||||
|
@ -85,6 +94,6 @@
|
|||
app:popEnterAnim="@anim/fragment_close_enter"
|
||||
app:popExitAnim="@anim/fragment_close_exit"
|
||||
app:popUpTo="@+id/exportYourSmsMessagesFragment"
|
||||
app:popUpToInclusive="true"/>
|
||||
app:popUpToInclusive="true" />
|
||||
|
||||
</navigation>
|
|
@ -229,6 +229,7 @@ class UpdateBuilderPart3(
|
|||
private val where: String,
|
||||
private val whereArgs: Array<String>
|
||||
) {
|
||||
@JvmOverloads
|
||||
fun run(conflictStrategy: Int = SQLiteDatabase.CONFLICT_NONE): Int {
|
||||
return db.update(tableName, conflictStrategy, values, where, whereArgs)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ interface Serializer<T, R> {
|
|||
|
||||
interface StringSerializer<T> : Serializer<T, String>
|
||||
|
||||
interface IntSerializer<T> : Serializer<T, Int>
|
||||
|
||||
interface LongSerializer<T> : Serializer<T, Long>
|
||||
|
||||
interface ByteSerializer<T> : Serializer<T, ByteArray>
|
||||
|
|
|
@ -63,7 +63,7 @@ object SqlUtil {
|
|||
return objects.map {
|
||||
when (it) {
|
||||
null -> throw NullPointerException("Cannot have null arg!")
|
||||
is DatabaseId -> (it as DatabaseId?)!!.serialize()
|
||||
is DatabaseId -> it.serialize()
|
||||
else -> it.toString()
|
||||
}
|
||||
}.toTypedArray()
|
||||
|
|
|
@ -19,11 +19,12 @@ sealed class SmsExportProgress {
|
|||
*/
|
||||
data class InProgress(
|
||||
val progress: Int,
|
||||
val errorCount: Int,
|
||||
val total: Int
|
||||
) : SmsExportProgress()
|
||||
|
||||
/**
|
||||
* All done.
|
||||
*/
|
||||
data class Done(val progress: Int) : SmsExportProgress()
|
||||
data class Done(val errorCount: Int, val total: Int) : SmsExportProgress()
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.signal.smsexporter.internal.mms.ExportMmsPartsUseCase
|
|||
import org.signal.smsexporter.internal.mms.ExportMmsRecipientsUseCase
|
||||
import org.signal.smsexporter.internal.mms.GetOrCreateMmsThreadIdsUseCase
|
||||
import org.signal.smsexporter.internal.sms.ExportSmsMessagesUseCase
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.InputStream
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
|
@ -60,31 +61,39 @@ abstract class SmsExportService : Service() {
|
|||
progressState.onNext(SmsExportProgress.Starting)
|
||||
|
||||
var progress = 0
|
||||
var errorCount = 0
|
||||
executor.execute {
|
||||
prepareForExport()
|
||||
val totalCount = getUnexportedMessageCount()
|
||||
getUnexportedMessages().forEach { message ->
|
||||
val exportState = message.exportState
|
||||
if (exportState.progress != SmsExportState.Progress.COMPLETED) {
|
||||
when (message) {
|
||||
val successful = when (message) {
|
||||
is ExportableMessage.Sms<*> -> exportSms(exportState, message)
|
||||
is ExportableMessage.Mms<*> -> exportMms(exportState, message)
|
||||
}
|
||||
|
||||
if (!successful) {
|
||||
errorCount++
|
||||
}
|
||||
|
||||
progress++
|
||||
if (progress == 1 || progress.mod(100) == 0) {
|
||||
updateNotification(progress, totalCount)
|
||||
}
|
||||
progressState.onNext(SmsExportProgress.InProgress(progress, totalCount))
|
||||
progressState.onNext(SmsExportProgress.InProgress(progress, errorCount, totalCount))
|
||||
}
|
||||
}
|
||||
|
||||
onExportPassCompleted()
|
||||
progressState.onNext(SmsExportProgress.Done(progress))
|
||||
progressState.onNext(SmsExportProgress.Done(errorCount, progress))
|
||||
|
||||
getExportCompleteNotification()?.let { notification ->
|
||||
NotificationManagerCompat.from(this).notify(notification.id, notification.notification)
|
||||
}
|
||||
|
||||
Log.d(TAG, "Export complete")
|
||||
|
||||
stopForeground(true)
|
||||
isStarted = false
|
||||
}
|
||||
|
@ -110,6 +119,9 @@ abstract class SmsExportService : Service() {
|
|||
*/
|
||||
protected abstract fun getExportCompleteNotification(): ExportNotification?
|
||||
|
||||
/** Called prior to starting export for any task setup that may need to occur. */
|
||||
protected open fun prepareForExport() = Unit
|
||||
|
||||
/**
|
||||
* Gets the total number of messages to process. This is only used for the notification and
|
||||
* progress events.
|
||||
|
@ -192,17 +204,19 @@ abstract class SmsExportService : Service() {
|
|||
startForeground(exportNotification.id, exportNotification.notification)
|
||||
}
|
||||
|
||||
private fun exportSms(smsExportState: SmsExportState, sms: ExportableMessage.Sms<*>) {
|
||||
private fun exportSms(smsExportState: SmsExportState, sms: ExportableMessage.Sms<*>): Boolean {
|
||||
onMessageExportStarted(sms)
|
||||
val mayAlreadyExist = smsExportState.progress == SmsExportState.Progress.STARTED
|
||||
ExportSmsMessagesUseCase.execute(this, sms, mayAlreadyExist).either(onSuccess = {
|
||||
return ExportSmsMessagesUseCase.execute(this, sms, mayAlreadyExist).either(onSuccess = {
|
||||
onMessageExportSucceeded(sms)
|
||||
true
|
||||
}, onFailure = {
|
||||
onMessageExportFailed(sms)
|
||||
false
|
||||
})
|
||||
}
|
||||
|
||||
private fun exportMms(smsExportState: SmsExportState, mms: ExportableMessage.Mms<*>) {
|
||||
private fun exportMms(smsExportState: SmsExportState, mms: ExportableMessage.Mms<*>): Boolean {
|
||||
onMessageExportStarted(mms)
|
||||
val threadIdOutput: GetOrCreateMmsThreadIdsUseCase.Output? = getThreadId(mms)
|
||||
val exportMmsOutput: ExportMmsMessagesUseCase.Output? = threadIdOutput?.let { exportMms(smsExportState, it) }
|
||||
|
@ -210,15 +224,17 @@ abstract class SmsExportService : Service() {
|
|||
val writeMmsPartsOutput: List<Result<Unit, Throwable>>? = exportMmsPartsOutput?.filterNotNull()?.map { writeAttachmentToDisk(smsExportState, it) }
|
||||
val exportMmsRecipients: List<Unit?>? = exportMmsOutput?.let { exportMmsRecipients(smsExportState, it) }
|
||||
|
||||
if (threadIdOutput != null &&
|
||||
return if (threadIdOutput != null &&
|
||||
exportMmsOutput != null &&
|
||||
exportMmsPartsOutput != null && !exportMmsPartsOutput.contains(null) &&
|
||||
writeMmsPartsOutput != null && writeMmsPartsOutput.all { it is Result.Success } &&
|
||||
writeMmsPartsOutput != null && writeMmsPartsOutput.all { it is Result.Success || (it is Result.Failure && (it.failure.cause ?: it.failure) is FileNotFoundException) } &&
|
||||
exportMmsRecipients != null && !exportMmsRecipients.contains(null)
|
||||
) {
|
||||
onMessageExportSucceeded(mms)
|
||||
true
|
||||
} else {
|
||||
onMessageExportFailed(mms)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue