Refactor code related to APK installs as preparation for upcoming changes
This commit is contained in:
parent
9830d2db95
commit
f45411d81b
16 changed files with 117 additions and 105 deletions
|
@ -13,6 +13,7 @@ import com.stevesoltys.seedvault.metadata.MetadataManager
|
||||||
import com.stevesoltys.seedvault.metadata.metadataModule
|
import com.stevesoltys.seedvault.metadata.metadataModule
|
||||||
import com.stevesoltys.seedvault.plugins.saf.documentsProviderModule
|
import com.stevesoltys.seedvault.plugins.saf.documentsProviderModule
|
||||||
import com.stevesoltys.seedvault.restore.RestoreViewModel
|
import com.stevesoltys.seedvault.restore.RestoreViewModel
|
||||||
|
import com.stevesoltys.seedvault.restore.install.installModule
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||||
import com.stevesoltys.seedvault.settings.SettingsViewModel
|
import com.stevesoltys.seedvault.settings.SettingsViewModel
|
||||||
import com.stevesoltys.seedvault.transport.backup.backupModule
|
import com.stevesoltys.seedvault.transport.backup.backupModule
|
||||||
|
@ -60,6 +61,7 @@ class App : Application() {
|
||||||
documentsProviderModule, // storage plugin
|
documentsProviderModule, // storage plugin
|
||||||
backupModule,
|
backupModule,
|
||||||
restoreModule,
|
restoreModule,
|
||||||
|
installModule,
|
||||||
appModule
|
appModule
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.annotation.CallSuper
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_APPS
|
import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_APPS
|
||||||
import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_BACKUP
|
import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_BACKUP
|
||||||
|
import com.stevesoltys.seedvault.restore.install.InstallProgressFragment
|
||||||
import com.stevesoltys.seedvault.ui.LiveEventHandler
|
import com.stevesoltys.seedvault.ui.LiveEventHandler
|
||||||
import com.stevesoltys.seedvault.ui.RequireProvisioningActivity
|
import com.stevesoltys.seedvault.ui.RequireProvisioningActivity
|
||||||
import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
|
import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
|
||||||
|
|
|
@ -37,10 +37,10 @@ import com.stevesoltys.seedvault.ui.AppBackupState.NOT_YET_BACKED_UP
|
||||||
import com.stevesoltys.seedvault.ui.AppBackupState.SUCCEEDED
|
import com.stevesoltys.seedvault.ui.AppBackupState.SUCCEEDED
|
||||||
import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_APPS
|
import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_APPS
|
||||||
import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_BACKUP
|
import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_BACKUP
|
||||||
|
import com.stevesoltys.seedvault.restore.install.InstallResult
|
||||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
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.ApkRestore
|
import com.stevesoltys.seedvault.restore.install.ApkRestore
|
||||||
import com.stevesoltys.seedvault.transport.restore.InstallResult
|
|
||||||
import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator
|
import com.stevesoltys.seedvault.transport.restore.RestoreCoordinator
|
||||||
import com.stevesoltys.seedvault.ui.LiveEvent
|
import com.stevesoltys.seedvault.ui.LiveEvent
|
||||||
import com.stevesoltys.seedvault.ui.MutableLiveEvent
|
import com.stevesoltys.seedvault.ui.MutableLiveEvent
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.stevesoltys.seedvault.transport.restore
|
package com.stevesoltys.seedvault.restore.install
|
||||||
|
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
@ -17,8 +17,8 @@ import android.content.pm.PackageInstaller.SessionParams
|
||||||
import android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL
|
import android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.FAILED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.SUCCEEDED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
@ -111,7 +111,7 @@ internal class ApkInstaller(private val context: Context) {
|
||||||
|
|
||||||
// update status and offer result
|
// update status and offer result
|
||||||
val status = if (success) SUCCEEDED else FAILED
|
val status = if (success) SUCCEEDED else FAILED
|
||||||
return installResult.update(packageName) { it.copy(status = status) }
|
return installResult.update(packageName) { it.copy(state = status) }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,33 +1,32 @@
|
||||||
package com.stevesoltys.seedvault.transport.restore
|
package com.stevesoltys.seedvault.restore.install
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager.GET_SIGNATURES
|
import android.content.pm.PackageManager.GET_SIGNATURES
|
||||||
import android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES
|
import android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES
|
||||||
import android.content.pm.PackageManager.NameNotFoundException
|
import android.content.pm.PackageManager.NameNotFoundException
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
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.restore.install.ApkInstallState.FAILED
|
||||||
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
||||||
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
||||||
import com.stevesoltys.seedvault.transport.backup.copyStreamsAndGetHash
|
import com.stevesoltys.seedvault.transport.backup.copyStreamsAndGetHash
|
||||||
import com.stevesoltys.seedvault.transport.backup.getSignatures
|
import com.stevesoltys.seedvault.transport.backup.getSignatures
|
||||||
import com.stevesoltys.seedvault.transport.backup.isSystemApp
|
import com.stevesoltys.seedvault.transport.backup.isSystemApp
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.FAILED
|
import com.stevesoltys.seedvault.transport.restore.RestorePlugin
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.IN_PROGRESS
|
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.QUEUED
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.TimeoutCancellationException
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.flow.flow
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
private val TAG = ApkRestore::class.java.simpleName
|
private val TAG = ApkRestore::class.java.simpleName
|
||||||
|
|
||||||
internal class ApkRestore(
|
internal class ApkRestore(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val restorePlugin: RestorePlugin,
|
private val restorePlugin: RestorePlugin,
|
||||||
private val apkInstaller: ApkInstaller = ApkInstaller(context)
|
private val apkInstaller: ApkInstaller
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val pm = context.packageManager
|
private val pm = context.packageManager
|
||||||
|
@ -43,7 +42,7 @@ internal class ApkRestore(
|
||||||
val installResult = MutableInstallResult(total)
|
val installResult = MutableInstallResult(total)
|
||||||
packages.forEach { (packageName, _) ->
|
packages.forEach { (packageName, _) ->
|
||||||
progress++
|
progress++
|
||||||
installResult[packageName] = ApkRestoreResult(packageName, progress, total, QUEUED)
|
installResult[packageName] = ApkInstallResult(packageName, progress, total, QUEUED)
|
||||||
}
|
}
|
||||||
emit(installResult)
|
emit(installResult)
|
||||||
|
|
||||||
|
@ -123,7 +122,7 @@ internal class ApkRestore(
|
||||||
|
|
||||||
installResult.update(packageName) { result ->
|
installResult.update(packageName) { result ->
|
||||||
result.copy(
|
result.copy(
|
||||||
status = IN_PROGRESS,
|
state = IN_PROGRESS,
|
||||||
name = name,
|
name = name,
|
||||||
icon = icon
|
icon = icon
|
||||||
)
|
)
|
||||||
|
@ -152,46 +151,7 @@ internal class ApkRestore(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fail(installResult: MutableInstallResult, packageName: String): InstallResult {
|
private fun fail(installResult: MutableInstallResult, packageName: String): InstallResult {
|
||||||
return installResult.update(packageName) { it.copy(status = FAILED) }
|
return installResult.update(packageName) { it.copy(state = FAILED) }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal typealias InstallResult = Map<String, ApkRestoreResult>
|
|
||||||
|
|
||||||
internal fun InstallResult.getInProgress(): ApkRestoreResult? {
|
|
||||||
val filtered = filterValues { result -> result.status == IN_PROGRESS }
|
|
||||||
if (filtered.isEmpty()) return null
|
|
||||||
check(filtered.size == 1) { "More than one package in progress: ${filtered.keys}" }
|
|
||||||
return filtered.values.first()
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class MutableInstallResult(initialCapacity: Int) :
|
|
||||||
ConcurrentHashMap<String, ApkRestoreResult>(initialCapacity) {
|
|
||||||
fun update(
|
|
||||||
packageName: String,
|
|
||||||
updateFun: (ApkRestoreResult) -> ApkRestoreResult
|
|
||||||
): MutableInstallResult {
|
|
||||||
val result = get(packageName)
|
|
||||||
check(result != null) { "ApkRestoreResult for $packageName does not exist." }
|
|
||||||
set(packageName, updateFun(result))
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal data class ApkRestoreResult(
|
|
||||||
val packageName: CharSequence,
|
|
||||||
val progress: Int,
|
|
||||||
val total: Int,
|
|
||||||
val status: ApkRestoreStatus,
|
|
||||||
val name: CharSequence? = null,
|
|
||||||
val icon: Drawable? = null
|
|
||||||
) : Comparable<ApkRestoreResult> {
|
|
||||||
override fun compareTo(other: ApkRestoreResult): Int {
|
|
||||||
return other.progress.compareTo(progress)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal enum class ApkRestoreStatus {
|
|
||||||
QUEUED, IN_PROGRESS, SUCCEEDED, FAILED
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.stevesoltys.seedvault.restore.install
|
||||||
|
|
||||||
|
import org.koin.android.ext.koin.androidContext
|
||||||
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
val installModule = module {
|
||||||
|
factory { ApkInstaller(androidContext()) }
|
||||||
|
factory { ApkRestore(androidContext(), get(), get()) }
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package com.stevesoltys.seedvault.restore
|
package com.stevesoltys.seedvault.restore.install
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -9,25 +9,24 @@ import androidx.recyclerview.widget.RecyclerView.Adapter
|
||||||
import androidx.recyclerview.widget.SortedList
|
import androidx.recyclerview.widget.SortedList
|
||||||
import androidx.recyclerview.widget.SortedListAdapterCallback
|
import androidx.recyclerview.widget.SortedListAdapterCallback
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreResult
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.FAILED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.IN_PROGRESS
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.QUEUED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.SUCCEEDED
|
|
||||||
import com.stevesoltys.seedvault.ui.AppViewHolder
|
import com.stevesoltys.seedvault.ui.AppViewHolder
|
||||||
|
|
||||||
internal class InstallProgressAdapter : Adapter<AppInstallViewHolder>() {
|
internal class InstallProgressAdapter : Adapter<AppInstallViewHolder>() {
|
||||||
|
|
||||||
private val items = SortedList<ApkRestoreResult>(
|
private val items = SortedList<ApkInstallResult>(
|
||||||
ApkRestoreResult::class.java,
|
ApkInstallResult::class.java,
|
||||||
object : SortedListAdapterCallback<ApkRestoreResult>(this) {
|
object : SortedListAdapterCallback<ApkInstallResult>(this) {
|
||||||
override fun areItemsTheSame(item1: ApkRestoreResult, item2: ApkRestoreResult) =
|
override fun areItemsTheSame(item1: ApkInstallResult, item2: ApkInstallResult) =
|
||||||
item1.packageName == item2.packageName
|
item1.packageName == item2.packageName
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: ApkRestoreResult, newItem: ApkRestoreResult) =
|
override fun areContentsTheSame(oldItem: ApkInstallResult, newItem: ApkInstallResult) =
|
||||||
oldItem == newItem
|
oldItem == newItem
|
||||||
|
|
||||||
override fun compare(item1: ApkRestoreResult, item2: ApkRestoreResult) =
|
override fun compare(item1: ApkInstallResult, item2: ApkInstallResult) =
|
||||||
item1.compareTo(item2)
|
item1.compareTo(item2)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -43,17 +42,17 @@ internal class InstallProgressAdapter : Adapter<AppInstallViewHolder>() {
|
||||||
holder.bind(items[position])
|
holder.bind(items[position])
|
||||||
}
|
}
|
||||||
|
|
||||||
fun update(items: Collection<ApkRestoreResult>) {
|
fun update(items: Collection<ApkInstallResult>) {
|
||||||
this.items.replaceAll(items)
|
this.items.replaceAll(items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AppInstallViewHolder(v: View) : AppViewHolder(v) {
|
internal class AppInstallViewHolder(v: View) : AppViewHolder(v) {
|
||||||
|
|
||||||
fun bind(item: ApkRestoreResult) {
|
fun bind(item: ApkInstallResult) {
|
||||||
appIcon.setImageDrawable(item.icon)
|
appIcon.setImageDrawable(item.icon)
|
||||||
appName.text = item.name
|
appName.text = item.name
|
||||||
when (item.status) {
|
when (item.state) {
|
||||||
IN_PROGRESS -> {
|
IN_PROGRESS -> {
|
||||||
appStatus.visibility = INVISIBLE
|
appStatus.visibility = INVISIBLE
|
||||||
progressBar.visibility = VISIBLE
|
progressBar.visibility = VISIBLE
|
|
@ -1,4 +1,4 @@
|
||||||
package com.stevesoltys.seedvault.restore
|
package com.stevesoltys.seedvault.restore.install
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -14,9 +14,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
|
import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.stevesoltys.seedvault.R
|
import com.stevesoltys.seedvault.R
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.QUEUED
|
import com.stevesoltys.seedvault.restore.RestoreViewModel
|
||||||
import com.stevesoltys.seedvault.transport.restore.InstallResult
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
||||||
import com.stevesoltys.seedvault.transport.restore.getInProgress
|
|
||||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
|
|
||||||
class InstallProgressFragment : Fragment() {
|
class InstallProgressFragment : Fragment() {
|
||||||
|
@ -76,7 +75,7 @@ class InstallProgressFragment : Fragment() {
|
||||||
// skip this screen, if there are no apps to install
|
// skip this screen, if there are no apps to install
|
||||||
if (installResult.isEmpty()) viewModel.onNextClicked()
|
if (installResult.isEmpty()) viewModel.onNextClicked()
|
||||||
|
|
||||||
val result = installResult.filterValues { it.status != QUEUED }
|
val result = installResult.filterValues { it.state != QUEUED }
|
||||||
val position = layoutManager.findFirstVisibleItemPosition()
|
val position = layoutManager.findFirstVisibleItemPosition()
|
||||||
adapter.update(result.values)
|
adapter.update(result.values)
|
||||||
if (position == 0) layoutManager.scrollToPosition(0)
|
if (position == 0) layoutManager.scrollToPosition(0)
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.stevesoltys.seedvault.restore.install
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
internal typealias InstallResult = Map<String, ApkInstallResult>
|
||||||
|
|
||||||
|
internal fun InstallResult.getInProgress(): ApkInstallResult? {
|
||||||
|
val filtered = filterValues { result -> result.state == ApkInstallState.IN_PROGRESS }
|
||||||
|
if (filtered.isEmpty()) return null
|
||||||
|
check(filtered.size == 1) { "More than one package in progress: ${filtered.keys}" }
|
||||||
|
return filtered.values.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class MutableInstallResult(initialCapacity: Int) :
|
||||||
|
ConcurrentHashMap<String, ApkInstallResult>(initialCapacity) {
|
||||||
|
fun update(
|
||||||
|
packageName: String,
|
||||||
|
updateFun: (ApkInstallResult) -> ApkInstallResult
|
||||||
|
): MutableInstallResult {
|
||||||
|
val result = get(packageName)
|
||||||
|
check(result != null) { "ApkRestoreResult for $packageName does not exist." }
|
||||||
|
set(packageName, updateFun(result))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal data class ApkInstallResult(
|
||||||
|
val packageName: CharSequence,
|
||||||
|
val progress: Int,
|
||||||
|
val total: Int,
|
||||||
|
val state: ApkInstallState,
|
||||||
|
val name: CharSequence? = null,
|
||||||
|
val icon: Drawable? = null
|
||||||
|
) : Comparable<ApkInstallResult> {
|
||||||
|
override fun compareTo(other: ApkInstallResult): Int {
|
||||||
|
return other.progress.compareTo(progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum class ApkInstallState {
|
||||||
|
QUEUED,
|
||||||
|
IN_PROGRESS,
|
||||||
|
SUCCEEDED,
|
||||||
|
FAILED
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import org.koin.dsl.module
|
||||||
|
|
||||||
val restoreModule = module {
|
val restoreModule = module {
|
||||||
single { OutputFactory() }
|
single { OutputFactory() }
|
||||||
factory { ApkRestore(androidContext(), get()) }
|
|
||||||
single { KVRestore(get<RestorePlugin>().kvRestorePlugin, get(), get(), get()) }
|
single { KVRestore(get<RestorePlugin>().kvRestorePlugin, get(), get(), get()) }
|
||||||
single { FullRestore(get<RestorePlugin>().fullRestorePlugin, get(), get(), get()) }
|
single { FullRestore(get<RestorePlugin>().fullRestorePlugin, get(), get(), get()) }
|
||||||
single { RestoreCoordinator(androidContext(), get(), get(), get(), get(), get(), get(), get()) }
|
single { RestoreCoordinator(androidContext(), get(), get(), get(), get(), get(), get(), get()) }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package com.stevesoltys.seedvault.transport.restore
|
package com.stevesoltys.seedvault.restore.install
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
|
@ -11,10 +11,12 @@ import android.graphics.drawable.Drawable
|
||||||
import com.stevesoltys.seedvault.getRandomString
|
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.transport.restore.ApkRestoreStatus.FAILED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.FAILED
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.IN_PROGRESS
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.IN_PROGRESS
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.QUEUED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.QUEUED
|
||||||
import com.stevesoltys.seedvault.transport.restore.ApkRestoreStatus.SUCCEEDED
|
import com.stevesoltys.seedvault.restore.install.ApkInstallState.SUCCEEDED
|
||||||
|
import com.stevesoltys.seedvault.transport.TransportTest
|
||||||
|
import com.stevesoltys.seedvault.transport.restore.RestorePlugin
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
@ -34,7 +36,7 @@ import kotlin.random.Random
|
||||||
|
|
||||||
@Suppress("BlockingMethodInNonBlockingContext")
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
internal class ApkRestoreTest : RestoreTest() {
|
internal class ApkRestoreTest : TransportTest() {
|
||||||
|
|
||||||
private val pm: PackageManager = mockk()
|
private val pm: PackageManager = mockk()
|
||||||
private val strictContext: Context = mockk<Context>().apply {
|
private val strictContext: Context = mockk<Context>().apply {
|
||||||
|
@ -79,13 +81,13 @@ internal class ApkRestoreTest : RestoreTest() {
|
||||||
when (index) {
|
when (index) {
|
||||||
0 -> {
|
0 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(QUEUED, result.status)
|
assertEquals(QUEUED, result.state)
|
||||||
assertEquals(1, result.progress)
|
assertEquals(1, result.progress)
|
||||||
assertEquals(1, result.total)
|
assertEquals(1, result.total)
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(FAILED, result.status)
|
assertEquals(FAILED, result.state)
|
||||||
}
|
}
|
||||||
else -> fail()
|
else -> fail()
|
||||||
}
|
}
|
||||||
|
@ -105,13 +107,13 @@ internal class ApkRestoreTest : RestoreTest() {
|
||||||
when (index) {
|
when (index) {
|
||||||
0 -> {
|
0 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(QUEUED, result.status)
|
assertEquals(QUEUED, result.state)
|
||||||
assertEquals(1, result.progress)
|
assertEquals(1, result.progress)
|
||||||
assertEquals(1, result.total)
|
assertEquals(1, result.total)
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(FAILED, result.status)
|
assertEquals(FAILED, result.state)
|
||||||
}
|
}
|
||||||
else -> fail()
|
else -> fail()
|
||||||
}
|
}
|
||||||
|
@ -143,19 +145,19 @@ internal class ApkRestoreTest : RestoreTest() {
|
||||||
when (index) {
|
when (index) {
|
||||||
0 -> {
|
0 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(QUEUED, result.status)
|
assertEquals(QUEUED, result.state)
|
||||||
assertEquals(1, result.progress)
|
assertEquals(1, result.progress)
|
||||||
assertEquals(1, result.total)
|
assertEquals(1, result.total)
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(IN_PROGRESS, result.status)
|
assertEquals(IN_PROGRESS, result.state)
|
||||||
assertEquals(appName, result.name)
|
assertEquals(appName, result.name)
|
||||||
assertEquals(icon, result.icon)
|
assertEquals(icon, result.icon)
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(FAILED, result.status)
|
assertEquals(FAILED, result.state)
|
||||||
}
|
}
|
||||||
else -> fail()
|
else -> fail()
|
||||||
}
|
}
|
||||||
|
@ -166,11 +168,11 @@ internal class ApkRestoreTest : RestoreTest() {
|
||||||
fun `test successful run`(@TempDir tmpDir: Path) = runBlocking {
|
fun `test successful run`(@TempDir tmpDir: Path) = runBlocking {
|
||||||
val installResult = MutableInstallResult(1).apply {
|
val installResult = MutableInstallResult(1).apply {
|
||||||
put(
|
put(
|
||||||
packageName, ApkRestoreResult(
|
packageName, ApkInstallResult(
|
||||||
packageName,
|
packageName,
|
||||||
progress = 1,
|
progress = 1,
|
||||||
total = 1,
|
total = 1,
|
||||||
status = SUCCEEDED
|
state = SUCCEEDED
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -194,19 +196,19 @@ internal class ApkRestoreTest : RestoreTest() {
|
||||||
when (i) {
|
when (i) {
|
||||||
0 -> {
|
0 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(QUEUED, result.status)
|
assertEquals(QUEUED, result.state)
|
||||||
assertEquals(1, result.progress)
|
assertEquals(1, result.progress)
|
||||||
assertEquals(1, result.total)
|
assertEquals(1, result.total)
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(IN_PROGRESS, result.status)
|
assertEquals(IN_PROGRESS, result.state)
|
||||||
assertEquals(appName, result.name)
|
assertEquals(appName, result.name)
|
||||||
assertEquals(icon, result.icon)
|
assertEquals(icon, result.icon)
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(SUCCEEDED, result.status)
|
assertEquals(SUCCEEDED, result.state)
|
||||||
}
|
}
|
||||||
else -> fail()
|
else -> fail()
|
||||||
}
|
}
|
||||||
|
@ -244,7 +246,7 @@ internal class ApkRestoreTest : RestoreTest() {
|
||||||
val installResult = MutableInstallResult(1).apply {
|
val installResult = MutableInstallResult(1).apply {
|
||||||
put(
|
put(
|
||||||
packageName,
|
packageName,
|
||||||
ApkRestoreResult(packageName, progress = 1, total = 1, status = SUCCEEDED)
|
ApkInstallResult(packageName, progress = 1, total = 1, state = SUCCEEDED)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
every {
|
every {
|
||||||
|
@ -262,22 +264,22 @@ internal class ApkRestoreTest : RestoreTest() {
|
||||||
when (i) {
|
when (i) {
|
||||||
0 -> {
|
0 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(QUEUED, result.status)
|
assertEquals(QUEUED, result.state)
|
||||||
assertEquals(1, result.progress)
|
assertEquals(1, result.progress)
|
||||||
assertEquals(1, result.total)
|
assertEquals(1, result.total)
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
assertEquals(IN_PROGRESS, result.status)
|
assertEquals(IN_PROGRESS, result.state)
|
||||||
assertEquals(appName, result.name)
|
assertEquals(appName, result.name)
|
||||||
assertEquals(icon, result.icon)
|
assertEquals(icon, result.icon)
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
val result = value[packageName] ?: fail()
|
val result = value[packageName] ?: fail()
|
||||||
if (willFail) {
|
if (willFail) {
|
||||||
assertEquals(FAILED, result.status)
|
assertEquals(FAILED, result.state)
|
||||||
} else {
|
} else {
|
||||||
assertEquals(SUCCEEDED, result.status)
|
assertEquals(SUCCEEDED, result.state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> fail()
|
else -> fail()
|
|
@ -103,7 +103,6 @@ internal class CoordinatorIntegrationTest : TransportTest() {
|
||||||
|
|
||||||
private val backupDataInput = mockk<BackupDataInput>()
|
private val backupDataInput = mockk<BackupDataInput>()
|
||||||
private val fileDescriptor = mockk<ParcelFileDescriptor>(relaxed = true)
|
private val fileDescriptor = mockk<ParcelFileDescriptor>(relaxed = true)
|
||||||
private val token = Random.nextLong()
|
|
||||||
private val appData = ByteArray(42).apply { Random.nextBytes(this) }
|
private val appData = ByteArray(42).apply { Random.nextBytes(this) }
|
||||||
private val appData2 = ByteArray(1337).apply { Random.nextBytes(this) }
|
private val appData2 = ByteArray(1337).apply { Random.nextBytes(this) }
|
||||||
private val metadataOutputStream = ByteArrayOutputStream()
|
private val metadataOutputStream = ByteArrayOutputStream()
|
||||||
|
|
|
@ -29,6 +29,7 @@ abstract class TransportTest {
|
||||||
protected val context = mockk<Context>(relaxed = true)
|
protected val context = mockk<Context>(relaxed = true)
|
||||||
|
|
||||||
protected val sigInfo: SigningInfo = mockk()
|
protected val sigInfo: SigningInfo = mockk()
|
||||||
|
protected val token = Random.nextLong()
|
||||||
protected val packageInfo = PackageInfo().apply {
|
protected val packageInfo = PackageInfo().apply {
|
||||||
packageName = "org.example"
|
packageName = "org.example"
|
||||||
longVersionCode = Random.nextLong()
|
longVersionCode = Random.nextLong()
|
||||||
|
|
|
@ -6,7 +6,6 @@ import com.stevesoltys.seedvault.header.VersionHeader
|
||||||
import com.stevesoltys.seedvault.transport.TransportTest
|
import com.stevesoltys.seedvault.transport.TransportTest
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
internal abstract class BackupTest : TransportTest() {
|
internal abstract class BackupTest : TransportTest() {
|
||||||
|
|
||||||
|
@ -15,7 +14,6 @@ internal abstract class BackupTest : TransportTest() {
|
||||||
protected val data = mockk<ParcelFileDescriptor>()
|
protected val data = mockk<ParcelFileDescriptor>()
|
||||||
protected val outputStream = mockk<OutputStream>()
|
protected val outputStream = mockk<OutputStream>()
|
||||||
|
|
||||||
protected val token = Random.nextLong()
|
|
||||||
protected val header = VersionHeader(packageName = packageInfo.packageName)
|
protected val header = VersionHeader(packageName = packageInfo.packageName)
|
||||||
protected val quota = 42L
|
protected val quota = 42L
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,6 @@ internal class RestoreCoordinatorTest : TransportTest() {
|
||||||
metadataReader
|
metadataReader
|
||||||
)
|
)
|
||||||
|
|
||||||
private val token = Random.nextLong()
|
|
||||||
private val inputStream = mockk<InputStream>()
|
private val inputStream = mockk<InputStream>()
|
||||||
private val storage: Storage = mockk()
|
private val storage: Storage = mockk()
|
||||||
private val documentFile: DocumentFile = mockk()
|
private val documentFile: DocumentFile = mockk()
|
||||||
|
|
|
@ -7,7 +7,6 @@ import com.stevesoltys.seedvault.header.VERSION
|
||||||
import com.stevesoltys.seedvault.transport.TransportTest
|
import com.stevesoltys.seedvault.transport.TransportTest
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
internal abstract class RestoreTest : TransportTest() {
|
internal abstract class RestoreTest : TransportTest() {
|
||||||
|
|
||||||
|
@ -15,7 +14,6 @@ internal abstract class RestoreTest : TransportTest() {
|
||||||
protected val headerReader = mockk<HeaderReader>()
|
protected val headerReader = mockk<HeaderReader>()
|
||||||
protected val fileDescriptor = mockk<ParcelFileDescriptor>()
|
protected val fileDescriptor = mockk<ParcelFileDescriptor>()
|
||||||
|
|
||||||
protected val token = Random.nextLong()
|
|
||||||
protected val data = getRandomByteArray()
|
protected val data = getRandomByteArray()
|
||||||
protected val inputStream = mockk<InputStream>()
|
protected val inputStream = mockk<InputStream>()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue