From 176a703720eed007e91ca716e5331ef3fcc220cb Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 18 Sep 2024 15:23:07 -0300 Subject: [PATCH] Offer option to recycle backup after restoring The most common restore scenario is assumed to be moving from one device to another, like when the old one was lost or stolen. Most users probably don't continue to use the old device themselves still. Since they just restored this backup on their phone, most data is already in this backup. Deduplication allows re-using that, so it doesn't need to be saved again. --- .../seedvault/KoinInstrumentationTestApp.kt | 1 + .../seedvault/repo/AppBackupManager.kt | 24 +++++++ .../restore/RecycleBackupFragment.kt | 42 ++++++++++++ .../seedvault/restore/RestoreActivity.kt | 2 + .../seedvault/restore/RestoreUiModule.kt | 1 + .../seedvault/restore/RestoreViewModel.kt | 23 +++++++ .../res/drawable/ic_cloud_arrow_right.xml | 16 +++++ .../res/layout/fragment_recycle_backup.xml | 67 +++++++++++++++++++ app/src/main/res/values/strings.xml | 4 ++ .../seedvault/repo/AppBackupManagerTest.kt | 23 +++++++ 10 files changed, 203 insertions(+) create mode 100644 app/src/main/java/com/stevesoltys/seedvault/restore/RecycleBackupFragment.kt create mode 100644 app/src/main/res/drawable/ic_cloud_arrow_right.xml create mode 100644 app/src/main/res/layout/fragment_recycle_backup.xml diff --git a/app/src/androidTest/java/com/stevesoltys/seedvault/KoinInstrumentationTestApp.kt b/app/src/androidTest/java/com/stevesoltys/seedvault/KoinInstrumentationTestApp.kt index 8e405f2a..a55a1b7a 100644 --- a/app/src/androidTest/java/com/stevesoltys/seedvault/KoinInstrumentationTestApp.kt +++ b/app/src/androidTest/java/com/stevesoltys/seedvault/KoinInstrumentationTestApp.kt @@ -53,6 +53,7 @@ class KoinInstrumentationTestApp : App() { keyManager = get(), backupManager = get(), restoreCoordinator = get(), + appBackupManager = get(), apkRestore = get(), iconManager = get(), storageBackup = get(), diff --git a/app/src/main/java/com/stevesoltys/seedvault/repo/AppBackupManager.kt b/app/src/main/java/com/stevesoltys/seedvault/repo/AppBackupManager.kt index dc35b05f..7eff9bd4 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/repo/AppBackupManager.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/repo/AppBackupManager.kt @@ -9,6 +9,7 @@ import androidx.annotation.WorkerThread import com.stevesoltys.seedvault.MemoryLogger import com.stevesoltys.seedvault.backend.BackendManager import com.stevesoltys.seedvault.crypto.Crypto +import com.stevesoltys.seedvault.header.VERSION import com.stevesoltys.seedvault.settings.SettingsManager import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.delay @@ -112,6 +113,29 @@ internal class AppBackupManager( } } + /** + * Returns true if the repo identified by [repoId] can be transferred to this device. + * This is the case when it isn't the same as the current repoId and the version is latest. + */ + fun canRecycleBackupRepo(repoId: String?, version: Byte?): Boolean { + if (repoId == null || version == null) return false + return repoId != crypto.repoId && version == VERSION + } + + /** + * Transfers the ownership of the backup repository identified by the [oldRepoId] + * to the current user and device + * by renaming the [TopLevelFolder] of the repo to the current repoId. + */ + @Throws(IOException::class) + suspend fun recycleBackupRepo(oldRepoId: String) { + val newRepoId = crypto.repoId + if (oldRepoId == newRepoId) return + val oldFolder = TopLevelFolder(oldRepoId) + val newFolder = TopLevelFolder(newRepoId) + backendManager.backend.rename(oldFolder, newFolder) + } + /** * Careful, this removes the entire backup repository from the backend * and clears local blob cache. diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/RecycleBackupFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/RecycleBackupFragment.kt new file mode 100644 index 00000000..cf054368 --- /dev/null +++ b/app/src/main/java/com/stevesoltys/seedvault/restore/RecycleBackupFragment.kt @@ -0,0 +1,42 @@ +/* + * SPDX-FileCopyrightText: 2024 The Calyx Institute + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.stevesoltys.seedvault.restore + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.TextView +import androidx.fragment.app.Fragment +import com.stevesoltys.seedvault.R +import org.koin.androidx.viewmodel.ext.android.sharedViewModel + +class RecycleBackupFragment : Fragment() { + + private val viewModel: RestoreViewModel by sharedViewModel() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + val v: View = inflater.inflate(R.layout.fragment_recycle_backup, container, false) + + val backupName = viewModel.chosenRestorableBackup.value?.name + v.requireViewById(R.id.descriptionView).text = + getString(R.string.restore_recycle_backup_text, backupName) + + v.requireViewById