diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachment.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachment.kt index 2052b11438..5965f84b20 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachment.kt @@ -5,6 +5,7 @@ import android.os.Parcel import androidx.core.os.ParcelCompat import org.thoughtcrime.securesms.audio.AudioHash import org.thoughtcrime.securesms.blurhash.BlurHash +import org.thoughtcrime.securesms.database.AttachmentTable import org.thoughtcrime.securesms.database.AttachmentTable.TransformProperties import org.thoughtcrime.securesms.mms.PartAuthority import org.thoughtcrime.securesms.stickers.StickerLocator @@ -36,6 +37,9 @@ class DatabaseAttachment : Attachment { @JvmField val archiveMediaId: String? + @JvmField + val thumbnailRestoreState: AttachmentTable.ThumbnailRestoreState + private val hasArchiveThumbnail: Boolean private val hasThumbnail: Boolean val displayOrder: Int @@ -74,7 +78,8 @@ class DatabaseAttachment : Attachment { archiveCdn: Int, archiveThumbnailCdn: Int, archiveMediaName: String?, - archiveMediaId: String? + archiveMediaId: String?, + thumbnailRestoreState: AttachmentTable.ThumbnailRestoreState ) : super( contentType = contentType!!, transferState = transferProgress, @@ -110,6 +115,7 @@ class DatabaseAttachment : Attachment { this.archiveThumbnailCdn = archiveThumbnailCdn this.archiveMediaName = archiveMediaName this.archiveMediaId = archiveMediaId + this.thumbnailRestoreState = thumbnailRestoreState } constructor(parcel: Parcel) : super(parcel) { @@ -124,6 +130,7 @@ class DatabaseAttachment : Attachment { archiveMediaName = parcel.readString() archiveMediaId = parcel.readString() hasArchiveThumbnail = ParcelUtil.readBoolean(parcel) + thumbnailRestoreState = AttachmentTable.ThumbnailRestoreState.deserialize(parcel.readInt()) } override fun writeToParcel(dest: Parcel, flags: Int) { @@ -139,6 +146,7 @@ class DatabaseAttachment : Attachment { dest.writeString(archiveMediaName) dest.writeString(archiveMediaId) ParcelUtil.writeBoolean(dest, hasArchiveThumbnail) + dest.writeInt(thumbnailRestoreState.value) } override val uri: Uri? diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt index 7ed5a09994..43c3a89eed 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt @@ -151,6 +151,7 @@ class AttachmentTable( const val ARCHIVE_THUMBNAIL_CDN = "archive_thumbnail_cdn" const val ARCHIVE_TRANSFER_FILE = "archive_transfer_file" const val ARCHIVE_TRANSFER_STATE = "archive_transfer_state" + const val THUMBNAIL_RESTORE_STATE = "thumbnail_restore_state" const val ATTACHMENT_JSON_ALIAS = "attachment_json" @@ -205,7 +206,8 @@ class AttachmentTable( ARCHIVE_MEDIA_NAME, ARCHIVE_MEDIA_ID, ARCHIVE_TRANSFER_FILE, - THUMBNAIL_FILE + THUMBNAIL_FILE, + THUMBNAIL_RESTORE_STATE ) @JvmField @@ -252,7 +254,8 @@ class AttachmentTable( $ARCHIVE_THUMBNAIL_CDN INTEGER DEFAULT 0, $ARCHIVE_THUMBNAIL_MEDIA_ID TEXT DEFAULT NULL, $THUMBNAIL_FILE TEXT DEFAULT NULL, - $THUMBNAIL_RANDOM BLOB DEFAULT NULL + $THUMBNAIL_RANDOM BLOB DEFAULT NULL, + $THUMBNAIL_RESTORE_STATE INTEGER DEFAULT ${ThumbnailRestoreState.NONE.value} ) """ @@ -1395,7 +1398,8 @@ class AttachmentTable( archiveThumbnailCdn = jsonObject.getInt(ARCHIVE_THUMBNAIL_CDN), archiveMediaName = jsonObject.getString(ARCHIVE_MEDIA_NAME), archiveMediaId = jsonObject.getString(ARCHIVE_MEDIA_ID), - hasArchiveThumbnail = !TextUtils.isEmpty(jsonObject.getString(THUMBNAIL_FILE)) + hasArchiveThumbnail = !TextUtils.isEmpty(jsonObject.getString(THUMBNAIL_FILE)), + thumbnailRestoreState = ThumbnailRestoreState.deserialize(jsonObject.getInt(THUMBNAIL_RESTORE_STATE)) ) } } @@ -1988,7 +1992,8 @@ class AttachmentTable( archiveThumbnailCdn = cursor.requireInt(ARCHIVE_THUMBNAIL_CDN), archiveMediaName = cursor.requireString(ARCHIVE_MEDIA_NAME), archiveMediaId = cursor.requireString(ARCHIVE_MEDIA_ID), - hasArchiveThumbnail = !cursor.isNull(THUMBNAIL_FILE) + hasArchiveThumbnail = !cursor.isNull(THUMBNAIL_FILE), + thumbnailRestoreState = ThumbnailRestoreState.deserialize(cursor.requireInt(THUMBNAIL_RESTORE_STATE)) ) } @@ -2200,6 +2205,29 @@ class AttachmentTable( } } + enum class ThumbnailRestoreState(val value: Int) { + /** No thumbnail downloaded. */ + NONE(0), + + /** The thumbnail needs to be restored still. */ + NEEDS_RESTORE(1), + + /** The restore of the thumbnail is in progress */ + IN_PROGRESS(2), + + /** Completely restored the thumbnail. */ + FINISHED(3), + + /** It is impossible to restore the thumbnail. */ + PERMANENT_FAILURE(4); + + companion object { + fun deserialize(value: Int): ThumbnailRestoreState { + return values().firstOrNull { it.value == value } ?: NONE + } + } + } + /** * This maintains two different state paths for uploading attachments to the archive. * diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt index 6b0f15d42d..da54f799f5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt @@ -55,6 +55,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_MEDIA_NAME}, ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_MEDIA_ID}, ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_THUMBNAIL_CDN}, + ${AttachmentTable.TABLE_NAME}.${AttachmentTable.THUMBNAIL_RESTORE_STATE}, ${MessageTable.TABLE_NAME}.${MessageTable.TYPE}, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_SENT}, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED}, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt index d2e6272911..b082425f8a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt @@ -385,7 +385,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat '${AttachmentTable.ARCHIVE_CDN}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_CDN}, '${AttachmentTable.ARCHIVE_THUMBNAIL_CDN}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_THUMBNAIL_CDN}, '${AttachmentTable.ARCHIVE_MEDIA_NAME}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_MEDIA_NAME}, - '${AttachmentTable.ARCHIVE_MEDIA_ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_MEDIA_ID} + '${AttachmentTable.ARCHIVE_MEDIA_ID}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.ARCHIVE_MEDIA_ID}, + '${AttachmentTable.THUMBNAIL_RESTORE_STATE}', ${AttachmentTable.TABLE_NAME}.${AttachmentTable.THUMBNAIL_RESTORE_STATE} ) ) AS ${AttachmentTable.ATTACHMENT_JSON_ALIAS} """.toSingleLine() diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index d1be3754f9..19eb484250 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -91,6 +91,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V230_UnreadCountInd import org.thoughtcrime.securesms.database.helpers.migration.V231_ArchiveThumbnailColumns import org.thoughtcrime.securesms.database.helpers.migration.V232_CreateInAppPaymentTable import org.thoughtcrime.securesms.database.helpers.migration.V233_FixInAppPaymentTableDefaultNotifiedValue +import org.thoughtcrime.securesms.database.helpers.migration.V234_ThumbnailRestoreStateColumn /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -184,10 +185,11 @@ object SignalDatabaseMigrations { 230 to V230_UnreadCountIndices, 231 to V231_ArchiveThumbnailColumns, 232 to V232_CreateInAppPaymentTable, - 233 to V233_FixInAppPaymentTableDefaultNotifiedValue + 233 to V233_FixInAppPaymentTableDefaultNotifiedValue, + 234 to V234_ThumbnailRestoreStateColumn ) - const val DATABASE_VERSION = 233 + const val DATABASE_VERSION = 234 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V234_ThumbnailRestoreStateColumn.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V234_ThumbnailRestoreStateColumn.kt new file mode 100644 index 0000000000..2a4951aeb2 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V234_ThumbnailRestoreStateColumn.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2024 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase + +/** + * Add a separate column to track thumbnail restore state + */ +object V234_ThumbnailRestoreStateColumn : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("ALTER TABLE attachment ADD COLUMN thumbnail_restore_state INTEGER DEFAULT 0") + } +} diff --git a/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt b/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt index a7b6f3df29..0928801254 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt @@ -261,7 +261,8 @@ class UploadDependencyGraphTest { archiveMediaId = null, archiveMediaName = null, archiveCdn = 0, - archiveThumbnailCdn = 0 + archiveThumbnailCdn = 0, + thumbnailRestoreState = AttachmentTable.ThumbnailRestoreState.NONE ) } diff --git a/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt b/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt index 91305387bd..e7fe657c09 100644 --- a/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt +++ b/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt @@ -63,7 +63,8 @@ object FakeMessageRecords { archiveThumbnailCdn: Int = 0, archiveMediaName: String? = null, archiveMediaId: String? = null, - archiveThumbnailId: String? = null + archiveThumbnailId: String? = null, + thumbnailRestoreState: AttachmentTable.ThumbnailRestoreState = AttachmentTable.ThumbnailRestoreState.NONE ): DatabaseAttachment { return DatabaseAttachment( attachmentId, @@ -99,7 +100,8 @@ object FakeMessageRecords { archiveCdn, archiveThumbnailCdn, archiveMediaId, - archiveMediaName + archiveMediaName, + thumbnailRestoreState ) }