mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 00:59:49 +01:00
Add restore local backupv2 infra.
This commit is contained in:
@@ -53,6 +53,7 @@ import org.signal.core.util.requireBlob
|
||||
import org.signal.core.util.requireBoolean
|
||||
import org.signal.core.util.requireInt
|
||||
import org.signal.core.util.requireLong
|
||||
import org.signal.core.util.requireLongOrNull
|
||||
import org.signal.core.util.requireNonNullBlob
|
||||
import org.signal.core.util.requireNonNullString
|
||||
import org.signal.core.util.requireObject
|
||||
@@ -495,7 +496,7 @@ class AttachmentTable(
|
||||
return readableDatabase
|
||||
.select(*PROJECTION)
|
||||
.from(TABLE_NAME)
|
||||
.where("$TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE.toString())
|
||||
.where("$TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE)
|
||||
.limit(batchSize)
|
||||
.orderBy("$ID DESC")
|
||||
.run()
|
||||
@@ -508,7 +509,7 @@ class AttachmentTable(
|
||||
return readableDatabase
|
||||
.select(*PROJECTION)
|
||||
.from(TABLE_NAME)
|
||||
.where("$REMOTE_KEY IS NOT NULL AND $REMOTE_DIGEST IS NOT NULL AND $TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE.toString())
|
||||
.where("$TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE)
|
||||
.limit(batchSize)
|
||||
.orderBy("$ID DESC")
|
||||
.run()
|
||||
@@ -517,17 +518,17 @@ class AttachmentTable(
|
||||
attachmentId = AttachmentId(it.requireLong(ID)),
|
||||
mmsId = it.requireLong(MESSAGE_ID),
|
||||
size = it.requireLong(DATA_SIZE),
|
||||
remoteDigest = it.requireBlob(REMOTE_DIGEST)!!,
|
||||
remoteKey = it.requireBlob(REMOTE_KEY)!!
|
||||
remoteDigest = it.requireBlob(REMOTE_DIGEST),
|
||||
remoteKey = it.requireBlob(REMOTE_KEY)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun getTotalRestorableAttachmentSize(): Long {
|
||||
fun getRemainingRestorableAttachmentSize(): Long {
|
||||
return readableDatabase
|
||||
.select("SUM($DATA_SIZE)")
|
||||
.from(TABLE_NAME)
|
||||
.where("$TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE.toString())
|
||||
.where("$TRANSFER_STATE = ? OR $TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE, TRANSFER_RESTORE_IN_PROGRESS)
|
||||
.run()
|
||||
.readToSingleLong()
|
||||
}
|
||||
@@ -628,7 +629,7 @@ class AttachmentTable(
|
||||
.where("$MESSAGE_ID = ?", mmsId)
|
||||
.run()
|
||||
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
|
||||
|
||||
deleteCount > 0
|
||||
}
|
||||
@@ -692,7 +693,7 @@ class AttachmentTable(
|
||||
.where("$MESSAGE_ID = ?", messageId)
|
||||
.run()
|
||||
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
|
||||
|
||||
val threadId = messages.getThreadIdForMessage(messageId)
|
||||
if (threadId > 0) {
|
||||
@@ -729,7 +730,7 @@ class AttachmentTable(
|
||||
.run()
|
||||
|
||||
deleteDataFileIfPossible(data, contentType, id)
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -849,7 +850,7 @@ class AttachmentTable(
|
||||
|
||||
FileUtils.deleteDirectoryContents(context.getDir(DIRECTORY, Context.MODE_PRIVATE))
|
||||
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
|
||||
}
|
||||
|
||||
fun setTransferState(messageId: Long, attachmentId: AttachmentId, transferState: Int) {
|
||||
@@ -874,7 +875,6 @@ class AttachmentTable(
|
||||
notifyConversationListeners(threadId)
|
||||
}
|
||||
|
||||
@Throws(MmsException::class)
|
||||
fun setTransferProgressFailed(attachmentId: AttachmentId, mmsId: Long) {
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
@@ -885,7 +885,6 @@ class AttachmentTable(
|
||||
notifyConversationListeners(messages.getThreadIdForMessage(mmsId))
|
||||
}
|
||||
|
||||
@Throws(MmsException::class)
|
||||
fun setThumbnailRestoreProgressFailed(attachmentId: AttachmentId, mmsId: Long) {
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
@@ -896,7 +895,6 @@ class AttachmentTable(
|
||||
notifyConversationListeners(messages.getThreadIdForMessage(mmsId))
|
||||
}
|
||||
|
||||
@Throws(MmsException::class)
|
||||
fun setTransferProgressPermanentFailure(attachmentId: AttachmentId, mmsId: Long) {
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
@@ -907,6 +905,57 @@ class AttachmentTable(
|
||||
notifyConversationListeners(messages.getThreadIdForMessage(mmsId))
|
||||
}
|
||||
|
||||
fun setRestoreInProgressTransferState(restorableAttachments: List<LocalRestorableAttachment>) {
|
||||
setRestoreTransferState(
|
||||
restorableAttachments = restorableAttachments,
|
||||
prefix = "$TRANSFER_STATE = $TRANSFER_NEEDS_RESTORE",
|
||||
state = TRANSFER_RESTORE_IN_PROGRESS
|
||||
)
|
||||
}
|
||||
|
||||
fun setRestoreFailedTransferState(notRestorableAttachments: List<LocalRestorableAttachment>) {
|
||||
setRestoreTransferState(
|
||||
restorableAttachments = notRestorableAttachments,
|
||||
prefix = "$TRANSFER_STATE != $TRANSFER_PROGRESS_PERMANENT_FAILURE",
|
||||
state = TRANSFER_PROGRESS_FAILED
|
||||
)
|
||||
}
|
||||
|
||||
private fun setRestoreTransferState(restorableAttachments: List<LocalRestorableAttachment>, prefix: String, state: Int) {
|
||||
writableDatabase.withinTransaction {
|
||||
val setQueries = SqlUtil.buildCollectionQuery(
|
||||
column = ID,
|
||||
values = restorableAttachments.map { it.attachmentId.id },
|
||||
prefix = "$prefix AND"
|
||||
)
|
||||
|
||||
setQueries.forEach { query ->
|
||||
writableDatabase
|
||||
.update(TABLE_NAME)
|
||||
.values(TRANSFER_STATE to state)
|
||||
.where(query.where, query.whereArgs)
|
||||
.run()
|
||||
}
|
||||
|
||||
val threadQueries = SqlUtil.buildCollectionQuery(
|
||||
column = MessageTable.ID,
|
||||
values = restorableAttachments.map { it.mmsId }
|
||||
)
|
||||
|
||||
val threads = mutableSetOf<Long>()
|
||||
threadQueries.forEach { query ->
|
||||
threads += readableDatabase
|
||||
.select("DISTINCT ${MessageTable.THREAD_ID}")
|
||||
.from(MessageTable.TABLE_NAME)
|
||||
.where(query.where, query.whereArgs)
|
||||
.run()
|
||||
.readToList { it.requireLongOrNull(MessageTable.THREAD_ID) ?: -1 }
|
||||
}
|
||||
|
||||
notifyConversationListeners(threads)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When we find out about a new inbound attachment pointer, we insert a row for it that contains all the info we need to download it via [insertAttachmentWithData].
|
||||
* Later, we download the data for that pointer. Call this method once you have the data to associate it with the attachment. At this point, it is assumed
|
||||
@@ -982,7 +1031,7 @@ class AttachmentTable(
|
||||
|
||||
notifyConversationListeners(threadId)
|
||||
notifyConversationListListeners()
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
|
||||
|
||||
if (foundDuplicate) {
|
||||
if (!fileWriteResult.file.delete()) {
|
||||
@@ -1020,7 +1069,7 @@ class AttachmentTable(
|
||||
}
|
||||
|
||||
notifyConversationListListeners()
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
|
||||
|
||||
if (!transferFile.delete()) {
|
||||
Log.w(TAG, "Unable to delete transfer file.")
|
||||
@@ -1904,7 +1953,7 @@ class AttachmentTable(
|
||||
AttachmentId(rowId)
|
||||
}
|
||||
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
|
||||
return attachmentId
|
||||
}
|
||||
|
||||
@@ -1961,7 +2010,7 @@ class AttachmentTable(
|
||||
AttachmentId(rowId)
|
||||
}
|
||||
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
|
||||
return attachmentId
|
||||
}
|
||||
|
||||
@@ -2101,7 +2150,7 @@ class AttachmentTable(
|
||||
}
|
||||
}
|
||||
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
|
||||
return attachmentId
|
||||
}
|
||||
|
||||
@@ -2460,7 +2509,7 @@ class AttachmentTable(
|
||||
val attachmentId: AttachmentId,
|
||||
val mmsId: Long,
|
||||
val size: Long,
|
||||
val remoteDigest: ByteArray,
|
||||
val remoteKey: ByteArray
|
||||
val remoteDigest: ByteArray?,
|
||||
val remoteKey: ByteArray?
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
@@ -24,7 +22,7 @@ import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Allows listening to database changes to varying degrees of specificity.
|
||||
*
|
||||
* <p>
|
||||
* A replacement for the observer system in {@link DatabaseTable}. We should move to this over time.
|
||||
*/
|
||||
public class DatabaseObserver {
|
||||
@@ -46,11 +44,10 @@ public class DatabaseObserver {
|
||||
private static final String KEY_SCHEDULED_MESSAGES = "ScheduledMessages";
|
||||
private static final String KEY_CONVERSATION_DELETES = "ConversationDeletes";
|
||||
|
||||
private static final String KEY_CALL_UPDATES = "CallUpdates";
|
||||
private static final String KEY_CALL_LINK_UPDATES = "CallLinkUpdates";
|
||||
private static final String KEY_IN_APP_PAYMENTS = "InAppPayments";
|
||||
private static final String KEY_CALL_UPDATES = "CallUpdates";
|
||||
private static final String KEY_CALL_LINK_UPDATES = "CallLinkUpdates";
|
||||
private static final String KEY_IN_APP_PAYMENTS = "InAppPayments";
|
||||
|
||||
private final Application application;
|
||||
private final Executor executor;
|
||||
|
||||
private final Set<Observer> conversationListObservers;
|
||||
@@ -63,7 +60,8 @@ public class DatabaseObserver {
|
||||
private final Set<Observer> chatColorsObservers;
|
||||
private final Set<Observer> stickerObservers;
|
||||
private final Set<Observer> stickerPackObservers;
|
||||
private final Set<Observer> attachmentObservers;
|
||||
private final Set<Observer> attachmentUpdatedObservers;
|
||||
private final Set<Observer> attachmentDeletedObservers;
|
||||
private final Set<MessageObserver> messageUpdateObservers;
|
||||
private final Map<Long, Set<MessageObserver>> messageInsertObservers;
|
||||
private final Set<Observer> notificationProfileObservers;
|
||||
@@ -72,8 +70,7 @@ public class DatabaseObserver {
|
||||
private final Map<CallLinkRoomId, Set<Observer>> callLinkObservers;
|
||||
private final Set<InAppPaymentObserver> inAppPaymentObservers;
|
||||
|
||||
public DatabaseObserver(Application application) {
|
||||
this.application = application;
|
||||
public DatabaseObserver() {
|
||||
this.executor = new SerialExecutor(SignalExecutors.BOUNDED);
|
||||
this.conversationListObservers = new HashSet<>();
|
||||
this.conversationObservers = new HashMap<>();
|
||||
@@ -84,7 +81,8 @@ public class DatabaseObserver {
|
||||
this.chatColorsObservers = new HashSet<>();
|
||||
this.stickerObservers = new HashSet<>();
|
||||
this.stickerPackObservers = new HashSet<>();
|
||||
this.attachmentObservers = new HashSet<>();
|
||||
this.attachmentUpdatedObservers = new HashSet<>();
|
||||
this.attachmentDeletedObservers = new HashSet<>();
|
||||
this.messageUpdateObservers = new HashSet<>();
|
||||
this.messageInsertObservers = new HashMap<>();
|
||||
this.notificationProfileObservers = new HashSet<>();
|
||||
@@ -149,9 +147,15 @@ public class DatabaseObserver {
|
||||
});
|
||||
}
|
||||
|
||||
public void registerAttachmentObserver(@NonNull Observer listener) {
|
||||
public void registerAttachmentUpdatedObserver(@NonNull Observer listener) {
|
||||
executor.execute(() -> {
|
||||
attachmentObservers.add(listener);
|
||||
attachmentUpdatedObservers.add(listener);
|
||||
});
|
||||
}
|
||||
|
||||
public void registerAttachmentDeletedObserver(@NonNull Observer listener) {
|
||||
executor.execute(() -> {
|
||||
attachmentDeletedObservers.add(listener);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -211,7 +215,8 @@ public class DatabaseObserver {
|
||||
chatColorsObservers.remove(listener);
|
||||
stickerObservers.remove(listener);
|
||||
stickerPackObservers.remove(listener);
|
||||
attachmentObservers.remove(listener);
|
||||
attachmentUpdatedObservers.remove(listener);
|
||||
attachmentDeletedObservers.remove(listener);
|
||||
notificationProfileObservers.remove(listener);
|
||||
unregisterMapped(storyObservers, listener);
|
||||
unregisterMapped(scheduledMessageObservers, listener);
|
||||
@@ -307,9 +312,16 @@ public class DatabaseObserver {
|
||||
});
|
||||
}
|
||||
|
||||
public void notifyAttachmentObservers() {
|
||||
public void notifyAttachmentUpdatedObservers() {
|
||||
runPostSuccessfulTransaction(KEY_ATTACHMENTS, () -> {
|
||||
notifySet(attachmentObservers);
|
||||
notifySet(attachmentUpdatedObservers);
|
||||
});
|
||||
}
|
||||
|
||||
public void notifyAttachmentDeletedObservers() {
|
||||
runPostSuccessfulTransaction(KEY_ATTACHMENTS, () -> {
|
||||
notifySet(attachmentDeletedObservers);
|
||||
notifySet(attachmentUpdatedObservers);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -71,10 +71,6 @@ public abstract class DatabaseTable {
|
||||
AppDependencies.getDatabaseObserver().notifyStickerObservers();
|
||||
}
|
||||
|
||||
protected void notifyAttachmentListeners() {
|
||||
AppDependencies.getDatabaseObserver().notifyAttachmentObservers();
|
||||
}
|
||||
|
||||
public void reset(SignalDatabase databaseHelper) {
|
||||
this.databaseHelper = databaseHelper;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import android.database.Cursor
|
||||
import androidx.compose.runtime.Immutable
|
||||
import org.signal.core.util.requireInt
|
||||
import org.signal.core.util.requireLong
|
||||
import org.signal.core.util.requireNonNullString
|
||||
import org.signal.core.util.requireString
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
@@ -159,6 +159,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
)
|
||||
)"""
|
||||
)
|
||||
|
||||
private fun applyEqualityOperator(threadId: Long, query: String): String {
|
||||
return query.replace("__EQUALITY__", if (threadId == ALL_THREADS.toLong()) "!=" else "=")
|
||||
}
|
||||
@@ -207,7 +208,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
readableDatabase.rawQuery(UNIQUE_MEDIA_QUERY, null).use { cursor ->
|
||||
while (cursor.moveToNext()) {
|
||||
val size: Int = cursor.requireInt(AttachmentTable.DATA_SIZE)
|
||||
val type: String = cursor.requireNonNullString(AttachmentTable.CONTENT_TYPE)
|
||||
val type: String? = cursor.requireString(AttachmentTable.CONTENT_TYPE)
|
||||
|
||||
when (MediaUtil.getSlideTypeFromContentType(type)) {
|
||||
SlideType.GIF,
|
||||
@@ -215,17 +216,21 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
SlideType.MMS -> {
|
||||
photoSize += size.toLong()
|
||||
}
|
||||
|
||||
SlideType.VIDEO -> {
|
||||
videoSize += size.toLong()
|
||||
}
|
||||
|
||||
SlideType.AUDIO -> {
|
||||
audioSize += size.toLong()
|
||||
}
|
||||
|
||||
SlideType.LONG_TEXT,
|
||||
SlideType.DOCUMENT -> {
|
||||
documentSize += size.toLong()
|
||||
}
|
||||
else -> {}
|
||||
|
||||
SlideType.VIEW_ONCE -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2115,7 +2115,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
||||
AppDependencies.databaseObserver.notifyConversationListListeners()
|
||||
|
||||
if (deletedAttachments) {
|
||||
AppDependencies.databaseObserver.notifyAttachmentObservers()
|
||||
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -361,7 +361,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
MultiDeviceDeleteSyncJob.enqueueThreadDeletes(threadTrimsToSync, isFullDelete = false)
|
||||
}
|
||||
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentUpdatedObservers()
|
||||
notifyStickerPackListeners()
|
||||
OptimizeMessageSearchIndexJob.enqueue()
|
||||
}
|
||||
@@ -395,7 +395,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
||||
MultiDeviceDeleteSyncJob.enqueueThreadDeletes(listOf(threadTrimToSync!!), isFullDelete = false)
|
||||
}
|
||||
|
||||
notifyAttachmentListeners()
|
||||
AppDependencies.databaseObserver.notifyAttachmentDeletedObservers()
|
||||
notifyStickerPackListeners()
|
||||
OptimizeMessageSearchIndexJob.enqueue()
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public final class GroupedThreadMediaLoader extends AsyncTaskLoader<GroupedThrea
|
||||
|
||||
PopulatedGroupedThreadMedia mediaGrouping = new PopulatedGroupedThreadMedia(groupingMethod);
|
||||
|
||||
AppDependencies.getDatabaseObserver().registerAttachmentObserver(observer);
|
||||
AppDependencies.getDatabaseObserver().registerAttachmentUpdatedObserver(observer);
|
||||
|
||||
try (Cursor cursor = ThreadMediaLoader.createThreadMediaCursor(context, threadId, mediaType, sorting)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
|
||||
Reference in New Issue
Block a user