Clean up code after refactorings
This commit is contained in:
parent
5c75574f65
commit
7b0e02c451
59 changed files with 84 additions and 240 deletions
|
@ -10,7 +10,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.filters.MediumTest
|
import androidx.test.filters.MediumTest
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import com.stevesoltys.seedvault.backend.LegacyStoragePlugin
|
import com.stevesoltys.seedvault.backend.LegacyStoragePlugin
|
||||||
import com.stevesoltys.seedvault.backend.getAvailableBackupFileHandles
|
|
||||||
import com.stevesoltys.seedvault.backend.saf.DocumentsProviderLegacyPlugin
|
import com.stevesoltys.seedvault.backend.saf.DocumentsProviderLegacyPlugin
|
||||||
import com.stevesoltys.seedvault.backend.saf.DocumentsStorage
|
import com.stevesoltys.seedvault.backend.saf.DocumentsStorage
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||||
|
|
|
@ -13,7 +13,6 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import androidx.test.filters.MediumTest
|
import androidx.test.filters.MediumTest
|
||||||
import com.stevesoltys.seedvault.repo.BackupData
|
import com.stevesoltys.seedvault.repo.BackupData
|
||||||
import com.stevesoltys.seedvault.repo.BackupReceiver
|
import com.stevesoltys.seedvault.repo.BackupReceiver
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
|
||||||
import io.mockk.CapturingSlot
|
import io.mockk.CapturingSlot
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
|
@ -34,7 +33,6 @@ import kotlin.test.assertEquals
|
||||||
@MediumTest
|
@MediumTest
|
||||||
class KvBackupInstrumentationTest : KoinComponent {
|
class KvBackupInstrumentationTest : KoinComponent {
|
||||||
|
|
||||||
private val settingsManager: SettingsManager by inject()
|
|
||||||
private val backupReceiver: BackupReceiver = mockk()
|
private val backupReceiver: BackupReceiver = mockk()
|
||||||
private val inputFactory: InputFactory = mockk()
|
private val inputFactory: InputFactory = mockk()
|
||||||
private val dbManager: KvDbManager by inject()
|
private val dbManager: KvDbManager by inject()
|
||||||
|
|
|
@ -13,9 +13,9 @@ import com.stevesoltys.seedvault.proto.SnapshotKt.blob
|
||||||
import com.stevesoltys.seedvault.repo.AppBackupManager
|
import com.stevesoltys.seedvault.repo.AppBackupManager
|
||||||
import com.stevesoltys.seedvault.repo.BackupData
|
import com.stevesoltys.seedvault.repo.BackupData
|
||||||
import com.stevesoltys.seedvault.repo.BackupReceiver
|
import com.stevesoltys.seedvault.repo.BackupReceiver
|
||||||
import com.stevesoltys.seedvault.transport.backup.PackageService
|
|
||||||
import com.stevesoltys.seedvault.repo.SnapshotCreatorFactory
|
|
||||||
import com.stevesoltys.seedvault.repo.Loader
|
import com.stevesoltys.seedvault.repo.Loader
|
||||||
|
import com.stevesoltys.seedvault.repo.SnapshotCreatorFactory
|
||||||
|
import com.stevesoltys.seedvault.transport.backup.PackageService
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
|
|
@ -86,11 +86,9 @@ open class App : Application() {
|
||||||
settingsManager = get(),
|
settingsManager = get(),
|
||||||
keyManager = get(),
|
keyManager = get(),
|
||||||
backendManager = get(),
|
backendManager = get(),
|
||||||
metadataManager = get(),
|
|
||||||
appListRetriever = get(),
|
appListRetriever = get(),
|
||||||
storageBackup = get(),
|
storageBackup = get(),
|
||||||
backupManager = get(),
|
backupManager = get(),
|
||||||
backupInitializer = get(),
|
|
||||||
backupStateManager = get(),
|
backupStateManager = get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@ import android.util.Log
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import com.stevesoltys.seedvault.getStorageContext
|
import com.stevesoltys.seedvault.getStorageContext
|
||||||
import com.stevesoltys.seedvault.permitDiskReads
|
import com.stevesoltys.seedvault.permitDiskReads
|
||||||
|
import com.stevesoltys.seedvault.repo.BlobCache
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||||
import com.stevesoltys.seedvault.settings.StoragePluginType
|
import com.stevesoltys.seedvault.settings.StoragePluginType
|
||||||
import com.stevesoltys.seedvault.repo.BlobCache
|
|
||||||
import org.calyxos.seedvault.core.backends.Backend
|
import org.calyxos.seedvault.core.backends.Backend
|
||||||
import org.calyxos.seedvault.core.backends.BackendFactory
|
import org.calyxos.seedvault.core.backends.BackendFactory
|
||||||
import org.calyxos.seedvault.core.backends.BackendProperties
|
import org.calyxos.seedvault.core.backends.BackendProperties
|
||||||
|
@ -89,6 +89,7 @@ class BackendManager(
|
||||||
mBackend = backend
|
mBackend = backend
|
||||||
mBackendProperties = storageProperties
|
mBackendProperties = storageProperties
|
||||||
blobCache.clearLocalCache()
|
blobCache.clearLocalCache()
|
||||||
|
// TODO not critical, but nice to have: clear also local snapshot cache
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -29,7 +29,6 @@ import org.calyxos.seedvault.core.backends.saf.SafProperties
|
||||||
import org.calyxos.seedvault.core.backends.saf.getTreeDocumentFile
|
import org.calyxos.seedvault.core.backends.saf.getTreeDocumentFile
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
|
||||||
@Deprecated("")
|
@Deprecated("")
|
||||||
|
@ -51,7 +50,7 @@ internal class DocumentsStorage(
|
||||||
private val context: Context get() = appContext.getStorageContext { safStorage.isUsb }
|
private val context: Context get() = appContext.getStorageContext { safStorage.isUsb }
|
||||||
private val contentResolver: ContentResolver get() = context.contentResolver
|
private val contentResolver: ContentResolver get() = context.contentResolver
|
||||||
|
|
||||||
internal var rootBackupDir: DocumentFile? = null
|
private var rootBackupDir: DocumentFile? = null
|
||||||
get() = runBlocking {
|
get() = runBlocking {
|
||||||
if (field == null) {
|
if (field == null) {
|
||||||
val parent = safStorage.getDocumentFile(context)
|
val parent = safStorage.getDocumentFile(context)
|
||||||
|
@ -94,16 +93,6 @@ internal class DocumentsStorage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
fun getOutputStream(file: DocumentFile): OutputStream {
|
|
||||||
return try {
|
|
||||||
contentResolver.openOutputStream(file.uri, "wt") ?: throw IOException()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// SAF can throw all sorts of exceptions, so wrap it in IOException
|
|
||||||
throw IOException(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -192,7 +181,7 @@ suspend fun DocumentFile.findFileBlocking(context: Context, displayName: String)
|
||||||
@Throws(IOException::class, TimeoutCancellationException::class)
|
@Throws(IOException::class, TimeoutCancellationException::class)
|
||||||
internal suspend fun getLoadedCursor(timeout: Long = 15_000, query: () -> Cursor?) =
|
internal suspend fun getLoadedCursor(timeout: Long = 15_000, query: () -> Cursor?) =
|
||||||
withTimeout(timeout) {
|
withTimeout(timeout) {
|
||||||
suspendCancellableCoroutine<Cursor> { cont ->
|
suspendCancellableCoroutine { cont ->
|
||||||
val cursor = query() ?: throw IOException()
|
val cursor = query() ?: throw IOException()
|
||||||
cont.invokeOnCancellation { cursor.close() }
|
cont.invokeOnCancellation { cursor.close() }
|
||||||
val loading = cursor.extras.getBoolean(EXTRA_LOADING, false)
|
val loading = cursor.extras.getBoolean(EXTRA_LOADING, false)
|
||||||
|
|
|
@ -139,17 +139,6 @@ internal object StorageRootResolver {
|
||||||
return if (index != -1) getInt(index) else 0
|
return if (index != -1) getInt(index) else 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Cursor.getLong(columnName: String): Long? {
|
|
||||||
val index = getColumnIndex(columnName)
|
|
||||||
if (index == -1) return null
|
|
||||||
val value = getString(index) ?: return null
|
|
||||||
return try {
|
|
||||||
java.lang.Long.parseLong(value)
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getIcon(context: Context, authority: String, rootId: String, icon: Int): Drawable? {
|
fun getIcon(context: Context, authority: String, rootId: String, icon: Int): Drawable? {
|
||||||
return getPackageIcon(context, authority, icon) ?: when {
|
return getPackageIcon(context, authority, icon) ?: when {
|
||||||
authority == AUTHORITY_STORAGE && rootId == ROOT_ID_DEVICE -> {
|
authority == AUTHORITY_STORAGE && rootId == ROOT_ID_DEVICE -> {
|
||||||
|
|
|
@ -102,17 +102,6 @@ internal interface Crypto {
|
||||||
@Deprecated("only for v1")
|
@Deprecated("only for v1")
|
||||||
fun getNameForApk(salt: String, packageName: String, suffix: String = ""): String
|
fun getNameForApk(salt: String, packageName: String, suffix: String = ""): String
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a [AesGcmHkdfStreaming] encrypting stream
|
|
||||||
* that gets encrypted and authenticated the given associated data.
|
|
||||||
*/
|
|
||||||
@Deprecated("only for v1")
|
|
||||||
@Throws(IOException::class, GeneralSecurityException::class)
|
|
||||||
fun newEncryptingStreamV1(
|
|
||||||
outputStream: OutputStream,
|
|
||||||
associatedData: ByteArray,
|
|
||||||
): OutputStream
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a [AesGcmHkdfStreaming] decrypting stream
|
* Returns a [AesGcmHkdfStreaming] decrypting stream
|
||||||
* that gets decrypted and authenticated the given associated data.
|
* that gets decrypted and authenticated the given associated data.
|
||||||
|
@ -245,13 +234,6 @@ internal class CryptoImpl(
|
||||||
return messageDigest.digest()
|
return messageDigest.digest()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("only for v1")
|
|
||||||
@Throws(IOException::class, GeneralSecurityException::class)
|
|
||||||
override fun newEncryptingStreamV1(
|
|
||||||
outputStream: OutputStream,
|
|
||||||
associatedData: ByteArray,
|
|
||||||
): OutputStream = CoreCrypto.newEncryptingStream(keyV1, outputStream, associatedData)
|
|
||||||
|
|
||||||
@Deprecated("only for v1")
|
@Deprecated("only for v1")
|
||||||
@Throws(IOException::class, GeneralSecurityException::class)
|
@Throws(IOException::class, GeneralSecurityException::class)
|
||||||
override fun newDecryptingStreamV1(
|
override fun newDecryptingStreamV1(
|
||||||
|
|
|
@ -33,12 +33,6 @@ internal class MetadataWriterImpl : MetadataWriter {
|
||||||
if (packageMetadata.size != null) {
|
if (packageMetadata.size != null) {
|
||||||
put(JSON_PACKAGE_SIZE, packageMetadata.size)
|
put(JSON_PACKAGE_SIZE, packageMetadata.size)
|
||||||
}
|
}
|
||||||
if (packageMetadata.system) {
|
|
||||||
put(JSON_PACKAGE_SYSTEM, true)
|
|
||||||
}
|
|
||||||
if (packageMetadata.isLaunchableSystemApp) {
|
|
||||||
put(JSON_PACKAGE_SYSTEM_LAUNCHER, true)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return json.toString().toByteArray(Utf8)
|
return json.toString().toByteArray(Utf8)
|
||||||
|
|
|
@ -144,6 +144,7 @@ internal class AppBackupManager(
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
suspend fun removeBackupRepo() {
|
suspend fun removeBackupRepo() {
|
||||||
blobCache.clearLocalCache()
|
blobCache.clearLocalCache()
|
||||||
|
// TODO not critical, but nice to have: clear also local snapshot cache
|
||||||
backendManager.backend.remove(TopLevelFolder(crypto.repoId))
|
backendManager.backend.remove(TopLevelFolder(crypto.repoId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,6 @@ val repoModule = module {
|
||||||
val snapshotFolder = File(androidContext().filesDir, FOLDER_SNAPSHOTS)
|
val snapshotFolder = File(androidContext().filesDir, FOLDER_SNAPSHOTS)
|
||||||
SnapshotManager(snapshotFolder, get(), get(), get())
|
SnapshotManager(snapshotFolder, get(), get(), get())
|
||||||
}
|
}
|
||||||
factory { SnapshotCreatorFactory(androidContext(), get(), get(), get(), get()) }
|
factory { SnapshotCreatorFactory(androidContext(), get(), get(), get()) }
|
||||||
factory { Pruner(get(), get(), get()) }
|
factory { Pruner(get(), get(), get()) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import com.stevesoltys.seedvault.proto.Snapshot
|
||||||
import com.stevesoltys.seedvault.proto.Snapshot.Apk
|
import com.stevesoltys.seedvault.proto.Snapshot.Apk
|
||||||
import com.stevesoltys.seedvault.proto.Snapshot.App
|
import com.stevesoltys.seedvault.proto.Snapshot.App
|
||||||
import com.stevesoltys.seedvault.proto.Snapshot.Blob
|
import com.stevesoltys.seedvault.proto.Snapshot.Blob
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
|
||||||
import com.stevesoltys.seedvault.transport.backup.PackageService
|
import com.stevesoltys.seedvault.transport.backup.PackageService
|
||||||
import com.stevesoltys.seedvault.transport.backup.isSystemApp
|
import com.stevesoltys.seedvault.transport.backup.isSystemApp
|
||||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
|
@ -38,7 +37,6 @@ internal class SnapshotCreator(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
private val packageService: PackageService,
|
private val packageService: PackageService,
|
||||||
private val settingsManager: SettingsManager,
|
|
||||||
private val metadataManager: MetadataManager,
|
private val metadataManager: MetadataManager,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ package com.stevesoltys.seedvault.repo
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.stevesoltys.seedvault.Clock
|
import com.stevesoltys.seedvault.Clock
|
||||||
import com.stevesoltys.seedvault.metadata.MetadataManager
|
import com.stevesoltys.seedvault.metadata.MetadataManager
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
|
||||||
import com.stevesoltys.seedvault.transport.backup.PackageService
|
import com.stevesoltys.seedvault.transport.backup.PackageService
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,9 +17,8 @@ internal class SnapshotCreatorFactory(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
private val packageService: PackageService,
|
private val packageService: PackageService,
|
||||||
private val settingsManager: SettingsManager,
|
|
||||||
private val metadataManager: MetadataManager,
|
private val metadataManager: MetadataManager,
|
||||||
) {
|
) {
|
||||||
fun createSnapshotCreator() =
|
fun createSnapshotCreator() =
|
||||||
SnapshotCreator(context, clock, packageService, settingsManager, metadataManager)
|
SnapshotCreator(context, clock, packageService, metadataManager)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ import com.stevesoltys.seedvault.backend.BackendManager
|
||||||
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
|
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
|
||||||
import com.stevesoltys.seedvault.metadata.PackageState
|
import com.stevesoltys.seedvault.metadata.PackageState
|
||||||
import com.stevesoltys.seedvault.restore.install.isInstalled
|
import com.stevesoltys.seedvault.restore.install.isInstalled
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
|
||||||
import com.stevesoltys.seedvault.transport.TRANSPORT_ID
|
import com.stevesoltys.seedvault.transport.TRANSPORT_ID
|
||||||
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
|
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
|
||||||
import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator
|
import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator
|
||||||
|
@ -55,7 +54,6 @@ internal data class AppRestoreResult(
|
||||||
internal class AppDataRestoreManager(
|
internal class AppDataRestoreManager(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val backupManager: IBackupManager,
|
private val backupManager: IBackupManager,
|
||||||
private val settingsManager: SettingsManager,
|
|
||||||
private val restoreCoordinator: RestoreCoordinator,
|
private val restoreCoordinator: RestoreCoordinator,
|
||||||
private val backendManager: BackendManager,
|
private val backendManager: BackendManager,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -96,7 +96,7 @@ internal class AppSelectionManager(
|
||||||
val backend = backendManager.backend
|
val backend = backendManager.backend
|
||||||
val token = restorableBackup.token
|
val token = restorableBackup.token
|
||||||
backend.load(LegacyAppBackupFile.IconsFile(token)).use {
|
backend.load(LegacyAppBackupFile.IconsFile(token)).use {
|
||||||
iconManager.downloadIconsV1(restorableBackup.version, token, it)
|
iconManager.downloadIconsV1(token, it)
|
||||||
}
|
}
|
||||||
} else if (restorableBackup.version >= 2) {
|
} else if (restorableBackup.version >= 2) {
|
||||||
val repoId = restorableBackup.repoId ?: error("No repoId in v2 backup")
|
val repoId = restorableBackup.repoId ?: error("No repoId in v2 backup")
|
||||||
|
|
|
@ -83,7 +83,7 @@ internal class RestoreViewModel(
|
||||||
private val appSelectionManager =
|
private val appSelectionManager =
|
||||||
AppSelectionManager(app, backendManager, iconManager, viewModelScope)
|
AppSelectionManager(app, backendManager, iconManager, viewModelScope)
|
||||||
private val appDataRestoreManager = AppDataRestoreManager(
|
private val appDataRestoreManager = AppDataRestoreManager(
|
||||||
app, backupManager, settingsManager, restoreCoordinator, backendManager
|
app, backupManager, restoreCoordinator, backendManager
|
||||||
)
|
)
|
||||||
|
|
||||||
private val mDisplayFragment = MutableLiveEvent<DisplayFragment>()
|
private val mDisplayFragment = MutableLiveEvent<DisplayFragment>()
|
||||||
|
|
|
@ -21,15 +21,15 @@ import com.stevesoltys.seedvault.crypto.Crypto
|
||||||
import com.stevesoltys.seedvault.encodeBase64
|
import com.stevesoltys.seedvault.encodeBase64
|
||||||
import com.stevesoltys.seedvault.metadata.ApkSplit
|
import com.stevesoltys.seedvault.metadata.ApkSplit
|
||||||
import com.stevesoltys.seedvault.metadata.PackageMetadata
|
import com.stevesoltys.seedvault.metadata.PackageMetadata
|
||||||
|
import com.stevesoltys.seedvault.repo.Loader
|
||||||
|
import com.stevesoltys.seedvault.repo.getBlobHandles
|
||||||
import com.stevesoltys.seedvault.restore.RestoreService
|
import com.stevesoltys.seedvault.restore.RestoreService
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
||||||
import com.stevesoltys.seedvault.repo.getBlobHandles
|
|
||||||
import com.stevesoltys.seedvault.transport.backup.isSystemApp
|
import com.stevesoltys.seedvault.transport.backup.isSystemApp
|
||||||
import com.stevesoltys.seedvault.repo.Loader
|
|
||||||
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
|
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
|
||||||
import com.stevesoltys.seedvault.worker.hashSignature
|
import com.stevesoltys.seedvault.worker.hashSignature
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
|
|
|
@ -84,7 +84,7 @@ internal class InstallProgressAdapter(
|
||||||
if (item.icon == null) iconJob = scope.launch {
|
if (item.icon == null) iconJob = scope.launch {
|
||||||
iconLoader(item, appIcon::setImageDrawable)
|
iconLoader(item, appIcon::setImageDrawable)
|
||||||
} else appIcon.setImageDrawable(item.icon)
|
} else appIcon.setImageDrawable(item.icon)
|
||||||
appName.text = item.name ?: getAppName(v.context, item.packageName.toString())
|
appName.text = item.name ?: getAppName(v.context, item.packageName)
|
||||||
appInfo.visibility = GONE
|
appInfo.visibility = GONE
|
||||||
when (item.state) {
|
when (item.state) {
|
||||||
IN_PROGRESS -> {
|
IN_PROGRESS -> {
|
||||||
|
|
|
@ -80,8 +80,7 @@ internal class AppListRetriever(
|
||||||
AppStatus(
|
AppStatus(
|
||||||
packageName = packageName,
|
packageName = packageName,
|
||||||
enabled = settingsManager.isBackupEnabled(packageName),
|
enabled = settingsManager.isBackupEnabled(packageName),
|
||||||
icon = data.iconRes?.let { getDrawable(context, it) }
|
icon = getDrawable(context, data.iconRes) ?: getIconFromPackageManager(packageName),
|
||||||
?: getIconFromPackageManager(packageName),
|
|
||||||
name = context.getString(data.nameRes),
|
name = context.getString(data.nameRes),
|
||||||
time = metadata?.time ?: 0,
|
time = metadata?.time ?: 0,
|
||||||
size = metadata?.size,
|
size = metadata?.size,
|
||||||
|
|
|
@ -16,8 +16,8 @@ import androidx.preference.PreferenceManager
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE
|
import androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy.UPDATE
|
import androidx.work.ExistingPeriodicWorkPolicy.UPDATE
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.permitDiskReads
|
|
||||||
import com.stevesoltys.seedvault.backend.BackendManager
|
import com.stevesoltys.seedvault.backend.BackendManager
|
||||||
|
import com.stevesoltys.seedvault.permitDiskReads
|
||||||
import com.stevesoltys.seedvault.settings.preference.M3ListPreference
|
import com.stevesoltys.seedvault.settings.preference.M3ListPreference
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
|
@ -35,12 +35,10 @@ import androidx.work.ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.stevesoltys.seedvault.BackupStateManager
|
import com.stevesoltys.seedvault.BackupStateManager
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.crypto.KeyManager
|
|
||||||
import com.stevesoltys.seedvault.metadata.MetadataManager
|
|
||||||
import com.stevesoltys.seedvault.permitDiskReads
|
|
||||||
import com.stevesoltys.seedvault.backend.BackendManager
|
import com.stevesoltys.seedvault.backend.BackendManager
|
||||||
|
import com.stevesoltys.seedvault.crypto.KeyManager
|
||||||
|
import com.stevesoltys.seedvault.permitDiskReads
|
||||||
import com.stevesoltys.seedvault.storage.StorageBackupJobService
|
import com.stevesoltys.seedvault.storage.StorageBackupJobService
|
||||||
import com.stevesoltys.seedvault.transport.backup.BackupInitializer
|
|
||||||
import com.stevesoltys.seedvault.ui.LiveEvent
|
import com.stevesoltys.seedvault.ui.LiveEvent
|
||||||
import com.stevesoltys.seedvault.ui.MutableLiveEvent
|
import com.stevesoltys.seedvault.ui.MutableLiveEvent
|
||||||
import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
|
import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
|
||||||
|
@ -68,11 +66,9 @@ internal class SettingsViewModel(
|
||||||
settingsManager: SettingsManager,
|
settingsManager: SettingsManager,
|
||||||
keyManager: KeyManager,
|
keyManager: KeyManager,
|
||||||
backendManager: BackendManager,
|
backendManager: BackendManager,
|
||||||
private val metadataManager: MetadataManager,
|
|
||||||
private val appListRetriever: AppListRetriever,
|
private val appListRetriever: AppListRetriever,
|
||||||
private val storageBackup: StorageBackup,
|
private val storageBackup: StorageBackup,
|
||||||
private val backupManager: IBackupManager,
|
private val backupManager: IBackupManager,
|
||||||
private val backupInitializer: BackupInitializer,
|
|
||||||
backupStateManager: BackupStateManager,
|
backupStateManager: BackupStateManager,
|
||||||
) : RequireProvisioningViewModel(app, settingsManager, keyManager, backendManager) {
|
) : RequireProvisioningViewModel(app, settingsManager, keyManager, backendManager) {
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
package com.stevesoltys.seedvault.storage
|
package com.stevesoltys.seedvault.storage
|
||||||
|
|
||||||
import com.stevesoltys.seedvault.crypto.KeyManager
|
|
||||||
import com.stevesoltys.seedvault.backend.BackendManager
|
import com.stevesoltys.seedvault.backend.BackendManager
|
||||||
|
import com.stevesoltys.seedvault.crypto.KeyManager
|
||||||
import org.calyxos.backup.storage.api.StorageBackup
|
import org.calyxos.backup.storage.api.StorageBackup
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ import android.os.ParcelFileDescriptor
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.settings.SettingsActivity
|
import com.stevesoltys.seedvault.settings.SettingsActivity
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
|
||||||
import com.stevesoltys.seedvault.transport.backup.BackupCoordinator
|
import com.stevesoltys.seedvault.transport.backup.BackupCoordinator
|
||||||
import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator
|
import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -43,7 +42,6 @@ class ConfigurableBackupTransport internal constructor(private val context: Cont
|
||||||
|
|
||||||
private val backupCoordinator by inject<BackupCoordinator>()
|
private val backupCoordinator by inject<BackupCoordinator>()
|
||||||
private val restoreCoordinator by inject<RestoreCoordinator>()
|
private val restoreCoordinator by inject<RestoreCoordinator>()
|
||||||
private val settingsManager by inject<SettingsManager>()
|
|
||||||
|
|
||||||
override fun transportDirName(): String {
|
override fun transportDirName(): String {
|
||||||
return TRANSPORT_DIRECTORY_NAME
|
return TRANSPORT_DIRECTORY_NAME
|
||||||
|
|
|
@ -20,7 +20,6 @@ import android.content.pm.PackageInfo
|
||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import com.stevesoltys.seedvault.Clock
|
|
||||||
import com.stevesoltys.seedvault.backend.BackendManager
|
import com.stevesoltys.seedvault.backend.BackendManager
|
||||||
import com.stevesoltys.seedvault.metadata.BackupType
|
import com.stevesoltys.seedvault.metadata.BackupType
|
||||||
import com.stevesoltys.seedvault.metadata.MetadataManager
|
import com.stevesoltys.seedvault.metadata.MetadataManager
|
||||||
|
@ -64,14 +63,12 @@ internal class BackupCoordinator(
|
||||||
private val appBackupManager: AppBackupManager,
|
private val appBackupManager: AppBackupManager,
|
||||||
private val kv: KVBackup,
|
private val kv: KVBackup,
|
||||||
private val full: FullBackup,
|
private val full: FullBackup,
|
||||||
private val clock: Clock,
|
|
||||||
private val packageService: PackageService,
|
private val packageService: PackageService,
|
||||||
private val metadataManager: MetadataManager,
|
private val metadataManager: MetadataManager,
|
||||||
private val settingsManager: SettingsManager,
|
private val settingsManager: SettingsManager,
|
||||||
private val nm: BackupNotificationManager,
|
private val nm: BackupNotificationManager,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val backend get() = backendManager.backend
|
|
||||||
private val snapshotCreator
|
private val snapshotCreator
|
||||||
get() = appBackupManager.snapshotCreator ?: error("No SnapshotCreator")
|
get() = appBackupManager.snapshotCreator ?: error("No SnapshotCreator")
|
||||||
private val state = CoordinatorState(
|
private val state = CoordinatorState(
|
||||||
|
@ -92,6 +89,8 @@ internal class BackupCoordinator(
|
||||||
*
|
*
|
||||||
* If the transport returns anything other than [TRANSPORT_OK] from this method,
|
* If the transport returns anything other than [TRANSPORT_OK] from this method,
|
||||||
* the OS will halt the current initialize operation and schedule a retry in the near future.
|
* the OS will halt the current initialize operation and schedule a retry in the near future.
|
||||||
|
* Attention: [finishBackup] will not be called in this case.
|
||||||
|
*
|
||||||
* Even if the transport is in a state
|
* Even if the transport is in a state
|
||||||
* such that attempting to "initialize" the backend storage is meaningless -
|
* such that attempting to "initialize" the backend storage is meaningless -
|
||||||
* for example, if there is no current live data-set at all,
|
* for example, if there is no current live data-set at all,
|
||||||
|
@ -103,12 +102,8 @@ internal class BackupCoordinator(
|
||||||
* [TRANSPORT_ERROR] (to retry following network error or other failure).
|
* [TRANSPORT_ERROR] (to retry following network error or other failure).
|
||||||
*/
|
*/
|
||||||
fun initializeDevice(): Int {
|
fun initializeDevice(): Int {
|
||||||
// we don't respect the intended system behavior here by always starting a new [RestoreSet]
|
|
||||||
// instead of simply deleting the current one
|
|
||||||
Log.i(TAG, "Initialize Device!")
|
Log.i(TAG, "Initialize Device!")
|
||||||
|
// we don't respect the intended system behavior of erasing all stored data
|
||||||
// [finishBackup] will only be called when we return [TRANSPORT_OK] here
|
|
||||||
// so we remember that we initialized successfully
|
|
||||||
state.calledInitialize = true
|
state.calledInitialize = true
|
||||||
return TRANSPORT_OK
|
return TRANSPORT_OK
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@ val backupModule = module {
|
||||||
appBackupManager = get(),
|
appBackupManager = get(),
|
||||||
kv = get(),
|
kv = get(),
|
||||||
full = get(),
|
full = get(),
|
||||||
clock = get(),
|
|
||||||
packageService = get(),
|
packageService = get(),
|
||||||
metadataManager = get(),
|
metadataManager = get(),
|
||||||
settingsManager = get(),
|
settingsManager = get(),
|
||||||
|
|
|
@ -138,14 +138,15 @@ internal class FullBackup(
|
||||||
suspend fun cancelFullBackup() {
|
suspend fun cancelFullBackup() {
|
||||||
val state = this.state ?: error("No state when canceling")
|
val state = this.state ?: error("No state when canceling")
|
||||||
Log.i(TAG, "Cancel full backup for ${state.packageName}")
|
Log.i(TAG, "Cancel full backup for ${state.packageName}")
|
||||||
// TODO check if worth keeping the blobs. they've been uploaded already and may be re-usable
|
// finalize the receiver
|
||||||
// so we could add them to the snapshot's blobMap or just let prune remove them at the end
|
|
||||||
try {
|
try {
|
||||||
backupReceiver.finalize(getOwner(state.packageName))
|
backupReceiver.finalize(getOwner(state.packageName))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
// as the backup was cancelled anyway, we don't care if finalizing had an error
|
// as the backup was cancelled anyway, we don't care if finalizing had an error
|
||||||
Log.e(TAG, "Error finalizing backup in cancelFullBackup().", e)
|
Log.e(TAG, "Error finalizing backup in cancelFullBackup().", e)
|
||||||
}
|
}
|
||||||
|
// If the transport receives this callback, it will *not* receive a call to [finishBackup].
|
||||||
|
// It needs to tear down any ongoing backup state here.
|
||||||
clearState()
|
clearState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,11 +125,6 @@ internal class PackageService(
|
||||||
packageInfo.allowsBackup()
|
packageInfo.allowsBackup()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of apps that do not allow backup.
|
|
||||||
*/
|
|
||||||
val userNotAllowedApps: List<PackageInfo> = emptyList()
|
|
||||||
|
|
||||||
val launchableSystemApps: List<ResolveInfo>
|
val launchableSystemApps: List<ResolveInfo>
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
get() {
|
get() {
|
||||||
|
|
|
@ -18,11 +18,10 @@ import android.util.Log.isLoggable
|
||||||
import com.stevesoltys.seedvault.ERROR_BACKUP_CANCELLED
|
import com.stevesoltys.seedvault.ERROR_BACKUP_CANCELLED
|
||||||
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
|
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.metadata.MetadataManager
|
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
|
||||||
import com.stevesoltys.seedvault.repo.AppBackupManager
|
import com.stevesoltys.seedvault.repo.AppBackupManager
|
||||||
import com.stevesoltys.seedvault.transport.backup.PackageService
|
|
||||||
import com.stevesoltys.seedvault.repo.hexFromProto
|
import com.stevesoltys.seedvault.repo.hexFromProto
|
||||||
|
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||||
|
import com.stevesoltys.seedvault.transport.backup.PackageService
|
||||||
import com.stevesoltys.seedvault.worker.AppBackupPruneWorker
|
import com.stevesoltys.seedvault.worker.AppBackupPruneWorker
|
||||||
import com.stevesoltys.seedvault.worker.BackupRequester
|
import com.stevesoltys.seedvault.worker.BackupRequester
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
@ -38,7 +37,6 @@ internal class NotificationBackupObserver(
|
||||||
) : IBackupObserver.Stub(), KoinComponent {
|
) : IBackupObserver.Stub(), KoinComponent {
|
||||||
|
|
||||||
private val nm: BackupNotificationManager by inject()
|
private val nm: BackupNotificationManager by inject()
|
||||||
private val metadataManager: MetadataManager by inject()
|
|
||||||
private val packageService: PackageService by inject()
|
private val packageService: PackageService by inject()
|
||||||
private val settingsManager: SettingsManager by inject()
|
private val settingsManager: SettingsManager by inject()
|
||||||
private val appBackupManager: AppBackupManager by inject()
|
private val appBackupManager: AppBackupManager by inject()
|
||||||
|
@ -153,7 +151,7 @@ internal class NotificationBackupObserver(
|
||||||
success = snapshot != null
|
success = snapshot != null
|
||||||
snapshot
|
snapshot
|
||||||
}
|
}
|
||||||
val size = if (snapshot != null) { // TODO count size of APKs separately
|
val size = if (snapshot != null) { // TODO for later: count size of APKs separately
|
||||||
val chunkIds = snapshot.appsMap.values.flatMap { it.chunkIdsList }
|
val chunkIds = snapshot.appsMap.values.flatMap { it.chunkIdsList }
|
||||||
chunkIds.sumOf {
|
chunkIds.sumOf {
|
||||||
snapshot.blobsMap[it.hexFromProto()]?.uncompressedLength?.toLong() ?: 0L
|
snapshot.blobsMap[it.hexFromProto()]?.uncompressedLength?.toLong() ?: 0L
|
||||||
|
|
|
@ -16,7 +16,6 @@ import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.backend.BackendManager
|
import com.stevesoltys.seedvault.backend.BackendManager
|
||||||
import com.stevesoltys.seedvault.backend.saf.SafHandler
|
import com.stevesoltys.seedvault.backend.saf.SafHandler
|
||||||
import com.stevesoltys.seedvault.backend.webdav.WebDavHandler
|
import com.stevesoltys.seedvault.backend.webdav.WebDavHandler
|
||||||
import org.calyxos.seedvault.core.backends.webdav.WebDavProperties
|
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||||
import com.stevesoltys.seedvault.storage.StorageBackupJobService
|
import com.stevesoltys.seedvault.storage.StorageBackupJobService
|
||||||
import com.stevesoltys.seedvault.transport.backup.BackupInitializer
|
import com.stevesoltys.seedvault.transport.backup.BackupInitializer
|
||||||
|
@ -28,6 +27,7 @@ import org.calyxos.backup.storage.api.StorageBackup
|
||||||
import org.calyxos.backup.storage.backup.BackupJobService
|
import org.calyxos.backup.storage.backup.BackupJobService
|
||||||
import org.calyxos.seedvault.core.backends.Backend
|
import org.calyxos.seedvault.core.backends.Backend
|
||||||
import org.calyxos.seedvault.core.backends.saf.SafProperties
|
import org.calyxos.seedvault.core.backends.saf.SafProperties
|
||||||
|
import org.calyxos.seedvault.core.backends.webdav.WebDavProperties
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,6 @@ import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_RESTORE
|
||||||
import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_SETUP_WIZARD
|
import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_SETUP_WIZARD
|
||||||
import org.koin.androidx.viewmodel.ext.android.getViewModel
|
import org.koin.androidx.viewmodel.ext.android.getViewModel
|
||||||
|
|
||||||
private val TAG = StorageActivity::class.java.name
|
|
||||||
|
|
||||||
class StorageActivity : BackupActivity() {
|
class StorageActivity : BackupActivity() {
|
||||||
|
|
||||||
private lateinit var viewModel: StorageViewModel
|
private lateinit var viewModel: StorageViewModel
|
||||||
|
|
|
@ -16,7 +16,6 @@ import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.backend.BackendManager
|
import com.stevesoltys.seedvault.backend.BackendManager
|
||||||
import com.stevesoltys.seedvault.backend.saf.SafHandler
|
import com.stevesoltys.seedvault.backend.saf.SafHandler
|
||||||
import com.stevesoltys.seedvault.backend.webdav.WebDavHandler
|
import com.stevesoltys.seedvault.backend.webdav.WebDavHandler
|
||||||
import org.calyxos.seedvault.core.backends.webdav.WebDavProperties
|
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||||
import com.stevesoltys.seedvault.ui.LiveEvent
|
import com.stevesoltys.seedvault.ui.LiveEvent
|
||||||
import com.stevesoltys.seedvault.ui.MutableLiveEvent
|
import com.stevesoltys.seedvault.ui.MutableLiveEvent
|
||||||
|
@ -26,6 +25,7 @@ import kotlinx.coroutines.launch
|
||||||
import org.calyxos.seedvault.core.backends.Backend
|
import org.calyxos.seedvault.core.backends.Backend
|
||||||
import org.calyxos.seedvault.core.backends.saf.SafProperties
|
import org.calyxos.seedvault.core.backends.saf.SafProperties
|
||||||
import org.calyxos.seedvault.core.backends.webdav.WebDavConfig
|
import org.calyxos.seedvault.core.backends.webdav.WebDavConfig
|
||||||
|
import org.calyxos.seedvault.core.backends.webdav.WebDavProperties
|
||||||
|
|
||||||
internal abstract class StorageViewModel(
|
internal abstract class StorageViewModel(
|
||||||
private val app: Application,
|
private val app: Application,
|
||||||
|
@ -48,8 +48,6 @@ internal abstract class StorageViewModel(
|
||||||
private var safOption: SafOption? = null
|
private var safOption: SafOption? = null
|
||||||
|
|
||||||
internal var isSetupWizard: Boolean = false
|
internal var isSetupWizard: Boolean = false
|
||||||
internal val hasStorageSet: Boolean
|
|
||||||
get() = backendManager.backendProperties != null
|
|
||||||
abstract val isRestoreOperation: Boolean
|
abstract val isRestoreOperation: Boolean
|
||||||
|
|
||||||
internal fun loadStorageRoots() {
|
internal fun loadStorageRoots() {
|
||||||
|
|
|
@ -17,11 +17,11 @@ import com.stevesoltys.seedvault.proto.Snapshot
|
||||||
import com.stevesoltys.seedvault.proto.Snapshot.Apk
|
import com.stevesoltys.seedvault.proto.Snapshot.Apk
|
||||||
import com.stevesoltys.seedvault.proto.Snapshot.Blob
|
import com.stevesoltys.seedvault.proto.Snapshot.Blob
|
||||||
import com.stevesoltys.seedvault.proto.SnapshotKt.split
|
import com.stevesoltys.seedvault.proto.SnapshotKt.split
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
|
||||||
import com.stevesoltys.seedvault.repo.AppBackupManager
|
import com.stevesoltys.seedvault.repo.AppBackupManager
|
||||||
import com.stevesoltys.seedvault.repo.BackupReceiver
|
import com.stevesoltys.seedvault.repo.BackupReceiver
|
||||||
import com.stevesoltys.seedvault.repo.forProto
|
import com.stevesoltys.seedvault.repo.forProto
|
||||||
import com.stevesoltys.seedvault.repo.hexFromProto
|
import com.stevesoltys.seedvault.repo.hexFromProto
|
||||||
|
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||||
import com.stevesoltys.seedvault.transport.backup.isNotUpdatedSystemApp
|
import com.stevesoltys.seedvault.transport.backup.isNotUpdatedSystemApp
|
||||||
import com.stevesoltys.seedvault.transport.backup.isTestOnly
|
import com.stevesoltys.seedvault.transport.backup.isTestOnly
|
||||||
import org.calyxos.seedvault.core.toHexString
|
import org.calyxos.seedvault.core.toHexString
|
||||||
|
|
|
@ -8,7 +8,7 @@ package com.stevesoltys.seedvault.worker
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.work.BackoffPolicy
|
import androidx.work.BackoffPolicy.EXPONENTIAL
|
||||||
import androidx.work.CoroutineWorker
|
import androidx.work.CoroutineWorker
|
||||||
import androidx.work.ExistingWorkPolicy.REPLACE
|
import androidx.work.ExistingWorkPolicy.REPLACE
|
||||||
import androidx.work.ForegroundInfo
|
import androidx.work.ForegroundInfo
|
||||||
|
@ -36,7 +36,7 @@ class AppBackupPruneWorker(
|
||||||
fun scheduleNow(context: Context) {
|
fun scheduleNow(context: Context) {
|
||||||
val workRequest = OneTimeWorkRequestBuilder<AppBackupPruneWorker>()
|
val workRequest = OneTimeWorkRequestBuilder<AppBackupPruneWorker>()
|
||||||
.setExpedited(RUN_AS_NON_EXPEDITED_WORK_REQUEST)
|
.setExpedited(RUN_AS_NON_EXPEDITED_WORK_REQUEST)
|
||||||
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, Duration.ofSeconds(10))
|
.setBackoffCriteria(EXPONENTIAL, Duration.ofSeconds(10))
|
||||||
.build()
|
.build()
|
||||||
val workManager = WorkManager.getInstance(context)
|
val workManager = WorkManager.getInstance(context)
|
||||||
Log.i(TAG, "Asking to prune app backups now...")
|
Log.i(TAG, "Asking to prune app backups now...")
|
||||||
|
|
|
@ -24,8 +24,8 @@ import androidx.work.WorkManager
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.backend.BackendManager
|
import com.stevesoltys.seedvault.backend.BackendManager
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
|
||||||
import com.stevesoltys.seedvault.repo.AppBackupManager
|
import com.stevesoltys.seedvault.repo.AppBackupManager
|
||||||
|
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||||
import com.stevesoltys.seedvault.ui.notification.NOTIFICATION_ID_OBSERVER
|
import com.stevesoltys.seedvault.ui.notification.NOTIFICATION_ID_OBSERVER
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
|
|
|
@ -20,8 +20,8 @@ import com.stevesoltys.seedvault.crypto.TYPE_ICONS
|
||||||
import com.stevesoltys.seedvault.proto.Snapshot
|
import com.stevesoltys.seedvault.proto.Snapshot
|
||||||
import com.stevesoltys.seedvault.repo.AppBackupManager
|
import com.stevesoltys.seedvault.repo.AppBackupManager
|
||||||
import com.stevesoltys.seedvault.repo.BackupReceiver
|
import com.stevesoltys.seedvault.repo.BackupReceiver
|
||||||
import com.stevesoltys.seedvault.transport.backup.PackageService
|
|
||||||
import com.stevesoltys.seedvault.repo.Loader
|
import com.stevesoltys.seedvault.repo.Loader
|
||||||
|
import com.stevesoltys.seedvault.transport.backup.PackageService
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.calyxos.backup.storage.crypto.StreamCrypto.toByteArray
|
import org.calyxos.backup.storage.crypto.StreamCrypto.toByteArray
|
||||||
|
@ -150,13 +150,13 @@ internal class IconManager(
|
||||||
*/
|
*/
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
@Throws(IOException::class, SecurityException::class, GeneralSecurityException::class)
|
@Throws(IOException::class, SecurityException::class, GeneralSecurityException::class)
|
||||||
fun downloadIconsV1(version: Byte, token: Long, inputStream: InputStream): Set<String> {
|
fun downloadIconsV1(token: Long, inputStream: InputStream): Set<String> {
|
||||||
Log.d(TAG, "Start downloading icons")
|
Log.d(TAG, "Start downloading icons")
|
||||||
val folder = File(context.cacheDir, CACHE_FOLDER)
|
val folder = File(context.cacheDir, CACHE_FOLDER)
|
||||||
if (!folder.isDirectory && !folder.mkdirs())
|
if (!folder.isDirectory && !folder.mkdirs())
|
||||||
throw IOException("Can't create cache folder for icons")
|
throw IOException("Can't create cache folder for icons")
|
||||||
val set = mutableSetOf<String>()
|
val set = mutableSetOf<String>()
|
||||||
crypto.newDecryptingStreamV1(inputStream, getAD(version, token)).use { cryptoStream ->
|
crypto.newDecryptingStreamV1(inputStream, getAD(1.toByte(), token)).use { cryptoStream ->
|
||||||
ZipInputStream(cryptoStream).use { zip ->
|
ZipInputStream(cryptoStream).use { zip ->
|
||||||
var entry = zip.nextEntry
|
var entry = zip.nextEntry
|
||||||
while (entry != null) {
|
while (entry != null) {
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.io.ByteArrayOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
@TestInstance(PER_METHOD)
|
@TestInstance(PER_METHOD)
|
||||||
class CryptoIntegrationTest {
|
class CryptoIntegrationTest {
|
||||||
|
|
||||||
|
@ -41,17 +40,6 @@ class CryptoIntegrationTest {
|
||||||
assertThat(crypto.getRandomBytes(42), not(equalTo(crypto.getRandomBytes(42))))
|
assertThat(crypto.getRandomBytes(42), not(equalTo(crypto.getRandomBytes(42))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `decrypting encrypted cleartext works v1`() {
|
|
||||||
val ad = Random.nextBytes(42)
|
|
||||||
val outputStream = ByteArrayOutputStream()
|
|
||||||
crypto.newEncryptingStreamV1(outputStream, ad).use { it.write(cleartext) }
|
|
||||||
val inputStream = ByteArrayInputStream(outputStream.toByteArray())
|
|
||||||
crypto.newDecryptingStreamV1(inputStream, ad).use {
|
|
||||||
assertReadEquals(cleartext, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `decrypting encrypted cleartext works v2`() {
|
fun `decrypting encrypted cleartext works v2`() {
|
||||||
val ad = Random.nextBytes(42)
|
val ad = Random.nextBytes(42)
|
||||||
|
@ -63,18 +51,6 @@ class CryptoIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `decrypting encrypted cleartext fails with different AD v1`() {
|
|
||||||
val outputStream = ByteArrayOutputStream()
|
|
||||||
crypto.newEncryptingStreamV1(outputStream, Random.nextBytes(42)).use { it.write(cleartext) }
|
|
||||||
val inputStream = ByteArrayInputStream(outputStream.toByteArray())
|
|
||||||
assertThrows(IOException::class.java) {
|
|
||||||
crypto.newDecryptingStreamV1(inputStream, Random.nextBytes(41)).use {
|
|
||||||
it.read()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `decrypting encrypted cleartext fails with different AD v2`() {
|
fun `decrypting encrypted cleartext fails with different AD v2`() {
|
||||||
val outputStream = ByteArrayOutputStream()
|
val outputStream = ByteArrayOutputStream()
|
||||||
|
|
|
@ -11,8 +11,8 @@ import io.mockk.every
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.slot
|
import io.mockk.slot
|
||||||
import junit.framework.Assert.assertTrue
|
import org.junit.jupiter.api.Assertions.assertArrayEquals
|
||||||
import org.junit.Assert.assertArrayEquals
|
import org.junit.jupiter.api.Assertions.assertTrue
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD
|
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_METHOD
|
||||||
|
|
|
@ -21,7 +21,6 @@ import com.stevesoltys.seedvault.metadata.PackageState.APK_AND_DATA
|
||||||
import com.stevesoltys.seedvault.metadata.PackageState.NOT_ALLOWED
|
import com.stevesoltys.seedvault.metadata.PackageState.NOT_ALLOWED
|
||||||
import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA
|
import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA
|
||||||
import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED
|
import com.stevesoltys.seedvault.metadata.PackageState.WAS_STOPPED
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
|
@ -49,7 +48,6 @@ class MetadataManagerTest {
|
||||||
private val clock: Clock = mockk()
|
private val clock: Clock = mockk()
|
||||||
private val metadataWriter: MetadataWriter = mockk()
|
private val metadataWriter: MetadataWriter = mockk()
|
||||||
private val metadataReader: MetadataReader = mockk()
|
private val metadataReader: MetadataReader = mockk()
|
||||||
private val settingsManager: SettingsManager = mockk()
|
|
||||||
|
|
||||||
private val manager = MetadataManager(
|
private val manager = MetadataManager(
|
||||||
context = context,
|
context = context,
|
||||||
|
|
|
@ -86,7 +86,7 @@ internal class BackupReceiverTest : TransportTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `readFromStream`() = runBlocking {
|
fun readFromStream() = runBlocking {
|
||||||
val bytes = getRandomByteArray()
|
val bytes = getRandomByteArray()
|
||||||
val chunkBytes1 = getRandomByteArray()
|
val chunkBytes1 = getRandomByteArray()
|
||||||
val chunkBytes2 = getRandomByteArray()
|
val chunkBytes2 = getRandomByteArray()
|
||||||
|
|
|
@ -38,8 +38,7 @@ internal class SnapshotCreatorTest : TransportTest() {
|
||||||
|
|
||||||
private val ctx: Context = ApplicationProvider.getApplicationContext()
|
private val ctx: Context = ApplicationProvider.getApplicationContext()
|
||||||
private val packageService: PackageService = mockk()
|
private val packageService: PackageService = mockk()
|
||||||
private val snapshotCreator =
|
private val snapshotCreator = SnapshotCreator(ctx, clock, packageService, metadataManager)
|
||||||
SnapshotCreator(ctx, clock, packageService, settingsManager, metadataManager)
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test onApkBackedUp`() {
|
fun `test onApkBackedUp`() {
|
||||||
|
|
|
@ -22,16 +22,16 @@ import com.stevesoltys.seedvault.getRandomString
|
||||||
import com.stevesoltys.seedvault.metadata.PackageMetadata
|
import com.stevesoltys.seedvault.metadata.PackageMetadata
|
||||||
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
|
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
|
||||||
import com.stevesoltys.seedvault.proto.Snapshot
|
import com.stevesoltys.seedvault.proto.Snapshot
|
||||||
|
import com.stevesoltys.seedvault.repo.AppBackupManager
|
||||||
|
import com.stevesoltys.seedvault.repo.BackupReceiver
|
||||||
|
import com.stevesoltys.seedvault.repo.Loader
|
||||||
|
import com.stevesoltys.seedvault.repo.SnapshotCreator
|
||||||
|
import com.stevesoltys.seedvault.repo.SnapshotManager
|
||||||
|
import com.stevesoltys.seedvault.repo.hexFromProto
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
||||||
import com.stevesoltys.seedvault.repo.SnapshotManager
|
|
||||||
import com.stevesoltys.seedvault.transport.TransportTest
|
import com.stevesoltys.seedvault.transport.TransportTest
|
||||||
import com.stevesoltys.seedvault.repo.AppBackupManager
|
|
||||||
import com.stevesoltys.seedvault.repo.BackupReceiver
|
|
||||||
import com.stevesoltys.seedvault.repo.SnapshotCreator
|
|
||||||
import com.stevesoltys.seedvault.repo.hexFromProto
|
|
||||||
import com.stevesoltys.seedvault.repo.Loader
|
|
||||||
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
|
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
|
||||||
import com.stevesoltys.seedvault.worker.ApkBackup
|
import com.stevesoltys.seedvault.worker.ApkBackup
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
|
@ -41,7 +41,6 @@ import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.mockkStatic
|
import io.mockk.mockkStatic
|
||||||
import io.mockk.slot
|
import io.mockk.slot
|
||||||
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.calyxos.seedvault.core.backends.AppBackupFileType
|
import org.calyxos.seedvault.core.backends.AppBackupFileType
|
||||||
import org.calyxos.seedvault.core.backends.Backend
|
import org.calyxos.seedvault.core.backends.Backend
|
||||||
|
|
|
@ -29,15 +29,15 @@ import com.stevesoltys.seedvault.metadata.PackageMetadataMap
|
||||||
import com.stevesoltys.seedvault.proto.SnapshotKt.blob
|
import com.stevesoltys.seedvault.proto.SnapshotKt.blob
|
||||||
import com.stevesoltys.seedvault.proto.SnapshotKt.split
|
import com.stevesoltys.seedvault.proto.SnapshotKt.split
|
||||||
import com.stevesoltys.seedvault.proto.copy
|
import com.stevesoltys.seedvault.proto.copy
|
||||||
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
|
import com.stevesoltys.seedvault.repo.Loader
|
||||||
|
import com.stevesoltys.seedvault.repo.hexFromProto
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
||||||
import com.stevesoltys.seedvault.transport.TransportTest
|
import com.stevesoltys.seedvault.transport.TransportTest
|
||||||
import com.stevesoltys.seedvault.repo.hexFromProto
|
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
|
||||||
import com.stevesoltys.seedvault.repo.Loader
|
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
|
|
@ -26,14 +26,14 @@ import com.stevesoltys.seedvault.getRandomString
|
||||||
import com.stevesoltys.seedvault.metadata.ApkSplit
|
import com.stevesoltys.seedvault.metadata.ApkSplit
|
||||||
import com.stevesoltys.seedvault.metadata.PackageMetadata
|
import com.stevesoltys.seedvault.metadata.PackageMetadata
|
||||||
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
|
import com.stevesoltys.seedvault.metadata.PackageMetadataMap
|
||||||
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
|
import com.stevesoltys.seedvault.repo.Loader
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED_SYSTEM_APP
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
||||||
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
||||||
import com.stevesoltys.seedvault.transport.TransportTest
|
import com.stevesoltys.seedvault.transport.TransportTest
|
||||||
import com.stevesoltys.seedvault.repo.Loader
|
import com.stevesoltys.seedvault.transport.restore.RestorableBackup
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
|
|
@ -9,9 +9,9 @@ import com.stevesoltys.seedvault.getRandomString
|
||||||
import com.stevesoltys.seedvault.transport.TransportTest
|
import com.stevesoltys.seedvault.transport.TransportTest
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.jupiter.api.Assertions.assertFalse
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.jupiter.api.Assertions.assertTrue
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
|
@ -93,16 +93,15 @@ internal class CoordinatorIntegrationTest : TransportTest() {
|
||||||
)
|
)
|
||||||
private val packageService: PackageService = mockk()
|
private val packageService: PackageService = mockk()
|
||||||
private val backup = BackupCoordinator(
|
private val backup = BackupCoordinator(
|
||||||
context,
|
context = context,
|
||||||
backendManager,
|
backendManager = backendManager,
|
||||||
appBackupManager,
|
appBackupManager = appBackupManager,
|
||||||
kvBackup,
|
kv = kvBackup,
|
||||||
fullBackup,
|
full = fullBackup,
|
||||||
clock,
|
packageService = packageService,
|
||||||
packageService,
|
metadataManager = metadataManager,
|
||||||
metadataManager,
|
settingsManager = settingsManager,
|
||||||
settingsManager,
|
nm = notificationManager,
|
||||||
notificationManager
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private val kvRestore = KVRestore(
|
private val kvRestore = KVRestore(
|
||||||
|
|
|
@ -13,7 +13,6 @@ import android.os.ParcelFileDescriptor
|
||||||
import com.stevesoltys.seedvault.backend.BackendManager
|
import com.stevesoltys.seedvault.backend.BackendManager
|
||||||
import com.stevesoltys.seedvault.getRandomString
|
import com.stevesoltys.seedvault.getRandomString
|
||||||
import com.stevesoltys.seedvault.metadata.BackupType
|
import com.stevesoltys.seedvault.metadata.BackupType
|
||||||
import com.stevesoltys.seedvault.metadata.PackageMetadata
|
|
||||||
import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA
|
import com.stevesoltys.seedvault.metadata.PackageState.NO_DATA
|
||||||
import com.stevesoltys.seedvault.metadata.PackageState.QUOTA_EXCEEDED
|
import com.stevesoltys.seedvault.metadata.PackageState.QUOTA_EXCEEDED
|
||||||
import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR
|
import com.stevesoltys.seedvault.metadata.PackageState.UNKNOWN_ERROR
|
||||||
|
@ -51,7 +50,6 @@ internal class BackupCoordinatorTest : BackupTest() {
|
||||||
appBackupManager = appBackupManager,
|
appBackupManager = appBackupManager,
|
||||||
kv = kv,
|
kv = kv,
|
||||||
full = full,
|
full = full,
|
||||||
clock = clock,
|
|
||||||
packageService = packageService,
|
packageService = packageService,
|
||||||
metadataManager = metadataManager,
|
metadataManager = metadataManager,
|
||||||
settingsManager = settingsManager,
|
settingsManager = settingsManager,
|
||||||
|
@ -60,7 +58,6 @@ internal class BackupCoordinatorTest : BackupTest() {
|
||||||
|
|
||||||
private val backend = mockk<Backend>()
|
private val backend = mockk<Backend>()
|
||||||
private val fileDescriptor: ParcelFileDescriptor = mockk()
|
private val fileDescriptor: ParcelFileDescriptor = mockk()
|
||||||
private val packageMetadata: PackageMetadata = mockk()
|
|
||||||
private val safProperties = SafProperties(
|
private val safProperties = SafProperties(
|
||||||
config = Uri.EMPTY,
|
config = Uri.EMPTY,
|
||||||
name = getRandomString(),
|
name = getRandomString(),
|
||||||
|
|
|
@ -66,7 +66,7 @@ internal class BackupCreationTest : BackupTest() {
|
||||||
private val appBackupManager = mockk<AppBackupManager>()
|
private val appBackupManager = mockk<AppBackupManager>()
|
||||||
private val packageService = mockk<PackageService>()
|
private val packageService = mockk<PackageService>()
|
||||||
private val snapshotCreator =
|
private val snapshotCreator =
|
||||||
SnapshotCreator(context, clock, packageService, settingsManager, mockk(relaxed = true))
|
SnapshotCreator(context, clock, packageService, mockk(relaxed = true))
|
||||||
private val notificationManager = mockk<BackupNotificationManager>()
|
private val notificationManager = mockk<BackupNotificationManager>()
|
||||||
private val db = TestKvDbManager()
|
private val db = TestKvDbManager()
|
||||||
|
|
||||||
|
@ -80,7 +80,6 @@ internal class BackupCreationTest : BackupTest() {
|
||||||
appBackupManager = appBackupManager,
|
appBackupManager = appBackupManager,
|
||||||
kv = kvBackup,
|
kv = kvBackup,
|
||||||
full = fullBackup,
|
full = fullBackup,
|
||||||
clock = clock,
|
|
||||||
packageService = packageService,
|
packageService = packageService,
|
||||||
metadataManager = metadataManager,
|
metadataManager = metadataManager,
|
||||||
settingsManager = settingsManager,
|
settingsManager = settingsManager,
|
||||||
|
|
|
@ -31,7 +31,6 @@ import io.mockk.coVerify
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.mockkStatic
|
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.calyxos.seedvault.core.backends.AppBackupFileType
|
import org.calyxos.seedvault.core.backends.AppBackupFileType
|
||||||
|
@ -90,28 +89,17 @@ internal class RestoreCoordinatorTest : TransportTest() {
|
||||||
chunkIds = listOf(chunkId2),
|
chunkIds = listOf(chunkId2),
|
||||||
)
|
)
|
||||||
|
|
||||||
mockkStatic("com.stevesoltys.seedvault.backend.BackendExtKt")
|
|
||||||
every { backendManager.backend } returns backend
|
every { backendManager.backend } returns backend
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getAvailableRestoreSets() builds set from plugin response`() = runBlocking {
|
fun `getAvailableRestoreSets() builds set from plugin response`() = runBlocking {
|
||||||
val info1 = FileInfo(LegacyAppBackupFile.Metadata(token), 1)
|
val handle1 = LegacyAppBackupFile.Metadata(token)
|
||||||
val info2 = FileInfo(LegacyAppBackupFile.Metadata(token + 1), 2)
|
val handle2 = LegacyAppBackupFile.Metadata(token + 1)
|
||||||
|
|
||||||
coEvery {
|
coEvery { backend.getAvailableBackupFileHandles() } returns listOf(handle1, handle2)
|
||||||
backend.list(
|
coEvery { backend.load(handle1) } returns inputStream
|
||||||
topLevelFolder = null,
|
coEvery { backend.load(handle2) } returns inputStream
|
||||||
AppBackupFileType.Snapshot::class, LegacyAppBackupFile.Metadata::class,
|
|
||||||
callback = captureLambda<(FileInfo) -> Unit>()
|
|
||||||
)
|
|
||||||
} answers {
|
|
||||||
val callback = lambda<(FileInfo) -> Unit>().captured
|
|
||||||
callback(info1)
|
|
||||||
callback(info2)
|
|
||||||
}
|
|
||||||
coEvery { backend.load(info1.fileHandle) } returns inputStream
|
|
||||||
coEvery { backend.load(info2.fileHandle) } returns inputStream
|
|
||||||
every { metadataReader.readMetadata(inputStream, token) } returns metadata
|
every { metadataReader.readMetadata(inputStream, token) } returns metadata
|
||||||
every { metadataReader.readMetadata(inputStream, token + 1) } returns metadata
|
every { metadataReader.readMetadata(inputStream, token + 1) } returns metadata
|
||||||
every { inputStream.close() } just Runs
|
every { inputStream.close() } just Runs
|
||||||
|
@ -146,22 +134,12 @@ internal class RestoreCoordinatorTest : TransportTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `startRestore() fetches metadata if missing`() = runBlocking {
|
fun `startRestore() fetches metadata if missing`() = runBlocking {
|
||||||
val info1 = FileInfo(LegacyAppBackupFile.Metadata(token), 1)
|
val handle1 = LegacyAppBackupFile.Metadata(token)
|
||||||
val info2 = FileInfo(LegacyAppBackupFile.Metadata(token + 1), 2)
|
val handle2 = LegacyAppBackupFile.Metadata(token + 1)
|
||||||
|
|
||||||
coEvery {
|
coEvery { backend.getAvailableBackupFileHandles() } returns listOf(handle1, handle2)
|
||||||
backend.list(
|
coEvery { backend.load(handle1) } returns inputStream
|
||||||
topLevelFolder = null,
|
coEvery { backend.load(handle2) } returns inputStream
|
||||||
AppBackupFileType.Snapshot::class, LegacyAppBackupFile.Metadata::class,
|
|
||||||
callback = captureLambda<(FileInfo) -> Unit>()
|
|
||||||
)
|
|
||||||
} answers {
|
|
||||||
val callback = lambda<(FileInfo) -> Unit>().captured
|
|
||||||
callback(info1)
|
|
||||||
callback(info2)
|
|
||||||
}
|
|
||||||
coEvery { backend.load(info1.fileHandle) } returns inputStream
|
|
||||||
coEvery { backend.load(info2.fileHandle) } returns inputStream
|
|
||||||
every { metadataReader.readMetadata(inputStream, token) } returns metadata
|
every { metadataReader.readMetadata(inputStream, token) } returns metadata
|
||||||
every { metadataReader.readMetadata(inputStream, token + 1) } returns metadata
|
every { metadataReader.readMetadata(inputStream, token + 1) } returns metadata
|
||||||
every { inputStream.close() } just Runs
|
every { inputStream.close() } just Runs
|
||||||
|
@ -273,21 +251,10 @@ internal class RestoreCoordinatorTest : TransportTest() {
|
||||||
@Test
|
@Test
|
||||||
fun `startRestore() errors when it can't find snapshots`() = runBlocking {
|
fun `startRestore() errors when it can't find snapshots`() = runBlocking {
|
||||||
val handle = AppBackupFileType.Snapshot(repoId, getRandomByteArray(32).toHexString())
|
val handle = AppBackupFileType.Snapshot(repoId, getRandomByteArray(32).toHexString())
|
||||||
val info = FileInfo(handle, 1)
|
|
||||||
|
|
||||||
every { backendManager.backendProperties } returns safStorage
|
every { backendManager.backendProperties } returns safStorage
|
||||||
every { safStorage.isUnavailableUsb(context) } returns false
|
every { safStorage.isUnavailableUsb(context) } returns false
|
||||||
|
coEvery { backend.getAvailableBackupFileHandles() } returns listOf(handle)
|
||||||
coEvery {
|
|
||||||
backend.list(
|
|
||||||
topLevelFolder = null,
|
|
||||||
AppBackupFileType.Snapshot::class, LegacyAppBackupFile.Metadata::class,
|
|
||||||
callback = captureLambda<(FileInfo) -> Unit>()
|
|
||||||
)
|
|
||||||
} answers {
|
|
||||||
val callback = lambda<(FileInfo) -> Unit>().captured
|
|
||||||
callback(info)
|
|
||||||
}
|
|
||||||
coEvery { snapshotManager.loadSnapshot(handle) } returns snapshot.copy {
|
coEvery { snapshotManager.loadSnapshot(handle) } returns snapshot.copy {
|
||||||
token = this@RestoreCoordinatorTest.token - 1 // unexpected token
|
token = this@RestoreCoordinatorTest.token - 1 // unexpected token
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ import com.stevesoltys.seedvault.proto.copy
|
||||||
import com.stevesoltys.seedvault.repo.AppBackupManager
|
import com.stevesoltys.seedvault.repo.AppBackupManager
|
||||||
import com.stevesoltys.seedvault.repo.BackupData
|
import com.stevesoltys.seedvault.repo.BackupData
|
||||||
import com.stevesoltys.seedvault.repo.BackupReceiver
|
import com.stevesoltys.seedvault.repo.BackupReceiver
|
||||||
import com.stevesoltys.seedvault.transport.backup.BackupTest
|
|
||||||
import com.stevesoltys.seedvault.repo.SnapshotCreator
|
import com.stevesoltys.seedvault.repo.SnapshotCreator
|
||||||
|
import com.stevesoltys.seedvault.transport.backup.BackupTest
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
|
|
|
@ -23,6 +23,5 @@ public object Constants {
|
||||||
public val appSnapshotRegex: Regex = Regex("(^[a-f0-9]{64})\\.snapshot$")
|
public val appSnapshotRegex: Regex = Regex("(^[a-f0-9]{64})\\.snapshot$")
|
||||||
public val fileSnapshotRegex: Regex = Regex("(^[0-9]{13})\\.SeedSnap$") // good until year 2286
|
public val fileSnapshotRegex: Regex = Regex("(^[0-9]{13})\\.SeedSnap$") // good until year 2286
|
||||||
public const val MIME_TYPE: String = "application/octet-stream"
|
public const val MIME_TYPE: String = "application/octet-stream"
|
||||||
public const val CHUNK_FOLDER_COUNT: Int = 256
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ import org.calyxos.backup.storage.api.BackupFile
|
||||||
import org.calyxos.backup.storage.api.StorageBackup
|
import org.calyxos.backup.storage.api.StorageBackup
|
||||||
import org.calyxos.backup.storage.backup.NotificationBackupObserver
|
import org.calyxos.backup.storage.backup.NotificationBackupObserver
|
||||||
import kotlin.time.DurationUnit
|
import kotlin.time.DurationUnit
|
||||||
import kotlin.time.ExperimentalTime
|
|
||||||
import kotlin.time.toDuration
|
import kotlin.time.toDuration
|
||||||
|
|
||||||
data class BackupProgress(
|
data class BackupProgress(
|
||||||
|
@ -91,7 +90,6 @@ internal class BackupStats(
|
||||||
liveData.postValue(BackupProgress(filesProcessed, totalFiles, null))
|
liveData.postValue(BackupProgress(filesProcessed, totalFiles, null))
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalTime::class)
|
|
||||||
override suspend fun onBackupComplete(backupDuration: Long?) {
|
override suspend fun onBackupComplete(backupDuration: Long?) {
|
||||||
super.onBackupComplete(backupDuration)
|
super.onBackupComplete(backupDuration)
|
||||||
|
|
||||||
|
@ -162,7 +160,6 @@ internal class BackupStats(
|
||||||
liveData.postValue(BackupProgress(filesProcessed, totalFiles, text))
|
liveData.postValue(BackupProgress(filesProcessed, totalFiles, text))
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalTime::class)
|
|
||||||
override suspend fun onPruneComplete(pruneDuration: Long) {
|
override suspend fun onPruneComplete(pruneDuration: Long) {
|
||||||
super.onPruneComplete(pruneDuration)
|
super.onPruneComplete(pruneDuration)
|
||||||
|
|
||||||
|
|
|
@ -10,17 +10,17 @@ import android.security.keystore.KeyProperties.PURPOSE_ENCRYPT
|
||||||
import android.security.keystore.KeyProperties.PURPOSE_SIGN
|
import android.security.keystore.KeyProperties.PURPOSE_SIGN
|
||||||
import android.security.keystore.KeyProperties.PURPOSE_VERIFY
|
import android.security.keystore.KeyProperties.PURPOSE_VERIFY
|
||||||
import android.security.keystore.KeyProtection
|
import android.security.keystore.KeyProtection
|
||||||
|
import org.calyxos.seedvault.core.crypto.CoreCrypto.ALGORITHM_HMAC
|
||||||
import java.security.KeyStore
|
import java.security.KeyStore
|
||||||
import javax.crypto.SecretKey
|
import javax.crypto.SecretKey
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
object KeyManager: org.calyxos.seedvault.core.crypto.KeyManager {
|
object KeyManager : org.calyxos.seedvault.core.crypto.KeyManager {
|
||||||
|
|
||||||
private const val KEY_SIZE = 256
|
private const val KEY_SIZE = 256
|
||||||
internal const val KEY_SIZE_BYTES = KEY_SIZE / 8
|
private const val KEY_SIZE_BYTES = KEY_SIZE / 8
|
||||||
private const val KEY_ALIAS_MASTER = "com.stevesoltys.seedvault.master"
|
private const val KEY_ALIAS_MASTER = "com.stevesoltys.seedvault.master"
|
||||||
private const val ANDROID_KEY_STORE = "AndroidKeyStore"
|
private const val ANDROID_KEY_STORE = "AndroidKeyStore"
|
||||||
private const val ALGORITHM_HMAC = "HmacSHA256"
|
|
||||||
|
|
||||||
private const val FAKE_SEED = "This is a legacy backup key 1234"
|
private const val FAKE_SEED = "This is a legacy backup key 1234"
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,8 @@ import org.calyxos.backup.storage.api.BackupFile
|
||||||
import org.calyxos.backup.storage.scanner.DocumentScanner
|
import org.calyxos.backup.storage.scanner.DocumentScanner
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.time.ExperimentalTime
|
|
||||||
import kotlin.time.measureTimedValue
|
import kotlin.time.measureTimedValue
|
||||||
|
|
||||||
@OptIn(ExperimentalTime::class)
|
|
||||||
fun scanTree(context: Context, documentScanner: DocumentScanner, treeUri: Uri): String {
|
fun scanTree(context: Context, documentScanner: DocumentScanner, treeUri: Uri): String {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
val timedResult = measureTimedValue {
|
val timedResult = measureTimedValue {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import org.calyxos.backup.storage.api.BackupFile
|
||||||
import org.calyxos.backup.storage.scanner.MediaScanner
|
import org.calyxos.backup.storage.scanner.MediaScanner
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.time.ExperimentalTime
|
|
||||||
import kotlin.time.TimedValue
|
import kotlin.time.TimedValue
|
||||||
import kotlin.time.measureTimedValue
|
import kotlin.time.measureTimedValue
|
||||||
|
|
||||||
|
@ -27,7 +26,6 @@ data class ScanResult(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalTime::class)
|
|
||||||
fun scanUri(context: Context, mediaScanner: MediaScanner, uri: Uri): String {
|
fun scanUri(context: Context, mediaScanner: MediaScanner, uri: Uri): String {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
val timedResult = measureTimedValue {
|
val timedResult = measureTimedValue {
|
||||||
|
@ -57,7 +55,6 @@ fun dump(context: Context, mediaFiles: List<BackupFile>, sb: StringBuilder? = nu
|
||||||
return ScanResult(itemsFound, totalSize)
|
return ScanResult(itemsFound, totalSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalTime::class)
|
|
||||||
fun appendStats(
|
fun appendStats(
|
||||||
context: Context,
|
context: Context,
|
||||||
sb: StringBuilder,
|
sb: StringBuilder,
|
||||||
|
|
|
@ -17,7 +17,6 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import android.widget.Toast.LENGTH_SHORT
|
import android.widget.Toast.LENGTH_SHORT
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import de.grobox.storagebackuptester.MainViewModel
|
import de.grobox.storagebackuptester.MainViewModel
|
||||||
|
|
|
@ -6,4 +6,5 @@
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@drawable/ic_launcher_background" />
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<item name="colorSecondaryVariant">@color/teal_200</item>
|
<item name="colorSecondaryVariant">@color/teal_200</item>
|
||||||
<item name="colorOnSecondary">@color/black</item>
|
<item name="colorOnSecondary">@color/black</item>
|
||||||
<!-- Status bar color. -->
|
<!-- Status bar color. -->
|
||||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
||||||
<!-- Customize your theme here. -->
|
<!-- Customize your theme here. -->
|
||||||
<item name="colorAccent">@color/matrix</item>
|
<item name="colorAccent">@color/matrix</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
SPDX-License-Identifier: Apache-2.0
|
SPDX-License-Identifier: Apache-2.0
|
||||||
-->
|
-->
|
||||||
<resources>
|
<resources>
|
||||||
<color name="purple_200">#FFBB86FC</color>
|
|
||||||
<color name="purple_500">#FF6200EE</color>
|
|
||||||
<color name="purple_700">#FF3700B3</color>
|
<color name="purple_700">#FF3700B3</color>
|
||||||
<color name="teal_200">#FF03DAC5</color>
|
<color name="teal_200">#FF03DAC5</color>
|
||||||
<color name="teal_700">#FF018786</color>
|
<color name="teal_700">#FF018786</color>
|
||||||
|
|
|
@ -11,7 +11,6 @@ import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.DurationUnit
|
import kotlin.time.DurationUnit
|
||||||
import kotlin.time.ExperimentalTime
|
|
||||||
import kotlin.time.toDuration
|
import kotlin.time.toDuration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +19,7 @@ import kotlin.time.toDuration
|
||||||
* So when building with AOSP 11, things will blow up.
|
* So when building with AOSP 11, things will blow up.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@OptIn(ExperimentalContracts::class, ExperimentalTime::class)
|
@OptIn(ExperimentalContracts::class)
|
||||||
internal inline fun measure(block: () -> Unit): Duration {
|
internal inline fun measure(block: () -> Unit): Duration {
|
||||||
contract {
|
contract {
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
|
@ -30,7 +29,7 @@ internal inline fun measure(block: () -> Unit): Duration {
|
||||||
return (System.currentTimeMillis() - start).toDuration(DurationUnit.MILLISECONDS)
|
return (System.currentTimeMillis() - start).toDuration(DurationUnit.MILLISECONDS)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalContracts::class, ExperimentalTime::class)
|
@OptIn(ExperimentalContracts::class)
|
||||||
internal inline fun <T> measure(text: String, block: () -> T): T {
|
internal inline fun <T> measure(text: String, block: () -> T): T {
|
||||||
contract {
|
contract {
|
||||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||||
|
|
Loading…
Reference in a new issue