Port auto restore optimization from legacy v0 code to new v1 code
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt
index 520b564..ed55267 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/KVRestore.kt
@@ -34,8 +34,7 @@
     /**
      * Optional [PackageInfo] for single package restore, optimizes restore of @pm@
      */
-    @Deprecated("TODO remove?")
-    val pmPackageInfo: PackageInfo?
+    val autoRestorePackageInfo: PackageInfo?
 )
 
 private val TAG = KVRestore::class.java.simpleName
@@ -70,16 +69,16 @@
      * It is possible that the system decides to not restore the package.
      * Then a new state will be initialized right away without calling other methods.
      *
-     * @param pmPackageInfo single optional [PackageInfo] to optimize restore of @pm@
+     * @param autoRestorePackageInfo single optional [PackageInfo] to optimize restore of @pm@
      */
     fun initializeState(
         version: Byte,
         token: Long,
         name: String,
         packageInfo: PackageInfo,
-        pmPackageInfo: PackageInfo? = null
+        autoRestorePackageInfo: PackageInfo? = null
     ) {
-        state = KVRestoreState(version, token, name, packageInfo, pmPackageInfo)
+        state = KVRestoreState(version, token, name, packageInfo, autoRestorePackageInfo)
     }
 
     /**
@@ -95,10 +94,20 @@
         // take legacy path for version 0
         if (state.version == 0x00.toByte()) return getRestoreDataV0(state, data)
 
+        val pmPackageName = state.autoRestorePackageInfo?.packageName
+        val isAutoRestore = state.packageInfo.packageName == MAGIC_PACKAGE_MANAGER &&
+            pmPackageName != null
         return try {
-            val db = getRestoreDb(state)
+            val db = if (isAutoRestore) getCachedRestoreDb(state) else downloadRestoreDb(state)
             val out = outputFactory.getBackupDataOutput(data)
-            db.getAll().sortedBy { it.first }.forEach { (key, value) ->
+            val records = if (isAutoRestore) {
+                val keys = listOf(ANCESTRAL_RECORD_KEY, GLOBAL_METADATA_KEY, pmPackageName)
+                Log.d(TAG, "Single package restore, restrict restore keys to $pmPackageName")
+                db.getAll().filter { it.first in keys }
+            } else {
+                db.getAll()
+            }
+            records.sortedBy { it.first }.forEach { (key, value) ->
                 val size = value.size
                 Log.v(TAG, "    ... key=$key size=$size")
                 out.writeEntityHeader(key, size)
@@ -125,7 +134,17 @@
     }
 
     @Throws(IOException::class, GeneralSecurityException::class, UnsupportedVersionException::class)
-    private suspend fun getRestoreDb(state: KVRestoreState): KVDb {
+    private suspend fun getCachedRestoreDb(state: KVRestoreState): KVDb {
+        val packageName = state.packageInfo.packageName
+        return if (dbManager.existsDb(packageName)) {
+            dbManager.getDb(packageName)
+        } else {
+            downloadRestoreDb(state)
+        }
+    }
+
+    @Throws(IOException::class, GeneralSecurityException::class, UnsupportedVersionException::class)
+    private suspend fun downloadRestoreDb(state: KVRestoreState): KVDb {
         val packageName = state.packageInfo.packageName
         plugin.getInputStream(state.token, state.name).use { inputStream ->
             headerReader.readVersion(inputStream, state.version)
@@ -198,18 +217,11 @@
         if (records.isEmpty()) return null
 
         // Decode the key filenames into keys then sort lexically by key
-        val contents = ArrayList<DecodedKey>()
-        for (recordKey in records) contents.add(DecodedKey(recordKey))
-        // remove keys that are not needed for single package @pm@ restore
-        val pmPackageName = state?.pmPackageInfo?.packageName
-        val sortedKeys =
-            if (packageInfo.packageName == MAGIC_PACKAGE_MANAGER && pmPackageName != null) {
-                val keys = listOf(ANCESTRAL_RECORD_KEY, GLOBAL_METADATA_KEY, pmPackageName)
-                Log.d(TAG, "Single package restore, restrict restore keys to $pmPackageName")
-                contents.filterTo(ArrayList()) { it.key in keys }
-            } else contents
-        sortedKeys.sort()
-        return sortedKeys
+        val contents = ArrayList<DecodedKey>().apply {
+            for (recordKey in records) add(DecodedKey(recordKey))
+        }
+        contents.sort()
+        return contents
     }
 
     /**
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt
index d73e738..9d700d5 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinator.kt
@@ -20,8 +20,8 @@
 import com.stevesoltys.seedvault.metadata.DecryptionFailedException
 import com.stevesoltys.seedvault.metadata.MetadataManager
 import com.stevesoltys.seedvault.metadata.MetadataReader
-import com.stevesoltys.seedvault.settings.SettingsManager
 import com.stevesoltys.seedvault.plugins.StoragePlugin
+import com.stevesoltys.seedvault.settings.SettingsManager
 import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
 import java.io.IOException
 
@@ -31,7 +31,7 @@
     /**
      * Optional [PackageInfo] for single package restore, to reduce data needed to read for @pm@
      */
-    val pmPackageInfo: PackageInfo?,
+    val autoRestorePackageInfo: PackageInfo?,
     val backupMetadata: BackupMetadata
 ) {
     var currentPackage: String? = null
@@ -212,7 +212,7 @@
                             token = state.token,
                             name = name,
                             packageInfo = packageInfo,
-                            pmPackageInfo = state.pmPackageInfo
+                            autoRestorePackageInfo = state.autoRestorePackageInfo
                         )
                         state.currentPackage = packageName
                         TYPE_KEY_VALUE
@@ -249,7 +249,7 @@
                 // check key/value data first and if available, don't even check for full data
                 kv.hasDataForPackage(state.token, packageInfo) -> {
                     Log.i(TAG, "Found K/V data for $packageName.")
-                    kv.initializeState(0x00, state.token, "", packageInfo, state.pmPackageInfo)
+                    kv.initializeState(0x00, state.token, "", packageInfo, null)
                     state.currentPackage = packageName
                     TYPE_KEY_VALUE
                 }