Code style and lint after Android 12 version bumps
This commit is contained in:
parent
e80d89f0a2
commit
579919d5e7
116 changed files with 254 additions and 252 deletions
|
@ -6,6 +6,7 @@
|
|||
</option>
|
||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
|
||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
|
||||
<option name="ALLOW_TRAILING_COMMA" value="true" />
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
|
|
|
@ -5,8 +5,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
|||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
|
||||
import com.stevesoltys.seedvault.plugins.StoragePlugin
|
||||
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderStoragePlugin
|
||||
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderLegacyPlugin
|
||||
import com.stevesoltys.seedvault.plugins.saf.DocumentsProviderStoragePlugin
|
||||
import com.stevesoltys.seedvault.plugins.saf.DocumentsStorage
|
||||
import com.stevesoltys.seedvault.plugins.saf.FILE_BACKUP_METADATA
|
||||
import com.stevesoltys.seedvault.plugins.saf.deleteContents
|
||||
|
@ -36,6 +36,7 @@ class PluginTest : KoinComponent {
|
|||
private val storage = DocumentsStorage(context, mockedSettingsManager)
|
||||
|
||||
private val storagePlugin: StoragePlugin = DocumentsProviderStoragePlugin(context, storage)
|
||||
|
||||
@Suppress("Deprecation")
|
||||
private val legacyStoragePlugin: LegacyStoragePlugin =
|
||||
DocumentsProviderLegacyPlugin(context, storage)
|
||||
|
|
|
@ -72,8 +72,8 @@
|
|||
|
||||
<activity
|
||||
android:name=".settings.SettingsActivity"
|
||||
android:permission="com.stevesoltys.seedvault.OPEN_SETTINGS"
|
||||
android:exported="true" />
|
||||
android:exported="true"
|
||||
android:permission="com.stevesoltys.seedvault.OPEN_SETTINGS" />
|
||||
|
||||
<activity
|
||||
android:name=".ui.storage.StorageActivity"
|
||||
|
@ -91,9 +91,9 @@
|
|||
|
||||
<activity
|
||||
android:name=".restore.RestoreActivity"
|
||||
android:permission="com.stevesoltys.seedvault.RESTORE_BACKUP"
|
||||
android:exported="true"
|
||||
android:label="@string/restore_title"
|
||||
android:permission="com.stevesoltys.seedvault.RESTORE_BACKUP"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="com.stevesoltys.seedvault.RESTORE_BACKUP" />
|
||||
|
@ -134,7 +134,9 @@
|
|||
<intent-filter>
|
||||
<action android:name="android.telephony.action.SECRET_CODE" />
|
||||
<!-- *#*#RESTORE#*#* -->
|
||||
<data android:scheme="android_secret_code" android:host="7378673" />
|
||||
<data
|
||||
android:host="7378673"
|
||||
android:scheme="android_secret_code" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import android.content.Context.BACKUP_SERVICE
|
|||
import android.os.Build
|
||||
import android.os.ServiceManager.getService
|
||||
import android.os.StrictMode
|
||||
import org.koin.core.logger.Level
|
||||
import com.stevesoltys.seedvault.crypto.cryptoModule
|
||||
import com.stevesoltys.seedvault.header.headerModule
|
||||
import com.stevesoltys.seedvault.metadata.MetadataManager
|
||||
|
@ -31,6 +30,7 @@ import org.koin.android.ext.koin.androidContext
|
|||
import org.koin.android.ext.koin.androidLogger
|
||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.core.logger.Level
|
||||
import org.koin.dsl.module
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,13 +8,13 @@ import android.util.Log
|
|||
import com.stevesoltys.seedvault.restore.RestoreActivity
|
||||
|
||||
private val TAG = BroadcastReceiver::class.java.simpleName
|
||||
private val RESTORE_SECRET_CODE = "7378673"
|
||||
private const val RESTORE_SECRET_CODE = "7378673"
|
||||
|
||||
class SecretCodeReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val host = intent.data.host
|
||||
if (!RESTORE_SECRET_CODE.equals(host)) return
|
||||
if (RESTORE_SECRET_CODE != host) return
|
||||
Log.d(TAG, "Restore secret code received.")
|
||||
val i = Intent(context, RestoreActivity::class.java).apply {
|
||||
flags = FLAG_ACTIVITY_NEW_TASK
|
||||
|
|
|
@ -57,7 +57,7 @@ internal interface Crypto {
|
|||
@Throws(IOException::class, GeneralSecurityException::class)
|
||||
fun newEncryptingStream(
|
||||
outputStream: OutputStream,
|
||||
associatedData: ByteArray
|
||||
associatedData: ByteArray,
|
||||
): OutputStream
|
||||
|
||||
/**
|
||||
|
@ -67,7 +67,7 @@ internal interface Crypto {
|
|||
@Throws(IOException::class, GeneralSecurityException::class)
|
||||
fun newDecryptingStream(
|
||||
inputStream: InputStream,
|
||||
associatedData: ByteArray
|
||||
associatedData: ByteArray,
|
||||
): InputStream
|
||||
|
||||
/**
|
||||
|
@ -78,13 +78,14 @@ internal interface Crypto {
|
|||
*
|
||||
* @return The read [VersionHeader] present in the beginning of the given [InputStream].
|
||||
*/
|
||||
@Suppress("Deprecation")
|
||||
@Deprecated("Use newDecryptingStream instead")
|
||||
@Throws(IOException::class, SecurityException::class)
|
||||
fun decryptHeader(
|
||||
inputStream: InputStream,
|
||||
expectedVersion: Byte,
|
||||
expectedPackageName: String,
|
||||
expectedKey: String? = null
|
||||
expectedKey: String? = null,
|
||||
): VersionHeader
|
||||
|
||||
/**
|
||||
|
@ -118,7 +119,7 @@ internal const val TYPE_BACKUP_FULL: Byte = 0x02
|
|||
internal class CryptoImpl(
|
||||
private val keyManager: KeyManager,
|
||||
private val cipherFactory: CipherFactory,
|
||||
private val headerReader: HeaderReader
|
||||
private val headerReader: HeaderReader,
|
||||
) : Crypto {
|
||||
|
||||
private val key: ByteArray by lazy {
|
||||
|
@ -151,7 +152,7 @@ internal class CryptoImpl(
|
|||
@Throws(IOException::class, GeneralSecurityException::class)
|
||||
override fun newEncryptingStream(
|
||||
outputStream: OutputStream,
|
||||
associatedData: ByteArray
|
||||
associatedData: ByteArray,
|
||||
): OutputStream {
|
||||
return StreamCrypto.newEncryptingStream(key, outputStream, associatedData)
|
||||
}
|
||||
|
@ -159,18 +160,19 @@ internal class CryptoImpl(
|
|||
@Throws(IOException::class, GeneralSecurityException::class)
|
||||
override fun newDecryptingStream(
|
||||
inputStream: InputStream,
|
||||
associatedData: ByteArray
|
||||
associatedData: ByteArray,
|
||||
): InputStream {
|
||||
return StreamCrypto.newDecryptingStream(key, inputStream, associatedData)
|
||||
}
|
||||
|
||||
@Suppress("Deprecation")
|
||||
@Throws(IOException::class, SecurityException::class)
|
||||
@Deprecated("Use newDecryptingStream instead")
|
||||
override fun decryptHeader(
|
||||
inputStream: InputStream,
|
||||
expectedVersion: Byte,
|
||||
expectedPackageName: String,
|
||||
expectedKey: String?
|
||||
expectedKey: String?,
|
||||
): VersionHeader {
|
||||
val decrypted = decryptSegment(inputStream, MAX_VERSION_HEADER_SIZE)
|
||||
val header = headerReader.getVersionHeader(decrypted)
|
||||
|
@ -214,6 +216,7 @@ internal class CryptoImpl(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("Deprecation")
|
||||
@Throws(EOFException::class, IOException::class, SecurityException::class)
|
||||
private fun decryptSegment(inputStream: InputStream, maxSegmentLength: Int): ByteArray {
|
||||
val segmentHeader = headerReader.readSegmentHeader(inputStream)
|
||||
|
|
|
@ -63,7 +63,7 @@ interface KeyManager {
|
|||
}
|
||||
|
||||
internal class KeyManagerImpl(
|
||||
private val keyStore: KeyStore
|
||||
private val keyStore: KeyStore,
|
||||
) : KeyManager {
|
||||
|
||||
override fun storeBackupKey(seed: ByteArray) {
|
||||
|
|
|
@ -19,7 +19,7 @@ internal const val MAX_VERSION_HEADER_SIZE =
|
|||
internal data class VersionHeader(
|
||||
internal val version: Byte = VERSION, // 1 byte
|
||||
internal val packageName: String, // ?? bytes (max 255)
|
||||
internal val key: String? = null // ?? bytes
|
||||
internal val key: String? = null, // ?? bytes
|
||||
) {
|
||||
init {
|
||||
check(packageName.length <= MAX_PACKAGE_LENGTH_SIZE) {
|
||||
|
@ -64,7 +64,7 @@ internal const val SEGMENT_HEADER_SIZE = SEGMENT_LENGTH_SIZE + IV_SIZE
|
|||
@Deprecated("Don't do manual segments, use Crypto interface instead.")
|
||||
class SegmentHeader(
|
||||
internal val segmentLength: Short, // 2 bytes
|
||||
internal val nonce: ByteArray // 12 bytes
|
||||
internal val nonce: ByteArray, // 12 bytes
|
||||
) {
|
||||
init {
|
||||
check(nonce.size == IV_SIZE) {
|
||||
|
|
|
@ -11,11 +11,13 @@ internal interface HeaderReader {
|
|||
@Throws(IOException::class, UnsupportedVersionException::class)
|
||||
fun readVersion(inputStream: InputStream, expectedVersion: Byte): Byte
|
||||
|
||||
@Deprecated("")
|
||||
@Suppress("Deprecation")
|
||||
@Deprecated("For restoring v0 backups only")
|
||||
@Throws(SecurityException::class)
|
||||
fun getVersionHeader(byteArray: ByteArray): VersionHeader
|
||||
|
||||
@Deprecated("")
|
||||
@Suppress("Deprecation")
|
||||
@Deprecated("For restoring v0 backups only")
|
||||
@Throws(EOFException::class, IOException::class)
|
||||
fun readSegmentHeader(inputStream: InputStream): SegmentHeader
|
||||
}
|
||||
|
@ -33,6 +35,7 @@ internal class HeaderReaderImpl : HeaderReader {
|
|||
return version
|
||||
}
|
||||
|
||||
@Suppress("OverridingDeprecatedMember", "Deprecation")
|
||||
override fun getVersionHeader(byteArray: ByteArray): VersionHeader {
|
||||
val buffer = ByteBuffer.wrap(byteArray)
|
||||
val version = buffer.get()
|
||||
|
@ -65,6 +68,7 @@ internal class HeaderReaderImpl : HeaderReader {
|
|||
}
|
||||
|
||||
@Throws(EOFException::class, IOException::class)
|
||||
@Suppress("OverridingDeprecatedMember", "Deprecation")
|
||||
override fun readSegmentHeader(inputStream: InputStream): SegmentHeader {
|
||||
val buffer = ByteArray(SEGMENT_HEADER_SIZE)
|
||||
val bytesRead = inputStream.read(buffer)
|
||||
|
|
|
@ -18,7 +18,7 @@ data class BackupMetadata(
|
|||
internal val androidVersion: Int = Build.VERSION.SDK_INT,
|
||||
internal val androidIncremental: String = Build.VERSION.INCREMENTAL,
|
||||
internal val deviceName: String = "${Build.MANUFACTURER} ${Build.MODEL}",
|
||||
internal val packageMetadataMap: PackageMetadataMap = PackageMetadataMap()
|
||||
internal val packageMetadataMap: PackageMetadataMap = PackageMetadataMap(),
|
||||
)
|
||||
|
||||
internal const val JSON_METADATA = "@meta@"
|
||||
|
@ -77,7 +77,7 @@ data class PackageMetadata(
|
|||
internal val installer: String? = null,
|
||||
internal val splits: List<ApkSplit>? = null,
|
||||
internal val sha256: String? = null,
|
||||
internal val signatures: List<String>? = null
|
||||
internal val signatures: List<String>? = null,
|
||||
) {
|
||||
fun hasApk(): Boolean {
|
||||
return version != null && sha256 != null && signatures != null
|
||||
|
@ -86,7 +86,7 @@ data class PackageMetadata(
|
|||
|
||||
data class ApkSplit(
|
||||
val name: String,
|
||||
val sha256: String
|
||||
val sha256: String,
|
||||
// There's also a revisionCode, but it doesn't seem to be used just yet
|
||||
)
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ internal class MetadataManager(
|
|||
private val clock: Clock,
|
||||
private val crypto: Crypto,
|
||||
private val metadataWriter: MetadataWriter,
|
||||
private val metadataReader: MetadataReader
|
||||
private val metadataReader: MetadataReader,
|
||||
) {
|
||||
|
||||
private val uninitializedMetadata = BackupMetadata(token = 0L, salt = "")
|
||||
|
@ -80,7 +80,7 @@ internal class MetadataManager(
|
|||
fun onApkBackedUp(
|
||||
packageInfo: PackageInfo,
|
||||
packageMetadata: PackageMetadata,
|
||||
metadataOutputStream: OutputStream
|
||||
metadataOutputStream: OutputStream,
|
||||
) {
|
||||
val packageName = packageInfo.packageName
|
||||
metadata.packageMetadataMap[packageName]?.let {
|
||||
|
@ -129,7 +129,7 @@ internal class MetadataManager(
|
|||
fun onPackageBackedUp(
|
||||
packageInfo: PackageInfo,
|
||||
type: BackupType,
|
||||
metadataOutputStream: OutputStream
|
||||
metadataOutputStream: OutputStream,
|
||||
) {
|
||||
val packageName = packageInfo.packageName
|
||||
modifyMetadata(metadataOutputStream) {
|
||||
|
@ -162,7 +162,7 @@ internal class MetadataManager(
|
|||
packageInfo: PackageInfo,
|
||||
packageState: PackageState,
|
||||
metadataOutputStream: OutputStream,
|
||||
backupType: BackupType? = null
|
||||
backupType: BackupType? = null,
|
||||
) {
|
||||
check(packageState != APK_AND_DATA) { "Backup Error with non-error package state." }
|
||||
val packageName = packageInfo.packageName
|
||||
|
|
|
@ -31,7 +31,7 @@ interface MetadataReader {
|
|||
fun decode(
|
||||
bytes: ByteArray,
|
||||
expectedVersion: Byte? = null,
|
||||
expectedToken: Long? = null
|
||||
expectedToken: Long? = null,
|
||||
): BackupMetadata
|
||||
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ internal class MetadataReaderImpl(private val crypto: Crypto) : MetadataReader {
|
|||
UnsupportedVersionException::class,
|
||||
IOException::class
|
||||
)
|
||||
@Suppress("Deprecation")
|
||||
private fun readMetadataV0(inputStream: InputStream, expectedToken: Long): BackupMetadata {
|
||||
val metadataBytes = try {
|
||||
crypto.decryptMultipleSegments(inputStream)
|
||||
|
@ -77,7 +78,7 @@ internal class MetadataReaderImpl(private val crypto: Crypto) : MetadataReader {
|
|||
override fun decode(
|
||||
bytes: ByteArray,
|
||||
expectedVersion: Byte?,
|
||||
expectedToken: Long?
|
||||
expectedToken: Long?,
|
||||
): BackupMetadata {
|
||||
// NOTE: We don't do extensive validation of the parsed input here,
|
||||
// because it was encrypted with authentication, so we should be able to trust it.
|
||||
|
|
|
@ -34,7 +34,7 @@ interface LegacyStoragePlugin {
|
|||
suspend fun getInputStreamForRecord(
|
||||
token: Long,
|
||||
packageInfo: PackageInfo,
|
||||
key: String
|
||||
key: String,
|
||||
): InputStream
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,7 +13,7 @@ import java.io.InputStream
|
|||
@Suppress("BlockingMethodInNonBlockingContext", "Deprecation") // all methods do I/O
|
||||
internal class DocumentsProviderLegacyPlugin(
|
||||
private val context: Context,
|
||||
private val storage: DocumentsStorage
|
||||
private val storage: DocumentsStorage,
|
||||
) : LegacyStoragePlugin {
|
||||
|
||||
private var packageDir: DocumentFile? = null
|
||||
|
@ -50,7 +50,7 @@ internal class DocumentsProviderLegacyPlugin(
|
|||
override suspend fun getInputStreamForRecord(
|
||||
token: Long,
|
||||
packageInfo: PackageInfo,
|
||||
key: String
|
||||
key: String,
|
||||
): InputStream {
|
||||
val packageDir = this.packageDir
|
||||
?: throw AssertionError("No cached packageDir for ${packageInfo.packageName}")
|
||||
|
@ -70,7 +70,7 @@ internal class DocumentsProviderLegacyPlugin(
|
|||
@Throws(IOException::class)
|
||||
override suspend fun getInputStreamForPackage(
|
||||
token: Long,
|
||||
packageInfo: PackageInfo
|
||||
packageInfo: PackageInfo,
|
||||
): InputStream {
|
||||
val backupDir = storage.getFullBackupDir(token) ?: throw IOException()
|
||||
val packageFile =
|
||||
|
@ -82,7 +82,7 @@ internal class DocumentsProviderLegacyPlugin(
|
|||
override suspend fun getApkInputStream(
|
||||
token: Long,
|
||||
packageName: String,
|
||||
suffix: String
|
||||
suffix: String,
|
||||
): InputStream {
|
||||
val setDir = storage.getSetDir(token) ?: throw IOException()
|
||||
val file = setDir.findFileBlocking(context, "$packageName$suffix.apk")
|
||||
|
|
|
@ -17,7 +17,7 @@ private val TAG = DocumentsProviderStoragePlugin::class.java.simpleName
|
|||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
internal class DocumentsProviderStoragePlugin(
|
||||
private val context: Context,
|
||||
private val storage: DocumentsStorage
|
||||
private val storage: DocumentsStorage,
|
||||
) : StoragePlugin {
|
||||
|
||||
private val packageManager: PackageManager = context.packageManager
|
||||
|
|
|
@ -27,8 +27,10 @@ import java.io.OutputStream
|
|||
import kotlin.coroutines.resume
|
||||
|
||||
const val DIRECTORY_ROOT = ".SeedVaultAndroidBackup"
|
||||
|
||||
@Deprecated("")
|
||||
const val DIRECTORY_FULL_BACKUP = "full"
|
||||
|
||||
@Deprecated("")
|
||||
const val DIRECTORY_KEY_VALUE_BACKUP = "kv"
|
||||
const val FILE_BACKUP_METADATA = ".backup.metadata"
|
||||
|
@ -39,7 +41,7 @@ private val TAG = DocumentsStorage::class.java.simpleName
|
|||
|
||||
internal class DocumentsStorage(
|
||||
private val context: Context,
|
||||
private val settingsManager: SettingsManager
|
||||
private val settingsManager: SettingsManager,
|
||||
) {
|
||||
|
||||
private val contentResolver = context.contentResolver
|
||||
|
@ -143,7 +145,7 @@ internal class DocumentsStorage(
|
|||
internal suspend fun DocumentFile.createOrGetFile(
|
||||
context: Context,
|
||||
name: String,
|
||||
mimeType: String = MIME_TYPE
|
||||
mimeType: String = MIME_TYPE,
|
||||
): DocumentFile {
|
||||
return try {
|
||||
findFileBlocking(context, name) ?: createFile(mimeType, name)?.apply {
|
||||
|
|
|
@ -8,7 +8,6 @@ import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_BACKUP
|
|||
import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_FILES
|
||||
import com.stevesoltys.seedvault.restore.DisplayFragment.RESTORE_FILES_STARTED
|
||||
import com.stevesoltys.seedvault.restore.install.InstallProgressFragment
|
||||
import com.stevesoltys.seedvault.ui.LiveEventHandler
|
||||
import com.stevesoltys.seedvault.ui.RequireProvisioningActivity
|
||||
import com.stevesoltys.seedvault.ui.RequireProvisioningViewModel
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
@ -26,7 +25,7 @@ class RestoreActivity : RequireProvisioningActivity() {
|
|||
|
||||
setContentView(R.layout.activity_fragment_container)
|
||||
|
||||
viewModel.displayFragment.observeEvent(this, LiveEventHandler { fragment ->
|
||||
viewModel.displayFragment.observeEvent(this, { fragment ->
|
||||
when (fragment) {
|
||||
RESTORE_APPS -> showFragment(InstallProgressFragment())
|
||||
RESTORE_BACKUP -> showFragment(RestoreProgressFragment())
|
||||
|
|
|
@ -15,9 +15,7 @@ internal const val REQUEST_CODE_UNINSTALL = 4576841
|
|||
class RestoreErrorBroadcastReceiver : BroadcastReceiver() {
|
||||
|
||||
// using KoinComponent would crash robolectric tests :(
|
||||
private val notificationManager: BackupNotificationManager by lazy {
|
||||
get().get<BackupNotificationManager>()
|
||||
}
|
||||
private val notificationManager: BackupNotificationManager by lazy { get().get() }
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action != ACTION_RESTORE_ERROR_UNINSTALL) return
|
||||
|
|
|
@ -20,7 +20,7 @@ internal class RestoreFilesFragment : SnapshotFragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v = super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
||||
|
@ -50,7 +50,7 @@ internal class RestoreFilesStartedFragment : Fragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v: View = inflater.inflate(R.layout.fragment_restore_files_started, container, false)
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ internal class RestoreProgressAdapter : Adapter<PackageViewHolder>() {
|
|||
|
||||
private class Diff(
|
||||
private val oldItems: LinkedList<AppRestoreResult>,
|
||||
private val newItems: LinkedList<AppRestoreResult>
|
||||
private val newItems: LinkedList<AppRestoreResult>,
|
||||
) : DiffUtil.Callback() {
|
||||
|
||||
override fun getOldListSize() = oldItems.size
|
||||
|
@ -74,5 +74,5 @@ internal class RestoreProgressAdapter : Adapter<PackageViewHolder>() {
|
|||
internal data class AppRestoreResult(
|
||||
val packageName: String,
|
||||
val name: CharSequence,
|
||||
val state: AppBackupState
|
||||
val state: AppBackupState,
|
||||
)
|
||||
|
|
|
@ -11,7 +11,6 @@ import android.widget.TextView
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat.getColor
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
|
||||
|
@ -36,7 +35,7 @@ class RestoreProgressFragment : Fragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v: View = inflater.inflate(R.layout.fragment_restore_progress, container, false)
|
||||
|
||||
|
@ -66,17 +65,17 @@ class RestoreProgressFragment : Fragment() {
|
|||
// decryption will fail when the device is locked, so keep the screen on to prevent locking
|
||||
requireActivity().window.addFlags(FLAG_KEEP_SCREEN_ON)
|
||||
|
||||
viewModel.chosenRestorableBackup.observe(viewLifecycleOwner, Observer { restorableBackup ->
|
||||
viewModel.chosenRestorableBackup.observe(viewLifecycleOwner, { restorableBackup ->
|
||||
backupNameView.text = restorableBackup.name
|
||||
progressBar.max = restorableBackup.packageMetadataMap.size
|
||||
})
|
||||
|
||||
viewModel.restoreProgress.observe(viewLifecycleOwner, Observer { list ->
|
||||
viewModel.restoreProgress.observe(viewLifecycleOwner, { list ->
|
||||
stayScrolledAtTop { adapter.update(list) }
|
||||
progressBar.progress = list.size
|
||||
})
|
||||
|
||||
viewModel.restoreBackupResult.observe(viewLifecycleOwner, Observer { finished ->
|
||||
viewModel.restoreBackupResult.observe(viewLifecycleOwner, { finished ->
|
||||
button.isEnabled = true
|
||||
if (finished.hasError()) {
|
||||
backupNameView.text = finished.errorMsg
|
||||
|
|
|
@ -14,7 +14,7 @@ import com.stevesoltys.seedvault.restore.RestoreSetAdapter.RestoreSetViewHolder
|
|||
|
||||
internal class RestoreSetAdapter(
|
||||
private val listener: RestorableBackupClickListener,
|
||||
private val items: List<RestorableBackup>
|
||||
private val items: List<RestorableBackup>,
|
||||
) : Adapter<RestoreSetViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RestoreSetViewHolder {
|
||||
|
|
|
@ -10,7 +10,6 @@ import android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
|||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.stevesoltys.seedvault.R
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
|
@ -27,7 +26,7 @@ class RestoreSetFragment : Fragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v: View = inflater.inflate(R.layout.fragment_restore_set, container, false)
|
||||
|
||||
|
@ -45,7 +44,7 @@ class RestoreSetFragment : Fragment() {
|
|||
// decryption will fail when the device is locked, so keep the screen on to prevent locking
|
||||
requireActivity().window.addFlags(FLAG_KEEP_SCREEN_ON)
|
||||
|
||||
viewModel.restoreSetResults.observe(viewLifecycleOwner, Observer { result ->
|
||||
viewModel.restoreSetResults.observe(viewLifecycleOwner, { result ->
|
||||
onRestoreResultsLoaded(result)
|
||||
})
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ internal class RestoreViewModel(
|
|||
private val restoreCoordinator: RestoreCoordinator,
|
||||
private val apkRestore: ApkRestore,
|
||||
storageBackup: StorageBackup,
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
) : RequireProvisioningViewModel(app, settingsManager, keyManager),
|
||||
RestorableBackupClickListener, SnapshotViewModel {
|
||||
|
||||
|
@ -247,7 +247,7 @@ internal class RestoreViewModel(
|
|||
@WorkerThread
|
||||
private fun getFailedStatus(
|
||||
packageName: String,
|
||||
restorableBackup: RestorableBackup = chosenRestorableBackup.value!!
|
||||
restorableBackup: RestorableBackup = chosenRestorableBackup.value!!,
|
||||
): AppBackupState {
|
||||
val metadata = restorableBackup.packageMetadataMap[packageName] ?: return FAILED
|
||||
return when (metadata.state) {
|
||||
|
@ -369,7 +369,7 @@ internal class RestoreViewModel(
|
|||
|
||||
internal class RestoreSetResult(
|
||||
internal val restorableBackups: List<RestorableBackup>,
|
||||
internal val errorMsg: String?
|
||||
internal val errorMsg: String?,
|
||||
) {
|
||||
|
||||
internal constructor(restorableBackups: List<RestorableBackup>) : this(restorableBackups, null)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.stevesoltys.seedvault.restore.install
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.app.PendingIntent.FLAG_MUTABLE
|
||||
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
|
@ -41,7 +42,7 @@ internal class ApkInstaller(private val context: Context) {
|
|||
cachedApks: List<File>,
|
||||
packageName: String,
|
||||
installerPackageName: String?,
|
||||
installResult: MutableInstallResult
|
||||
installResult: MutableInstallResult,
|
||||
) = suspendCancellableCoroutine<InstallResult> { cont ->
|
||||
val broadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, i: Intent) {
|
||||
|
@ -84,8 +85,12 @@ internal class ApkInstaller(private val context: Context) {
|
|||
flags = FLAG_RECEIVER_FOREGROUND
|
||||
setPackage(context.packageName)
|
||||
}
|
||||
val pendingIntent =
|
||||
PendingIntent.getBroadcast(context, 0, broadcastIntent, FLAG_UPDATE_CURRENT)
|
||||
val pendingIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
0,
|
||||
broadcastIntent,
|
||||
FLAG_UPDATE_CURRENT or FLAG_MUTABLE, // needs to be mutable, otherwise no extras
|
||||
)
|
||||
return pendingIntent.intentSender
|
||||
}
|
||||
|
||||
|
@ -93,7 +98,7 @@ internal class ApkInstaller(private val context: Context) {
|
|||
i: Intent,
|
||||
expectedPackageName: String,
|
||||
cachedApks: List<File>,
|
||||
installResult: MutableInstallResult
|
||||
installResult: MutableInstallResult,
|
||||
): InstallResult {
|
||||
val packageName = i.getStringExtra(EXTRA_PACKAGE_NAME)!!
|
||||
val success = i.getIntExtra(EXTRA_STATUS, -1) == STATUS_SUCCESS
|
||||
|
|
|
@ -33,7 +33,7 @@ internal class ApkRestore(
|
|||
private val legacyStoragePlugin: LegacyStoragePlugin,
|
||||
private val crypto: Crypto,
|
||||
private val splitCompatChecker: ApkSplitCompatibilityChecker,
|
||||
private val apkInstaller: ApkInstaller
|
||||
private val apkInstaller: ApkInstaller,
|
||||
) {
|
||||
|
||||
private val pm = context.packageManager
|
||||
|
@ -84,7 +84,7 @@ internal class ApkRestore(
|
|||
backup: RestorableBackup,
|
||||
packageName: String,
|
||||
metadata: PackageMetadata,
|
||||
installResult: MutableInstallResult
|
||||
installResult: MutableInstallResult,
|
||||
) {
|
||||
// cache the APK and get its hash
|
||||
val (cachedApk, sha256) = cacheApk(backup.version, backup.token, backup.salt, packageName)
|
||||
|
@ -169,7 +169,7 @@ internal class ApkRestore(
|
|||
backup: RestorableBackup,
|
||||
packageName: String,
|
||||
cachedApk: File,
|
||||
splits: List<ApkSplit>?
|
||||
splits: List<ApkSplit>?,
|
||||
): List<File>? {
|
||||
// if null, there are no splits, so we just have a single base APK to consider
|
||||
val splitNames = splits?.map { it.name } ?: return listOf(cachedApk)
|
||||
|
@ -208,7 +208,7 @@ internal class ApkRestore(
|
|||
token: Long,
|
||||
salt: String,
|
||||
packageName: String,
|
||||
suffix: String = ""
|
||||
suffix: String = "",
|
||||
): Pair<File, String> {
|
||||
// create a cache file to write the APK into
|
||||
val cachedApk = File.createTempFile(packageName + suffix, ".apk", context.cacheDir)
|
||||
|
@ -231,7 +231,7 @@ internal class ApkRestore(
|
|||
private fun shouldInstallSystemApp(
|
||||
packageName: String,
|
||||
metadata: PackageMetadata,
|
||||
installResult: MutableInstallResult
|
||||
installResult: MutableInstallResult,
|
||||
): InstallResult? {
|
||||
val installedPackageInfo = try {
|
||||
pm.getPackageInfo(packageName, 0)
|
||||
|
|
|
@ -58,7 +58,7 @@ class ApkSplitCompatibilityChecker(private val deviceInfo: DeviceInfo) {
|
|||
private fun isCompatible(
|
||||
deviceName: String,
|
||||
unknownAllowed: Boolean,
|
||||
splitName: String
|
||||
splitName: String,
|
||||
): Boolean {
|
||||
val index = splitName.indexOf(CONFIG_PREFIX)
|
||||
// If this is not a standardized config split
|
||||
|
|
|
@ -8,7 +8,7 @@ import android.content.pm.PackageManager
|
|||
import android.net.Uri
|
||||
|
||||
internal class InstallIntentCreator(
|
||||
private val packageManager: PackageManager
|
||||
private val packageManager: PackageManager,
|
||||
) {
|
||||
|
||||
private val installerToPackage = mapOf(
|
||||
|
|
|
@ -23,12 +23,12 @@ internal interface InstallItemListener {
|
|||
}
|
||||
|
||||
internal class InstallProgressAdapter(
|
||||
private val listener: InstallItemListener
|
||||
private val listener: InstallItemListener,
|
||||
) : Adapter<InstallProgressAdapter.AppInstallViewHolder>() {
|
||||
|
||||
private var finished = false
|
||||
private val finishedComparator = FailedFirstComparator()
|
||||
private val items = SortedList<ApkInstallResult>(
|
||||
private val items = SortedList(
|
||||
ApkInstallResult::class.java,
|
||||
object : SortedListAdapterCallback<ApkInstallResult>(this) {
|
||||
override fun areItemsTheSame(item1: ApkInstallResult, item2: ApkInstallResult) =
|
||||
|
|
|
@ -12,7 +12,6 @@ import android.widget.TextView
|
|||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
|
||||
|
@ -37,8 +36,8 @@ class InstallProgressFragment : Fragment(), InstallItemListener {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v: View = inflater.inflate(R.layout.fragment_restore_progress, container, false)
|
||||
|
||||
progressBar = v.findViewById(R.id.progressBar)
|
||||
|
@ -61,15 +60,15 @@ class InstallProgressFragment : Fragment(), InstallItemListener {
|
|||
button.setText(R.string.restore_next)
|
||||
button.setOnClickListener { viewModel.onNextClickedAfterInstallingApps() }
|
||||
|
||||
viewModel.chosenRestorableBackup.observe(viewLifecycleOwner, Observer { restorableBackup ->
|
||||
viewModel.chosenRestorableBackup.observe(viewLifecycleOwner, { restorableBackup ->
|
||||
backupNameView.text = restorableBackup.name
|
||||
})
|
||||
|
||||
viewModel.installResult.observe(viewLifecycleOwner, Observer { result ->
|
||||
viewModel.installResult.observe(viewLifecycleOwner, { result ->
|
||||
onInstallResult(result)
|
||||
})
|
||||
|
||||
viewModel.nextButtonEnabled.observe(viewLifecycleOwner, Observer { enabled ->
|
||||
viewModel.nextButtonEnabled.observe(viewLifecycleOwner, { enabled ->
|
||||
button.isEnabled = enabled
|
||||
})
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ internal class MutableInstallResult(override val total: Int) : InstallResult {
|
|||
|
||||
fun update(
|
||||
packageName: String,
|
||||
updateFun: (ApkInstallResult) -> ApkInstallResult
|
||||
updateFun: (ApkInstallResult) -> ApkInstallResult,
|
||||
): MutableInstallResult {
|
||||
val result = get(packageName)
|
||||
check(result != null) { "ApkRestoreResult for $packageName does not exist." }
|
||||
|
@ -118,7 +118,7 @@ data class ApkInstallResult(
|
|||
val state: ApkInstallState,
|
||||
val name: CharSequence? = null,
|
||||
val icon: Drawable? = null,
|
||||
val installerPackageName: CharSequence? = null
|
||||
val installerPackageName: CharSequence? = null,
|
||||
) : Comparable<ApkInstallResult> {
|
||||
override fun compareTo(other: ApkInstallResult): Int {
|
||||
return other.progress.compareTo(progress)
|
||||
|
|
|
@ -28,8 +28,8 @@ class AboutDialogFragment : DialogFragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v: View = inflater.inflate(R.layout.fragment_about, container, false)
|
||||
|
||||
versionView = v.findViewById(R.id.versionView)
|
||||
|
|
|
@ -39,7 +39,7 @@ data class AppStatus(
|
|||
val name: String,
|
||||
val time: Long,
|
||||
val status: AppBackupState,
|
||||
val isSpecial: Boolean = false
|
||||
val isSpecial: Boolean = false,
|
||||
) : AppListItem()
|
||||
|
||||
class AppSectionTitle(@StringRes val titleRes: Int) : AppListItem()
|
||||
|
@ -48,7 +48,7 @@ internal class AppListRetriever(
|
|||
private val context: Context,
|
||||
private val packageService: PackageService,
|
||||
private val settingsManager: SettingsManager,
|
||||
private val metadataManager: MetadataManager
|
||||
private val metadataManager: MetadataManager,
|
||||
) {
|
||||
|
||||
private val pm: PackageManager = context.packageManager
|
||||
|
|
|
@ -139,7 +139,7 @@ internal class AppStatusAdapter(private val toggleListener: AppStatusToggleListe
|
|||
|
||||
internal class AppStatusDiff(
|
||||
private val oldItems: List<AppListItem>,
|
||||
private val newItems: List<AppListItem>
|
||||
private val newItems: List<AppListItem>,
|
||||
) : DiffUtil.Callback() {
|
||||
|
||||
override fun getOldListSize() = oldItems.size
|
||||
|
@ -163,5 +163,5 @@ internal class AppStatusDiff(
|
|||
|
||||
internal class AppStatusResult(
|
||||
val appStatusList: List<AppListItem>,
|
||||
val diff: DiffResult
|
||||
val diff: DiffResult,
|
||||
)
|
||||
|
|
|
@ -11,7 +11,6 @@ import android.view.View.VISIBLE
|
|||
import android.view.ViewGroup
|
||||
import android.widget.ProgressBar
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.stevesoltys.seedvault.R
|
||||
|
@ -35,7 +34,7 @@ class AppStatusFragment : Fragment(), AppStatusToggleListener {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
setHasOptionsMenu(true)
|
||||
val v: View = inflater.inflate(R.layout.fragment_app_status, container, false)
|
||||
|
@ -57,7 +56,7 @@ class AppStatusFragment : Fragment(), AppStatusToggleListener {
|
|||
}
|
||||
|
||||
progressBar.visibility = VISIBLE
|
||||
viewModel.appStatusList.observe(viewLifecycleOwner, Observer { result ->
|
||||
viewModel.appStatusList.observe(viewLifecycleOwner, { result ->
|
||||
adapter.update(result.appStatusList, result.diff)
|
||||
progressBar.visibility = INVISIBLE
|
||||
})
|
||||
|
@ -69,7 +68,7 @@ class AppStatusFragment : Fragment(), AppStatusToggleListener {
|
|||
appEditMenuItem = menu.findItem(R.id.edit_app_blacklist)
|
||||
|
||||
// observe edit mode changes here where we are sure to have the MenuItem
|
||||
viewModel.appEditMode.observe(viewLifecycleOwner, Observer { enabled ->
|
||||
viewModel.appEditMode.observe(viewLifecycleOwner, { enabled ->
|
||||
appEditMenuItem.isChecked = enabled
|
||||
adapter.setEditMode(enabled)
|
||||
})
|
||||
|
|
|
@ -55,7 +55,7 @@ class SettingsActivity : RequireProvisioningActivity(), OnPreferenceStartFragmen
|
|||
|
||||
override fun onPreferenceStartFragment(
|
||||
caller: PreferenceFragmentCompat,
|
||||
pref: Preference
|
||||
pref: Preference,
|
||||
): Boolean {
|
||||
val fragment =
|
||||
supportFragmentManager.fragmentFactory.instantiate(classLoader, pref.fragment)
|
||||
|
|
|
@ -12,7 +12,6 @@ import android.view.MenuInflater
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.Preference.OnPreferenceChangeListener
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
|
@ -128,12 +127,12 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
viewModel.lastBackupTime.observe(viewLifecycleOwner, Observer { time ->
|
||||
viewModel.lastBackupTime.observe(viewLifecycleOwner, { time ->
|
||||
setAppBackupStatusSummary(time)
|
||||
})
|
||||
|
||||
val backupFiles: Preference = findPreference("backup_files")!!
|
||||
viewModel.filesSummary.observe(viewLifecycleOwner, Observer { summary ->
|
||||
viewModel.filesSummary.observe(viewLifecycleOwner, { summary ->
|
||||
backupFiles.summary = summary
|
||||
})
|
||||
}
|
||||
|
@ -158,7 +157,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
if (resources.getBoolean(R.bool.show_restore_in_settings)) {
|
||||
menuRestore?.isVisible = true
|
||||
}
|
||||
viewModel.backupPossible.observe(viewLifecycleOwner, Observer { possible ->
|
||||
viewModel.backupPossible.observe(viewLifecycleOwner, { possible ->
|
||||
menuBackupNow?.isEnabled = possible
|
||||
menuRestore?.isEnabled = possible
|
||||
})
|
||||
|
|
|
@ -146,7 +146,7 @@ data class Storage(
|
|||
val uri: Uri,
|
||||
val name: String,
|
||||
val isUsb: Boolean,
|
||||
val requiresNetwork: Boolean
|
||||
val requiresNetwork: Boolean,
|
||||
) {
|
||||
fun getDocumentFile(context: Context) = DocumentFile.fromTreeUri(context, uri)
|
||||
?: throw AssertionError("Should only happen on API < 21.")
|
||||
|
@ -171,7 +171,7 @@ data class Storage(
|
|||
|
||||
private fun hasUnmeteredInternet(context: Context): Boolean {
|
||||
val cm = context.getSystemService(ConnectivityManager::class.java)
|
||||
val isMetered = cm.isActiveNetworkMetered()
|
||||
val isMetered = cm.isActiveNetworkMetered
|
||||
val capabilities = cm.getNetworkCapabilities(cm.activeNetwork) ?: return false
|
||||
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && !isMetered
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ data class FlashDrive(
|
|||
val name: String,
|
||||
val serialNumber: String?,
|
||||
val vendorId: Int,
|
||||
val productId: Int
|
||||
val productId: Int,
|
||||
) {
|
||||
companion object {
|
||||
fun from(device: UsbDevice) = FlashDrive(
|
||||
|
|
|
@ -48,7 +48,7 @@ internal class SettingsViewModel(
|
|||
private val notificationManager: BackupNotificationManager,
|
||||
private val metadataManager: MetadataManager,
|
||||
private val appListRetriever: AppListRetriever,
|
||||
private val storageBackup: StorageBackup
|
||||
private val storageBackup: StorageBackup,
|
||||
) : RequireProvisioningViewModel(app, settingsManager, keyManager) {
|
||||
|
||||
private val contentResolver = app.contentResolver
|
||||
|
@ -56,7 +56,7 @@ internal class SettingsViewModel(
|
|||
|
||||
override val isRestoreOperation = false
|
||||
|
||||
private val mBackupPossible = MutableLiveData<Boolean>(false)
|
||||
private val mBackupPossible = MutableLiveData(false)
|
||||
val backupPossible: LiveData<Boolean> = mBackupPossible
|
||||
|
||||
internal val lastBackupTime = metadataManager.lastBackupTime
|
||||
|
|
|
@ -10,7 +10,7 @@ import javax.crypto.SecretKey
|
|||
internal class SeedvaultStoragePlugin(
|
||||
context: Context,
|
||||
private val storage: DocumentsStorage,
|
||||
private val keyManager: KeyManager
|
||||
private val keyManager: KeyManager,
|
||||
) : SafStoragePlugin(context) {
|
||||
override val root: DocumentFile
|
||||
get() = storage.rootBackupDir ?: error("No storage set")
|
||||
|
|
|
@ -117,7 +117,7 @@ class ConfigurableBackupTransport internal constructor(private val context: Cont
|
|||
|
||||
override fun isAppEligibleForBackup(
|
||||
targetPackage: PackageInfo,
|
||||
isFullBackup: Boolean
|
||||
isFullBackup: Boolean,
|
||||
): Boolean {
|
||||
return backupCoordinator.isAppEligibleForBackup(targetPackage, isFullBackup)
|
||||
}
|
||||
|
@ -145,14 +145,14 @@ class ConfigurableBackupTransport internal constructor(private val context: Cont
|
|||
override fun performBackup(
|
||||
packageInfo: PackageInfo,
|
||||
inFd: ParcelFileDescriptor,
|
||||
flags: Int
|
||||
flags: Int,
|
||||
): Int = runBlocking {
|
||||
backupCoordinator.performIncrementalBackup(packageInfo, inFd, flags)
|
||||
}
|
||||
|
||||
override fun performBackup(
|
||||
targetPackage: PackageInfo,
|
||||
fileDescriptor: ParcelFileDescriptor
|
||||
fileDescriptor: ParcelFileDescriptor,
|
||||
): Int {
|
||||
Log.w(TAG, "Warning: Legacy performBackup() method called.")
|
||||
return performBackup(targetPackage, fileDescriptor, 0)
|
||||
|
@ -173,14 +173,14 @@ class ConfigurableBackupTransport internal constructor(private val context: Cont
|
|||
override fun performFullBackup(
|
||||
targetPackage: PackageInfo,
|
||||
socket: ParcelFileDescriptor,
|
||||
flags: Int
|
||||
flags: Int,
|
||||
): Int = runBlocking {
|
||||
backupCoordinator.performFullBackup(targetPackage, socket, flags)
|
||||
}
|
||||
|
||||
override fun performFullBackup(
|
||||
targetPackage: PackageInfo,
|
||||
fileDescriptor: ParcelFileDescriptor
|
||||
fileDescriptor: ParcelFileDescriptor,
|
||||
): Int = runBlocking {
|
||||
Log.w(TAG, "Warning: Legacy performFullBackup() method called.")
|
||||
backupCoordinator.performFullBackup(targetPackage, fileDescriptor, 0)
|
||||
|
|
|
@ -30,7 +30,7 @@ internal class ApkBackup(
|
|||
private val pm: PackageManager,
|
||||
private val crypto: Crypto,
|
||||
private val settingsManager: SettingsManager,
|
||||
private val metadataManager: MetadataManager
|
||||
private val metadataManager: MetadataManager,
|
||||
) {
|
||||
|
||||
/**
|
||||
|
@ -46,7 +46,7 @@ internal class ApkBackup(
|
|||
suspend fun backupApkIfNecessary(
|
||||
packageInfo: PackageInfo,
|
||||
packageState: PackageState,
|
||||
streamGetter: suspend (name: String) -> OutputStream
|
||||
streamGetter: suspend (name: String) -> OutputStream,
|
||||
): PackageMetadata? {
|
||||
// do not back up @pm@
|
||||
val packageName = packageInfo.packageName
|
||||
|
@ -126,7 +126,7 @@ internal class ApkBackup(
|
|||
|
||||
private fun signaturesChanged(
|
||||
packageMetadata: PackageMetadata,
|
||||
signatures: List<String>
|
||||
signatures: List<String>,
|
||||
): Boolean {
|
||||
// no signatures in package metadata counts as them not having changed
|
||||
if (packageMetadata.signatures == null) return false
|
||||
|
@ -151,7 +151,7 @@ internal class ApkBackup(
|
|||
@Throws(IOException::class)
|
||||
private suspend fun backupSplitApks(
|
||||
packageInfo: PackageInfo,
|
||||
streamGetter: suspend (name: String) -> OutputStream
|
||||
streamGetter: suspend (name: String) -> OutputStream,
|
||||
): List<ApkSplit> {
|
||||
check(packageInfo.splitNames != null)
|
||||
val splitSourceDirs = packageInfo.applicationInfo.splitSourceDirs
|
||||
|
@ -178,7 +178,7 @@ internal class ApkBackup(
|
|||
packageName: String,
|
||||
splitName: String,
|
||||
sourceDir: String,
|
||||
streamGetter: suspend (name: String) -> OutputStream
|
||||
streamGetter: suspend (name: String) -> OutputStream,
|
||||
): ApkSplit {
|
||||
// Calculate sha256 hash first to determine file name suffix.
|
||||
// We could also just use the split name as a suffix, but there is a theoretical risk
|
||||
|
|
|
@ -43,7 +43,7 @@ private val TAG = BackupCoordinator::class.java.simpleName
|
|||
private class CoordinatorState(
|
||||
var calledInitialize: Boolean,
|
||||
var calledClearBackupData: Boolean,
|
||||
var cancelReason: PackageState
|
||||
var cancelReason: PackageState,
|
||||
) {
|
||||
val expectFinish: Boolean
|
||||
get() = calledInitialize || calledClearBackupData
|
||||
|
@ -71,7 +71,7 @@ internal class BackupCoordinator(
|
|||
private val packageService: PackageService,
|
||||
private val metadataManager: MetadataManager,
|
||||
private val settingsManager: SettingsManager,
|
||||
private val nm: BackupNotificationManager
|
||||
private val nm: BackupNotificationManager,
|
||||
) {
|
||||
|
||||
private val state = CoordinatorState(
|
||||
|
@ -140,7 +140,7 @@ internal class BackupCoordinator(
|
|||
|
||||
fun isAppEligibleForBackup(
|
||||
targetPackage: PackageInfo,
|
||||
@Suppress("UNUSED_PARAMETER") isFullBackup: Boolean
|
||||
@Suppress("UNUSED_PARAMETER") isFullBackup: Boolean,
|
||||
): Boolean {
|
||||
val packageName = targetPackage.packageName
|
||||
// Check that the app is not blacklisted by the user
|
||||
|
@ -230,7 +230,7 @@ internal class BackupCoordinator(
|
|||
suspend fun performIncrementalBackup(
|
||||
packageInfo: PackageInfo,
|
||||
data: ParcelFileDescriptor,
|
||||
flags: Int
|
||||
flags: Int,
|
||||
): Int {
|
||||
state.cancelReason = UNKNOWN_ERROR
|
||||
if (metadataManager.requiresInit) {
|
||||
|
@ -280,7 +280,7 @@ internal class BackupCoordinator(
|
|||
suspend fun performFullBackup(
|
||||
targetPackage: PackageInfo,
|
||||
fileDescriptor: ParcelFileDescriptor,
|
||||
flags: Int
|
||||
flags: Int,
|
||||
): Int {
|
||||
state.cancelReason = UNKNOWN_ERROR
|
||||
val token = settingsManager.getToken() ?: error("no token in performFullBackup")
|
||||
|
@ -448,7 +448,7 @@ internal class BackupCoordinator(
|
|||
*/
|
||||
private suspend fun backUpApk(
|
||||
packageInfo: PackageInfo,
|
||||
packageState: PackageState = UNKNOWN_ERROR
|
||||
packageState: PackageState = UNKNOWN_ERROR,
|
||||
): Boolean {
|
||||
val packageName = packageInfo.packageName
|
||||
return try {
|
||||
|
|
|
@ -23,7 +23,7 @@ private class FullBackupState(
|
|||
val packageInfo: PackageInfo,
|
||||
val inputFileDescriptor: ParcelFileDescriptor,
|
||||
val inputStream: InputStream,
|
||||
var outputStreamInit: (suspend () -> OutputStream)?
|
||||
var outputStreamInit: (suspend () -> OutputStream)?,
|
||||
) {
|
||||
/**
|
||||
* This is an encrypted stream that can be written to directly.
|
||||
|
@ -42,7 +42,7 @@ internal class FullBackup(
|
|||
private val plugin: StoragePlugin,
|
||||
private val settingsManager: SettingsManager,
|
||||
private val inputFactory: InputFactory,
|
||||
private val crypto: Crypto
|
||||
private val crypto: Crypto,
|
||||
) {
|
||||
|
||||
private var state: FullBackupState? = null
|
||||
|
@ -104,7 +104,7 @@ internal class FullBackup(
|
|||
socket: ParcelFileDescriptor,
|
||||
@Suppress("UNUSED_PARAMETER") flags: Int = 0,
|
||||
token: Long,
|
||||
salt: String
|
||||
salt: String,
|
||||
): Int {
|
||||
if (state != null) throw AssertionError()
|
||||
val packageName = targetPackage.packageName
|
||||
|
|
|
@ -22,7 +22,7 @@ class KVBackupState(
|
|||
internal val packageInfo: PackageInfo,
|
||||
val token: Long,
|
||||
val name: String,
|
||||
val db: KVDb
|
||||
val db: KVDb,
|
||||
) {
|
||||
var needsUpload: Boolean = false
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ internal class KVBackup(
|
|||
private val settingsManager: SettingsManager,
|
||||
private val inputFactory: InputFactory,
|
||||
private val crypto: Crypto,
|
||||
private val dbManager: KvDbManager
|
||||
private val dbManager: KvDbManager,
|
||||
) {
|
||||
|
||||
private var state: KVBackupState? = null
|
||||
|
@ -57,7 +57,7 @@ internal class KVBackup(
|
|||
data: ParcelFileDescriptor,
|
||||
flags: Int,
|
||||
token: Long,
|
||||
salt: String
|
||||
salt: String,
|
||||
): Int {
|
||||
val dataNotChanged = flags and FLAG_DATA_NOT_CHANGED != 0
|
||||
val isIncremental = flags and FLAG_INCREMENTAL != 0
|
||||
|
@ -235,7 +235,7 @@ internal class KVBackup(
|
|||
token: Long,
|
||||
name: String,
|
||||
packageName: String,
|
||||
db: KVDb
|
||||
db: KVDb,
|
||||
) {
|
||||
db.vacuum()
|
||||
db.close()
|
||||
|
@ -259,7 +259,7 @@ internal class KVBackup(
|
|||
/**
|
||||
* value is null when this is a deletion operation
|
||||
*/
|
||||
val value: ByteArray?
|
||||
val value: ByteArray?,
|
||||
)
|
||||
|
||||
private sealed class Result<out T> {
|
||||
|
|
|
@ -28,7 +28,7 @@ private const val LOG_MAX_PACKAGES = 100
|
|||
*/
|
||||
internal class PackageService(
|
||||
private val context: Context,
|
||||
private val backupManager: IBackupManager
|
||||
private val backupManager: IBackupManager,
|
||||
) {
|
||||
|
||||
private val packageManager: PackageManager = context.packageManager
|
||||
|
@ -144,7 +144,7 @@ internal data class ExpectedAppTotals(
|
|||
/**
|
||||
* The number of non-system apps that has opted-out of backup.
|
||||
*/
|
||||
val appsOptOut: Int
|
||||
val appsOptOut: Int,
|
||||
)
|
||||
|
||||
internal fun PackageInfo.isUserVisible(context: Context): Boolean {
|
||||
|
|
|
@ -25,7 +25,7 @@ private class FullRestoreState(
|
|||
val version: Byte,
|
||||
val token: Long,
|
||||
val name: String,
|
||||
val packageInfo: PackageInfo
|
||||
val packageInfo: PackageInfo,
|
||||
) {
|
||||
var inputStream: InputStream? = null
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ internal class FullRestore(
|
|||
private val legacyPlugin: LegacyStoragePlugin,
|
||||
private val outputFactory: OutputFactory,
|
||||
private val headerReader: HeaderReader,
|
||||
private val crypto: Crypto
|
||||
private val crypto: Crypto,
|
||||
) {
|
||||
|
||||
private var state: FullRestoreState? = null
|
||||
|
|
|
@ -34,7 +34,7 @@ private class KVRestoreState(
|
|||
/**
|
||||
* Optional [PackageInfo] for single package restore, optimizes restore of @pm@
|
||||
*/
|
||||
val autoRestorePackageInfo: PackageInfo?
|
||||
val autoRestorePackageInfo: PackageInfo?,
|
||||
)
|
||||
|
||||
private val TAG = KVRestore::class.java.simpleName
|
||||
|
@ -47,7 +47,7 @@ internal class KVRestore(
|
|||
private val outputFactory: OutputFactory,
|
||||
private val headerReader: HeaderReader,
|
||||
private val crypto: Crypto,
|
||||
private val dbManager: KvDbManager
|
||||
private val dbManager: KvDbManager,
|
||||
) {
|
||||
|
||||
private var state: KVRestoreState? = null
|
||||
|
@ -76,7 +76,7 @@ internal class KVRestore(
|
|||
token: Long,
|
||||
name: String,
|
||||
packageInfo: PackageInfo,
|
||||
autoRestorePackageInfo: PackageInfo? = null
|
||||
autoRestorePackageInfo: PackageInfo? = null,
|
||||
) {
|
||||
state = KVRestoreState(version, token, name, packageInfo, autoRestorePackageInfo)
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ internal class KVRestore(
|
|||
private suspend fun readAndWriteValueV0(
|
||||
state: KVRestoreState,
|
||||
dKey: DecodedKey,
|
||||
out: BackupDataOutput
|
||||
out: BackupDataOutput,
|
||||
) = legacyPlugin.getInputStreamForRecord(state.token, state.packageInfo, dKey.base64Key)
|
||||
.use { inputStream ->
|
||||
val version = headerReader.readVersion(inputStream, state.version)
|
||||
|
|
|
@ -33,7 +33,7 @@ private data class RestoreCoordinatorState(
|
|||
* Optional [PackageInfo] for single package restore, to reduce data needed to read for @pm@
|
||||
*/
|
||||
val autoRestorePackageInfo: PackageInfo?,
|
||||
val backupMetadata: BackupMetadata
|
||||
val backupMetadata: BackupMetadata,
|
||||
) {
|
||||
var currentPackage: String? = null
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ internal class RestoreCoordinator(
|
|||
private val plugin: StoragePlugin,
|
||||
private val kv: KVRestore,
|
||||
private val full: FullRestore,
|
||||
private val metadataReader: MetadataReader
|
||||
private val metadataReader: MetadataReader,
|
||||
) {
|
||||
|
||||
private var state: RestoreCoordinatorState? = null
|
||||
|
@ -249,7 +249,7 @@ internal class RestoreCoordinator(
|
|||
@Suppress("deprecation")
|
||||
private suspend fun nextRestorePackageV0(
|
||||
state: RestoreCoordinatorState,
|
||||
packageInfo: PackageInfo
|
||||
packageInfo: PackageInfo,
|
||||
): RestoreDescription? {
|
||||
val packageName = packageInfo.packageName
|
||||
val type = try {
|
||||
|
|
|
@ -49,7 +49,7 @@ abstract class RequireProvisioningActivity : BackupActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
getViewModel().chooseBackupLocation.observeEvent(this, LiveEventHandler { show ->
|
||||
getViewModel().chooseBackupLocation.observeEvent(this, { show ->
|
||||
if (show) showStorageActivity()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import com.stevesoltys.seedvault.ui.storage.StorageViewModel
|
|||
abstract class RequireProvisioningViewModel(
|
||||
protected val app: Application,
|
||||
protected val settingsManager: SettingsManager,
|
||||
protected val keyManager: KeyManager
|
||||
protected val keyManager: KeyManager,
|
||||
) : AndroidViewModel(app) {
|
||||
|
||||
abstract val isRestoreOperation: Boolean
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.calyxos.backup.storage.ui.backup.BackupContentFragment
|
|||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
class FileSelectionFragment() : BackupContentFragment() {
|
||||
class FileSelectionFragment : BackupContentFragment() {
|
||||
|
||||
override val viewModel by viewModel<FileSelectionViewModel>()
|
||||
private val settingsViewModel by sharedViewModel<SettingsViewModel>()
|
||||
|
@ -18,7 +18,7 @@ class FileSelectionFragment() : BackupContentFragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
requireActivity().setTitle(R.string.settings_backup_files_title)
|
||||
return super.onCreateView(inflater, container, savedInstanceState)
|
||||
|
|
|
@ -8,7 +8,7 @@ import org.calyxos.backup.storage.ui.backup.BackupContentViewModel
|
|||
|
||||
class FileSelectionViewModel(
|
||||
app: Application,
|
||||
override val storageBackup: StorageBackup
|
||||
override val storageBackup: StorageBackup,
|
||||
) : BackupContentViewModel(app) {
|
||||
|
||||
init {
|
||||
|
|
|
@ -70,7 +70,7 @@ internal class BackupNotificationManager(private val context: Context) {
|
|||
*/
|
||||
fun onBackupStarted(
|
||||
expectedPackages: Int,
|
||||
appTotals: ExpectedAppTotals
|
||||
appTotals: ExpectedAppTotals,
|
||||
) {
|
||||
updateBackupNotification(
|
||||
infoText = "", // This passes quickly, no need to show something here
|
||||
|
@ -112,7 +112,7 @@ internal class BackupNotificationManager(private val context: Context) {
|
|||
private fun updateBackupNotification(
|
||||
infoText: CharSequence,
|
||||
transferred: Int,
|
||||
expected: Int
|
||||
expected: Int,
|
||||
) {
|
||||
@Suppress("MagicNumber")
|
||||
val percentage = (transferred.toFloat() / expected) * 100
|
||||
|
@ -223,7 +223,7 @@ internal class BackupNotificationManager(private val context: Context) {
|
|||
setPackage(context.packageName)
|
||||
putExtra(EXTRA_PACKAGE_NAME, packageName)
|
||||
}
|
||||
val flags = FLAG_UPDATE_CURRENT and FLAG_IMMUTABLE
|
||||
val flags = FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
|
||||
val pendingIntent =
|
||||
PendingIntent.getBroadcast(context, REQUEST_CODE_UNINSTALL, intent, flags)
|
||||
val actionText = context.getString(R.string.notification_restore_error_action)
|
||||
|
|
|
@ -19,7 +19,7 @@ private val TAG = NotificationBackupObserver::class.java.simpleName
|
|||
internal class NotificationBackupObserver(
|
||||
private val context: Context,
|
||||
private val expectedPackages: Int,
|
||||
appTotals: ExpectedAppTotals
|
||||
appTotals: ExpectedAppTotals,
|
||||
) : IBackupObserver.Stub(), KoinComponent {
|
||||
|
||||
private val nm: BackupNotificationManager by inject()
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.stevesoltys.seedvault.R
|
|||
import com.stevesoltys.seedvault.ui.BackupActivity
|
||||
import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_RESTORE
|
||||
import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_SETUP_WIZARD
|
||||
import com.stevesoltys.seedvault.ui.LiveEventHandler
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
class RecoveryCodeActivity : BackupActivity() {
|
||||
|
@ -23,10 +22,10 @@ class RecoveryCodeActivity : BackupActivity() {
|
|||
setContentView(R.layout.activity_recovery_code)
|
||||
|
||||
viewModel.isRestore = isRestore()
|
||||
viewModel.confirmButtonClicked.observeEvent(this, LiveEventHandler { clicked ->
|
||||
viewModel.confirmButtonClicked.observeEvent(this, { clicked ->
|
||||
if (clicked) showInput(true)
|
||||
})
|
||||
viewModel.recoveryCodeSaved.observeEvent(this, LiveEventHandler { saved ->
|
||||
viewModel.recoveryCodeSaved.observeEvent(this, { saved ->
|
||||
if (saved) {
|
||||
setResult(RESULT_OK)
|
||||
finishAfterTransition()
|
||||
|
|
|
@ -34,7 +34,6 @@ import com.google.android.material.snackbar.Snackbar
|
|||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.stevesoltys.seedvault.R
|
||||
import com.stevesoltys.seedvault.isDebugBuild
|
||||
import com.stevesoltys.seedvault.ui.LiveEventHandler
|
||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||
import java.util.Locale
|
||||
|
||||
|
@ -70,7 +69,7 @@ class RecoveryCodeInputFragment : Fragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v: View = inflater.inflate(R.layout.fragment_recovery_code_input, container, false)
|
||||
|
||||
|
@ -127,9 +126,9 @@ class RecoveryCodeInputFragment : Fragment() {
|
|||
newCodeButton.visibility = if (forStoringNewCode) GONE else VISIBLE
|
||||
newCodeButton.setOnClickListener { generateNewCode() }
|
||||
|
||||
viewModel.existingCodeChecked.observeEvent(viewLifecycleOwner,
|
||||
LiveEventHandler { verified -> onExistingCodeChecked(verified) }
|
||||
)
|
||||
viewModel.existingCodeChecked.observeEvent(viewLifecycleOwner, { verified ->
|
||||
onExistingCodeChecked(verified)
|
||||
})
|
||||
|
||||
if (forStoringNewCode && isDebugBuild() && !viewModel.isRestore) debugPreFill()
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class RecoveryCodeOutputFragment : Fragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v: View = inflater.inflate(R.layout.fragment_recovery_code_output, container, false)
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ internal class RecoveryCodeViewModel(
|
|||
private val backupManager: IBackupManager,
|
||||
private val backupCoordinator: BackupCoordinator,
|
||||
private val notificationManager: BackupNotificationManager,
|
||||
private val storageBackup: StorageBackup
|
||||
private val storageBackup: StorageBackup,
|
||||
) : AndroidViewModel(app) {
|
||||
|
||||
internal val wordList: List<CharArray> by lazy {
|
||||
|
|
|
@ -26,7 +26,7 @@ internal class BackupStorageViewModel(
|
|||
private val backupManager: IBackupManager,
|
||||
private val backupCoordinator: BackupCoordinator,
|
||||
private val storageBackup: StorageBackup,
|
||||
settingsManager: SettingsManager
|
||||
settingsManager: SettingsManager,
|
||||
) : StorageViewModel(app, settingsManager) {
|
||||
|
||||
override val isRestoreOperation = false
|
||||
|
|
|
@ -5,9 +5,9 @@ import android.net.Uri
|
|||
import android.util.Log
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.stevesoltys.seedvault.R
|
||||
import com.stevesoltys.seedvault.plugins.StoragePlugin
|
||||
import com.stevesoltys.seedvault.plugins.saf.DIRECTORY_ROOT
|
||||
import com.stevesoltys.seedvault.settings.SettingsManager
|
||||
import com.stevesoltys.seedvault.plugins.StoragePlugin
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
|
@ -17,7 +17,7 @@ private val TAG = RestoreStorageViewModel::class.java.simpleName
|
|||
internal class RestoreStorageViewModel(
|
||||
private val app: Application,
|
||||
private val storagePlugin: StoragePlugin,
|
||||
settingsManager: SettingsManager
|
||||
settingsManager: SettingsManager,
|
||||
) : StorageViewModel(app, settingsManager) {
|
||||
|
||||
override val isRestoreOperation = true
|
||||
|
|
|
@ -17,7 +17,6 @@ import com.stevesoltys.seedvault.R
|
|||
import com.stevesoltys.seedvault.ui.BackupActivity
|
||||
import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_RESTORE
|
||||
import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_SETUP_WIZARD
|
||||
import com.stevesoltys.seedvault.ui.LiveEventHandler
|
||||
import org.koin.androidx.viewmodel.ext.android.getViewModel
|
||||
|
||||
private val TAG = StorageActivity::class.java.name
|
||||
|
@ -59,11 +58,11 @@ class StorageActivity : BackupActivity() {
|
|||
}
|
||||
viewModel.isSetupWizard = isSetupWizard()
|
||||
|
||||
viewModel.locationSet.observeEvent(this, LiveEventHandler {
|
||||
viewModel.locationSet.observeEvent(this, {
|
||||
showFragment(StorageCheckFragment.newInstance(getCheckFragmentTitle()), true)
|
||||
})
|
||||
|
||||
viewModel.locationChecked.observeEvent(this, LiveEventHandler { result ->
|
||||
viewModel.locationChecked.observeEvent(this, { result ->
|
||||
val errorMsg = result.errorMsg
|
||||
if (errorMsg == null) {
|
||||
setResult(RESULT_OK)
|
||||
|
|
|
@ -37,7 +37,7 @@ class StorageCheckFragment : Fragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v: View = inflater.inflate(R.layout.fragment_storage_check, container, false)
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import com.stevesoltys.seedvault.ui.storage.StorageRootAdapter.StorageRootViewHo
|
|||
|
||||
internal class StorageRootAdapter(
|
||||
private val isRestore: Boolean,
|
||||
private val listener: StorageRootClickedListener
|
||||
private val listener: StorageRootClickedListener,
|
||||
) : Adapter<StorageRootViewHolder>() {
|
||||
|
||||
private val items = ArrayList<StorageRoot>()
|
||||
|
|
|
@ -41,7 +41,7 @@ data class StorageRoot(
|
|||
internal val isUsb: Boolean,
|
||||
internal val requiresNetwork: Boolean,
|
||||
internal val enabled: Boolean = true,
|
||||
internal val overrideClickListener: (() -> Unit)? = null
|
||||
internal val overrideClickListener: (() -> Unit)? = null,
|
||||
) {
|
||||
|
||||
internal val uri: Uri by lazy {
|
||||
|
|
|
@ -20,7 +20,6 @@ import android.widget.TextView
|
|||
import androidx.activity.result.contract.ActivityResultContracts.OpenDocumentTree
|
||||
import androidx.annotation.RequiresPermission
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.stevesoltys.seedvault.R
|
||||
import com.stevesoltys.seedvault.ui.INTENT_EXTRA_IS_RESTORE
|
||||
|
@ -53,8 +52,8 @@ internal class StorageRootsFragment : Fragment(), StorageRootClickedListener {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v: View = inflater.inflate(R.layout.fragment_storage_root, container, false)
|
||||
|
||||
titleView = v.findViewById(R.id.titleView)
|
||||
|
@ -92,7 +91,7 @@ internal class StorageRootsFragment : Fragment(), StorageRootClickedListener {
|
|||
|
||||
listView.adapter = adapter
|
||||
|
||||
viewModel.storageRoots.observe(viewLifecycleOwner, Observer { roots ->
|
||||
viewModel.storageRoots.observe(viewLifecycleOwner, { roots ->
|
||||
onRootsLoaded(roots)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ private val TAG = StorageViewModel::class.java.simpleName
|
|||
|
||||
internal abstract class StorageViewModel(
|
||||
private val app: Application,
|
||||
protected val settingsManager: SettingsManager
|
||||
protected val settingsManager: SettingsManager,
|
||||
) : AndroidViewModel(app), RemovableStorageListener {
|
||||
|
||||
private val mStorageRoots = MutableLiveData<List<StorageRoot>>()
|
||||
|
@ -48,7 +48,7 @@ internal abstract class StorageViewModel(
|
|||
companion object {
|
||||
internal fun validLocationIsSet(
|
||||
context: Context,
|
||||
settingsManager: SettingsManager
|
||||
settingsManager: SettingsManager,
|
||||
): Boolean {
|
||||
val storage = settingsManager.getStorage() ?: return false
|
||||
if (storage.isUsb) return true
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
<color name="primaryDark">@*android:color/primary_dark_device_default_settings_light</color>
|
||||
<color name="background">@*android:color/background_device_default_light</color>
|
||||
<color name="actionBarPrimary">@*android:color/primary_device_default_light</color>
|
||||
<color name="statusBarColor">@*android:color/primary_dark_material_light_light_status_bar</color>
|
||||
<color name="statusBarColor">@*android:color/primary_dark_material_light_light_status_bar
|
||||
</color>
|
||||
<color name="red">@*android:color/error_color_device_default_dark</color>
|
||||
<color name="divider">#20ffffff</color>
|
||||
<color name="green">#558B2F</color>
|
||||
|
|
|
@ -48,14 +48,6 @@ fun ByteArray.toHexString(spacer: String = " "): String {
|
|||
|
||||
fun String.toByteArrayFromHex() = chunked(2).map { it.toInt(16).toByte() }.toByteArray()
|
||||
|
||||
fun ByteArray.toIntString(): String {
|
||||
var str = ""
|
||||
for (b in this) {
|
||||
str += String.format("%02d ", b)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
fun OutputStream.writeAndClose(data: ByteArray) = use {
|
||||
it.write(data)
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ internal class MetadataReadWriteTest {
|
|||
}
|
||||
|
||||
private fun getMetadata(
|
||||
packageMetadata: HashMap<String, PackageMetadata> = HashMap()
|
||||
packageMetadata: HashMap<String, PackageMetadata> = HashMap(),
|
||||
): BackupMetadata {
|
||||
return BackupMetadata(
|
||||
version = VERSION,
|
||||
|
|
|
@ -169,7 +169,7 @@ class MetadataReaderTest {
|
|||
}
|
||||
|
||||
private fun getMetadata(
|
||||
packageMetadata: PackageMetadataMap = PackageMetadataMap()
|
||||
packageMetadata: PackageMetadataMap = PackageMetadataMap(),
|
||||
): BackupMetadata {
|
||||
return BackupMetadata(
|
||||
version = 1.toByte(),
|
||||
|
|
|
@ -50,7 +50,7 @@ internal class MetadataV0ReadTest {
|
|||
}
|
||||
|
||||
private fun getMetadata(
|
||||
packageMetadata: HashMap<String, PackageMetadata> = HashMap()
|
||||
packageMetadata: HashMap<String, PackageMetadata> = HashMap(),
|
||||
) = BackupMetadata(
|
||||
version = 0x00,
|
||||
token = 1337L,
|
||||
|
|
|
@ -120,7 +120,7 @@ internal class MetadataWriterDecoderTest {
|
|||
}
|
||||
|
||||
private fun getMetadata(
|
||||
packageMetadata: HashMap<String, PackageMetadata> = HashMap()
|
||||
packageMetadata: HashMap<String, PackageMetadata> = HashMap(),
|
||||
): BackupMetadata {
|
||||
return BackupMetadata(
|
||||
version = Random.nextBytes(1)[0],
|
||||
|
|
|
@ -46,6 +46,7 @@ internal class ApkBackupRestoreTest : TransportTest() {
|
|||
private val strictContext: Context = mockk<Context>().apply {
|
||||
every { packageManager } returns pm
|
||||
}
|
||||
|
||||
@Suppress("Deprecation")
|
||||
private val legacyStoragePlugin: LegacyStoragePlugin = mockk()
|
||||
private val storagePlugin: StoragePlugin = mockk()
|
||||
|
|
|
@ -14,10 +14,10 @@ import com.stevesoltys.seedvault.header.VERSION
|
|||
import com.stevesoltys.seedvault.metadata.BackupType
|
||||
import com.stevesoltys.seedvault.metadata.MetadataReader
|
||||
import com.stevesoltys.seedvault.metadata.PackageMetadata
|
||||
import com.stevesoltys.seedvault.plugins.EncryptedMetadata
|
||||
import com.stevesoltys.seedvault.plugins.StoragePlugin
|
||||
import com.stevesoltys.seedvault.settings.Storage
|
||||
import com.stevesoltys.seedvault.transport.TransportTest
|
||||
import com.stevesoltys.seedvault.plugins.StoragePlugin
|
||||
import com.stevesoltys.seedvault.plugins.EncryptedMetadata
|
||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||
import io.mockk.Runs
|
||||
import io.mockk.coEvery
|
||||
|
|
|
@ -14,10 +14,10 @@ import com.stevesoltys.seedvault.encodeBase64
|
|||
import com.stevesoltys.seedvault.header.HeaderReaderImpl
|
||||
import com.stevesoltys.seedvault.metadata.MetadataReaderImpl
|
||||
import com.stevesoltys.seedvault.plugins.LegacyStoragePlugin
|
||||
import com.stevesoltys.seedvault.plugins.StoragePlugin
|
||||
import com.stevesoltys.seedvault.toByteArrayFromHex
|
||||
import com.stevesoltys.seedvault.transport.TransportTest
|
||||
import com.stevesoltys.seedvault.transport.backup.KvDbManager
|
||||
import com.stevesoltys.seedvault.plugins.StoragePlugin
|
||||
import com.stevesoltys.seedvault.ui.notification.BackupNotificationManager
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.every
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package org.calyxos.backup.contacts;
|
||||
|
||||
import static android.Manifest.permission.READ_CONTACTS;
|
||||
import static android.Manifest.permission.WRITE_CONTACTS;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
import android.app.backup.BackupAgent;
|
||||
import android.app.backup.BackupDataInput;
|
||||
import android.app.backup.BackupDataOutput;
|
||||
|
@ -16,10 +20,6 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import static android.Manifest.permission.READ_CONTACTS;
|
||||
import static android.Manifest.permission.WRITE_CONTACTS;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
public class ContactsBackupAgent extends BackupAgent implements FullBackupFileHandler {
|
||||
|
||||
private final static String TAG = "ContactsBackupAgent";
|
||||
|
|
|
@ -53,7 +53,7 @@ open class LogFragment : Fragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
setHasOptionsMenu(true)
|
||||
val v = inflater.inflate(R.layout.fragment_log, container, false)
|
||||
|
|
|
@ -37,7 +37,7 @@ internal class BackupStats(
|
|||
totalSize: Long,
|
||||
numFiles: Int,
|
||||
numSmallFiles: Int,
|
||||
numLargeFiles: Int
|
||||
numLargeFiles: Int,
|
||||
) {
|
||||
super.onBackupStart(totalSize, numFiles, numSmallFiles, numLargeFiles)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class DemoSnapshotFragment : SnapshotFragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
val v = super.onCreateView(inflater, container, savedInstanceState)
|
||||
val bottomStub: ViewStub = v.findViewById(R.id.bottomStub)
|
||||
|
|
|
@ -33,7 +33,7 @@ class RestoreFragment : Fragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
setHasOptionsMenu(true)
|
||||
val v = inflater.inflate(R.layout.fragment_log, container, false)
|
||||
|
|
|
@ -29,7 +29,7 @@ private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
|
|||
fun scanDocument(
|
||||
context: Context,
|
||||
documentFiles: List<BackupFile>,
|
||||
sb: StringBuilder? = null
|
||||
sb: StringBuilder? = null,
|
||||
): ScanResult {
|
||||
var totalSize = 0L
|
||||
val warnings = StringBuilder()
|
||||
|
|
|
@ -46,7 +46,7 @@ open class MediaScanFragment : Fragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
setHasOptionsMenu(true)
|
||||
requireActivity().title = arguments?.getString("name")
|
||||
|
|
|
@ -14,7 +14,7 @@ import kotlin.time.measureTimedValue
|
|||
|
||||
data class ScanResult(
|
||||
var itemsFound: Long,
|
||||
var totalSize: Long
|
||||
var totalSize: Long,
|
||||
) {
|
||||
operator fun plusAssign(other: ScanResult) {
|
||||
itemsFound += other.itemsFound
|
||||
|
@ -57,7 +57,7 @@ fun appendStats(
|
|||
context: Context,
|
||||
sb: StringBuilder,
|
||||
timedResult: TimedValue<ScanResult>,
|
||||
title: String? = null
|
||||
title: String? = null,
|
||||
): String {
|
||||
val result = timedResult.value
|
||||
if (title != null || sb.isNotEmpty()) {
|
||||
|
|
|
@ -42,7 +42,7 @@ class SettingsFragment : BackupContentFragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View {
|
||||
setHasOptionsMenu(true)
|
||||
requireActivity().title = "Settings"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<resources>
|
||||
|
||||
<style name="Theme.StorageBackupTester" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<item name="colorPrimary">@color/matrix</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
|
|
|
@ -28,7 +28,7 @@ public val mediaUris: List<Uri> = listOf(
|
|||
|
||||
public sealed class BackupContentType(
|
||||
@DrawableRes
|
||||
public val drawableRes: Int
|
||||
public val drawableRes: Int,
|
||||
) {
|
||||
public object Custom : BackupContentType(R.drawable.ic_folder) {
|
||||
public fun getName(uri: Uri): String {
|
||||
|
|
|
@ -119,7 +119,7 @@ internal class Backup(
|
|||
private suspend fun backupFiles(
|
||||
filesResult: FileScannerResult,
|
||||
availableChunkIds: HashSet<String>,
|
||||
backupObserver: BackupObserver?
|
||||
backupObserver: BackupObserver?,
|
||||
) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
val numSmallFiles = filesResult.smallFiles.size
|
||||
|
|
|
@ -36,7 +36,7 @@ internal class ChunkWriter(
|
|||
fun writeChunk(
|
||||
inputStream: InputStream,
|
||||
chunks: List<Chunk>,
|
||||
missingChunkIds: List<String>
|
||||
missingChunkIds: List<String>,
|
||||
): ChunkWriterResult {
|
||||
var writtenChunks = 0
|
||||
var writtenBytes = 0L
|
||||
|
@ -77,7 +77,7 @@ internal class ChunkWriter(
|
|||
private fun copyChunkFromInputStream(
|
||||
inputStream: InputStream,
|
||||
chunk: Chunk,
|
||||
outputStream: OutputStream
|
||||
outputStream: OutputStream,
|
||||
) {
|
||||
var totalBytesRead = 0L
|
||||
do {
|
||||
|
@ -101,7 +101,7 @@ internal class ChunkWriter(
|
|||
fun writeZipChunk(
|
||||
chunk: ZipChunk,
|
||||
zip: ByteArrayOutputStream,
|
||||
missingChunkIds: List<String>
|
||||
missingChunkIds: List<String>,
|
||||
): Boolean {
|
||||
val cachedChunk = chunksCache.get(chunk.id)
|
||||
val isMissing = chunk.id in missingChunkIds
|
||||
|
|
|
@ -10,7 +10,7 @@ import kotlin.math.min
|
|||
internal data class Chunk(
|
||||
val id: String,
|
||||
val offset: Long,
|
||||
val size: Long
|
||||
val size: Long,
|
||||
) {
|
||||
fun toCachedChunk() = CachedChunk(id, 0, size)
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ internal class ChunksCacheRepopulater(
|
|||
@OptIn(ExperimentalTime::class)
|
||||
private suspend fun repopulateInternal(
|
||||
streamKey: ByteArray,
|
||||
availableChunkIds: HashSet<String>
|
||||
availableChunkIds: HashSet<String>,
|
||||
) {
|
||||
val start = System.currentTimeMillis()
|
||||
val snapshots = storagePlugin.getCurrentBackupSnapshots().mapNotNull { storedSnapshot ->
|
||||
|
@ -85,7 +85,7 @@ internal class ChunksCacheRepopulater(
|
|||
snapshotTimeStamp: Long,
|
||||
availableChunks: HashSet<String>,
|
||||
chunkMap: HashMap<String, CachedChunk>,
|
||||
chunksInSnapshot: HashSet<String>
|
||||
chunksInSnapshot: HashSet<String>,
|
||||
) = chunksInSnapshot.forEach { chunkId ->
|
||||
if (!availableChunks.contains(chunkId)) {
|
||||
Log.w(TAG, "ChunkId $chunkId referenced in $snapshotTimeStamp, but not in storage.")
|
||||
|
|
|
@ -27,7 +27,7 @@ internal class FileBackup(
|
|||
suspend fun backupFiles(
|
||||
files: List<ContentFile>,
|
||||
availableChunkIds: HashSet<String>,
|
||||
backupObserver: BackupObserver?
|
||||
backupObserver: BackupObserver?,
|
||||
): BackupResult {
|
||||
val chunkIds = HashSet<String>()
|
||||
val backupMediaFiles = ArrayList<BackupMediaFile>()
|
||||
|
@ -71,7 +71,7 @@ internal class FileBackup(
|
|||
@Throws(IOException::class, GeneralSecurityException::class)
|
||||
private fun backupFile(
|
||||
file: ContentFile,
|
||||
availableChunkIds: HashSet<String>
|
||||
availableChunkIds: HashSet<String>,
|
||||
): FileBackupResult {
|
||||
val cachedFile = filesCache.getByUri(file.uri)
|
||||
val missingChunkIds = cachedFile?.chunks?.minus(availableChunkIds) ?: emptyList()
|
||||
|
|
|
@ -25,7 +25,7 @@ public open class NotificationBackupObserver internal constructor(private val n:
|
|||
totalSize: Long,
|
||||
numFiles: Int,
|
||||
numSmallFiles: Int,
|
||||
numLargeFiles: Int
|
||||
numLargeFiles: Int,
|
||||
) {
|
||||
totalFiles = numFiles
|
||||
n.updateBackupNotification(
|
||||
|
@ -40,7 +40,7 @@ public open class NotificationBackupObserver internal constructor(private val n:
|
|||
wasUploaded: Boolean,
|
||||
reusedChunks: Int,
|
||||
bytesWritten: Long,
|
||||
tag: String
|
||||
tag: String,
|
||||
) {
|
||||
filesBackedUp++
|
||||
n.updateBackupNotification(
|
||||
|
|
|
@ -27,7 +27,7 @@ internal class SmallFileBackup(
|
|||
suspend fun backupFiles(
|
||||
files: List<ContentFile>,
|
||||
availableChunkIds: HashSet<String>,
|
||||
backupObserver: BackupObserver?
|
||||
backupObserver: BackupObserver?,
|
||||
): BackupResult {
|
||||
val chunkIds = HashSet<String>()
|
||||
val missingChunkIds = ArrayList<String>()
|
||||
|
@ -105,7 +105,7 @@ internal class SmallFileBackup(
|
|||
@Throws(IOException::class, GeneralSecurityException::class)
|
||||
private fun makeZipChunk(
|
||||
window: List<ContentFile>,
|
||||
missingChunkIds: List<String>
|
||||
missingChunkIds: List<String>,
|
||||
): SmallFileBackupResult? {
|
||||
val file = window[0]
|
||||
val nextFile = window.getOrNull(1)
|
||||
|
@ -124,7 +124,7 @@ internal class SmallFileBackup(
|
|||
@Throws(IOException::class, GeneralSecurityException::class)
|
||||
private fun finalizeAndReset(
|
||||
zipChunker: ZipChunker,
|
||||
missingChunkIds: List<String>
|
||||
missingChunkIds: List<String>,
|
||||
): SmallFileBackupResult {
|
||||
val zipChunk = zipChunker.finalizeAndReset(missingChunkIds)
|
||||
val chunkIds = listOf(zipChunk.id)
|
||||
|
|
|
@ -21,7 +21,7 @@ internal object ChunkCrypto {
|
|||
@Throws(GeneralSecurityException::class)
|
||||
fun deriveChunkIdKey(
|
||||
masterKey: SecretKey,
|
||||
info: ByteArray = INFO_CHUNK_ID.toByteArray()
|
||||
info: ByteArray = INFO_CHUNK_ID.toByteArray(),
|
||||
): ByteArray = Hkdf.expand(
|
||||
secretKey = masterKey,
|
||||
info = info,
|
||||
|
|
|
@ -22,7 +22,7 @@ public object StreamCrypto {
|
|||
@Throws(GeneralSecurityException::class)
|
||||
public fun deriveStreamKey(
|
||||
masterKey: SecretKey,
|
||||
info: ByteArray = INFO_STREAM_KEY.toByteArray()
|
||||
info: ByteArray = INFO_STREAM_KEY.toByteArray(),
|
||||
): ByteArray = Hkdf.expand(
|
||||
secretKey = masterKey,
|
||||
info = info,
|
||||
|
@ -51,7 +51,7 @@ public object StreamCrypto {
|
|||
public fun newEncryptingStream(
|
||||
secret: ByteArray,
|
||||
outputStream: OutputStream,
|
||||
associatedData: ByteArray = ByteArray(0)
|
||||
associatedData: ByteArray = ByteArray(0),
|
||||
): OutputStream {
|
||||
return AesGcmHkdfStreaming(
|
||||
secret,
|
||||
|
@ -66,7 +66,7 @@ public object StreamCrypto {
|
|||
public fun newDecryptingStream(
|
||||
secret: ByteArray,
|
||||
inputStream: InputStream,
|
||||
associatedData: ByteArray = ByteArray(0)
|
||||
associatedData: ByteArray = ByteArray(0),
|
||||
): InputStream {
|
||||
return AesGcmHkdfStreaming(
|
||||
secret,
|
||||
|
|
|
@ -23,7 +23,7 @@ internal data class CachedFile(
|
|||
*/
|
||||
@ColumnInfo(name = "zip_index") val zipIndex: Int? = null,
|
||||
// TODO also purge files from the cache from time to time
|
||||
@ColumnInfo(name = "last_seen") val lastSeen: Long
|
||||
@ColumnInfo(name = "last_seen") val lastSeen: Long,
|
||||
)
|
||||
|
||||
@Dao
|
||||
|
|
|
@ -108,7 +108,7 @@ public object DocumentFileExt {
|
|||
public fun getTreeDocumentFile(
|
||||
parent: DocumentFile,
|
||||
context: Context,
|
||||
uri: Uri
|
||||
uri: Uri,
|
||||
): DocumentFile {
|
||||
@SuppressWarnings("MagicNumber")
|
||||
val constructor = parent.javaClass.declaredConstructors.find {
|
||||
|
@ -128,7 +128,7 @@ public object DocumentFileExt {
|
|||
*/
|
||||
public suspend fun DocumentFile.findFileBlocking(
|
||||
context: Context,
|
||||
displayName: String
|
||||
displayName: String,
|
||||
): DocumentFile? {
|
||||
val files = try {
|
||||
listFilesBlocking(context)
|
||||
|
|
|
@ -84,7 +84,7 @@ public abstract class SafStoragePlugin(
|
|||
private suspend fun populateChunkFolders(
|
||||
folder: DocumentFile,
|
||||
chunkFolders: HashMap<String, DocumentFile>,
|
||||
fileOp: ((DocumentFile, String) -> Unit)? = null
|
||||
fileOp: ((DocumentFile, String) -> Unit)? = null,
|
||||
) {
|
||||
val expectedChunkFolders = (0x00..0xff).map {
|
||||
Integer.toHexString(it).padStart(2, '0')
|
||||
|
@ -121,7 +121,7 @@ public abstract class SafStoragePlugin(
|
|||
private fun createMissingChunkFolders(
|
||||
root: DocumentFile,
|
||||
chunkFolders: HashMap<String, DocumentFile>,
|
||||
expectedChunkFolders: Set<String>
|
||||
expectedChunkFolders: Set<String>,
|
||||
) {
|
||||
val s = expectedChunkFolders.size
|
||||
val duration = measure {
|
||||
|
@ -194,7 +194,7 @@ public abstract class SafStoragePlugin(
|
|||
@Throws(IOException::class)
|
||||
override suspend fun getChunkInputStream(
|
||||
snapshot: StoredSnapshot,
|
||||
chunkId: String
|
||||
chunkId: String,
|
||||
): InputStream {
|
||||
if (cache.restoreChunkFolders.size < CHUNK_FOLDER_COUNT) {
|
||||
populateChunkFolders(getFolder(snapshot), cache.restoreChunkFolders)
|
||||
|
|
|
@ -53,7 +53,7 @@ internal class Pruner(
|
|||
@Throws(IOException::class, GeneralSecurityException::class)
|
||||
private suspend fun pruneSnapshot(
|
||||
storedSnapshot: StoredSnapshot,
|
||||
backupObserver: BackupObserver?
|
||||
backupObserver: BackupObserver?,
|
||||
) {
|
||||
val snapshot = snapshotRetriever.getSnapshot(streamKey, storedSnapshot)
|
||||
val chunks = HashSet<String>()
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue