From 38adb519e31771eecfc616ad173236eb5294a32b Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Tue, 10 Jun 2025 10:32:45 -0400 Subject: [PATCH] Improve speed/feedback of final steps of backup restore. --- .../securesms/backup/v2/BackupRepository.kt | 2 ++ .../securesms/backup/v2/RestoreV2Event.kt | 2 +- .../securesms/jobs/ReclaimUsernameAndLinkJob.kt | 1 + .../securesms/jobs/RefreshAttributesJob.java | 9 +++++++++ .../securesms/jobs/RetrieveProfileAvatarJob.java | 11 ++++++++++- .../securesms/jobs/StorageAccountRestoreJob.kt | 5 +++-- .../org/thoughtcrime/securesms/jobs/StorageSyncJob.kt | 10 ++++++++-- .../ui/restore/RemoteRestoreActivity.kt | 7 ++++--- .../ui/restore/StorageServiceRestore.kt | 2 +- app/src/main/res/values/strings.xml | 2 ++ 10 files changed, 41 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt index 2d296c66d8..276f83eb24 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt @@ -974,6 +974,8 @@ object BackupRepository { eventTimer.emit("chatItem") } + EventBus.getDefault().post(RestoreV2Event(RestoreV2Event.Type.PROGRESS_FINALIZING, 0.bytes, 0.bytes)) + if (!importState.importedChatFolders) { // Add back default All Chats chat folder after clearing data if missing SignalDatabase.chatFolders.insertAllChatFolder() diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/RestoreV2Event.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/RestoreV2Event.kt index 3d7fdf006a..3111c7ea4c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/RestoreV2Event.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/RestoreV2Event.kt @@ -11,7 +11,7 @@ class RestoreV2Event(val type: Type, val count: ByteSize, val estimatedTotalCoun enum class Type { PROGRESS_DOWNLOAD, PROGRESS_RESTORE, - FINISHED + PROGRESS_FINALIZING } fun getProgress(): Float { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReclaimUsernameAndLinkJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReclaimUsernameAndLinkJob.kt index c93638a49a..d6e8f6fee9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReclaimUsernameAndLinkJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReclaimUsernameAndLinkJob.kt @@ -32,6 +32,7 @@ class ReclaimUsernameAndLinkJob private constructor(parameters: Parameters) : Jo constructor() : this( Parameters.Builder() + .setGlobalPriority(Parameters.PRIORITY_HIGH) .setQueue(StorageSyncJob.QUEUE_KEY) .addConstraint(NetworkConstraint.KEY) .setMaxAttempts(Parameters.UNLIMITED) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java index e009027409..24cd6e5ce5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RefreshAttributesJob.java @@ -40,6 +40,10 @@ public class RefreshAttributesJob extends BaseJob { private final boolean forced; + public static RefreshAttributesJob forAccountRestore() { + return new RefreshAttributesJob(true, Parameters.PRIORITY_HIGH); + } + public RefreshAttributesJob() { this(true); } @@ -49,7 +53,12 @@ public class RefreshAttributesJob extends BaseJob { * to run if it hasn't run yet this app cycle. */ public RefreshAttributesJob(boolean forced) { + this(forced, Parameters.PRIORITY_DEFAULT); + } + + private RefreshAttributesJob(boolean forced, @Parameters.Priority int priority) { this(new Job.Parameters.Builder() + .setGlobalPriority(priority) .addConstraint(NetworkConstraint.KEY) .setQueue("RefreshAttributesJob") .setMaxInstancesForFactory(2) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java index 96ef62ee0c..71818d0437 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java @@ -57,6 +57,10 @@ public class RetrieveProfileAvatarJob extends BaseJob { SignalExecutors.BOUNDED.execute(() -> AppDependencies.getJobManager().add(new RetrieveProfileAvatarJob(recipient, recipient.resolve().getProfileAvatar(), true, true))); } + public static RetrieveProfileAvatarJob forAccountRestore(Recipient recipient, String profileAvatar, boolean forceUpdate) { + return new RetrieveProfileAvatarJob(recipient, profileAvatar, forceUpdate, false, Parameters.PRIORITY_HIGH); + } + public RetrieveProfileAvatarJob(Recipient recipient, String profileAvatar) { this(recipient, profileAvatar, false); } @@ -66,7 +70,12 @@ public class RetrieveProfileAvatarJob extends BaseJob { } public RetrieveProfileAvatarJob(Recipient recipient, String profileAvatar, boolean forceUpdate, boolean forUnblurred) { - this(new Job.Parameters.Builder().setQueue("RetrieveProfileAvatarJob::" + recipient.getId().toQueueKey()) + this(recipient, profileAvatar, forceUpdate, forUnblurred, Parameters.PRIORITY_DEFAULT); + } + + private RetrieveProfileAvatarJob(Recipient recipient, String profileAvatar, boolean forceUpdate, boolean forUnblurred, @Parameters.Priority int priority) { + this(new Job.Parameters.Builder().setGlobalPriority(priority) + .setQueue("RetrieveProfileAvatarJob::" + recipient.getId().toQueueKey()) .addConstraint(NetworkConstraint.KEY) .setLifespan(TimeUnit.HOURS.toMillis(1)) .build(), diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageAccountRestoreJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageAccountRestoreJob.kt index c20e38ea22..c80a3bf53f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageAccountRestoreJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageAccountRestoreJob.kt @@ -33,6 +33,7 @@ class StorageAccountRestoreJob private constructor(parameters: Parameters) : Bas constructor() : this( Parameters.Builder() + .setGlobalPriority(Parameters.PRIORITY_HIGH) .setQueue(StorageSyncJob.QUEUE_KEY) .addConstraint(NetworkConstraint.KEY) .setMaxInstancesForFactory(1) @@ -129,7 +130,7 @@ class StorageAccountRestoreJob private constructor(parameters: Parameters) : Bas if (accountRecord.proto.avatarUrlPath.isNotEmpty()) { Log.i(TAG, "Fetching avatar...") - val state = AppDependencies.jobManager.runSynchronously(RetrieveProfileAvatarJob(self(), accountRecord.proto.avatarUrlPath, true), LIFESPAN / 2) + val state = AppDependencies.jobManager.runSynchronously(RetrieveProfileAvatarJob.forAccountRestore(self(), accountRecord.proto.avatarUrlPath, true), LIFESPAN / 2) if (state.isPresent) { Log.i(TAG, "Avatar retrieved successfully. ${state.get()}") @@ -141,7 +142,7 @@ class StorageAccountRestoreJob private constructor(parameters: Parameters) : Bas } Log.i(TAG, "Refreshing attributes...") - val state = AppDependencies.jobManager.runSynchronously(RefreshAttributesJob(), LIFESPAN / 2) + val state = AppDependencies.jobManager.runSynchronously(RefreshAttributesJob.forAccountRestore(), LIFESPAN / 2) if (state.isPresent) { Log.i(TAG, "Attributes refreshed successfully. ${state.get()}") diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.kt index dfa45e5e8c..5ab4671a2a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/StorageSyncJob.kt @@ -151,10 +151,16 @@ class StorageSyncJob private constructor(parameters: Parameters, private var loc fun forRemoteChange(): StorageSyncJob { return StorageSyncJob(localManifestOutOfDate = true) } + + fun forAccountRestore(): StorageSyncJob { + return StorageSyncJob(localManifestOutOfDate = true, priority = Parameters.PRIORITY_HIGH) + } } - constructor(localManifestOutOfDate: Boolean) : this( - Parameters.Builder().addConstraint(NetworkConstraint.KEY) + private constructor(localManifestOutOfDate: Boolean, @Parameters.Priority priority: Int = Parameters.PRIORITY_DEFAULT) : this( + Parameters.Builder() + .addConstraint(NetworkConstraint.KEY) + .setGlobalPriority(priority) .setQueue(QUEUE_KEY) .setMaxInstancesForFactory(2) .setLifespan(TimeUnit.DAYS.toMillis(1)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RemoteRestoreActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RemoteRestoreActivity.kt index bc937720b3..3e0c00da02 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RemoteRestoreActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/RemoteRestoreActivity.kt @@ -374,7 +374,7 @@ private fun RestoreProgressDialog(restoreProgress: RestoreV2Event?) { horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.wrapContentSize() ) { - if (restoreProgress == null) { + if (restoreProgress == null || restoreProgress.type == RestoreV2Event.Type.PROGRESS_FINALIZING) { CircularProgressIndicator( modifier = Modifier .padding(top = 55.dp, bottom = 16.dp) @@ -393,7 +393,8 @@ private fun RestoreProgressDialog(restoreProgress: RestoreV2Event?) { val progressText = when (restoreProgress?.type) { RestoreV2Event.Type.PROGRESS_DOWNLOAD -> stringResource(id = R.string.RemoteRestoreActivity__downloading_backup) - RestoreV2Event.Type.PROGRESS_RESTORE -> stringResource(id = R.string.RemoteRestoreActivity__downloading_backup) + RestoreV2Event.Type.PROGRESS_RESTORE -> stringResource(id = R.string.RemoteRestoreActivity__restoring_messages) + RestoreV2Event.Type.PROGRESS_FINALIZING -> stringResource(id = R.string.RemoteRestoreActivity__finishing_restore) else -> stringResource(id = R.string.RemoteRestoreActivity__restoring) } @@ -403,7 +404,7 @@ private fun RestoreProgressDialog(restoreProgress: RestoreV2Event?) { modifier = Modifier.padding(bottom = 12.dp) ) - if (restoreProgress != null) { + if (restoreProgress != null && restoreProgress.type != RestoreV2Event.Type.PROGRESS_FINALIZING) { val progressBytes = restoreProgress.count.toUnitString() val totalBytes = restoreProgress.estimatedTotalCount.toUnitString() Text( diff --git a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/StorageServiceRestore.kt b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/StorageServiceRestore.kt index 63d33a1740..c0d79b6f6c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/StorageServiceRestore.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/registrationv3/ui/restore/StorageServiceRestore.kt @@ -41,7 +41,7 @@ object StorageServiceRestore { AppDependencies .jobManager - .startChain(StorageSyncJob.forRemoteChange()) + .startChain(StorageSyncJob.forAccountRestore()) .then(ReclaimUsernameAndLinkJob()) .enqueueBlocking(10.seconds) stopwatch.split("storage-sync-restore") diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index df51e29669..f48661846b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1446,6 +1446,8 @@ Downloading backup… Restoring messages… + + Finishing… Restoring…