diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTableTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTableTest.kt index f0f26ff1c8..6cd460e281 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTableTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTableTest.kt @@ -51,6 +51,30 @@ class BackupMediaSnapshotTableTest { assertThat(count).isEqualTo(countWithThumbnails) } + @Test + fun givenAnEmptyTable_whenIWriteToTableAndCommitQuotes_thenIExpectFilledTableWithNoThumbnails() { + val inputCount = 100 + + SignalDatabase.backupMediaSnapshots.writePendingMediaObjects(generateArchiveMediaItemSequence(count = inputCount, quote = true)) + SignalDatabase.backupMediaSnapshots.commitPendingRows() + + val count = getCountForLatestSnapshot(includeThumbnails = true) + + assertThat(count).isEqualTo(inputCount) + } + + @Test + fun givenAnEmptyTable_whenIWriteToTableAndCommitNonMedia_thenIExpectFilledTableWithNoThumbnails() { + val inputCount = 100 + + SignalDatabase.backupMediaSnapshots.writePendingMediaObjects(generateArchiveMediaItemSequence(count = inputCount, contentType = "text/plain")) + SignalDatabase.backupMediaSnapshots.commitPendingRows() + + val count = getCountForLatestSnapshot(includeThumbnails = true) + + assertThat(count).isEqualTo(inputCount) + } + @Test fun givenAFilledTable_whenIReinsertObjects_thenIExpectUncommittedOverrides() { val initialCount = 100 @@ -290,19 +314,21 @@ class BackupMediaSnapshotTableTest { .readToSingleInt(0) } - private fun generateArchiveMediaItemSequence(count: Int): Sequence { + private fun generateArchiveMediaItemSequence(count: Int, quote: Boolean = false, contentType: String = "image/jpeg"): Sequence { return (1..count) .asSequence() - .map { createArchiveMediaItem(it) } + .map { createArchiveMediaItem(it, quote = quote, contentType = contentType) } } - private fun createArchiveMediaItem(seed: Int, cdn: Int = 0): ArchiveMediaItem { + private fun createArchiveMediaItem(seed: Int, cdn: Int = 0, quote: Boolean = false, contentType: String = "image/jpeg"): ArchiveMediaItem { return ArchiveMediaItem( mediaId = "media_id_$seed", thumbnailMediaId = "thumbnail_media_id_$seed", cdn = cdn, plaintextHash = Util.toByteArray(seed), - remoteKey = Util.toByteArray(seed) + remoteKey = Util.toByteArray(seed), + quote = quote, + contentType = contentType ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt index 8c6ae86664..0c0ac18812 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt @@ -41,8 +41,10 @@ import org.signal.core.util.getForeignKeyViolations import org.signal.core.util.logging.Log import org.signal.core.util.logging.logW import org.signal.core.util.money.FiatMoney +import org.signal.core.util.requireBoolean import org.signal.core.util.requireIntOrNull import org.signal.core.util.requireNonNullString +import org.signal.core.util.requireString import org.signal.core.util.stream.NonClosingOutputStream import org.signal.core.util.urlEncode import org.signal.core.util.withinTransaction @@ -2393,11 +2395,22 @@ class ArchiveMediaItemIterator(private val cursor: Cursor) : Iterator) { + if (chunk.isEmpty()) { + return + } + val values = chunk.map { contentValuesOf( MEDIA_ID to it.mediaId, @@ -324,7 +332,9 @@ class BackupMediaSnapshotTable(context: Context, database: SignalDatabase) : Dat val thumbnailMediaId: String, val cdn: Int?, val plaintextHash: ByteArray, - val remoteKey: ByteArray + val remoteKey: ByteArray, + val quote: Boolean, + val contentType: String? ) class CdnMismatchResult( diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveThumbnailUploadJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveThumbnailUploadJob.kt index 30943d4663..048822a7a6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveThumbnailUploadJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveThumbnailUploadJob.kt @@ -98,6 +98,11 @@ class ArchiveThumbnailUploadJob private constructor( return Result.success() } + if (attachment.quote) { + Log.w(TAG, "$attachmentId is a quote, skipping.") + return Result.success() + } + if (attachment.remoteDigest == null && attachment.dataHash == null && attachment.hadIntegrityCheckPerformed()) { Log.w(TAG, "$attachmentId has no integrity check! Cannot proceed.") return Result.success() diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt index 83b01622e4..4bff098e29 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt @@ -366,7 +366,7 @@ class BackupMessagesJob private constructor( cancellationSignal = { this.isCanceled }, currentTime = currentTime ) { - writeMediaCursorToTemporaryTable(it, currentTime = currentTime, mediaBackupEnabled = SignalStore.backup.backsUpMedia) + writeMediaCursorToTemporaryTable(it, mediaBackupEnabled = SignalStore.backup.backsUpMedia) } if (isCanceled) { @@ -415,7 +415,7 @@ class BackupMessagesJob private constructor( ) } - private fun writeMediaCursorToTemporaryTable(db: SignalDatabase, mediaBackupEnabled: Boolean, currentTime: Long) { + private fun writeMediaCursorToTemporaryTable(db: SignalDatabase, mediaBackupEnabled: Boolean) { if (mediaBackupEnabled) { db.attachmentTable.getAttachmentsEligibleForArchiveUpload().use { SignalDatabase.backupMediaSnapshots.writePendingMediaObjects( diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/CopyAttachmentToArchiveJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/CopyAttachmentToArchiveJob.kt index a2b5ffef19..589f2da55f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/CopyAttachmentToArchiveJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/CopyAttachmentToArchiveJob.kt @@ -192,7 +192,7 @@ class CopyAttachmentToArchiveJob private constructor(private val attachmentId: A Log.d(TAG, "[$attachmentId] Updating archive transfer state to ${AttachmentTable.ArchiveTransferState.FINISHED}") SignalDatabase.attachments.setArchiveTransferState(attachmentId, AttachmentTable.ArchiveTransferState.FINISHED) - if (!isCanceled) { + if (!isCanceled && !attachment.quote) { ArchiveThumbnailUploadJob.enqueueIfNecessary(attachmentId) } else { Log.d(TAG, "[$attachmentId] Refusing to enqueue thumb for canceled upload.")