diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_00.binproto new file mode 100644 index 0000000000..2c433064eb Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_00.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_01.binproto new file mode 100644 index 0000000000..1f5ed550c1 Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_01.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_02.binproto new file mode 100644 index 0000000000..680de438ca Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_02.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_03.binproto new file mode 100644 index 0000000000..76e25352ae Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_03.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_04.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_04.binproto new file mode 100644 index 0000000000..8c8e8850d7 Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_04.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_05.binproto new file mode 100644 index 0000000000..9c7f97d495 Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_05.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_06.binproto new file mode 100644 index 0000000000..1e07b498b8 Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_06.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_07.binproto new file mode 100644 index 0000000000..f5a7158e4f Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_07.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_08.binproto new file mode 100644 index 0000000000..169e283397 Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_08.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_09.binproto new file mode 100644 index 0000000000..08b2ec1ec4 Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_09.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_10.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_10.binproto new file mode 100644 index 0000000000..cf0fde5d1d Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_10.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_11.binproto new file mode 100644 index 0000000000..7de0eed15d Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_11.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_12.binproto new file mode 100644 index 0000000000..0ecb89526f Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_12.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_13.binproto new file mode 100644 index 0000000000..e38ccec9e2 Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_13.binproto differ diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_14.binproto new file mode 100644 index 0000000000..2964801cc2 Binary files /dev/null and b/app/src/androidTest/assets/backupTests/chat_item_view_once_14.binproto differ diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ArchiveImportExportTests.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ArchiveImportExportTests.kt index dcf306d586..5a00419a46 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ArchiveImportExportTests.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/backup/v2/ArchiveImportExportTests.kt @@ -182,7 +182,12 @@ class ArchiveImportExportTests { runTests { it.startsWith("chat_item_thread_merge_update_") } } -// @Test + @Test + fun chatItemViewOnce() { + runTests { it.startsWith("chat_item_view_once_") } + } + + // @Test fun recipientCallLink() { runTests { it.startsWith("recipient_call_link_") } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableArchiveExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableArchiveExtensions.kt index 459830137d..c809a04950 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableArchiveExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/database/MessageTableArchiveExtensions.kt @@ -52,7 +52,8 @@ fun MessageTable.getMessagesForBackup(db: SignalDatabase, backupTime: Long, medi MessageTable.NETWORK_FAILURES, MessageTable.MISMATCHED_IDENTITIES, "${MessageTable.TYPE} & ${MessageTypes.BASE_TYPE_MASK} AS $COLUMN_BASE_TYPE", - MessageTable.MESSAGE_EXTRAS + MessageTable.MESSAGE_EXTRAS, + MessageTable.VIEW_ONCE ) .from(MessageTable.TABLE_NAME) .where( diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt index e8392b745f..2e8664f439 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/ChatItemArchiveExporter.kt @@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.backup.v2.proto.Sticker import org.thoughtcrime.securesms.backup.v2.proto.StickerMessage import org.thoughtcrime.securesms.backup.v2.proto.Text import org.thoughtcrime.securesms.backup.v2.proto.ThreadMergeChatUpdate +import org.thoughtcrime.securesms.backup.v2.proto.ViewOnceMessage import org.thoughtcrime.securesms.backup.v2.util.toRemoteFilePointer import org.thoughtcrime.securesms.contactshare.Contact import org.thoughtcrime.securesms.database.AttachmentTable @@ -245,6 +246,10 @@ class ChatItemArchiveExporter( builder.contactMessage = record.toRemoteContactMessage(mediaArchiveEnabled = mediaArchiveEnabled, reactionRecords = reactionsById[id], attachments = attachmentsById[id]) } + record.viewOnce -> { + builder.viewOnceMessage = record.toRemoteViewOnceMessage(mediaArchiveEnabled = mediaArchiveEnabled, reactionRecords = reactionsById[id], attachments = attachmentsById[id]) + } + else -> { if (record.body == null && !attachmentsById.containsKey(record.id)) { Log.w(TAG, "Record with ID ${record.id} missing a body and doesn't have attachments. Skipping.") @@ -556,6 +561,15 @@ private fun LinkPreview.toRemoteLinkPreview(mediaArchiveEnabled: Boolean): org.t ) } +private fun BackupMessageRecord.toRemoteViewOnceMessage(mediaArchiveEnabled: Boolean, reactionRecords: List?, attachments: List?): ViewOnceMessage { + val attachment: DatabaseAttachment? = attachments?.firstOrNull() + + return ViewOnceMessage( + attachment = attachment?.toRemoteMessageAttachment(mediaArchiveEnabled), + reactions = reactionRecords?.toRemote() ?: emptyList() + ) +} + private fun BackupMessageRecord.toRemoteContactMessage(mediaArchiveEnabled: Boolean, reactionRecords: List?, attachments: List?): ContactMessage { val sharedContacts = toRemoteSharedContacts(attachments) @@ -1082,7 +1096,8 @@ private fun Cursor.toBackupMessageRecord(): BackupMessageRecord { networkFailureRecipientIds = this.requireString(MessageTable.NETWORK_FAILURES).parseNetworkFailures(), identityMismatchRecipientIds = this.requireString(MessageTable.MISMATCHED_IDENTITIES).parseIdentityMismatches(), baseType = this.requireLong(COLUMN_BASE_TYPE), - messageExtras = this.requireBlob(MessageTable.MESSAGE_EXTRAS).parseMessageExtras() + messageExtras = this.requireBlob(MessageTable.MESSAGE_EXTRAS).parseMessageExtras(), + viewOnce = this.requireBoolean(MessageTable.VIEW_ONCE) ) } @@ -1119,5 +1134,6 @@ private class BackupMessageRecord( val networkFailureRecipientIds: Set, val identityMismatchRecipientIds: Set, val baseType: Long, - val messageExtras: MessageExtras? + val messageExtras: MessageExtras?, + val viewOnce: Boolean ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatItemArchiveImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatItemArchiveImporter.kt index a308777d2f..1a4417899b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatItemArchiveImporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/ChatItemArchiveImporter.kt @@ -34,6 +34,7 @@ import org.thoughtcrime.securesms.backup.v2.proto.SendStatus import org.thoughtcrime.securesms.backup.v2.proto.SimpleChatUpdate import org.thoughtcrime.securesms.backup.v2.proto.StandardMessage import org.thoughtcrime.securesms.backup.v2.proto.Sticker +import org.thoughtcrime.securesms.backup.v2.proto.ViewOnceMessage import org.thoughtcrime.securesms.backup.v2.util.toLocalAttachment import org.thoughtcrime.securesms.contactshare.Contact import org.thoughtcrime.securesms.database.CallTable @@ -429,6 +430,15 @@ class ChatItemArchiveImporter( } } + if (this.viewOnceMessage != null) { + val attachment = this.viewOnceMessage.attachment?.toLocalAttachment() + if (attachment != null) { + followUp = { messageRowId -> + SignalDatabase.attachments.insertAttachmentsForMessage(messageRowId, listOf(attachment), emptyList()) + } + } + } + return MessageInsert(contentValues, followUp) } @@ -484,6 +494,7 @@ class ChatItemArchiveImporter( this.updateMessage != null -> contentValues.addUpdateMessage(this.updateMessage) this.paymentNotification != null -> contentValues.addPaymentNotification(this, chatRecipientId) this.giftBadge != null -> contentValues.addGiftBadge(this.giftBadge) + this.viewOnceMessage != null -> contentValues.addViewOnce(this.viewOnceMessage) } return contentValues @@ -526,6 +537,7 @@ class ChatItemArchiveImporter( this.standardMessage != null -> this.standardMessage.reactions this.contactMessage != null -> this.contactMessage.reactions this.stickerMessage != null -> this.stickerMessage.reactions + this.viewOnceMessage != null -> this.viewOnceMessage.reactions else -> emptyList() } @@ -822,6 +834,10 @@ class ChatItemArchiveImporter( put(MessageTable.BODY, Base64.encodeWithPadding(GiftBadge.ADAPTER.encode(dbGiftBadge))) } + private fun ContentValues.addViewOnce(viewOnce: ViewOnceMessage) { + put(MessageTable.VIEW_ONCE, true.toInt()) + } + private fun String?.tryParseMoney(): Money? { if (this.isNullOrEmpty()) { return null diff --git a/app/src/main/protowire/Backup.proto b/app/src/main/protowire/Backup.proto index 624433d16a..7ee3246385 100644 --- a/app/src/main/protowire/Backup.proto +++ b/app/src/main/protowire/Backup.proto @@ -341,6 +341,7 @@ message ChatItem { ChatUpdateMessage updateMessage = 15; PaymentNotification paymentNotification = 16; GiftBadge giftBadge = 17; + ViewOnceMessage viewOnceMessage = 18; } } @@ -469,6 +470,12 @@ message GiftBadge { State state = 2; } +message ViewOnceMessage { + // Will be null for viewed messages + MessageAttachment attachment = 1; + repeated Reaction reactions = 2; +} + message ContactAttachment { message Name { optional string givenName = 1;