Improve speed/feedback of final steps of backup restore.

This commit is contained in:
Cody Henthorne
2025-06-10 10:32:45 -04:00
committed by GitHub
parent 37c3578329
commit 38adb519e3
10 changed files with 41 additions and 10 deletions

View File

@@ -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()

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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)

View File

@@ -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(),

View File

@@ -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()}")

View File

@@ -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))

View File

@@ -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(

View File

@@ -41,7 +41,7 @@ object StorageServiceRestore {
AppDependencies
.jobManager
.startChain(StorageSyncJob.forRemoteChange())
.startChain(StorageSyncJob.forAccountRestore())
.then(ReclaimUsernameAndLinkJob())
.enqueueBlocking(10.seconds)
stopwatch.split("storage-sync-restore")

View File

@@ -1446,6 +1446,8 @@
<string name="RemoteRestoreActivity__downloading_backup">Downloading backup…</string>
<!-- Progress dialog label when restoring a backup -->
<string name="RemoteRestoreActivity__restoring_messages">Restoring messages…</string>
<!-- Progress dialog label when finishing a backup restore -->
<string name="RemoteRestoreActivity__finishing_restore">Finishing…</string>
<!-- Progress dialog label while awaiting updates -->
<string name="RemoteRestoreActivity__restoring">Restoring…</string>
<!-- Progress readout for dialog while downloading or restoring a backup. First placeholder is the formatted size of the backup downloaded, the second is formatted total amount to go, and the last is a percentage. -->