mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-03-01 22:22:15 +00:00
Fix various backup import-export inconsistencies.
This commit is contained in:
@@ -48,6 +48,7 @@ class TombstoneAttachment : Attachment {
|
||||
width: Int?,
|
||||
height: Int?,
|
||||
caption: String?,
|
||||
fileName: String? = null,
|
||||
blurHash: String?,
|
||||
voiceNote: Boolean = false,
|
||||
borderless: Boolean = false,
|
||||
@@ -59,7 +60,7 @@ class TombstoneAttachment : Attachment {
|
||||
quote = quote,
|
||||
transferState = AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE,
|
||||
size = 0,
|
||||
fileName = null,
|
||||
fileName = fileName,
|
||||
cdn = Cdn.CDN_0,
|
||||
remoteLocation = null,
|
||||
remoteKey = null,
|
||||
|
||||
@@ -21,15 +21,12 @@ import org.signal.core.util.requireLong
|
||||
import org.signal.core.util.requireLongOrNull
|
||||
import org.signal.core.util.requireString
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentId
|
||||
import org.thoughtcrime.securesms.attachments.Cdn
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupRepository.getMediaName
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ChatItem
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ChatUpdateMessage
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ContactAttachment
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ContactMessage
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ExpirationTimerChatUpdate
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.FilePointer
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.GroupCall
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.IndividualCall
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.LearnedProfileChatUpdate
|
||||
@@ -47,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.util.toRemoteFilePointer
|
||||
import org.thoughtcrime.securesms.contactshare.Contact
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable
|
||||
import org.thoughtcrime.securesms.database.CallTable
|
||||
@@ -96,7 +94,7 @@ import org.thoughtcrime.securesms.backup.v2.proto.GiftBadge as BackupGiftBadge
|
||||
*
|
||||
* All of this complexity is hidden from the user -- they just get a normal iterator interface.
|
||||
*/
|
||||
class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: Int, private val archiveMedia: Boolean) : Iterator<ChatItem?>, Closeable {
|
||||
class ChatItemExportIterator(private val cursor: Cursor, private val batchSize: Int, private val mediaArchiveEnabled: Boolean) : Iterator<ChatItem?>, Closeable {
|
||||
|
||||
companion object {
|
||||
private val TAG = Log.tag(ChatItemExportIterator::class.java)
|
||||
@@ -582,7 +580,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
return org.thoughtcrime.securesms.backup.v2.proto.LinkPreview(
|
||||
url = url,
|
||||
title = title,
|
||||
image = (thumbnail.orNull() as? DatabaseAttachment)?.toBackupAttachment()?.pointer,
|
||||
image = (thumbnail.orNull() as? DatabaseAttachment)?.toRemoteMessageAttachment()?.pointer,
|
||||
description = description,
|
||||
date = date
|
||||
)
|
||||
@@ -594,7 +592,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
val contacts = sharedContacts.map {
|
||||
ContactAttachment(
|
||||
name = it.name.toBackup(),
|
||||
avatar = (it.avatar?.attachment as? DatabaseAttachment)?.toBackupAttachment()?.pointer,
|
||||
avatar = (it.avatar?.attachment as? DatabaseAttachment)?.toRemoteMessageAttachment()?.pointer,
|
||||
organization = it.organization,
|
||||
number = it.phoneNumbers.map { phone ->
|
||||
ContactAttachment.Phone(
|
||||
@@ -741,7 +739,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
packKey = Hex.fromStringCondensed(stickerLocator.packKey).toByteString(),
|
||||
stickerId = stickerLocator.stickerId,
|
||||
emoji = stickerLocator.emoji,
|
||||
data_ = this.toBackupAttachment().pointer
|
||||
data_ = this.toRemoteMessageAttachment().pointer
|
||||
),
|
||||
reactions = reactions.toBackupReactions()
|
||||
)
|
||||
@@ -752,50 +750,14 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
Quote.QuotedAttachment(
|
||||
contentType = attachment.contentType,
|
||||
fileName = attachment.fileName,
|
||||
thumbnail = attachment.toBackupAttachment()
|
||||
thumbnail = attachment.toRemoteMessageAttachment()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun DatabaseAttachment.toBackupAttachment(): MessageAttachment {
|
||||
val builder = FilePointer.Builder()
|
||||
builder.contentType = this.contentType?.takeUnless { it.isBlank() }
|
||||
builder.incrementalMac = this.incrementalDigest?.toByteString()
|
||||
builder.incrementalMacChunkSize = this.incrementalMacChunkSize.takeIf { it > 0 }
|
||||
builder.fileName = this.fileName
|
||||
builder.width = this.width.takeUnless { it == 0 }
|
||||
builder.height = this.height.takeUnless { it == 0 }
|
||||
builder.caption = this.caption
|
||||
builder.blurHash = this.blurHash?.hash
|
||||
|
||||
if (this.remoteKey.isNullOrBlank() || this.remoteDigest == null || this.size == 0L) {
|
||||
builder.invalidAttachmentLocator = FilePointer.InvalidAttachmentLocator()
|
||||
} else {
|
||||
if (archiveMedia) {
|
||||
builder.backupLocator = FilePointer.BackupLocator(
|
||||
mediaName = this.archiveMediaName ?: this.getMediaName().toString(),
|
||||
cdnNumber = if (this.archiveMediaName != null) this.archiveCdn else Cdn.CDN_3.cdnNumber, // TODO (clark): Update when new proto with optional cdn is landed
|
||||
key = Base64.decode(remoteKey).toByteString(),
|
||||
size = this.size.toInt(),
|
||||
digest = this.remoteDigest.toByteString()
|
||||
)
|
||||
} else {
|
||||
if (this.remoteLocation.isNullOrBlank()) {
|
||||
builder.invalidAttachmentLocator = FilePointer.InvalidAttachmentLocator()
|
||||
} else {
|
||||
builder.attachmentLocator = FilePointer.AttachmentLocator(
|
||||
cdnKey = this.remoteLocation,
|
||||
cdnNumber = this.cdn.cdnNumber,
|
||||
uploadTimestamp = this.uploadTimestamp,
|
||||
key = Base64.decode(remoteKey).toByteString(),
|
||||
size = this.size.toInt(),
|
||||
digest = this.remoteDigest.toByteString()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun DatabaseAttachment.toRemoteMessageAttachment(): MessageAttachment {
|
||||
return MessageAttachment(
|
||||
pointer = builder.build(),
|
||||
pointer = this.toRemoteFilePointer(mediaArchiveEnabled),
|
||||
wasDownloaded = this.transferState == AttachmentTable.TRANSFER_PROGRESS_DONE || this.transferState == AttachmentTable.TRANSFER_NEEDS_RESTORE,
|
||||
flag = if (this.voiceNote) {
|
||||
MessageAttachment.Flag.VOICE_MESSAGE
|
||||
@@ -812,7 +774,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
|
||||
private fun List<DatabaseAttachment>.toBackupAttachments(): List<MessageAttachment> {
|
||||
return this.map { attachment ->
|
||||
attachment.toBackupAttachment()
|
||||
attachment.toRemoteMessageAttachment()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,13 +899,8 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
reason = SendStatus.Failed.FailureReason.NETWORK
|
||||
)
|
||||
}
|
||||
this.baseType == MessageTypes.BASE_SENT_TYPE -> {
|
||||
statusBuilder.sent = SendStatus.Sent(
|
||||
sealedSender = this.sealedSender
|
||||
)
|
||||
}
|
||||
this.hasDeliveryReceipt -> {
|
||||
statusBuilder.delivered = SendStatus.Delivered(
|
||||
this.viewed -> {
|
||||
statusBuilder.viewed = SendStatus.Viewed(
|
||||
sealedSender = this.sealedSender
|
||||
)
|
||||
}
|
||||
@@ -952,8 +909,21 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
||||
sealedSender = this.sealedSender
|
||||
)
|
||||
}
|
||||
this.viewed -> {
|
||||
statusBuilder.viewed = SendStatus.Viewed(
|
||||
this.hasDeliveryReceipt -> {
|
||||
statusBuilder.delivered = SendStatus.Delivered(
|
||||
sealedSender = this.sealedSender
|
||||
)
|
||||
}
|
||||
this.baseType == MessageTypes.BASE_SENT_FAILED_TYPE -> {
|
||||
statusBuilder.failed = SendStatus.Failed(
|
||||
reason = SendStatus.Failed.FailureReason.UNKNOWN
|
||||
)
|
||||
}
|
||||
this.baseType == MessageTypes.BASE_SENDING_SKIPPED_TYPE -> {
|
||||
statusBuilder.skipped = SendStatus.Skipped()
|
||||
}
|
||||
this.baseType == MessageTypes.BASE_SENT_TYPE -> {
|
||||
statusBuilder.sent = SendStatus.Sent(
|
||||
sealedSender = this.sealedSender
|
||||
)
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ class ChatItemImportInserter(
|
||||
MessageTable.DATE_SENT,
|
||||
MessageTable.DATE_RECEIVED,
|
||||
MessageTable.DATE_SERVER,
|
||||
MessageTable.RECEIPT_TIMESTAMP,
|
||||
MessageTable.TYPE,
|
||||
MessageTable.THREAD_ID,
|
||||
MessageTable.READ,
|
||||
@@ -566,8 +567,19 @@ class ChatItemImportInserter(
|
||||
var type: Long = if (this.outgoing != null) {
|
||||
if (this.outgoing.sendStatus.count { it.failed?.reason == SendStatus.Failed.FailureReason.IDENTITY_KEY_MISMATCH } > 0) {
|
||||
MessageTypes.BASE_SENT_FAILED_TYPE
|
||||
} else if (this.outgoing.sendStatus.count { it.failed?.reason == SendStatus.Failed.FailureReason.UNKNOWN } > 0) {
|
||||
MessageTypes.BASE_SENT_FAILED_TYPE
|
||||
} else if (this.outgoing.sendStatus.count { it.failed?.reason == SendStatus.Failed.FailureReason.NETWORK } > 0) {
|
||||
MessageTypes.BASE_SENDING_TYPE
|
||||
} else if (this.outgoing.sendStatus.count { it.pending != null } > 0) {
|
||||
MessageTypes.BASE_SENDING_TYPE
|
||||
} else if (this.outgoing.sendStatus.count { it.skipped != null } > 0) {
|
||||
val count = this.outgoing.sendStatus.count { it.skipped != null }
|
||||
if (count == this.outgoing.sendStatus.size) {
|
||||
MessageTypes.BASE_SENDING_SKIPPED_TYPE
|
||||
} else {
|
||||
MessageTypes.BASE_SENDING_TYPE
|
||||
}
|
||||
} else {
|
||||
MessageTypes.BASE_SENT_TYPE
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ private fun DecryptedGroup.toSnapshot(): Group.GroupSnapshot? {
|
||||
return Group.GroupSnapshot(
|
||||
title = Group.GroupAttributeBlob(title = this.title),
|
||||
avatarUrl = this.avatar,
|
||||
disappearingMessagesTimer = Group.GroupAttributeBlob(disappearingMessagesDuration = this.disappearingMessagesTimer?.duration ?: 0),
|
||||
disappearingMessagesTimer = this.disappearingMessagesTimer?.takeIf { it.duration > 0 }?.let { Group.GroupAttributeBlob(disappearingMessagesDuration = it.duration) },
|
||||
accessControl = this.accessControl?.toSnapshot(),
|
||||
version = this.revision,
|
||||
members = this.members.map { it.toSnapshot() },
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.thoughtcrime.securesms.backup.v2.util.toLocal
|
||||
import org.thoughtcrime.securesms.backup.v2.util.toLocalAttachment
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColors
|
||||
import org.thoughtcrime.securesms.database.RecipientTable
|
||||
import org.thoughtcrime.securesms.database.SQLiteDatabase
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.ThreadTable
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ChatColor
|
||||
@@ -39,7 +38,7 @@ import java.io.Closeable
|
||||
|
||||
private val TAG = Log.tag(ThreadTable::class.java)
|
||||
|
||||
fun ThreadTable.getThreadsForBackup(): ChatExportIterator {
|
||||
fun ThreadTable.getThreadsForBackup(db: SignalDatabase): ChatExportIterator {
|
||||
//language=sql
|
||||
val query = """
|
||||
SELECT
|
||||
@@ -61,7 +60,7 @@ fun ThreadTable.getThreadsForBackup(): ChatExportIterator {
|
||||
"""
|
||||
val cursor = readableDatabase.query(query)
|
||||
|
||||
return ChatExportIterator(cursor, readableDatabase)
|
||||
return ChatExportIterator(cursor, db)
|
||||
}
|
||||
|
||||
fun ThreadTable.clearAllDataForBackupRestore() {
|
||||
@@ -72,13 +71,6 @@ fun ThreadTable.clearAllDataForBackupRestore() {
|
||||
|
||||
fun ThreadTable.restoreFromBackup(chat: Chat, recipientId: RecipientId, importState: ImportState): Long {
|
||||
val chatColor = chat.style?.toLocal(importState)
|
||||
val chatColorWithId = if (chatColor != null && chatColor.id is ChatColors.Id.NotSet) {
|
||||
val savedColors = SignalDatabase.chatColors.getSavedChatColors()
|
||||
val match = savedColors.find { it.matchesWithoutId(chatColor) }
|
||||
match ?: SignalDatabase.chatColors.saveChatColors(chatColor)
|
||||
} else {
|
||||
chatColor
|
||||
}
|
||||
|
||||
val wallpaperAttachmentId: AttachmentId? = chat.style?.wallpaperPhoto?.let { filePointer ->
|
||||
filePointer.toLocalAttachment(importState)?.let {
|
||||
@@ -125,7 +117,7 @@ fun ThreadTable.restoreFromBackup(chat: Chat, recipientId: RecipientId, importSt
|
||||
return threadId
|
||||
}
|
||||
|
||||
class ChatExportIterator(private val cursor: Cursor, private val readableDatabase: SQLiteDatabase) : Iterator<Chat>, Closeable {
|
||||
class ChatExportIterator(private val cursor: Cursor, private val db: SignalDatabase) : Iterator<Chat>, Closeable {
|
||||
override fun hasNext(): Boolean {
|
||||
return cursor.count > 0 && !cursor.isLast
|
||||
}
|
||||
@@ -157,7 +149,7 @@ class ChatExportIterator(private val cursor: Cursor, private val readableDatabas
|
||||
markedUnread = ThreadTable.ReadStatus.deserialize(cursor.requireInt(ThreadTable.READ)) == ThreadTable.ReadStatus.FORCED_UNREAD,
|
||||
dontNotifyForMentionsIfMuted = RecipientTable.MentionSetting.DO_NOT_NOTIFY.id == cursor.requireInt(RecipientTable.MENTION_SETTING),
|
||||
style = ChatStyleConverter.constructRemoteChatStyle(
|
||||
readableDatabase = readableDatabase,
|
||||
db = db,
|
||||
chatColors = chatColors,
|
||||
chatColorId = customChatColorsId,
|
||||
chatWallpaper = chatWallpaper
|
||||
|
||||
@@ -89,7 +89,7 @@ object AccountDataProcessor {
|
||||
hasCompletedUsernameOnboarding = signalStore.uiHintValues.hasCompletedUsernameOnboarding(),
|
||||
customChatColors = db.chatColorsTable.getSavedChatColors().toRemoteChatColors(),
|
||||
defaultChatStyle = ChatStyleConverter.constructRemoteChatStyle(
|
||||
readableDatabase = db.signalReadableDatabase,
|
||||
db = db,
|
||||
chatColors = chatColors,
|
||||
chatColorId = chatColors?.id ?: ChatColors.Id.NotSet,
|
||||
chatWallpaper = chatWallpaper
|
||||
|
||||
@@ -20,7 +20,7 @@ object ChatBackupProcessor {
|
||||
val TAG = Log.tag(ChatBackupProcessor::class.java)
|
||||
|
||||
fun export(db: SignalDatabase, exportState: ExportState, emitter: BackupFrameEmitter) {
|
||||
db.threadTable.getThreadsForBackup().use { reader ->
|
||||
db.threadTable.getThreadsForBackup(db).use { reader ->
|
||||
for (chat in reader) {
|
||||
if (exportState.recipientIds.contains(chat.recipientId)) {
|
||||
exportState.threadIds.add(chat.id)
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
package org.thoughtcrime.securesms.backup.v2.util
|
||||
|
||||
import okio.ByteString
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.signal.core.util.Base64
|
||||
import org.signal.core.util.orNull
|
||||
import org.thoughtcrime.securesms.attachments.ArchivedAttachment
|
||||
import org.thoughtcrime.securesms.attachments.Attachment
|
||||
import org.thoughtcrime.securesms.attachments.Cdn
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
|
||||
import org.thoughtcrime.securesms.attachments.PointerAttachment
|
||||
import org.thoughtcrime.securesms.attachments.TombstoneAttachment
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupRepository.getMediaName
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.FilePointer
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable
|
||||
@@ -73,6 +77,7 @@ fun FilePointer?.toLocalAttachment(
|
||||
width = this.width,
|
||||
height = this.height,
|
||||
caption = this.caption,
|
||||
fileName = this.fileName,
|
||||
blurHash = this.blurHash,
|
||||
voiceNote = voiceNote,
|
||||
borderless = borderless,
|
||||
@@ -110,3 +115,58 @@ fun FilePointer?.toLocalAttachment(
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mediaArchiveEnabled True if this user has enable media backup, otherwise false.
|
||||
*/
|
||||
fun DatabaseAttachment.toRemoteFilePointer(mediaArchiveEnabled: Boolean): FilePointer {
|
||||
val builder = FilePointer.Builder()
|
||||
builder.contentType = this.contentType?.takeUnless { it.isBlank() }
|
||||
builder.incrementalMac = this.incrementalDigest?.toByteString()
|
||||
builder.incrementalMacChunkSize = this.incrementalMacChunkSize.takeIf { it > 0 }
|
||||
builder.fileName = this.fileName
|
||||
builder.width = this.width.takeIf { it > 0 }
|
||||
builder.height = this.height.takeIf { it > 0 }
|
||||
builder.caption = this.caption
|
||||
builder.blurHash = this.blurHash?.hash
|
||||
|
||||
if (this.remoteKey.isNullOrBlank() || this.remoteDigest == null || this.size == 0L) {
|
||||
builder.invalidAttachmentLocator = FilePointer.InvalidAttachmentLocator()
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
if (this.transferState == AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE && this.archiveTransferState != AttachmentTable.ArchiveTransferState.FINISHED) {
|
||||
builder.invalidAttachmentLocator = FilePointer.InvalidAttachmentLocator()
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
val pending = this.archiveTransferState != AttachmentTable.ArchiveTransferState.FINISHED && (this.transferState != AttachmentTable.TRANSFER_PROGRESS_DONE && this.transferState != AttachmentTable.TRANSFER_RESTORE_OFFLOADED)
|
||||
|
||||
if (mediaArchiveEnabled && !pending) {
|
||||
builder.backupLocator = FilePointer.BackupLocator(
|
||||
mediaName = this.archiveMediaName ?: this.getMediaName().toString(),
|
||||
cdnNumber = if (this.archiveMediaName != null) this.archiveCdn else Cdn.CDN_3.cdnNumber, // TODO [backup]: Update when new proto with optional cdn is landed
|
||||
key = Base64.decode(remoteKey).toByteString(),
|
||||
size = this.size.toInt(),
|
||||
digest = this.remoteDigest.toByteString(),
|
||||
transitCdnNumber = this.cdn.cdnNumber.takeIf { this.remoteLocation != null },
|
||||
transitCdnKey = this.remoteLocation
|
||||
)
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
if (this.remoteLocation.isNullOrBlank()) {
|
||||
builder.invalidAttachmentLocator = FilePointer.InvalidAttachmentLocator()
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
builder.attachmentLocator = FilePointer.AttachmentLocator(
|
||||
cdnKey = this.remoteLocation,
|
||||
cdnNumber = this.cdn.cdnNumber,
|
||||
uploadTimestamp = this.uploadTimestamp,
|
||||
key = Base64.decode(remoteKey).toByteString(),
|
||||
size = this.size.toInt(),
|
||||
digest = this.remoteDigest.toByteString()
|
||||
)
|
||||
return builder.build()
|
||||
}
|
||||
@@ -5,24 +5,13 @@
|
||||
|
||||
package org.thoughtcrime.securesms.backup.v2.util
|
||||
|
||||
import android.database.Cursor
|
||||
import okio.ByteString
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.signal.core.util.Base64
|
||||
import org.signal.core.util.readToSingleObject
|
||||
import org.signal.core.util.requireBlob
|
||||
import org.signal.core.util.requireInt
|
||||
import org.signal.core.util.requireLong
|
||||
import org.signal.core.util.requireString
|
||||
import org.signal.core.util.select
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentId
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ChatStyle
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.FilePointer
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColors
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable
|
||||
import org.thoughtcrime.securesms.database.SQLiteDatabase
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper
|
||||
import org.thoughtcrime.securesms.mms.PartUriParser
|
||||
import org.thoughtcrime.securesms.util.UriUtil
|
||||
@@ -36,7 +25,7 @@ import org.thoughtcrime.securesms.wallpaper.SingleColorChatWallpaper
|
||||
*/
|
||||
object ChatStyleConverter {
|
||||
fun constructRemoteChatStyle(
|
||||
readableDatabase: SQLiteDatabase,
|
||||
db: SignalDatabase,
|
||||
chatColors: ChatColors?,
|
||||
chatColorId: ChatColors.Id,
|
||||
chatWallpaper: Wallpaper?
|
||||
@@ -73,7 +62,7 @@ object ChatStyleConverter {
|
||||
chatStyleBuilder.wallpaperPreset = chatWallpaper.linearGradient.toRemoteWallpaperPreset()
|
||||
}
|
||||
chatWallpaper.file_ != null -> {
|
||||
chatStyleBuilder.wallpaperPhoto = chatWallpaper.file_.toFilePointer(readableDatabase)
|
||||
chatStyleBuilder.wallpaperPhoto = chatWallpaper.file_.toFilePointer(db)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,61 +208,8 @@ private fun Wallpaper.LinearGradient.toRemoteWallpaperPreset(): ChatStyle.Wallpa
|
||||
}
|
||||
}
|
||||
|
||||
private fun Wallpaper.File.toFilePointer(readableDatabase: SQLiteDatabase): FilePointer? {
|
||||
private fun Wallpaper.File.toFilePointer(db: SignalDatabase): FilePointer? {
|
||||
val attachmentId: AttachmentId = UriUtil.parseOrNull(this.uri)?.let { PartUriParser(it).partId } ?: return null
|
||||
|
||||
val wallpaperAttachment: ArchiveAttachmentData? = readableDatabase
|
||||
.select(
|
||||
AttachmentTable.ARCHIVE_MEDIA_NAME,
|
||||
AttachmentTable.ARCHIVE_CDN,
|
||||
AttachmentTable.REMOTE_KEY,
|
||||
AttachmentTable.REMOTE_DIGEST,
|
||||
AttachmentTable.DATA_SIZE,
|
||||
AttachmentTable.CONTENT_TYPE,
|
||||
AttachmentTable.WIDTH,
|
||||
AttachmentTable.HEIGHT
|
||||
)
|
||||
.from(AttachmentTable.TABLE_NAME)
|
||||
.where("${AttachmentTable.ID} = ?", attachmentId.id)
|
||||
.run()
|
||||
.readToSingleObject { cursor -> cursor.toArchiveAttachmentData() }
|
||||
|
||||
return wallpaperAttachment?.let { attachment ->
|
||||
FilePointer(
|
||||
backupLocator = FilePointer.BackupLocator(
|
||||
mediaName = attachment.archiveMediaName ?: "",
|
||||
cdnNumber = attachment.archiveCdn,
|
||||
key = attachment.remoteKey?.toByteString() ?: ByteString.EMPTY,
|
||||
size = attachment.size.toInt(),
|
||||
digest = attachment.remoteDigest?.toByteString() ?: ByteString.EMPTY
|
||||
),
|
||||
contentType = attachment.contentType,
|
||||
width = attachment.width,
|
||||
height = attachment.height
|
||||
)
|
||||
}
|
||||
val attachment = db.attachmentTable.getAttachment(attachmentId)
|
||||
return attachment?.toRemoteFilePointer(mediaArchiveEnabled = true)
|
||||
}
|
||||
|
||||
private fun Cursor.toArchiveAttachmentData(): ArchiveAttachmentData {
|
||||
return ArchiveAttachmentData(
|
||||
archiveMediaName = this.requireString(AttachmentTable.ARCHIVE_MEDIA_NAME),
|
||||
archiveCdn = this.requireInt(AttachmentTable.ARCHIVE_CDN),
|
||||
remoteKey = this.requireString(AttachmentTable.REMOTE_KEY)?.let { Base64.decodeOrNull(it) },
|
||||
remoteDigest = this.requireBlob(AttachmentTable.REMOTE_DIGEST),
|
||||
size = this.requireLong(AttachmentTable.DATA_SIZE),
|
||||
contentType = this.requireString(AttachmentTable.CONTENT_TYPE),
|
||||
width = this.requireInt(AttachmentTable.WIDTH),
|
||||
height = this.requireInt(AttachmentTable.HEIGHT)
|
||||
)
|
||||
}
|
||||
|
||||
private class ArchiveAttachmentData(
|
||||
val archiveMediaName: String?,
|
||||
val archiveCdn: Int,
|
||||
val remoteKey: ByteArray?,
|
||||
val remoteDigest: ByteArray?,
|
||||
val size: Long,
|
||||
val contentType: String?,
|
||||
val width: Int,
|
||||
val height: Int
|
||||
)
|
||||
|
||||
@@ -2227,6 +2227,7 @@ class AttachmentTable(
|
||||
put(ARCHIVE_MEDIA_NAME, attachment.archiveMediaName)
|
||||
put(ARCHIVE_MEDIA_ID, attachment.archiveMediaId)
|
||||
put(ARCHIVE_THUMBNAIL_MEDIA_ID, attachment.archiveThumbnailMediaId)
|
||||
put(ARCHIVE_TRANSFER_STATE, ArchiveTransferState.FINISHED.value)
|
||||
put(THUMBNAIL_RESTORE_STATE, ThumbnailRestoreState.NEEDS_RESTORE.value)
|
||||
put(ATTACHMENT_UUID, attachment.uuid?.toString())
|
||||
put(BLUR_HASH, attachment.blurHash?.hash)
|
||||
|
||||
@@ -60,12 +60,14 @@ public interface MessageTypes {
|
||||
long BASE_PENDING_SECURE_SMS_FALLBACK = 25;
|
||||
long BASE_PENDING_INSECURE_SMS_FALLBACK = 26;
|
||||
long BASE_DRAFT_TYPE = 27;
|
||||
long BASE_SENDING_SKIPPED_TYPE = 28;
|
||||
|
||||
long[] OUTGOING_MESSAGE_TYPES = { BASE_OUTBOX_TYPE, BASE_SENT_TYPE,
|
||||
BASE_SENDING_TYPE, BASE_SENT_FAILED_TYPE,
|
||||
BASE_PENDING_SECURE_SMS_FALLBACK,
|
||||
BASE_PENDING_INSECURE_SMS_FALLBACK,
|
||||
OUTGOING_AUDIO_CALL_TYPE, OUTGOING_VIDEO_CALL_TYPE };
|
||||
OUTGOING_AUDIO_CALL_TYPE, OUTGOING_VIDEO_CALL_TYPE,
|
||||
BASE_SENDING_SKIPPED_TYPE };
|
||||
|
||||
// Message attributes
|
||||
long MESSAGE_ATTRIBUTE_MASK = 0xE0;
|
||||
|
||||
Reference in New Issue
Block a user