Use new storage API for full restore
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt
index 6769036..67fc1da 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt
@@ -12,6 +12,7 @@
 import com.stevesoltys.seedvault.header.MAX_SEGMENT_LENGTH
 import com.stevesoltys.seedvault.header.UnsupportedVersionException
 import com.stevesoltys.seedvault.header.getADForFull
+import com.stevesoltys.seedvault.transport.backup.BackupPlugin
 import libcore.io.IoUtils.closeQuietly
 import java.io.EOFException
 import java.io.IOException
@@ -22,6 +23,7 @@
 private class FullRestoreState(
     val version: Byte,
     val token: Long,
+    val name: String,
     val packageInfo: PackageInfo
 ) {
     var inputStream: InputStream? = null
@@ -31,7 +33,8 @@
 
 @Suppress("BlockingMethodInNonBlockingContext")
 internal class FullRestore(
-    private val plugin: FullRestorePlugin,
+    private val plugin: BackupPlugin,
+    private val legacyPlugin: FullRestorePlugin,
     private val outputFactory: OutputFactory,
     private val headerReader: HeaderReader,
     private val crypto: Crypto
@@ -43,10 +46,13 @@
 
     /**
      * Return true if there is data stored for the given package.
+     *
+     * Deprecated. Use only for v0 backups.
      */
     @Throws(IOException::class)
+    @Deprecated("Use BackupPlugin#hasData() instead")
     suspend fun hasDataForPackage(token: Long, packageInfo: PackageInfo): Boolean {
-        return plugin.hasDataForPackage(token, packageInfo)
+        return legacyPlugin.hasDataForPackage(token, packageInfo)
     }
 
     /**
@@ -55,8 +61,8 @@
      * 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.
      */
-    fun initializeState(version: Byte, token: Long, packageInfo: PackageInfo) {
-        state = FullRestoreState(version, token, packageInfo)
+    fun initializeState(version: Byte, token: Long, name: String, packageInfo: PackageInfo) {
+        state = FullRestoreState(version, token, name, packageInfo)
     }
 
     /**
@@ -93,12 +99,16 @@
         if (state.inputStream == null) {
             Log.i(TAG, "First Chunk, initializing package input stream.")
             try {
-                val inputStream = plugin.getInputStreamForPackage(state.token, state.packageInfo)
-                val version = headerReader.readVersion(inputStream, state.version)
-                if (version == 0.toByte()) {
+                if (state.version == 0.toByte()) {
+                    val inputStream =
+                        legacyPlugin.getInputStreamForPackage(state.token, state.packageInfo)
+                    val version = headerReader.readVersion(inputStream, state.version)
+                    @Suppress("deprecation")
                     crypto.decryptHeader(inputStream, version, packageName)
                     state.inputStream = inputStream
                 } else {
+                    val inputStream = plugin.getInputStream(state.token, state.name)
+                    val version = headerReader.readVersion(inputStream, state.version)
                     val ad = getADForFull(version, packageName)
                     state.inputStream = crypto.newDecryptingStream(inputStream, ad)
                 }
@@ -135,6 +145,7 @@
         if (state.version == 0.toByte()) {
             // read segment from input stream and decrypt it
             val decrypted = try {
+                @Suppress("deprecation")
                 crypto.decryptSegment(inputStream)
             } catch (e: EOFException) {
                 Log.i(TAG, "   EOF")
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 5951185..0859cda 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
@@ -216,7 +216,7 @@
                     val name = crypto.getNameForPackage(state.backupMetadata.salt, packageName)
                     if (plugin.hasData(state.token, name)) {
                         Log.i(TAG, "Found full backup data for $packageName.")
-                        full.initializeState(version, state.token, packageInfo)
+                        full.initializeState(version, state.token, name, packageInfo)
                         state.currentPackage = packageName
                         TYPE_FULL_STREAM
                     } else throw IOException("No data found for $packageName. Skipping.")
@@ -232,6 +232,7 @@
         return RestoreDescription(packageName, type)
     }
 
+    @Suppress("deprecation")
     private suspend fun nextRestorePackageV0(
         state: RestoreCoordinatorState,
         packageInfo: PackageInfo
@@ -248,7 +249,7 @@
                 }
                 full.hasDataForPackage(state.token, packageInfo) -> {
                     Log.i(TAG, "Found full backup data for $packageName.")
-                    full.initializeState(0x00, state.token, packageInfo)
+                    full.initializeState(0x00, state.token, "", packageInfo)
                     state.currentPackage = packageName
                     TYPE_FULL_STREAM
                 }
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreModule.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreModule.kt
index 833b47d..62756a8 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreModule.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/RestoreModule.kt
@@ -6,7 +6,7 @@
 val restoreModule = module {
     single { OutputFactory() }
     single { KVRestore(get<RestorePlugin>().kvRestorePlugin, get(), get(), get()) }
-    single { FullRestore(get<RestorePlugin>().fullRestorePlugin, get(), get(), get()) }
+    single { FullRestore(get(), get<RestorePlugin>().fullRestorePlugin, get(), get(), get()) }
     single {
         RestoreCoordinator(androidContext(), get(), get(), get(), get(), get(), get(), get(), get())
     }
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/CoordinatorIntegrationTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/CoordinatorIntegrationTest.kt
index 5098851..7c52c3d 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/CoordinatorIntegrationTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/CoordinatorIntegrationTest.kt
@@ -97,7 +97,7 @@
     private val kvRestore = KVRestore(kvRestorePlugin, outputFactory, headerReader, cryptoImpl)
     private val fullRestorePlugin = mockk<FullRestorePlugin>()
     private val fullRestore =
-        FullRestore(fullRestorePlugin, outputFactory, headerReader, cryptoImpl)
+        FullRestore(backupPlugin, fullRestorePlugin, outputFactory, headerReader, cryptoImpl)
     private val restore = RestoreCoordinator(
         context,
         crypto,
@@ -122,7 +122,9 @@
     private val key264 = key2.encodeBase64()
 
     init {
+        @Suppress("deprecation")
         every { backupPlugin.kvBackupPlugin } returns kvBackupPlugin
+        @Suppress("deprecation")
         every { backupPlugin.fullBackupPlugin } returns fullBackupPlugin
     }
 
@@ -349,12 +351,7 @@
         // reverse the backup streams into restore input
         val rInputStream = ByteArrayInputStream(bOutputStream.toByteArray())
         val rOutputStream = ByteArrayOutputStream()
-        coEvery {
-            fullRestorePlugin.getInputStreamForPackage(
-                token,
-                packageInfo
-            )
-        } returns rInputStream
+        coEvery { backupPlugin.getInputStream(token, name) } returns rInputStream
         every { outputFactory.getOutputStream(fileDescriptor) } returns rOutputStream
 
         // restore data
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt
index 9764377..e689805 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt
@@ -11,6 +11,7 @@
 import com.stevesoltys.seedvault.header.VERSION
 import com.stevesoltys.seedvault.header.VersionHeader
 import com.stevesoltys.seedvault.header.getADForFull
+import com.stevesoltys.seedvault.transport.backup.BackupPlugin
 import io.mockk.CapturingSlot
 import io.mockk.Runs
 import io.mockk.coEvery
@@ -32,8 +33,9 @@
 @Suppress("BlockingMethodInNonBlockingContext")
 internal class FullRestoreTest : RestoreTest() {
 
-    private val plugin = mockk<FullRestorePlugin>()
-    private val restore = FullRestore(plugin, outputFactory, headerReader, crypto)
+    private val plugin = mockk<BackupPlugin>()
+    private val legacyPlugin = mockk<FullRestorePlugin>()
+    private val restore = FullRestore(plugin, legacyPlugin, outputFactory, headerReader, crypto)
 
     private val encrypted = getRandomByteArray()
     private val outputStream = ByteArrayOutputStream()
@@ -45,16 +47,17 @@
     }
 
     @Test
-    fun `hasDataForPackage() delegates to plugin`() = runBlocking {
+    @Suppress("deprecation")
+    fun `v0 hasDataForPackage() delegates to plugin`() = runBlocking {
         val result = Random.nextBoolean()
-        coEvery { plugin.hasDataForPackage(token, packageInfo) } returns result
+        coEvery { legacyPlugin.hasDataForPackage(token, packageInfo) } returns result
         assertEquals(result, restore.hasDataForPackage(token, packageInfo))
     }
 
     @Test
     fun `initializing state leaves a state`() {
         assertFalse(restore.hasState())
-        restore.initializeState(VERSION, token, packageInfo)
+        restore.initializeState(VERSION, token, name, packageInfo)
         assertTrue(restore.hasState())
     }
 
@@ -68,9 +71,9 @@
 
     @Test
     fun `getting InputStream for package when getting first chunk throws`() = runBlocking {
-        restore.initializeState(VERSION, token, packageInfo)
+        restore.initializeState(VERSION, token, name, packageInfo)
 
-        coEvery { plugin.getInputStreamForPackage(token, packageInfo) } throws IOException()
+        coEvery { plugin.getInputStream(token, name) } throws IOException()
         every { fileDescriptor.close() } just Runs
 
         assertEquals(
@@ -81,9 +84,9 @@
 
     @Test
     fun `reading version header when getting first chunk throws`() = runBlocking {
-        restore.initializeState(VERSION, token, packageInfo)
+        restore.initializeState(VERSION, token, name, packageInfo)
 
-        coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
+        coEvery { plugin.getInputStream(token, name) } returns inputStream
         every { headerReader.readVersion(inputStream, VERSION) } throws IOException()
         every { fileDescriptor.close() } just Runs
 
@@ -95,9 +98,9 @@
 
     @Test
     fun `reading unsupported version when getting first chunk`() = runBlocking {
-        restore.initializeState(VERSION, token, packageInfo)
+        restore.initializeState(VERSION, token, name, packageInfo)
 
-        coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
+        coEvery { plugin.getInputStream(token, name) } returns inputStream
         every {
             headerReader.readVersion(inputStream, VERSION)
         } throws UnsupportedVersionException(unsupportedVersion)
@@ -111,9 +114,9 @@
 
     @Test
     fun `getting decrypted stream when getting first chunk throws`() = runBlocking {
-        restore.initializeState(VERSION, token, packageInfo)
+        restore.initializeState(VERSION, token, name, packageInfo)
 
-        coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
+        coEvery { plugin.getInputStream(token, name) } returns inputStream
         every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } throws IOException()
         every { fileDescriptor.close() } just Runs
@@ -127,9 +130,9 @@
     @Test
     fun `getting decrypted stream when getting first chunk throws general security exception`() =
         runBlocking {
-            restore.initializeState(VERSION, token, packageInfo)
+            restore.initializeState(VERSION, token, name, packageInfo)
 
-            coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
+            coEvery { plugin.getInputStream(token, name) } returns inputStream
             every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
             every { crypto.newDecryptingStream(inputStream, ad) } throws GeneralSecurityException()
             every { fileDescriptor.close() } just Runs
@@ -139,7 +142,7 @@
 
     @Test
     fun `full chunk gets decrypted`() = runBlocking {
-        restore.initializeState(VERSION, token, packageInfo)
+        restore.initializeState(VERSION, token, name, packageInfo)
 
         initInputStream()
         readAndEncryptInputStream(encrypted)
@@ -152,10 +155,11 @@
     }
 
     @Test
+    @Suppress("deprecation")
     fun `full chunk gets decrypted from version 0`() = runBlocking {
-        restore.initializeState(0.toByte(), token, packageInfo)
+        restore.initializeState(0.toByte(), token, name, packageInfo)
 
-        coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
+        coEvery { legacyPlugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
         every { headerReader.readVersion(inputStream, 0.toByte()) } returns 0.toByte()
         every {
             crypto.decryptHeader(inputStream, 0.toByte(), packageInfo.packageName)
@@ -174,9 +178,9 @@
 
     @Test
     fun `unexpected version aborts with error`() = runBlocking {
-        restore.initializeState(Byte.MAX_VALUE, token, packageInfo)
+        restore.initializeState(Byte.MAX_VALUE, token, name, packageInfo)
 
-        coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
+        coEvery { plugin.getInputStream(token, name) } returns inputStream
         every {
             headerReader.readVersion(inputStream, Byte.MAX_VALUE)
         } throws GeneralSecurityException()
@@ -192,9 +196,9 @@
     fun `three full chunk get decrypted and then return no more data`() = runBlocking {
         val encryptedBytes = Random.nextBytes(MAX_SEGMENT_LENGTH * 2 + 1)
         val decryptedInputStream = ByteArrayInputStream(encryptedBytes)
-        restore.initializeState(VERSION, token, packageInfo)
+        restore.initializeState(VERSION, token, name, packageInfo)
 
-        coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
+        coEvery { plugin.getInputStream(token, name) } returns inputStream
         every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
         every { outputFactory.getOutputStream(fileDescriptor) } returns outputStream
@@ -213,7 +217,7 @@
 
     @Test
     fun `aborting full restore closes stream, resets state`() = runBlocking {
-        restore.initializeState(VERSION, token, packageInfo)
+        restore.initializeState(VERSION, token, name, packageInfo)
 
         initInputStream()
         readAndEncryptInputStream(encrypted)
@@ -227,7 +231,7 @@
     }
 
     private fun initInputStream() {
-        coEvery { plugin.getInputStreamForPackage(token, packageInfo) } returns inputStream
+        coEvery { plugin.getInputStream(token, name) } returns inputStream
         every { headerReader.readVersion(inputStream, VERSION) } returns VERSION
         every { crypto.newDecryptingStream(inputStream, ad) } returns decryptedInputStream
     }
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt
index 1bd51fe..72fe53a 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreCoordinatorTest.kt
@@ -242,13 +242,14 @@
     }
 
     @Test
+    @Suppress("deprecation")
     fun `v0 nextRestorePackage() returns full description if no KV data found`() = runBlocking {
         restore.beforeStartRestore(metadata.copy(version = 0x00))
         restore.startRestore(token, packageInfoArray)
 
         coEvery { kv.hasDataForPackage(token, packageInfo) } returns false
         coEvery { full.hasDataForPackage(token, packageInfo) } returns true
-        every { full.initializeState(0x00, token, packageInfo) } just Runs
+        every { full.initializeState(0x00, token, "", packageInfo) } just Runs
 
         val expected = RestoreDescription(packageInfo.packageName, TYPE_FULL_STREAM)
         assertEquals(expected, restore.nextRestorePackage())
@@ -276,7 +277,7 @@
 
         every { crypto.getNameForPackage(metadata.salt, packageInfo2.packageName) } returns name2
         coEvery { plugin.hasData(token, name2) } returns true
-        every { full.initializeState(VERSION, token, packageInfo2) } just Runs
+        every { full.initializeState(VERSION, token, name2, packageInfo2) } just Runs
 
         val expected = RestoreDescription(packageInfo2.packageName, TYPE_FULL_STREAM)
         assertEquals(expected, restore.nextRestorePackage())
@@ -298,7 +299,7 @@
 
         every { crypto.getNameForPackage(metadata.salt, packageInfo2.packageName) } returns name2
         coEvery { plugin.hasData(token, name2) } returns true
-        every { full.initializeState(VERSION, token, packageInfo2) } just Runs
+        every { full.initializeState(VERSION, token, name2, packageInfo2) } just Runs
 
         val expected2 =
             RestoreDescription(packageInfo2.packageName, TYPE_FULL_STREAM)
@@ -308,6 +309,7 @@
     }
 
     @Test
+    @Suppress("deprecation")
     fun `v0 nextRestorePackage() returns all packages from startRestore()`() = runBlocking {
         restore.beforeStartRestore(metadata.copy(version = 0x00))
         restore.startRestore(token, packageInfoArray2)
@@ -320,7 +322,7 @@
 
         coEvery { kv.hasDataForPackage(token, packageInfo2) } returns false
         coEvery { full.hasDataForPackage(token, packageInfo2) } returns true
-        every { full.initializeState(0.toByte(), token, packageInfo2) } just Runs
+        every { full.initializeState(0.toByte(), token, "", packageInfo2) } just Runs
 
         val expected2 = RestoreDescription(packageInfo2.packageName, TYPE_FULL_STREAM)
         assertEquals(expected2, restore.nextRestorePackage())
@@ -352,6 +354,7 @@
     }
 
     @Test
+    @Suppress("deprecation")
     fun `v0 when full#hasDataForPackage() throws, it tries next package`() = runBlocking {
         restore.beforeStartRestore(metadata.copy(version = 0x00))
         restore.startRestore(token, packageInfoArray)
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt
index fd1fe72..1b06ed7 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/RestoreV0IntegrationTest.kt
@@ -52,7 +52,7 @@
     private val kvRestore = KVRestore(kvRestorePlugin, outputFactory, headerReader, cryptoImpl)
     private val fullRestorePlugin = mockk<FullRestorePlugin>()
     private val fullRestore =
-        FullRestore(fullRestorePlugin, outputFactory, headerReader, cryptoImpl)
+        FullRestore(backupPlugin, fullRestorePlugin, outputFactory, headerReader, cryptoImpl)
     private val restore = RestoreCoordinator(
         context,
         crypto,