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