commit
c856048f8f
23 changed files with 86 additions and 96 deletions
|
@ -32,6 +32,8 @@ android_app {
|
||||||
"androidx.lifecycle_lifecycle-livedata-ktx",
|
"androidx.lifecycle_lifecycle-livedata-ktx",
|
||||||
"androidx-constraintlayout_constraintlayout",
|
"androidx-constraintlayout_constraintlayout",
|
||||||
"com.google.android.material_material",
|
"com.google.android.material_material",
|
||||||
|
"kotlinx-coroutines-android",
|
||||||
|
"kotlinx-coroutines-core",
|
||||||
// storage backup lib
|
// storage backup lib
|
||||||
"seedvault-lib-storage",
|
"seedvault-lib-storage",
|
||||||
// koin
|
// koin
|
||||||
|
|
|
@ -38,12 +38,12 @@ android {
|
||||||
abortOnError true
|
abortOnError true
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
targetCompatibility 1.8
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
sourceCompatibility 1.8
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||||
languageVersion = "1.4"
|
languageVersion = "1.6"
|
||||||
}
|
}
|
||||||
testOptions {
|
testOptions {
|
||||||
unitTests.all {
|
unitTests.all {
|
||||||
|
@ -138,10 +138,11 @@ dependencies {
|
||||||
// anything less than 'implementation' fails tests run with gradlew
|
// anything less than 'implementation' fails tests run with gradlew
|
||||||
testImplementation rootProject.ext.aosp_libs
|
testImplementation rootProject.ext.aosp_libs
|
||||||
testImplementation 'androidx.test.ext:junit:1.1.3'
|
testImplementation 'androidx.test.ext:junit:1.1.3'
|
||||||
testImplementation('org.robolectric:robolectric:4.3.1') { // 4.4 has issue with non-idle Looper
|
testImplementation('org.robolectric:robolectric:4.8.1') {
|
||||||
// https://github.com/robolectric/robolectric/issues/5245
|
// https://github.com/robolectric/robolectric/issues/5245
|
||||||
exclude group: "com.google.auto.service", module: "auto-service"
|
exclude group: "com.google.auto.service", module: "auto-service"
|
||||||
}
|
}
|
||||||
|
testImplementation 'org.hamcrest:hamcrest:2.2'
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junit5_version"
|
testImplementation "org.junit.jupiter:junit-jupiter-api:$junit5_version"
|
||||||
testImplementation "org.junit.jupiter:junit-jupiter-params:$junit5_version"
|
testImplementation "org.junit.jupiter:junit-jupiter-params:$junit5_version"
|
||||||
testImplementation "io.mockk:mockk:$mockk_version"
|
testImplementation "io.mockk:mockk:$mockk_version"
|
||||||
|
@ -159,9 +160,6 @@ apply from: "${rootProject.rootDir}/gradle/ktlint.gradle"
|
||||||
|
|
||||||
gradle.projectsEvaluated {
|
gradle.projectsEvaluated {
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
if (JavaVersion.current() >= JavaVersion.VERSION_1_9) {
|
|
||||||
options.compilerArgs.addAll(['--release', '8'])
|
|
||||||
}
|
|
||||||
options.compilerArgs.add('-Xbootclasspath/p:app/libs/android.jar:app/libs/libcore.jar')
|
options.compilerArgs.add('-Xbootclasspath/p:app/libs/android.jar:app/libs/libcore.jar')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -106,7 +106,7 @@ internal class AppListRetriever(
|
||||||
time = time,
|
time = time,
|
||||||
status = status
|
status = status
|
||||||
)
|
)
|
||||||
}.sortedBy { it.name.toLowerCase(locale) }
|
}.sortedBy { it.name.lowercase(locale) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNotAllowedApps(): List<AppStatus> {
|
private fun getNotAllowedApps(): List<AppStatus> {
|
||||||
|
@ -120,7 +120,7 @@ internal class AppListRetriever(
|
||||||
time = 0,
|
time = 0,
|
||||||
status = FAILED_NOT_ALLOWED
|
status = FAILED_NOT_ALLOWED
|
||||||
)
|
)
|
||||||
}.sortedBy { it.name.toLowerCase(locale) }
|
}.sortedBy { it.name.lowercase(locale) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getIcon(packageName: String): Drawable = when (packageName) {
|
private fun getIcon(packageName: String): Drawable = when (packageName) {
|
||||||
|
|
|
@ -133,14 +133,8 @@ internal class ApkBackupRestoreTest : TransportTest() {
|
||||||
every { strictContext.cacheDir } returns tmpFile
|
every { strictContext.cacheDir } returns tmpFile
|
||||||
every { crypto.getNameForApk(salt, packageName, "") } returns name
|
every { crypto.getNameForApk(salt, packageName, "") } returns name
|
||||||
coEvery { storagePlugin.getInputStream(token, name) } returns inputStream
|
coEvery { storagePlugin.getInputStream(token, name) } returns inputStream
|
||||||
every { pm.getPackageArchiveInfo(capture(apkPath), any()) } returns packageInfo
|
every { pm.getPackageArchiveInfo(capture(apkPath), any<Int>()) } returns packageInfo
|
||||||
every {
|
every { applicationInfo.loadIcon(pm) } returns icon
|
||||||
@Suppress("UNRESOLVED_REFERENCE")
|
|
||||||
pm.loadItemIcon(
|
|
||||||
packageInfo.applicationInfo,
|
|
||||||
packageInfo.applicationInfo
|
|
||||||
)
|
|
||||||
} returns icon
|
|
||||||
every { pm.getApplicationLabel(packageInfo.applicationInfo) } returns appName
|
every { pm.getApplicationLabel(packageInfo.applicationInfo) } returns appName
|
||||||
every {
|
every {
|
||||||
splitCompatChecker.isCompatible(metadata.deviceName, listOf(splitName))
|
splitCompatChecker.isCompatible(metadata.deviceName, listOf(splitName))
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package com.stevesoltys.seedvault.restore.install
|
package com.stevesoltys.seedvault.restore.install
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.ApplicationInfo
|
|
||||||
import android.content.pm.ApplicationInfo.FLAG_INSTALLED
|
import android.content.pm.ApplicationInfo.FLAG_INSTALLED
|
||||||
import android.content.pm.ApplicationInfo.FLAG_SYSTEM
|
import android.content.pm.ApplicationInfo.FLAG_SYSTEM
|
||||||
import android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
|
import android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
|
||||||
|
@ -112,7 +111,7 @@ internal class ApkRestoreTest : TransportTest() {
|
||||||
every { strictContext.cacheDir } returns File(tmpDir.toString())
|
every { strictContext.cacheDir } returns File(tmpDir.toString())
|
||||||
every { crypto.getNameForApk(salt, packageName, "") } returns name
|
every { crypto.getNameForApk(salt, packageName, "") } returns name
|
||||||
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
|
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
|
||||||
every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo
|
every { pm.getPackageArchiveInfo(any(), any<Int>()) } returns packageInfo
|
||||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||||
|
|
||||||
apkRestore.restore(backup).collectIndexed { i, value ->
|
apkRestore.restore(backup).collectIndexed { i, value ->
|
||||||
|
@ -176,14 +175,8 @@ internal class ApkRestoreTest : TransportTest() {
|
||||||
coEvery {
|
coEvery {
|
||||||
legacyStoragePlugin.getApkInputStream(token, packageName, "")
|
legacyStoragePlugin.getApkInputStream(token, packageName, "")
|
||||||
} returns apkInputStream
|
} returns apkInputStream
|
||||||
every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo
|
every { pm.getPackageArchiveInfo(any(), any<Int>()) } returns packageInfo
|
||||||
every {
|
every { applicationInfo.loadIcon(pm) } returns icon
|
||||||
@Suppress("UNRESOLVED_REFERENCE")
|
|
||||||
pm.loadItemIcon(
|
|
||||||
packageInfo.applicationInfo,
|
|
||||||
packageInfo.applicationInfo
|
|
||||||
)
|
|
||||||
} returns icon
|
|
||||||
every { pm.getApplicationLabel(packageInfo.applicationInfo) } returns appName
|
every { pm.getApplicationLabel(packageInfo.applicationInfo) } returns appName
|
||||||
coEvery {
|
coEvery {
|
||||||
apkInstaller.install(match { it.size == 1 }, packageName, installerName, any())
|
apkInstaller.install(match { it.size == 1 }, packageName, installerName, any())
|
||||||
|
@ -200,13 +193,11 @@ internal class ApkRestoreTest : TransportTest() {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val packageMetadata = this@ApkRestoreTest.packageMetadata.copy(system = true)
|
val packageMetadata = this@ApkRestoreTest.packageMetadata.copy(system = true)
|
||||||
packageMetadataMap[packageName] = packageMetadata
|
packageMetadataMap[packageName] = packageMetadata
|
||||||
packageInfo.applicationInfo = mockk()
|
|
||||||
val installedPackageInfo: PackageInfo = mockk()
|
val installedPackageInfo: PackageInfo = mockk()
|
||||||
val willFail = Random.nextBoolean()
|
val willFail = Random.nextBoolean()
|
||||||
val isSystemApp = Random.nextBoolean()
|
val isSystemApp = Random.nextBoolean()
|
||||||
|
|
||||||
cacheBaseApkAndGetInfo(tmpDir)
|
cacheBaseApkAndGetInfo(tmpDir)
|
||||||
every { packageInfo.applicationInfo.loadIcon(pm) } returns icon
|
|
||||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||||
|
|
||||||
if (willFail) {
|
if (willFail) {
|
||||||
|
@ -214,7 +205,7 @@ internal class ApkRestoreTest : TransportTest() {
|
||||||
pm.getPackageInfo(packageName, 0)
|
pm.getPackageInfo(packageName, 0)
|
||||||
} throws PackageManager.NameNotFoundException()
|
} throws PackageManager.NameNotFoundException()
|
||||||
} else {
|
} else {
|
||||||
installedPackageInfo.applicationInfo = ApplicationInfo().apply {
|
installedPackageInfo.applicationInfo = mockk {
|
||||||
flags =
|
flags =
|
||||||
if (!isSystemApp) FLAG_INSTALLED else FLAG_SYSTEM or FLAG_UPDATED_SYSTEM_APP
|
if (!isSystemApp) FLAG_INSTALLED else FLAG_SYSTEM or FLAG_UPDATED_SYSTEM_APP
|
||||||
}
|
}
|
||||||
|
@ -421,14 +412,8 @@ internal class ApkRestoreTest : TransportTest() {
|
||||||
every { strictContext.cacheDir } returns File(tmpDir.toString())
|
every { strictContext.cacheDir } returns File(tmpDir.toString())
|
||||||
every { crypto.getNameForApk(salt, packageName, "") } returns name
|
every { crypto.getNameForApk(salt, packageName, "") } returns name
|
||||||
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
|
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
|
||||||
every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo
|
every { pm.getPackageArchiveInfo(any(), any<Int>()) } returns packageInfo
|
||||||
every {
|
every { applicationInfo.loadIcon(pm) } returns icon
|
||||||
@Suppress("UNRESOLVED_REFERENCE")
|
|
||||||
pm.loadItemIcon(
|
|
||||||
packageInfo.applicationInfo,
|
|
||||||
packageInfo.applicationInfo
|
|
||||||
)
|
|
||||||
} returns icon
|
|
||||||
every { pm.getApplicationLabel(packageInfo.applicationInfo) } returns appName
|
every { pm.getApplicationLabel(packageInfo.applicationInfo) } returns appName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,12 +37,13 @@ internal abstract class TransportTest {
|
||||||
|
|
||||||
protected val sigInfo: SigningInfo = mockk()
|
protected val sigInfo: SigningInfo = mockk()
|
||||||
protected val token = Random.nextLong()
|
protected val token = Random.nextLong()
|
||||||
|
protected val applicationInfo = mockk<ApplicationInfo> {
|
||||||
|
flags = FLAG_ALLOW_BACKUP or FLAG_INSTALLED
|
||||||
|
}
|
||||||
protected val packageInfo = PackageInfo().apply {
|
protected val packageInfo = PackageInfo().apply {
|
||||||
packageName = "org.example"
|
packageName = "org.example"
|
||||||
longVersionCode = Random.nextLong()
|
longVersionCode = Random.nextLong()
|
||||||
applicationInfo = ApplicationInfo().apply {
|
applicationInfo = this@TransportTest.applicationInfo
|
||||||
flags = FLAG_ALLOW_BACKUP or FLAG_INSTALLED
|
|
||||||
}
|
|
||||||
signingInfo = sigInfo
|
signingInfo = sigInfo
|
||||||
}
|
}
|
||||||
protected val pmPackageInfo = PackageInfo().apply {
|
protected val pmPackageInfo = PackageInfo().apply {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import android.app.backup.BackupTransport.TRANSPORT_NOT_INITIALIZED
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_OK
|
import android.app.backup.BackupTransport.TRANSPORT_OK
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_PACKAGE_REJECTED
|
import android.app.backup.BackupTransport.TRANSPORT_PACKAGE_REJECTED
|
||||||
import android.app.backup.BackupTransport.TRANSPORT_QUOTA_EXCEEDED
|
import android.app.backup.BackupTransport.TRANSPORT_QUOTA_EXCEEDED
|
||||||
import android.content.pm.ApplicationInfo
|
|
||||||
import android.content.pm.ApplicationInfo.FLAG_STOPPED
|
import android.content.pm.ApplicationInfo.FLAG_STOPPED
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
@ -399,7 +398,9 @@ internal class BackupCoordinatorTest : BackupTest() {
|
||||||
PackageInfo().apply {
|
PackageInfo().apply {
|
||||||
packageName = "org.example.2"
|
packageName = "org.example.2"
|
||||||
// the second package does not get backed up, because it is stopped
|
// the second package does not get backed up, because it is stopped
|
||||||
applicationInfo = ApplicationInfo().apply { flags = FLAG_STOPPED }
|
applicationInfo = mockk {
|
||||||
|
flags = FLAG_STOPPED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val packageMetadata: PackageMetadata = mockk()
|
val packageMetadata: PackageMetadata = mockk()
|
||||||
|
|
16
build.gradle
16
build.gradle
|
@ -1,11 +1,11 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
// 1.3.21 Android 10
|
|
||||||
// 1.3.61 Android 11
|
// 1.3.61 Android 11
|
||||||
// 1.4.30 Android 12
|
// 1.4.30 Android 12
|
||||||
|
// 1.6.10 Android 13
|
||||||
// Check:
|
// Check:
|
||||||
// https://android.googlesource.com/platform/external/kotlinc/+/refs/tags/android-12.0.0_r2/build.txt
|
// https://android.googlesource.com/platform/external/kotlinc/+/refs/tags/android-13.0.0_r3/build.txt
|
||||||
ext.aosp_kotlin_version = '1.4.31' // 1.4.30 breaks Kotlin plugin in Android Studio
|
ext.aosp_kotlin_version = '1.6.10' // 1.6.10-release-923 in AOSP
|
||||||
ext.kotlin_version = '1.4.31'
|
ext.kotlin_version = '1.6.10'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -15,15 +15,15 @@ buildscript {
|
||||||
//noinspection DifferentKotlinGradleVersion
|
//noinspection DifferentKotlinGradleVersion
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.17"
|
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.17"
|
||||||
classpath 'com.android.tools.build:gradle:7.0.2'
|
classpath 'com.android.tools.build:gradle:7.2.2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
buildToolsVersion = '31.0.0'
|
buildToolsVersion = '33.0.0'
|
||||||
compileSdkVersion = 31
|
compileSdkVersion = 33
|
||||||
minSdkVersion = 29
|
minSdkVersion = 29
|
||||||
targetSdkVersion = 31
|
targetSdkVersion = 33
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: 'gradle/dependencies.gradle'
|
apply from: 'gradle/dependencies.gradle'
|
||||||
|
|
|
@ -15,12 +15,12 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = 1.8
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
targetCompatibility = 1.8
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
testOptions {
|
testOptions {
|
||||||
|
|
Binary file not shown.
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/androidx/Android.bp#2943
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/androidx/Android.bp#3901
|
||||||
ext.room_version = "2.3.0-beta02"
|
ext.room_version = "2.4.0-alpha05"
|
||||||
// https://android.googlesource.com/platform/external/protobuf/+/refs/tags/android-12.0.0_r2/java/pom.xml#7
|
// https://android.googlesource.com/platform/external/protobuf/+/refs/tags/android-13.0.0_r3/java/pom.xml#7
|
||||||
ext.protobuf_version = "3.9.1"
|
ext.protobuf_version = "3.9.1"
|
||||||
junit4_version = "4.13.2"
|
junit4_version = "4.13.2"
|
||||||
junit5_version = "5.5.2" // careful, upgrading this can change a Cipher's IV size in tests!?
|
junit5_version = "5.5.2" // careful, upgrading this can change a Cipher's IV size in tests!?
|
||||||
|
@ -37,58 +37,58 @@ ext.kotlin_libs = [
|
||||||
],
|
],
|
||||||
coroutines: [
|
coroutines: [
|
||||||
dependencies.create('org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm') {
|
dependencies.create('org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm') {
|
||||||
// https://android.googlesource.com/platform/prebuilts/tools/+/refs/tags/android-12.0.0_r2/common/m2/Android.bp#273
|
// https://android.googlesource.com/platform/external/kotlinx.coroutines/+/refs/tags/android-13.0.0_r3/CHANGES.md
|
||||||
version { strictly '1.4.2' }
|
version { strictly '1.5.2' }
|
||||||
},
|
},
|
||||||
dependencies.create('org.jetbrains.kotlinx:kotlinx-coroutines-android') {
|
dependencies.create('org.jetbrains.kotlinx:kotlinx-coroutines-android') {
|
||||||
// https://android.googlesource.com/platform/prebuilts/tools/+/refs/tags/android-12.0.0_r2/common/m2/Android.bp#288
|
// https://android.googlesource.com/platform/external/kotlinx.coroutines/+/refs/tags/android-13.0.0_r3/CHANGES.md
|
||||||
version { strictly '1.3.0' }
|
version { strictly '1.5.2' }
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
|
|
||||||
ext.std_libs = [
|
ext.std_libs = [
|
||||||
androidx_core: [
|
androidx_core: [
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/androidx/Android.bp#867
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/androidx/Android.bp#1761
|
||||||
dependencies.create('androidx.core:core') {
|
dependencies.create('androidx.core:core') {
|
||||||
version { strictly '1.6.0' } // should be 1.6.0-beta03, but that is not even released, yet
|
version { strictly '1.9.0-alpha03' }
|
||||||
},
|
},
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/androidx/Android.bp#833
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/androidx/Android.bp#1727
|
||||||
dependencies.create('androidx.core:core-ktx') {
|
dependencies.create('androidx.core:core-ktx') {
|
||||||
version { strictly '1.5.0-beta02' }
|
version { strictly '1.9.0-alpha03' }
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/androidx/Android.bp#1189
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/androidx/Android.bp#2159
|
||||||
androidx_fragment: dependencies.create('androidx.fragment:fragment-ktx') {
|
androidx_fragment: dependencies.create('androidx.fragment:fragment-ktx') {
|
||||||
version { strictly '1.4.0-alpha01' }
|
version { strictly '1.4.0-alpha09' }
|
||||||
},
|
},
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/androidx/Android.bp#20
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/androidx/Android.bp#57
|
||||||
androidx_activity: dependencies.create('androidx.activity:activity-ktx') {
|
androidx_activity: dependencies.create('androidx.activity:activity-ktx') {
|
||||||
version { strictly '1.3.0-alpha03' }
|
version { strictly '1.4.0-alpha02' }
|
||||||
},
|
},
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/androidx/Android.bp#2695
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/androidx/Android.bp#3597
|
||||||
androidx_preference: dependencies.create('androidx.preference:preference') {
|
androidx_preference: dependencies.create('androidx.preference:preference') {
|
||||||
version { strictly '1.1.1' } // should be 1.2.0-alpha01, but that is not even released, yet
|
version { strictly '1.2.0-alpha01' }
|
||||||
},
|
},
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/androidx/Android.bp#1820
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/androidx/Android.bp#2754
|
||||||
androidx_lifecycle_viewmodel_ktx: dependencies.create('androidx.lifecycle:lifecycle-viewmodel-ktx') {
|
androidx_lifecycle_viewmodel_ktx: dependencies.create('androidx.lifecycle:lifecycle-viewmodel-ktx') {
|
||||||
version { strictly '2.4.0-alpha01' }
|
version { strictly '2.4.0-alpha03' } // 2.4.0-alpha04 in AOSP but was never released
|
||||||
},
|
},
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/androidx/Android.bp#1618
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/androidx/Android.bp#2550
|
||||||
androidx_lifecycle_livedata_ktx: dependencies.create('androidx.lifecycle:lifecycle-livedata-ktx') {
|
androidx_lifecycle_livedata_ktx: dependencies.create('androidx.lifecycle:lifecycle-livedata-ktx') {
|
||||||
version { strictly '2.4.0-alpha01' }
|
version { strictly '2.4.0-alpha03' } // 2.4.0-alpha04 in AOSP but was never released
|
||||||
},
|
},
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/extras/constraint-layout-x/Android.bp#39
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/extras/constraint-layout-x/Android.bp#39
|
||||||
androidx_constraintlayout: dependencies.create('androidx.constraintlayout:constraintlayout') {
|
androidx_constraintlayout: dependencies.create('androidx.constraintlayout:constraintlayout') {
|
||||||
version { strictly '2.0.0-beta7' }
|
version { strictly '2.0.0-beta7' }
|
||||||
},
|
},
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/androidx/Android.bp#969
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/androidx/Android.bp#1865
|
||||||
androidx_documentfile: dependencies.create('androidx.documentfile:documentfile') {
|
androidx_documentfile: dependencies.create('androidx.documentfile:documentfile') {
|
||||||
version { strictly '1.1.0-alpha01' }
|
version { strictly '1.1.0-alpha01' } // 1.1.0-alpha02 in AOSP but not released yet
|
||||||
},
|
},
|
||||||
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-12.0.0_r2/current/extras/material-design-x/Android.bp#6
|
// https://android.googlesource.com/platform/prebuilts/sdk/+/refs/tags/android-13.0.0_r3/current/extras/material-design-x/Android.bp#6
|
||||||
com_google_android_material: dependencies.create('com.google.android.material:material') {
|
com_google_android_material: dependencies.create('com.google.android.material:material') {
|
||||||
version { strictly '1.4.0' }
|
version { strictly '1.6.0-alpha03' } // 1.6.0-alpha0301 in AOSP
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
8
gradle/wrapper/gradle-wrapper.properties
vendored
8
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,7 +1,7 @@
|
||||||
#Tue Aug 04 14:40:48 BRT 2020
|
#Fri Aug 19 10:56:09 IST 2022
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
distributionSha256Sum=a8da5b02437a60819cad23e10fc7e9cf32bcb57029d9cb277e26eeff76ce014b
|
distributionSha256Sum=b586e04868a22fd817c8971330fec37e298f3242eb85c374181b12d637f80302
|
||||||
|
|
|
@ -27,11 +27,11 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||||
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
|
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
|
||||||
}
|
}
|
||||||
lintOptions {
|
lintOptions {
|
||||||
|
|
|
@ -22,6 +22,8 @@ android_library {
|
||||||
"androidx.room_room-runtime",
|
"androidx.room_room-runtime",
|
||||||
"androidx-constraintlayout_constraintlayout",
|
"androidx-constraintlayout_constraintlayout",
|
||||||
"com.google.android.material_material",
|
"com.google.android.material_material",
|
||||||
|
"kotlinx-coroutines-android",
|
||||||
|
"kotlinx-coroutines-core",
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
"androidx.room_room-compiler-plugin",
|
"androidx.room_room-compiler-plugin",
|
||||||
|
|
|
@ -28,12 +28,12 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||||
languageVersion = "1.4"
|
languageVersion = "1.6"
|
||||||
freeCompilerArgs += '-Xopt-in=kotlin.RequiresOptIn'
|
freeCompilerArgs += '-Xopt-in=kotlin.RequiresOptIn'
|
||||||
freeCompilerArgs += '-Xexplicit-api=strict'
|
freeCompilerArgs += '-Xexplicit-api=strict'
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,11 +111,12 @@ internal class Backup(
|
||||||
}
|
}
|
||||||
Log.e(TAG, "Changed files backup took $duration")
|
Log.e(TAG, "Changed files backup took $duration")
|
||||||
} finally {
|
} finally {
|
||||||
backupObserver?.onBackupComplete(duration?.toLongMilliseconds())
|
backupObserver?.onBackupComplete(duration?.inWholeMilliseconds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class, GeneralSecurityException::class)
|
@Throws(IOException::class, GeneralSecurityException::class)
|
||||||
|
@OptIn(ExperimentalTime::class)
|
||||||
private suspend fun backupFiles(
|
private suspend fun backupFiles(
|
||||||
filesResult: FileScannerResult,
|
filesResult: FileScannerResult,
|
||||||
availableChunkIds: HashSet<String>,
|
availableChunkIds: HashSet<String>,
|
||||||
|
|
|
@ -8,7 +8,7 @@ import org.calyxos.backup.storage.measure
|
||||||
import org.calyxos.backup.storage.plugin.SnapshotRetriever
|
import org.calyxos.backup.storage.plugin.SnapshotRetriever
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.security.GeneralSecurityException
|
import java.security.GeneralSecurityException
|
||||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
import kotlin.time.DurationUnit.MILLISECONDS
|
||||||
import kotlin.time.ExperimentalTime
|
import kotlin.time.ExperimentalTime
|
||||||
import kotlin.time.toDuration
|
import kotlin.time.toDuration
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.calyxos.backup.storage.plugin.saf.DocumentFileExt.listFilesBlocking
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
import kotlin.time.ExperimentalTime
|
||||||
|
|
||||||
private val folderRegex = Regex("^[a-f0-9]{16}\\.sv$")
|
private val folderRegex = Regex("^[a-f0-9]{16}\\.sv$")
|
||||||
private val chunkFolderRegex = Regex("[a-f0-9]{2}")
|
private val chunkFolderRegex = Regex("[a-f0-9]{2}")
|
||||||
|
@ -89,6 +90,7 @@ public abstract class SafStoragePlugin(
|
||||||
* Chunk folders will get cached in the given [chunkFolders] for faster access.
|
* Chunk folders will get cached in the given [chunkFolders] for faster access.
|
||||||
*/
|
*/
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
|
@OptIn(ExperimentalTime::class)
|
||||||
private suspend fun populateChunkFolders(
|
private suspend fun populateChunkFolders(
|
||||||
folder: DocumentFile,
|
folder: DocumentFile,
|
||||||
chunkFolders: HashMap<String, DocumentFile>,
|
chunkFolders: HashMap<String, DocumentFile>,
|
||||||
|
@ -126,6 +128,7 @@ public abstract class SafStoragePlugin(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
|
@OptIn(ExperimentalTime::class)
|
||||||
private fun createMissingChunkFolders(
|
private fun createMissingChunkFolders(
|
||||||
root: DocumentFile,
|
root: DocumentFile,
|
||||||
chunkFolders: HashMap<String, DocumentFile>,
|
chunkFolders: HashMap<String, DocumentFile>,
|
||||||
|
|
|
@ -47,7 +47,7 @@ internal class Pruner(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.i(TAG, "Pruning took $duration")
|
Log.i(TAG, "Pruning took $duration")
|
||||||
backupObserver?.onPruneComplete(duration.toLongMilliseconds())
|
backupObserver?.onPruneComplete(duration.inWholeMilliseconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class, GeneralSecurityException::class)
|
@Throws(IOException::class, GeneralSecurityException::class)
|
||||||
|
|
|
@ -52,6 +52,7 @@ internal class Restore(
|
||||||
MultiChunkRestore(context, storagePlugin, fileRestore, streamCrypto, streamKey)
|
MultiChunkRestore(context, storagePlugin, fileRestore, streamCrypto, streamKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalTime::class)
|
||||||
fun getBackupSnapshots(): Flow<SnapshotResult> = flow {
|
fun getBackupSnapshots(): Flow<SnapshotResult> = flow {
|
||||||
val numSnapshots: Int
|
val numSnapshots: Int
|
||||||
val time = measure {
|
val time = measure {
|
||||||
|
@ -138,7 +139,7 @@ internal class Restore(
|
||||||
Log.e(TAG, "Restoring ${split.multiChunkFiles.size} multi chunks took $multiChunkDuration.")
|
Log.e(TAG, "Restoring ${split.multiChunkFiles.size} multi chunks took $multiChunkDuration.")
|
||||||
|
|
||||||
val totalDuration = smallFilesDuration + singleChunkDuration + multiChunkDuration
|
val totalDuration = smallFilesDuration + singleChunkDuration + multiChunkDuration
|
||||||
observer?.onRestoreComplete(totalDuration.toLongMilliseconds())
|
observer?.onRestoreComplete(totalDuration.inWholeMilliseconds)
|
||||||
Log.e(TAG, "Restored $restoredFiles/$filesTotal files.")
|
Log.e(TAG, "Restored $restoredFiles/$filesTotal files.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.calyxos.backup.storage.content.DocFile
|
||||||
import org.calyxos.backup.storage.content.MediaFile
|
import org.calyxos.backup.storage.content.MediaFile
|
||||||
import org.calyxos.backup.storage.db.UriStore
|
import org.calyxos.backup.storage.db.UriStore
|
||||||
import org.calyxos.backup.storage.measure
|
import org.calyxos.backup.storage.measure
|
||||||
|
import kotlin.time.ExperimentalTime
|
||||||
|
|
||||||
internal class FileScannerResult(
|
internal class FileScannerResult(
|
||||||
val smallFiles: List<ContentFile>,
|
val smallFiles: List<ContentFile>,
|
||||||
|
@ -30,6 +31,7 @@ internal class FileScanner(
|
||||||
private const val FILES_LARGE = "large"
|
private const val FILES_LARGE = "large"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalTime::class)
|
||||||
fun getFiles(): FileScannerResult {
|
fun getFiles(): FileScannerResult {
|
||||||
// scan both APIs
|
// scan both APIs
|
||||||
val mediaFiles = ArrayList<ContentFile>()
|
val mediaFiles = ArrayList<ContentFile>()
|
||||||
|
|
Loading…
Reference in a new issue