Update to latest Backup.proto.
This commit is contained in:
parent
c2bdac80dc
commit
fb2a332513
17 changed files with 211 additions and 227 deletions
|
@ -128,7 +128,7 @@ class ImportExportTest {
|
|||
linkPreviews = true,
|
||||
notDiscoverableByPhoneNumber = true,
|
||||
preferContactAvatars = true,
|
||||
universalExpireTimer = 42,
|
||||
universalExpireTimerSeconds = 42,
|
||||
displayBadgesOnProfile = true,
|
||||
keepMutedChatsArchived = true,
|
||||
hasSetMyStoriesPrivacy = true,
|
||||
|
@ -556,46 +556,6 @@ class ImportExportTest {
|
|||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deletedDistributionList() {
|
||||
val alexa = Recipient(
|
||||
id = 4,
|
||||
contact = Contact(
|
||||
aci = TestRecipientUtils.nextAci().toByteString(),
|
||||
pni = TestRecipientUtils.nextPni().toByteString(),
|
||||
username = "cool.01",
|
||||
e164 = 141255501234,
|
||||
blocked = true,
|
||||
visibility = Contact.Visibility.HIDDEN,
|
||||
registered = Contact.Registered(),
|
||||
profileKey = TestRecipientUtils.generateProfileKey().toByteString(),
|
||||
profileSharing = true,
|
||||
profileGivenName = "Alexa",
|
||||
profileFamilyName = "Kim",
|
||||
hideStory = true
|
||||
)
|
||||
)
|
||||
val importData = exportFrames(
|
||||
*standardFrames,
|
||||
alexa,
|
||||
Recipient(
|
||||
id = 6,
|
||||
distributionList = DistributionListItem(
|
||||
distributionId = DistributionId.create().asUuid().toByteArray().toByteString(),
|
||||
deletionTimestamp = 12345L
|
||||
)
|
||||
)
|
||||
)
|
||||
import(importData)
|
||||
val exported = BackupRepository.debugExport()
|
||||
val expected = exportFrames(
|
||||
*standardFrames,
|
||||
alexa
|
||||
)
|
||||
|
||||
compare(expected, exported)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun chatThreads() {
|
||||
importExport(
|
||||
|
@ -1254,12 +1214,7 @@ class ImportExportTest {
|
|||
chatId = 1,
|
||||
authorId = alice.id,
|
||||
dateSent = dateSentStart++,
|
||||
incoming = ChatItem.IncomingMessageDetails(
|
||||
dateReceived = dateSentStart,
|
||||
dateServerSent = dateSentStart,
|
||||
read = true,
|
||||
sealedSender = true
|
||||
),
|
||||
directionless = ChatItem.DirectionlessMessageDetails(),
|
||||
updateMessage = ChatUpdateMessage(
|
||||
simpleUpdate = SimpleChatUpdate(
|
||||
type = SimpleChatUpdate.Type.fromValue(i)!!
|
||||
|
@ -1287,12 +1242,7 @@ class ImportExportTest {
|
|||
chatId = 1,
|
||||
authorId = alice.id,
|
||||
dateSent = dateSentStart++,
|
||||
incoming = ChatItem.IncomingMessageDetails(
|
||||
dateReceived = dateSentStart,
|
||||
dateServerSent = dateSentStart,
|
||||
read = true,
|
||||
sealedSender = true
|
||||
),
|
||||
directionless = ChatItem.DirectionlessMessageDetails(),
|
||||
updateMessage = ChatUpdateMessage(
|
||||
expirationTimerChange = ExpirationTimerChatUpdate(
|
||||
1000
|
||||
|
@ -1303,11 +1253,7 @@ class ImportExportTest {
|
|||
chatId = 1,
|
||||
authorId = selfRecipient.id,
|
||||
dateSent = dateSentStart++,
|
||||
outgoing = ChatItem.OutgoingMessageDetails(
|
||||
sendStatus = listOf(
|
||||
SendStatus(alice.id, deliveryStatus = SendStatus.Status.READ, sealedSender = true, lastStatusUpdateTimestamp = -1)
|
||||
)
|
||||
),
|
||||
directionless = ChatItem.DirectionlessMessageDetails(),
|
||||
updateMessage = ChatUpdateMessage(
|
||||
expirationTimerChange = ExpirationTimerChatUpdate(
|
||||
0
|
||||
|
@ -1318,9 +1264,7 @@ class ImportExportTest {
|
|||
chatId = 1,
|
||||
authorId = selfRecipient.id,
|
||||
dateSent = dateSentStart++,
|
||||
outgoing = ChatItem.OutgoingMessageDetails(
|
||||
sendStatus = listOf(SendStatus(alice.id, deliveryStatus = SendStatus.Status.READ, sealedSender = true, lastStatusUpdateTimestamp = -1))
|
||||
),
|
||||
directionless = ChatItem.DirectionlessMessageDetails(),
|
||||
updateMessage = ChatUpdateMessage(
|
||||
expirationTimerChange = ExpirationTimerChatUpdate(
|
||||
10000
|
||||
|
@ -1331,12 +1275,7 @@ class ImportExportTest {
|
|||
chatId = 1,
|
||||
authorId = alice.id,
|
||||
dateSent = dateSentStart++,
|
||||
incoming = ChatItem.IncomingMessageDetails(
|
||||
dateReceived = dateSentStart,
|
||||
dateServerSent = dateSentStart,
|
||||
read = true,
|
||||
sealedSender = true
|
||||
),
|
||||
directionless = ChatItem.DirectionlessMessageDetails(),
|
||||
updateMessage = ChatUpdateMessage(
|
||||
expirationTimerChange = ExpirationTimerChatUpdate(
|
||||
0
|
||||
|
@ -1348,7 +1287,6 @@ class ImportExportTest {
|
|||
|
||||
@Test
|
||||
fun profileChangeChatUpdateMessage() {
|
||||
var dateSentStart = 100L
|
||||
importExport(
|
||||
*standardFrames,
|
||||
alice,
|
||||
|
@ -1356,13 +1294,8 @@ class ImportExportTest {
|
|||
ChatItem(
|
||||
chatId = 1,
|
||||
authorId = alice.id,
|
||||
dateSent = dateSentStart++,
|
||||
incoming = ChatItem.IncomingMessageDetails(
|
||||
dateReceived = dateSentStart,
|
||||
dateServerSent = dateSentStart,
|
||||
read = true,
|
||||
sealedSender = true
|
||||
),
|
||||
dateSent = 100L,
|
||||
directionless = ChatItem.DirectionlessMessageDetails(),
|
||||
updateMessage = ChatUpdateMessage(
|
||||
profileChange = ProfileChangeChatUpdate(
|
||||
previousName = "Aliceee Kim",
|
||||
|
@ -1375,7 +1308,6 @@ class ImportExportTest {
|
|||
|
||||
@Test
|
||||
fun threadMergeChatUpdate() {
|
||||
var dateSentStart = 100L
|
||||
importExport(
|
||||
*standardFrames,
|
||||
alice,
|
||||
|
@ -1383,13 +1315,8 @@ class ImportExportTest {
|
|||
ChatItem(
|
||||
chatId = 1,
|
||||
authorId = alice.id,
|
||||
dateSent = dateSentStart++,
|
||||
incoming = ChatItem.IncomingMessageDetails(
|
||||
dateReceived = dateSentStart,
|
||||
dateServerSent = dateSentStart,
|
||||
read = true,
|
||||
sealedSender = true
|
||||
),
|
||||
dateSent = 100L,
|
||||
directionless = ChatItem.DirectionlessMessageDetails(),
|
||||
updateMessage = ChatUpdateMessage(
|
||||
threadMerge = ThreadMergeChatUpdate(
|
||||
previousE164 = 141255501237
|
||||
|
@ -1409,13 +1336,8 @@ class ImportExportTest {
|
|||
ChatItem(
|
||||
chatId = 1,
|
||||
authorId = alice.id,
|
||||
dateSent = dateSentStart++,
|
||||
incoming = ChatItem.IncomingMessageDetails(
|
||||
dateReceived = dateSentStart,
|
||||
dateServerSent = dateSentStart,
|
||||
read = true,
|
||||
sealedSender = true
|
||||
),
|
||||
dateSent = dateSentStart,
|
||||
directionless = ChatItem.DirectionlessMessageDetails(),
|
||||
updateMessage = ChatUpdateMessage(
|
||||
sessionSwitchover = SessionSwitchoverChatUpdate(
|
||||
e164 = 141255501237
|
||||
|
|
|
@ -220,8 +220,8 @@ object BackupRepository {
|
|||
backupTimeMs = exportState.backupTime
|
||||
)
|
||||
)
|
||||
// Note: Without a transaction, we may export inconsistent state. But because we have a transaction,
|
||||
// writes from other threads are blocked. This is something to think more about.
|
||||
|
||||
// We're using a snapshot, so the transaction is more for perf than correctness
|
||||
dbSnapshot.rawWritableDatabase.withinTransaction {
|
||||
AccountDataProcessor.export(dbSnapshot, signalStoreSnapshot) {
|
||||
writer.write(it)
|
||||
|
@ -316,29 +316,29 @@ object BackupRepository {
|
|||
SignalDatabase.recipients.setProfileSharing(selfId, true)
|
||||
|
||||
eventTimer.emit("setup")
|
||||
val backupState = BackupState(backupKey)
|
||||
val chatItemInserter: ChatItemImportInserter = ChatItemBackupProcessor.beginImport(backupState)
|
||||
val importState = ImportState(backupKey)
|
||||
val chatItemInserter: ChatItemImportInserter = ChatItemBackupProcessor.beginImport(importState)
|
||||
|
||||
val totalLength = frameReader.getStreamLength()
|
||||
for (frame in frameReader) {
|
||||
when {
|
||||
frame.account != null -> {
|
||||
AccountDataProcessor.import(frame.account, selfId)
|
||||
AccountDataProcessor.import(frame.account, selfId, importState)
|
||||
eventTimer.emit("account")
|
||||
}
|
||||
|
||||
frame.recipient != null -> {
|
||||
RecipientBackupProcessor.import(frame.recipient, backupState)
|
||||
RecipientBackupProcessor.import(frame.recipient, importState)
|
||||
eventTimer.emit("recipient")
|
||||
}
|
||||
|
||||
frame.chat != null -> {
|
||||
ChatBackupProcessor.import(frame.chat, backupState)
|
||||
ChatBackupProcessor.import(frame.chat, importState)
|
||||
eventTimer.emit("chat")
|
||||
}
|
||||
|
||||
frame.adHocCall != null -> {
|
||||
AdHocCallBackupProcessor.import(frame.adHocCall, backupState)
|
||||
AdHocCallBackupProcessor.import(frame.adHocCall, importState)
|
||||
eventTimer.emit("call")
|
||||
}
|
||||
|
||||
|
@ -362,7 +362,7 @@ object BackupRepository {
|
|||
eventTimer.emit("chatItem")
|
||||
}
|
||||
|
||||
backupState.chatIdToLocalThreadId.values.forEach {
|
||||
importState.chatIdToLocalThreadId.values.forEach {
|
||||
SignalDatabase.threads.update(it, unarchive = false, allowDeletion = false)
|
||||
}
|
||||
}
|
||||
|
@ -947,15 +947,17 @@ data class ArchivedMediaObject(val mediaId: String, val cdn: Int)
|
|||
data class BackupDirectories(val backupDir: String, val mediaDir: String)
|
||||
|
||||
class ExportState(val backupTime: Long, val allowMediaBackup: Boolean) {
|
||||
val recipientIds = HashSet<Long>()
|
||||
val threadIds = HashSet<Long>()
|
||||
val recipientIds: MutableSet<Long> = hashSetOf()
|
||||
val threadIds: MutableSet<Long> = hashSetOf()
|
||||
val localToRemoteCustomChatColors: MutableMap<Long, Int> = hashMapOf()
|
||||
}
|
||||
|
||||
class BackupState(val backupKey: BackupKey) {
|
||||
val backupToLocalRecipientId = HashMap<Long, RecipientId>()
|
||||
val chatIdToLocalThreadId = HashMap<Long, Long>()
|
||||
val chatIdToLocalRecipientId = HashMap<Long, RecipientId>()
|
||||
val chatIdToBackupRecipientId = HashMap<Long, Long>()
|
||||
class ImportState(val backupKey: BackupKey) {
|
||||
val remoteToLocalRecipientId: MutableMap<Long, RecipientId> = hashMapOf()
|
||||
val chatIdToLocalThreadId: MutableMap<Long, Long> = hashMapOf()
|
||||
val chatIdToLocalRecipientId: MutableMap<Long, RecipientId> = hashMapOf()
|
||||
val chatIdToBackupRecipientId: MutableMap<Long, Long> = hashMapOf()
|
||||
val remoteToLocalColorId: MutableMap<Long, Long> = hashMapOf()
|
||||
}
|
||||
|
||||
class BackupMetadata(
|
||||
|
|
|
@ -10,7 +10,7 @@ import android.database.sqlite.SQLiteDatabase
|
|||
import androidx.core.content.contentValuesOf
|
||||
import org.signal.core.util.requireLong
|
||||
import org.signal.core.util.select
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupState
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.AdHocCall
|
||||
import org.thoughtcrime.securesms.database.CallTable
|
||||
import org.thoughtcrime.securesms.database.RecipientTable
|
||||
|
@ -26,7 +26,7 @@ fun CallTable.getAdhocCallsForBackup(): CallLogIterator {
|
|||
)
|
||||
}
|
||||
|
||||
fun CallTable.restoreCallLogFromBackup(call: AdHocCall, backupState: BackupState) {
|
||||
fun CallTable.restoreCallLogFromBackup(call: AdHocCall, importState: ImportState) {
|
||||
val event = when (call.state) {
|
||||
AdHocCall.State.GENERIC -> CallTable.Event.GENERIC_GROUP_CALL
|
||||
AdHocCall.State.UNKNOWN_STATE -> CallTable.Event.GENERIC_GROUP_CALL
|
||||
|
@ -34,7 +34,7 @@ fun CallTable.restoreCallLogFromBackup(call: AdHocCall, backupState: BackupState
|
|||
|
||||
val values = contentValuesOf(
|
||||
CallTable.CALL_ID to call.callId,
|
||||
CallTable.PEER to backupState.backupToLocalRecipientId[call.recipientId]!!.serialize(),
|
||||
CallTable.PEER to importState.remoteToLocalRecipientId[call.recipientId]!!.serialize(),
|
||||
CallTable.TYPE to CallTable.Type.serialize(CallTable.Type.AD_HOC_CALL),
|
||||
CallTable.DIRECTION to CallTable.Direction.serialize(CallTable.Direction.OUTGOING),
|
||||
CallTable.EVENT to CallTable.Event.serialize(event),
|
||||
|
|
|
@ -183,7 +183,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
|||
builder.updateMessage = simpleUpdate(SimpleChatUpdate.Type.REPORTED_SPAM)
|
||||
}
|
||||
MessageTypes.isExpirationTimerUpdate(record.type) -> {
|
||||
builder.updateMessage = ChatUpdateMessage(expirationTimerChange = ExpirationTimerChatUpdate(record.expiresIn.toInt()))
|
||||
builder.updateMessage = ChatUpdateMessage(expirationTimerChange = ExpirationTimerChatUpdate(record.expiresIn))
|
||||
builder.expiresInMs = 0
|
||||
}
|
||||
MessageTypes.isProfileChange(record.type) -> {
|
||||
|
@ -774,7 +774,7 @@ class ChatItemExportIterator(private val cursor: Cursor, private val batchSize:
|
|||
mediaName = archiveMediaName ?: this.getMediaName().toString(),
|
||||
cdnNumber = if (archiveMediaName != null) 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(),
|
||||
size = this.size,
|
||||
digest = remoteDigest.toByteString()
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -20,7 +20,7 @@ import org.thoughtcrime.securesms.attachments.Attachment
|
|||
import org.thoughtcrime.securesms.attachments.Cdn
|
||||
import org.thoughtcrime.securesms.attachments.PointerAttachment
|
||||
import org.thoughtcrime.securesms.attachments.TombstoneAttachment
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupState
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.BodyRange
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ChatItem
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ChatUpdateMessage
|
||||
|
@ -89,7 +89,7 @@ import org.thoughtcrime.securesms.backup.v2.proto.GiftBadge as BackupGiftBadge
|
|||
*/
|
||||
class ChatItemImportInserter(
|
||||
private val db: SQLiteDatabase,
|
||||
private val backupState: BackupState,
|
||||
private val importState: ImportState,
|
||||
private val batchSize: Int
|
||||
) {
|
||||
companion object {
|
||||
|
@ -155,25 +155,25 @@ class ChatItemImportInserter(
|
|||
* If this item causes the buffer to hit the batch size, then a batch of items will actually be inserted.
|
||||
*/
|
||||
fun insert(chatItem: ChatItem) {
|
||||
val fromLocalRecipientId: RecipientId? = backupState.backupToLocalRecipientId[chatItem.authorId]
|
||||
val fromLocalRecipientId: RecipientId? = importState.remoteToLocalRecipientId[chatItem.authorId]
|
||||
if (fromLocalRecipientId == null) {
|
||||
Log.w(TAG, "[insert] Could not find a local recipient for backup recipient ID ${chatItem.authorId}! Skipping.")
|
||||
return
|
||||
}
|
||||
|
||||
val chatLocalRecipientId: RecipientId? = backupState.chatIdToLocalRecipientId[chatItem.chatId]
|
||||
val chatLocalRecipientId: RecipientId? = importState.chatIdToLocalRecipientId[chatItem.chatId]
|
||||
if (chatLocalRecipientId == null) {
|
||||
Log.w(TAG, "[insert] Could not find a local recipient for chatId ${chatItem.chatId}! Skipping.")
|
||||
return
|
||||
}
|
||||
|
||||
val localThreadId: Long? = backupState.chatIdToLocalThreadId[chatItem.chatId]
|
||||
val localThreadId: Long? = importState.chatIdToLocalThreadId[chatItem.chatId]
|
||||
if (localThreadId == null) {
|
||||
Log.w(TAG, "[insert] Could not find a local threadId for backup chatId ${chatItem.chatId}! Skipping.")
|
||||
return
|
||||
}
|
||||
|
||||
val chatBackupRecipientId: Long? = backupState.chatIdToBackupRecipientId[chatItem.chatId]
|
||||
val chatBackupRecipientId: Long? = importState.chatIdToBackupRecipientId[chatItem.chatId]
|
||||
if (chatBackupRecipientId == null) {
|
||||
Log.w(TAG, "[insert] Could not find a backup recipientId for backup chatId ${chatItem.chatId}! Skipping.")
|
||||
return
|
||||
|
@ -283,7 +283,7 @@ class ChatItemImportInserter(
|
|||
CallTable.MESSAGE_ID to messageRowId,
|
||||
CallTable.PEER to chatRecipientId.serialize(),
|
||||
CallTable.TYPE to CallTable.Type.serialize(CallTable.Type.GROUP_CALL),
|
||||
CallTable.DIRECTION to CallTable.Direction.serialize(if (backupState.backupToLocalRecipientId[updateMessage.groupCall.ringerRecipientId] == selfId) CallTable.Direction.OUTGOING else CallTable.Direction.INCOMING),
|
||||
CallTable.DIRECTION to CallTable.Direction.serialize(if (importState.remoteToLocalRecipientId[updateMessage.groupCall.ringerRecipientId] == selfId) CallTable.Direction.OUTGOING else CallTable.Direction.INCOMING),
|
||||
CallTable.EVENT to CallTable.Event.serialize(
|
||||
when (updateMessage.groupCall.state) {
|
||||
GroupCall.State.ACCEPTED -> CallTable.Event.ACCEPTED
|
||||
|
@ -460,8 +460,8 @@ class ChatItemImportInserter(
|
|||
contentValues.put(MessageTable.UNIDENTIFIED, this.outgoing.sendStatus.count { it.sealedSender })
|
||||
contentValues.put(MessageTable.READ, 1)
|
||||
|
||||
contentValues.addNetworkFailures(this, backupState)
|
||||
contentValues.addIdentityKeyMismatches(this, backupState)
|
||||
contentValues.addNetworkFailures(this, importState)
|
||||
contentValues.addIdentityKeyMismatches(this, importState)
|
||||
} else {
|
||||
contentValues.put(MessageTable.VIEWED_COLUMN, 0)
|
||||
contentValues.put(MessageTable.HAS_READ_RECEIPT, 0)
|
||||
|
@ -529,7 +529,7 @@ class ChatItemImportInserter(
|
|||
|
||||
return reactions
|
||||
.mapNotNull {
|
||||
val authorId: Long? = backupState.backupToLocalRecipientId[it.authorId]?.toLong()
|
||||
val authorId: Long? = importState.remoteToLocalRecipientId[it.authorId]?.toLong()
|
||||
|
||||
if (authorId != null) {
|
||||
contentValuesOf(
|
||||
|
@ -557,7 +557,7 @@ class ChatItemImportInserter(
|
|||
}
|
||||
|
||||
return this.outgoing.sendStatus.mapNotNull { sendStatus ->
|
||||
val recipientId = backupState.backupToLocalRecipientId[sendStatus.recipientId]
|
||||
val recipientId = importState.remoteToLocalRecipientId[sendStatus.recipientId]
|
||||
|
||||
if (recipientId != null) {
|
||||
contentValuesOf(
|
||||
|
@ -674,7 +674,7 @@ class ChatItemImportInserter(
|
|||
}
|
||||
updateMessage.groupCall != null -> {
|
||||
val startedCallRecipientId = if (updateMessage.groupCall.startedCallRecipientId != null) {
|
||||
backupState.backupToLocalRecipientId[updateMessage.groupCall.startedCallRecipientId]
|
||||
importState.remoteToLocalRecipientId[updateMessage.groupCall.startedCallRecipientId]
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
@ -815,7 +815,7 @@ class ChatItemImportInserter(
|
|||
|
||||
private fun ContentValues.addQuote(quote: Quote) {
|
||||
this.put(MessageTable.QUOTE_ID, quote.targetSentTimestamp ?: MessageTable.QUOTE_TARGET_MISSING_ID)
|
||||
this.put(MessageTable.QUOTE_AUTHOR, backupState.backupToLocalRecipientId[quote.authorId]!!.serialize())
|
||||
this.put(MessageTable.QUOTE_AUTHOR, importState.remoteToLocalRecipientId[quote.authorId]!!.serialize())
|
||||
this.put(MessageTable.QUOTE_BODY, quote.text)
|
||||
this.put(MessageTable.QUOTE_TYPE, quote.type.toLocalQuoteType())
|
||||
this.put(MessageTable.QUOTE_BODY_RANGES, quote.bodyRanges.toLocalBodyRanges()?.encode())
|
||||
|
@ -840,14 +840,14 @@ class ChatItemImportInserter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun ContentValues.addNetworkFailures(chatItem: ChatItem, backupState: BackupState) {
|
||||
private fun ContentValues.addNetworkFailures(chatItem: ChatItem, importState: ImportState) {
|
||||
if (chatItem.outgoing == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val networkFailures = chatItem.outgoing.sendStatus
|
||||
.filter { status -> status.networkFailure }
|
||||
.mapNotNull { status -> backupState.backupToLocalRecipientId[status.recipientId] }
|
||||
.mapNotNull { status -> importState.remoteToLocalRecipientId[status.recipientId] }
|
||||
.map { recipientId -> NetworkFailure(recipientId) }
|
||||
.toSet()
|
||||
|
||||
|
@ -856,14 +856,14 @@ class ChatItemImportInserter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun ContentValues.addIdentityKeyMismatches(chatItem: ChatItem, backupState: BackupState) {
|
||||
private fun ContentValues.addIdentityKeyMismatches(chatItem: ChatItem, importState: ImportState) {
|
||||
if (chatItem.outgoing == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val mismatches = chatItem.outgoing.sendStatus
|
||||
.filter { status -> status.identityKeyMismatch }
|
||||
.mapNotNull { status -> backupState.backupToLocalRecipientId[status.recipientId] }
|
||||
.mapNotNull { status -> importState.remoteToLocalRecipientId[status.recipientId] }
|
||||
.map { recipientId -> IdentityKeyMismatch(recipientId, null) } // TODO We probably want the actual identity key in this status situation?
|
||||
.toSet()
|
||||
|
||||
|
@ -965,8 +965,8 @@ class ChatItemImportInserter(
|
|||
cdnKey = backupLocator.transitCdnKey,
|
||||
archiveCdn = backupLocator.cdnNumber,
|
||||
archiveMediaName = backupLocator.mediaName,
|
||||
archiveMediaId = backupState.backupKey.deriveMediaId(MediaName(backupLocator.mediaName)).encode(),
|
||||
archiveThumbnailMediaId = backupState.backupKey.deriveMediaId(MediaName.forThumbnailFromMediaName(backupLocator.mediaName)).encode(),
|
||||
archiveMediaId = importState.backupKey.deriveMediaId(MediaName(backupLocator.mediaName)).encode(),
|
||||
archiveThumbnailMediaId = importState.backupKey.deriveMediaId(MediaName.forThumbnailFromMediaName(backupLocator.mediaName)).encode(),
|
||||
digest = backupLocator.digest.toByteArray(),
|
||||
incrementalMac = incrementalMac?.toByteArray(),
|
||||
incrementalMacChunkSize = incrementalMacChunkSize,
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.signal.core.util.requireNonNullString
|
|||
import org.signal.core.util.requireObject
|
||||
import org.signal.core.util.select
|
||||
import org.signal.core.util.withinTransaction
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupState
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.DistributionList
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.DistributionListItem
|
||||
import org.thoughtcrime.securesms.database.DistributionListTables
|
||||
|
@ -98,7 +98,7 @@ fun DistributionListTables.getMembersForBackup(id: DistributionListId): List<Rec
|
|||
}
|
||||
}
|
||||
|
||||
fun DistributionListTables.restoreFromBackup(dlistItem: DistributionListItem, backupState: BackupState): RecipientId? {
|
||||
fun DistributionListTables.restoreFromBackup(dlistItem: DistributionListItem, importState: ImportState): RecipientId? {
|
||||
if (dlistItem.deletionTimestamp != null && dlistItem.deletionTimestamp > 0) {
|
||||
val dlistId = createList(
|
||||
name = "",
|
||||
|
@ -115,7 +115,7 @@ fun DistributionListTables.restoreFromBackup(dlistItem: DistributionListItem, ba
|
|||
|
||||
val dlist = dlistItem.distributionList ?: return null
|
||||
val members: List<RecipientId> = dlist.memberRecipientIds
|
||||
.mapNotNull { backupState.backupToLocalRecipientId[it] }
|
||||
.mapNotNull { importState.remoteToLocalRecipientId[it] }
|
||||
|
||||
if (members.size != dlist.memberRecipientIds.size) {
|
||||
Log.w(TAG, "Couldn't find some member recipients! Missing backup recipientIds: ${dlist.memberRecipientIds.toSet() - members.toSet()}")
|
||||
|
|
|
@ -8,7 +8,7 @@ package org.thoughtcrime.securesms.backup.v2.database
|
|||
import org.signal.core.util.SqlUtil
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.core.util.select
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupState
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.database.MessageTable
|
||||
import org.thoughtcrime.securesms.database.MessageTypes
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -69,8 +69,8 @@ fun MessageTable.getMessagesForBackup(backupTime: Long, archiveMedia: Boolean):
|
|||
return ChatItemExportIterator(cursor, 100, archiveMedia)
|
||||
}
|
||||
|
||||
fun MessageTable.createChatItemInserter(backupState: BackupState): ChatItemImportInserter {
|
||||
return ChatItemImportInserter(writableDatabase, backupState, 100)
|
||||
fun MessageTable.createChatItemInserter(importState: ImportState): ChatItemImportInserter {
|
||||
return ChatItemImportInserter(writableDatabase, importState, 100)
|
||||
}
|
||||
|
||||
fun MessageTable.clearAllDataForBackupRestore() {
|
||||
|
|
|
@ -16,12 +16,12 @@ import org.signal.core.util.requireBoolean
|
|||
import org.signal.core.util.requireInt
|
||||
import org.signal.core.util.requireLong
|
||||
import org.signal.core.util.toInt
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.Chat
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ChatStyle
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColors
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette
|
||||
import org.thoughtcrime.securesms.database.RecipientTable
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.ThreadTable
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.ChatColor
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
|
@ -29,7 +29,7 @@ import java.io.Closeable
|
|||
|
||||
private val TAG = Log.tag(ThreadTable::class.java)
|
||||
|
||||
fun ThreadTable.getThreadsForBackup(): ChatIterator {
|
||||
fun ThreadTable.getThreadsForBackup(): ChatExportIterator {
|
||||
//language=sql
|
||||
val query = """
|
||||
SELECT
|
||||
|
@ -49,7 +49,7 @@ fun ThreadTable.getThreadsForBackup(): ChatIterator {
|
|||
"""
|
||||
val cursor = readableDatabase.query(query)
|
||||
|
||||
return ChatIterator(cursor)
|
||||
return ChatExportIterator(cursor)
|
||||
}
|
||||
|
||||
fun ThreadTable.clearAllDataForBackupRestore() {
|
||||
|
@ -58,15 +58,10 @@ fun ThreadTable.clearAllDataForBackupRestore() {
|
|||
clearCache()
|
||||
}
|
||||
|
||||
fun ThreadTable.restoreFromBackup(chat: Chat, recipientId: RecipientId): Long? {
|
||||
val chatColor = chat.style?.parseChatColor()
|
||||
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
|
||||
}
|
||||
fun ThreadTable.restoreFromBackup(chat: Chat, recipientId: RecipientId, importState: ImportState): Long? {
|
||||
val chatColor = chat.style?.remoteToLocalChatColors(importState)
|
||||
|
||||
// TODO [backup] Wallpaper
|
||||
|
||||
val threadId = writableDatabase
|
||||
.insertInto(ThreadTable.TABLE_NAME)
|
||||
|
@ -85,8 +80,8 @@ fun ThreadTable.restoreFromBackup(chat: Chat, recipientId: RecipientId): Long? {
|
|||
RecipientTable.MENTION_SETTING to (if (chat.dontNotifyForMentionsIfMuted) RecipientTable.MentionSetting.DO_NOT_NOTIFY.id else RecipientTable.MentionSetting.ALWAYS_NOTIFY.id),
|
||||
RecipientTable.MUTE_UNTIL to chat.muteUntilMs,
|
||||
RecipientTable.MESSAGE_EXPIRATION_TIME to chat.expirationTimerMs,
|
||||
RecipientTable.CHAT_COLORS to chatColorWithId?.serialize()?.encode(),
|
||||
RecipientTable.CUSTOM_CHAT_COLORS_ID to (chatColorWithId?.id ?: ChatColors.Id.NotSet).longValue
|
||||
RecipientTable.CHAT_COLORS to chatColor?.serialize()?.encode(),
|
||||
RecipientTable.CUSTOM_CHAT_COLORS_ID to (chatColor?.id ?: ChatColors.Id.NotSet).longValue
|
||||
),
|
||||
"${RecipientTable.ID} = ?",
|
||||
SqlUtil.buildArgs(recipientId.toLong())
|
||||
|
@ -95,7 +90,7 @@ fun ThreadTable.restoreFromBackup(chat: Chat, recipientId: RecipientId): Long? {
|
|||
return threadId
|
||||
}
|
||||
|
||||
class ChatIterator(private val cursor: Cursor) : Iterator<Chat>, Closeable {
|
||||
class ChatExportIterator(private val cursor: Cursor) : Iterator<Chat>, Closeable {
|
||||
override fun hasNext(): Boolean {
|
||||
return cursor.count > 0 && !cursor.isLast
|
||||
}
|
||||
|
@ -106,31 +101,32 @@ class ChatIterator(private val cursor: Cursor) : Iterator<Chat>, Closeable {
|
|||
}
|
||||
|
||||
val serializedChatColors = cursor.requireBlob(RecipientTable.CHAT_COLORS)
|
||||
val customChatColorsId = ChatColors.Id.forLongValue(cursor.requireLong(RecipientTable.CUSTOM_CHAT_COLORS_ID))
|
||||
val chatColors: ChatColors? = if (serializedChatColors != null) {
|
||||
val chatColorId = ChatColors.Id.forLongValue(cursor.requireLong(RecipientTable.CUSTOM_CHAT_COLORS_ID))
|
||||
val chatColors: ChatColors? = serializedChatColors?.let { serialized ->
|
||||
try {
|
||||
ChatColors.forChatColor(customChatColorsId, ChatColor.ADAPTER.decode(serializedChatColors))
|
||||
ChatColors.forChatColor(chatColorId, ChatColor.ADAPTER.decode(serialized))
|
||||
} catch (e: InvalidProtocolBufferException) {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
var chatStyleBuilder: ChatStyle.Builder? = null
|
||||
if (chatColors != null) {
|
||||
chatStyleBuilder = ChatStyle.Builder()
|
||||
val presetBubbleColor = chatColors.tryToMapToBackupPreset()
|
||||
if (presetBubbleColor != null) {
|
||||
chatStyleBuilder.bubbleColorPreset = presetBubbleColor
|
||||
} else if (chatColors.isGradient()) {
|
||||
chatStyleBuilder.bubbleGradient = ChatStyle.Gradient(angle = chatColors.getDegrees().toInt(), colors = chatColors.getColors().toList())
|
||||
} else if (customChatColorsId is ChatColors.Id.Auto) {
|
||||
chatStyleBuilder.autoBubbleColor = ChatStyle.AutomaticBubbleColor()
|
||||
} else {
|
||||
chatStyleBuilder.bubbleSolidColor = chatColors.asSingleColor()
|
||||
when (chatColorId) {
|
||||
ChatColors.Id.NotSet -> {}
|
||||
ChatColors.Id.Auto -> {
|
||||
chatStyleBuilder.autoBubbleColor = ChatStyle.AutomaticBubbleColor()
|
||||
}
|
||||
ChatColors.Id.BuiltIn -> {
|
||||
chatStyleBuilder.bubbleColorPreset = chatColors.localToRemoteChatColors()
|
||||
}
|
||||
is ChatColors.Id.Custom -> {
|
||||
chatStyleBuilder.customColorId = chatColorId.longValue
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO [backup] wallpaper
|
||||
|
||||
return Chat(
|
||||
id = cursor.requireLong(ThreadTable.ID),
|
||||
|
@ -150,9 +146,9 @@ class ChatIterator(private val cursor: Cursor) : Iterator<Chat>, Closeable {
|
|||
}
|
||||
}
|
||||
|
||||
private fun ChatStyle.parseChatColor(): ChatColors? {
|
||||
if (bubbleColorPreset != null) {
|
||||
return when (bubbleColorPreset) {
|
||||
private fun ChatStyle.remoteToLocalChatColors(importState: ImportState): ChatColors? {
|
||||
if (this.bubbleColorPreset != null) {
|
||||
return when (this.bubbleColorPreset) {
|
||||
ChatStyle.BubbleColorPreset.SOLID_CRIMSON -> ChatColorsPalette.Bubbles.CRIMSON
|
||||
ChatStyle.BubbleColorPreset.SOLID_VERMILION -> ChatColorsPalette.Bubbles.VERMILION
|
||||
ChatStyle.BubbleColorPreset.SOLID_BURLAP -> ChatColorsPalette.Bubbles.BURLAP
|
||||
|
@ -177,27 +173,22 @@ private fun ChatStyle.parseChatColor(): ChatColors? {
|
|||
ChatStyle.BubbleColorPreset.UNKNOWN_BUBBLE_COLOR_PRESET, ChatStyle.BubbleColorPreset.SOLID_ULTRAMARINE -> ChatColorsPalette.Bubbles.ULTRAMARINE
|
||||
}
|
||||
}
|
||||
if (autoBubbleColor != null) {
|
||||
|
||||
if (this.autoBubbleColor != null) {
|
||||
return ChatColorsPalette.Bubbles.default.withId(ChatColors.Id.Auto)
|
||||
}
|
||||
if (bubbleSolidColor != null) {
|
||||
return ChatColors(id = ChatColors.Id.NotSet, singleColor = bubbleSolidColor, linearGradient = null)
|
||||
}
|
||||
if (bubbleGradient != null) {
|
||||
return ChatColors(
|
||||
id = ChatColors.Id.NotSet,
|
||||
singleColor = null,
|
||||
linearGradient = ChatColors.LinearGradient(
|
||||
degrees = bubbleGradient.angle.toFloat(),
|
||||
colors = bubbleGradient.colors.toIntArray(),
|
||||
positions = floatArrayOf(0f, 1f)
|
||||
)
|
||||
)
|
||||
|
||||
if (this.customColorId != null) {
|
||||
return importState.remoteToLocalColorId[this.customColorId]?.let { localId ->
|
||||
val colorId = ChatColors.Id.forLongValue(localId)
|
||||
ChatColorsPalette.Bubbles.default.withId(colorId)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun ChatColors.tryToMapToBackupPreset(): ChatStyle.BubbleColorPreset? {
|
||||
private fun ChatColors.localToRemoteChatColors(): ChatStyle.BubbleColorPreset? {
|
||||
when (this) {
|
||||
// Solids
|
||||
ChatColorsPalette.Bubbles.CRIMSON -> return ChatStyle.BubbleColorPreset.SOLID_CRIMSON
|
||||
|
|
|
@ -7,12 +7,16 @@ package org.thoughtcrime.securesms.backup.v2.processor
|
|||
|
||||
import okio.ByteString.Companion.EMPTY
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.database.restoreSelfFromBackup
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.AccountData
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.ChatStyle
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.Frame
|
||||
import org.thoughtcrime.securesms.backup.v2.stream.BackupFrameEmitter
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.InAppPaymentsRepository
|
||||
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.UsernameQrCodeColorScheme
|
||||
import org.thoughtcrime.securesms.conversation.colors.ChatColors
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.model.InAppPaymentSubscriberRecord
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
|
@ -32,6 +36,8 @@ import java.util.Currency
|
|||
|
||||
object AccountDataProcessor {
|
||||
|
||||
private val TAG = Log.tag(AccountDataProcessor::class)
|
||||
|
||||
fun export(db: SignalDatabase, signalStore: SignalStore, emitter: BackupFrameEmitter) {
|
||||
val context = AppDependencies.application
|
||||
|
||||
|
@ -53,7 +59,7 @@ object AccountDataProcessor {
|
|||
AccountData.UsernameLink(
|
||||
entropy = signalStore.accountValues.usernameLink?.entropy?.toByteString() ?: EMPTY,
|
||||
serverId = signalStore.accountValues.usernameLink?.serverId?.toByteArray()?.toByteString() ?: EMPTY,
|
||||
color = signalStore.miscValues.usernameQrCodeColorScheme.toBackupUsernameColor() ?: AccountData.UsernameLink.Color.BLUE
|
||||
color = signalStore.miscValues.usernameQrCodeColorScheme.toBackupUsernameColor()
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
@ -67,7 +73,7 @@ object AccountDataProcessor {
|
|||
notDiscoverableByPhoneNumber = signalStore.phoneNumberPrivacyValues.phoneNumberDiscoverabilityMode == PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE,
|
||||
phoneNumberSharingMode = signalStore.phoneNumberPrivacyValues.phoneNumberSharingMode.toBackupPhoneNumberSharingMode(),
|
||||
preferContactAvatars = signalStore.settingsValues.isPreferSystemContactPhotos,
|
||||
universalExpireTimer = signalStore.settingsValues.universalExpireTimer,
|
||||
universalExpireTimerSeconds = signalStore.settingsValues.universalExpireTimer,
|
||||
preferredReactionEmoji = signalStore.emojiValues.rawReactions,
|
||||
storiesDisabled = signalStore.storyValues.isFeatureDisabled,
|
||||
hasViewedOnboardingStory = signalStore.storyValues.userHasViewedOnboardingStory,
|
||||
|
@ -75,7 +81,8 @@ object AccountDataProcessor {
|
|||
keepMutedChatsArchived = signalStore.settingsValues.shouldKeepMutedChatsArchived(),
|
||||
displayBadgesOnProfile = signalStore.inAppPaymentValues.getDisplayBadgesOnProfile(),
|
||||
hasSeenGroupStoryEducationSheet = signalStore.storyValues.userHasSeenGroupStoryEducationSheet,
|
||||
hasCompletedUsernameOnboarding = signalStore.uiHintValues.hasCompletedUsernameOnboarding()
|
||||
hasCompletedUsernameOnboarding = signalStore.uiHintValues.hasCompletedUsernameOnboarding(),
|
||||
customChatColors = db.chatColorsTable.getSavedChatColors().toRemoteChatColors()
|
||||
),
|
||||
donationSubscriberData = donationSubscriber?.toSubscriberData(signalStore.inAppPaymentValues.isDonationSubscriptionManuallyCancelled())
|
||||
)
|
||||
|
@ -83,7 +90,7 @@ object AccountDataProcessor {
|
|||
)
|
||||
}
|
||||
|
||||
fun import(accountData: AccountData, selfId: RecipientId) {
|
||||
fun import(accountData: AccountData, selfId: RecipientId, importState: ImportState) {
|
||||
SignalDatabase.recipients.restoreSelfFromBackup(accountData, selfId)
|
||||
|
||||
SignalStore.account.setRegistered(true)
|
||||
|
@ -99,7 +106,7 @@ object AccountDataProcessor {
|
|||
SignalStore.phoneNumberPrivacy.phoneNumberDiscoverabilityMode = if (settings.notDiscoverableByPhoneNumber) PhoneNumberDiscoverabilityMode.NOT_DISCOVERABLE else PhoneNumberDiscoverabilityMode.DISCOVERABLE
|
||||
SignalStore.phoneNumberPrivacy.phoneNumberSharingMode = settings.phoneNumberSharingMode.toLocalPhoneNumberMode()
|
||||
SignalStore.settings.isPreferSystemContactPhotos = settings.preferContactAvatars
|
||||
SignalStore.settings.universalExpireTimer = settings.universalExpireTimer
|
||||
SignalStore.settings.universalExpireTimer = settings.universalExpireTimerSeconds
|
||||
SignalStore.emoji.reactions = settings.preferredReactionEmoji
|
||||
SignalStore.inAppPayments.setDisplayBadgesOnProfile(settings.displayBadgesOnProfile)
|
||||
SignalStore.settings.setKeepMutedChatsArchived(settings.keepMutedChatsArchived)
|
||||
|
@ -109,6 +116,32 @@ object AccountDataProcessor {
|
|||
SignalStore.story.userHasSeenGroupStoryEducationSheet = settings.hasSeenGroupStoryEducationSheet
|
||||
SignalStore.story.viewedReceiptsEnabled = settings.storyViewReceiptsEnabled ?: settings.readReceipts
|
||||
|
||||
settings.customChatColors
|
||||
.mapNotNull { chatColor ->
|
||||
val id = ChatColors.Id.forLongValue(chatColor.id)
|
||||
when {
|
||||
chatColor.solid != null -> {
|
||||
ChatColors.forColor(id, chatColor.solid)
|
||||
}
|
||||
chatColor.gradient != null -> {
|
||||
ChatColors.forGradient(
|
||||
id,
|
||||
ChatColors.LinearGradient(
|
||||
degrees = chatColor.gradient.angle.toFloat(),
|
||||
colors = chatColor.gradient.colors.toIntArray(),
|
||||
positions = chatColor.gradient.positions.toFloatArray()
|
||||
)
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
.forEach { chatColor ->
|
||||
// We need to use the "NotSet" chatId so that this operation is treated as an insert rather than an update
|
||||
val saved = SignalDatabase.chatColors.saveChatColors(chatColor.withId(ChatColors.Id.NotSet))
|
||||
importState.remoteToLocalColorId[chatColor.id.longValue] = saved.id.longValue
|
||||
}
|
||||
|
||||
if (accountData.donationSubscriberData != null) {
|
||||
if (accountData.donationSubscriberData.subscriberId.size > 0) {
|
||||
val remoteSubscriberId = SubscriberId.fromBytes(accountData.donationSubscriberData.subscriberId.toByteArray())
|
||||
|
@ -204,4 +237,28 @@ object AccountDataProcessor {
|
|||
val currencyCode = currency.currencyCode
|
||||
return AccountData.SubscriberData(subscriberId = subscriberId, currencyCode = currencyCode, manuallyCancelled = manuallyCancelled)
|
||||
}
|
||||
|
||||
private fun List<ChatColors>.toRemoteChatColors(): List<ChatStyle.CustomChatColor> {
|
||||
return this
|
||||
.mapNotNull { local ->
|
||||
if (local.linearGradient != null) {
|
||||
ChatStyle.CustomChatColor(
|
||||
id = local.id.longValue,
|
||||
gradient = ChatStyle.Gradient(
|
||||
angle = local.linearGradient.degrees.toInt(),
|
||||
colors = local.linearGradient.colors.toList(),
|
||||
positions = local.linearGradient.positions.toList()
|
||||
)
|
||||
)
|
||||
} else if (local.singleColor != null) {
|
||||
ChatStyle.CustomChatColor(
|
||||
id = local.id.longValue,
|
||||
solid = local.singleColor
|
||||
)
|
||||
} else {
|
||||
Log.w(TAG, "Invalid custom color (id = ${local.id}, no gradient or solid color!")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
package org.thoughtcrime.securesms.backup.v2.processor
|
||||
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupState
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.database.getAdhocCallsForBackup
|
||||
import org.thoughtcrime.securesms.backup.v2.database.restoreCallLogFromBackup
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.AdHocCall
|
||||
|
@ -28,7 +28,7 @@ object AdHocCallBackupProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
fun import(call: AdHocCall, backupState: BackupState) {
|
||||
SignalDatabase.calls.restoreCallLogFromBackup(call, backupState)
|
||||
fun import(call: AdHocCall, importState: ImportState) {
|
||||
SignalDatabase.calls.restoreCallLogFromBackup(call, importState)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
package org.thoughtcrime.securesms.backup.v2.processor
|
||||
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupState
|
||||
import org.thoughtcrime.securesms.backup.v2.ExportState
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.database.getThreadsForBackup
|
||||
import org.thoughtcrime.securesms.backup.v2.database.restoreFromBackup
|
||||
import org.thoughtcrime.securesms.backup.v2.proto.Chat
|
||||
|
@ -32,19 +32,17 @@ object ChatBackupProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
fun import(chat: Chat, backupState: BackupState) {
|
||||
val recipientId: RecipientId? = backupState.backupToLocalRecipientId[chat.recipientId]
|
||||
fun import(chat: Chat, importState: ImportState) {
|
||||
val recipientId: RecipientId? = importState.remoteToLocalRecipientId[chat.recipientId]
|
||||
if (recipientId == null) {
|
||||
Log.w(TAG, "Missing recipient for chat ${chat.id}")
|
||||
return
|
||||
}
|
||||
|
||||
SignalDatabase.threads.restoreFromBackup(chat, recipientId)?.let { threadId ->
|
||||
backupState.chatIdToLocalRecipientId[chat.id] = recipientId
|
||||
backupState.chatIdToLocalThreadId[chat.id] = threadId
|
||||
backupState.chatIdToBackupRecipientId[chat.id] = chat.recipientId
|
||||
SignalDatabase.threads.restoreFromBackup(chat, recipientId, importState)?.let { threadId ->
|
||||
importState.chatIdToLocalRecipientId[chat.id] = recipientId
|
||||
importState.chatIdToLocalThreadId[chat.id] = threadId
|
||||
importState.chatIdToBackupRecipientId[chat.id] = chat.recipientId
|
||||
}
|
||||
|
||||
// TODO there's several fields in the chat that actually need to be restored on the recipient table
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
package org.thoughtcrime.securesms.backup.v2.processor
|
||||
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupState
|
||||
import org.thoughtcrime.securesms.backup.v2.ExportState
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.database.ChatItemImportInserter
|
||||
import org.thoughtcrime.securesms.backup.v2.database.createChatItemInserter
|
||||
import org.thoughtcrime.securesms.backup.v2.database.getMessagesForBackup
|
||||
|
@ -31,7 +31,7 @@ object ChatItemBackupProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
fun beginImport(backupState: BackupState): ChatItemImportInserter {
|
||||
return SignalDatabase.messages.createChatItemInserter(backupState)
|
||||
fun beginImport(importState: ImportState): ChatItemImportInserter {
|
||||
return SignalDatabase.messages.createChatItemInserter(importState)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
package org.thoughtcrime.securesms.backup.v2.processor
|
||||
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.backup.v2.BackupState
|
||||
import org.thoughtcrime.securesms.backup.v2.ExportState
|
||||
import org.thoughtcrime.securesms.backup.v2.ImportState
|
||||
import org.thoughtcrime.securesms.backup.v2.database.BackupRecipient
|
||||
import org.thoughtcrime.securesms.backup.v2.database.getAllForBackup
|
||||
import org.thoughtcrime.securesms.backup.v2.database.getCallLinksForBackup
|
||||
|
@ -28,11 +28,11 @@ object RecipientBackupProcessor {
|
|||
|
||||
val TAG = Log.tag(RecipientBackupProcessor::class.java)
|
||||
|
||||
fun export(db: SignalDatabase, signalStore: SignalStore, state: ExportState, emitter: BackupFrameEmitter) {
|
||||
fun export(db: SignalDatabase, signalStore: SignalStore, exportState: ExportState, emitter: BackupFrameEmitter) {
|
||||
val selfId = db.recipientTable.getByAci(signalStore.accountValues.aci!!).get().toLong()
|
||||
val releaseChannelId = signalStore.releaseChannelValues.releaseChannelRecipientId
|
||||
if (releaseChannelId != null) {
|
||||
state.recipientIds.add(releaseChannelId.toLong())
|
||||
exportState.recipientIds.add(releaseChannelId.toLong())
|
||||
emitter.emit(
|
||||
Frame(
|
||||
recipient = BackupRecipient(
|
||||
|
@ -46,7 +46,7 @@ object RecipientBackupProcessor {
|
|||
db.recipientTable.getContactsForBackup(selfId).use { reader ->
|
||||
for (backupRecipient in reader) {
|
||||
if (backupRecipient != null) {
|
||||
state.recipientIds.add(backupRecipient.id)
|
||||
exportState.recipientIds.add(backupRecipient.id)
|
||||
emitter.emit(Frame(recipient = backupRecipient))
|
||||
}
|
||||
}
|
||||
|
@ -54,27 +54,27 @@ object RecipientBackupProcessor {
|
|||
|
||||
db.recipientTable.getGroupsForBackup().use { reader ->
|
||||
for (backupRecipient in reader) {
|
||||
state.recipientIds.add(backupRecipient.id)
|
||||
exportState.recipientIds.add(backupRecipient.id)
|
||||
emitter.emit(Frame(recipient = backupRecipient))
|
||||
}
|
||||
}
|
||||
|
||||
db.distributionListTables.getAllForBackup().forEach {
|
||||
state.recipientIds.add(it.id)
|
||||
exportState.recipientIds.add(it.id)
|
||||
emitter.emit(Frame(recipient = it))
|
||||
}
|
||||
|
||||
db.callLinkTable.getCallLinksForBackup().forEach {
|
||||
state.recipientIds.add(it.id)
|
||||
exportState.recipientIds.add(it.id)
|
||||
emitter.emit(Frame(recipient = it))
|
||||
}
|
||||
}
|
||||
|
||||
fun import(recipient: BackupRecipient, backupState: BackupState) {
|
||||
fun import(recipient: BackupRecipient, importState: ImportState) {
|
||||
val newId = when {
|
||||
recipient.contact != null -> SignalDatabase.recipients.restoreContactFromBackup(recipient.contact)
|
||||
recipient.group != null -> SignalDatabase.recipients.restoreGroupFromBackup(recipient.group)
|
||||
recipient.distributionList != null -> SignalDatabase.distributionLists.restoreFromBackup(recipient.distributionList, backupState)
|
||||
recipient.distributionList != null -> SignalDatabase.distributionLists.restoreFromBackup(recipient.distributionList, importState)
|
||||
recipient.self != null -> Recipient.self().id
|
||||
recipient.releaseNotes != null -> SignalDatabase.recipients.restoreReleaseNotes()
|
||||
recipient.callLink != null -> SignalDatabase.callLinks.restoreFromBackup(recipient.callLink)
|
||||
|
@ -84,7 +84,7 @@ object RecipientBackupProcessor {
|
|||
}
|
||||
}
|
||||
if (newId != null) {
|
||||
backupState.backupToLocalRecipientId[recipient.id] = newId
|
||||
importState.remoteToLocalRecipientId[recipient.id] = newId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ import kotlin.math.min
|
|||
@Parcelize
|
||||
class ChatColors(
|
||||
val id: Id,
|
||||
private val linearGradient: LinearGradient?,
|
||||
private val singleColor: Int?
|
||||
val linearGradient: LinearGradient?,
|
||||
val singleColor: Int?
|
||||
) : Parcelable {
|
||||
|
||||
fun isGradient(): Boolean = linearGradient != null
|
||||
|
|
|
@ -384,7 +384,7 @@ object GroupsV2UpdateMessageConverter {
|
|||
updates.add(
|
||||
GroupChangeChatUpdate.Update(
|
||||
groupExpirationTimerUpdate = GroupExpirationTimerUpdate(
|
||||
expiresInMs = (change.newTimer!!.duration * 1000L).toUInt().toInt(),
|
||||
expiresInMs = (change.newTimer!!.duration * 1000L).toUInt().toLong(),
|
||||
updaterAci = if (editorUnknown) null else change.editorServiceIdBytes
|
||||
)
|
||||
)
|
||||
|
|
|
@ -234,7 +234,7 @@ final class GroupsV2UpdateMessageProducer {
|
|||
}
|
||||
}
|
||||
private void describeGroupExpirationTimerUpdate(@NonNull GroupExpirationTimerUpdate update, @NonNull List<UpdateDescription> updates) {
|
||||
final int duration = Math.toIntExact(Integer.toUnsignedLong(update.expiresInMs) / 1000);
|
||||
final int duration = Math.toIntExact(update.expiresInMs / 1000);
|
||||
String time = ExpirationUtil.getExpirationDisplayValue(context, duration);
|
||||
if (update.updaterAci == null) {
|
||||
updates.add(updateDescription(context.getString(R.string.MessageRecord_disappearing_message_time_set_to_s, time), R.drawable.ic_update_timer_16));
|
||||
|
|
|
@ -63,7 +63,7 @@ message AccountData {
|
|||
bool linkPreviews = 4;
|
||||
bool notDiscoverableByPhoneNumber = 5;
|
||||
bool preferContactAvatars = 6;
|
||||
uint32 universalExpireTimer = 7; // 0 means no universal expire timer.
|
||||
uint32 universalExpireTimerSeconds = 7; // 0 means no universal expire timer.
|
||||
repeated string preferredReactionEmoji = 8;
|
||||
bool displayBadgesOnProfile = 9;
|
||||
bool keepMutedChatsArchived = 10;
|
||||
|
@ -75,6 +75,7 @@ message AccountData {
|
|||
bool hasCompletedUsernameOnboarding = 16;
|
||||
PhoneNumberSharingMode phoneNumberSharingMode = 17;
|
||||
ChatStyle defaultChatStyle = 18;
|
||||
repeated ChatStyle.CustomChatColor customChatColors = 19;
|
||||
}
|
||||
|
||||
message SubscriberData {
|
||||
|
@ -564,7 +565,7 @@ message FilePointer {
|
|||
optional uint32 cdnNumber = 2;
|
||||
bytes key = 3;
|
||||
bytes digest = 4;
|
||||
uint32 size = 5;
|
||||
uint64 size = 5;
|
||||
// Fallback in case backup tier upload failed.
|
||||
optional string transitCdnKey = 6;
|
||||
optional uint32 transitCdnNumber = 7;
|
||||
|
@ -756,7 +757,7 @@ message SimpleChatUpdate {
|
|||
// For 1:1 chat updates only.
|
||||
// For group thread updates use GroupExpirationTimerUpdate.
|
||||
message ExpirationTimerChatUpdate {
|
||||
uint32 expiresInMs = 1; // 0 means the expiration timer was disabled
|
||||
uint64 expiresInMs = 1; // 0 means the expiration timer was disabled
|
||||
}
|
||||
|
||||
message ProfileChangeChatUpdate {
|
||||
|
@ -1022,7 +1023,7 @@ message GroupV2MigrationDroppedMembersUpdate {
|
|||
|
||||
// For 1:1 timer updates, use ExpirationTimerChatUpdate.
|
||||
message GroupExpirationTimerUpdate {
|
||||
uint32 expiresInMs = 1; // 0 means the expiration timer was disabled
|
||||
uint64 expiresInMs = 1; // 0 means the expiration timer was disabled
|
||||
optional bytes updaterAci = 2;
|
||||
}
|
||||
|
||||
|
@ -1034,10 +1035,19 @@ message StickerPack {
|
|||
message ChatStyle {
|
||||
message Gradient {
|
||||
uint32 angle = 1; // degrees
|
||||
repeated uint32 colors = 2;
|
||||
repeated fixed32 colors = 2;
|
||||
repeated float positions = 3; // percent from 0 to 1
|
||||
}
|
||||
|
||||
message CustomChatColor {
|
||||
uint64 id = 1;
|
||||
|
||||
oneof color {
|
||||
fixed32 solid = 2;
|
||||
Gradient gradient = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message AutomaticBubbleColor {
|
||||
}
|
||||
|
||||
|
@ -1098,10 +1108,14 @@ message ChatStyle {
|
|||
}
|
||||
|
||||
oneof bubbleColor {
|
||||
BubbleColorPreset bubbleColorPreset = 3;
|
||||
Gradient bubbleGradient = 4;
|
||||
uint32 bubbleSolidColor = 5;
|
||||
// Bubble setting is automatically determined based on the wallpaper setting.
|
||||
AutomaticBubbleColor autoBubbleColor = 6;
|
||||
// Bubble setting is automatically determined based on the wallpaper setting,
|
||||
// or `SOLID_ULTRAMARINE` for `noWallpaper`
|
||||
AutomaticBubbleColor autoBubbleColor = 3;
|
||||
BubbleColorPreset bubbleColorPreset = 4;
|
||||
|
||||
// See AccountSettings.customChatColors
|
||||
uint64 customColorId = 5;
|
||||
}
|
||||
|
||||
bool dimWallpaperInDarkMode = 7;
|
||||
}
|
Loading…
Add table
Reference in a new issue