From fb5a44ea0e9cac6ad654856336b6f08bac145452 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 16 Sep 2026 20:10:04 +0200 Subject: [PATCH] Migrate Greendao to Room --- build.gradle | 1 - buildsystem/dependencies.gradle | 6 +- data/build.gradle | 20 +- .../14.json | 211 +++++++ .../db/CryptomatorDatabaseMigrationTest.kt | 164 ++++++ .../data/db/CryptomatorDatabaseTest.kt | 103 ++++ .../cryptomator/data/db/LegacyDatabaseV1.kt | 61 ++ .../data/db/UpgradeDatabaseTest.kt | 543 +++++++++--------- .../data/db/CompoundDatabaseUpgrade.java | 21 - .../data/db/CryptomatorDatabase.java | 31 + .../org/cryptomator/data/db/Database.java | 53 -- .../cryptomator/data/db/DatabaseFactory.java | 57 -- .../cryptomator/data/db/DatabaseModule.java | 45 ++ .../cryptomator/data/db/DatabaseUpgrade.java | 36 +- .../cryptomator/data/db/DatabaseUpgrades.java | 64 +-- .../data/db/InitialDataCallback.java | 36 ++ .../java/org/cryptomator/data/db/Sql.java | 70 +-- .../org/cryptomator/data/db/Upgrade0To1.kt | 92 --- .../org/cryptomator/data/db/Upgrade10To11.kt | 10 +- .../org/cryptomator/data/db/Upgrade11To12.kt | 4 +- .../org/cryptomator/data/db/Upgrade12To13.kt | 16 +- .../org/cryptomator/data/db/Upgrade13To14.kt | 22 +- .../org/cryptomator/data/db/Upgrade1To2.kt | 8 +- .../org/cryptomator/data/db/Upgrade2To3.kt | 4 +- .../org/cryptomator/data/db/Upgrade3To4.kt | 8 +- .../org/cryptomator/data/db/Upgrade4To5.kt | 8 +- .../org/cryptomator/data/db/Upgrade5To6.kt | 8 +- .../org/cryptomator/data/db/Upgrade6To7.kt | 8 +- .../org/cryptomator/data/db/Upgrade7To8.kt | 8 +- .../org/cryptomator/data/db/Upgrade8To9.kt | 4 +- .../org/cryptomator/data/db/Upgrade9To10.kt | 4 +- .../org/cryptomator/data/db/dao/CloudDao.java | 42 ++ .../data/db/dao/UpdateCheckDao.java | 17 + .../org/cryptomator/data/db/dao/VaultDao.java | 51 ++ .../data/db/entities/CloudEntity.java | 88 ++- .../data/db/entities/DatabaseEntity.java | 10 - .../data/db/entities/UpdateCheckEntity.java | 60 +- .../data/db/entities/VaultEntity.java | 216 +++---- .../data/db/entities/VaultWithCloud.java | 33 ++ .../data/db/mappers/EntityMapper.java | 11 +- .../data/db/mappers/VaultEntityMapper.java | 58 +- .../data/repository/CloudRepositoryImpl.java | 18 +- .../repository/UpdateCheckRepositoryImpl.java | 14 +- .../data/repository/VaultRepositoryImpl.java | 17 +- .../di/component/ApplicationComponent.java | 3 +- 45 files changed, 1371 insertions(+), 993 deletions(-) create mode 100644 data/schemas/org.cryptomator.data.db.CryptomatorDatabase/14.json create mode 100644 data/src/androidTest/java/org/cryptomator/data/db/CryptomatorDatabaseMigrationTest.kt create mode 100644 data/src/androidTest/java/org/cryptomator/data/db/CryptomatorDatabaseTest.kt create mode 100644 data/src/androidTest/java/org/cryptomator/data/db/LegacyDatabaseV1.kt delete mode 100755 data/src/main/java/org/cryptomator/data/db/CompoundDatabaseUpgrade.java create mode 100644 data/src/main/java/org/cryptomator/data/db/CryptomatorDatabase.java delete mode 100644 data/src/main/java/org/cryptomator/data/db/Database.java delete mode 100644 data/src/main/java/org/cryptomator/data/db/DatabaseFactory.java create mode 100644 data/src/main/java/org/cryptomator/data/db/DatabaseModule.java create mode 100644 data/src/main/java/org/cryptomator/data/db/InitialDataCallback.java delete mode 100644 data/src/main/java/org/cryptomator/data/db/Upgrade0To1.kt create mode 100644 data/src/main/java/org/cryptomator/data/db/dao/CloudDao.java create mode 100644 data/src/main/java/org/cryptomator/data/db/dao/UpdateCheckDao.java create mode 100644 data/src/main/java/org/cryptomator/data/db/dao/VaultDao.java delete mode 100755 data/src/main/java/org/cryptomator/data/db/entities/DatabaseEntity.java create mode 100644 data/src/main/java/org/cryptomator/data/db/entities/VaultWithCloud.java diff --git a/build.gradle b/build.gradle index 3a1f67eef9..ea6ea50216 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,6 @@ buildscript { dependencies { // before upgrading AGP, check https://gitlab.com/fdroid/admin/-/issues/593 classpath 'com.android.tools.build:gradle:8.13.2' - classpath 'org.greenrobot:greendao-gradle-plugin:3.3.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "de.mannodermaus.gradle.plugins:android-junit5:1.7.1.1" } diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index f41ed12c8f..6a1b374c6a 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -81,8 +81,7 @@ ext { lruFileCacheVersion = '1.2' - // KEEP IN SYNC WITH GENERATOR VERSION IN root build.gradle - greenDaoVersion = '3.3.0' + roomVersion = '2.8.5' // cloud provider libs // todo updaten @@ -168,7 +167,6 @@ ext { googlePlayServicesAuth : "com.google.android.gms:play-services-auth:${googlePlayServicesVersion}", trackingFreeGoogleCLient : "com.github.cryptomator.google-http-java-client:google-http-client:${trackingFreeGoogleCLientVersion}", trackingFreeGoogleAndroidCLient: "com.github.cryptomator.google-http-java-client:google-http-client-android:${trackingFreeGoogleCLientVersion}", - greenDao : "org.greenrobot:greendao:${greenDaoVersion}", gson : "com.google.code.gson:gson:${gsonVersion}", hamcrest : "org.hamcrest:hamcrest-all:${hamcrestVersion}", javaxAnnotation : "javax.annotation:jsr250-api:${javaxAnnotationVersion}", @@ -190,6 +188,8 @@ ext { okHttpDigest : "io.github.rburgst:okhttp-digest:${okHttpDigestVersion}", pcloud : "com.github.cryptomator.pcloud-sdk-java:java-core:${pcloudVersion}", recyclerViewFastScroll : "com.simplecityapps:recyclerview-fastscroll:${recyclerViewFastScrollVersion}", + roomRuntime : "androidx.room:room-runtime:${roomVersion}", + roomCompiler : "androidx.room:room-compiler:${roomVersion}", rxJava : "io.reactivex.rxjava2:rxjava:${rxJavaVersion}", rxAndroid : "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}", rxBinding : "com.jakewharton.rxbinding2:rxbinding:${rxBindingVersion}", diff --git a/data/build.gradle b/data/build.gradle index 69ca59c8f4..a3da15e213 100644 --- a/data/build.gradle +++ b/data/build.gradle @@ -1,4 +1,3 @@ -apply plugin: 'org.greenrobot.greendao' apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'de.mannodermaus.android-junit5' @@ -17,6 +16,12 @@ android { buildConfigField "String", "VERSION_NAME", "\"${globalConfiguration["androidVersionName"]}\"" testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + + javaCompileOptions { + annotationProcessorOptions { + arguments += ["room.schemaLocation": "$projectDir/schemas".toString()] + } + } } compileOptions { @@ -71,6 +76,10 @@ android { } sourceSets { + androidTest { + assets.srcDirs += files("$projectDir/schemas".toString()) + } + playstore { java.srcDirs = ['src/main/java/', 'src/apiKey/java/', 'src/apkStorePlaystore/java/'] } @@ -109,10 +118,6 @@ android { namespace 'org.cryptomator.data' } -greendao { - schemaVersion 14 -} - configurations.all { // Check for updates every build (use for cryptolib snapshot) //resolutionStrategy.cacheChangingModulesFor 0, 'seconds' @@ -140,8 +145,9 @@ dependencies { // cryptomator implementation dependencies.cryptolib - // greendao - api dependencies.greenDao + // room + api dependencies.roomRuntime + annotationProcessor dependencies.roomCompiler // dagger annotationProcessor dependencies.daggerCompiler implementation dependencies.dagger diff --git a/data/schemas/org.cryptomator.data.db.CryptomatorDatabase/14.json b/data/schemas/org.cryptomator.data.db.CryptomatorDatabase/14.json new file mode 100644 index 0000000000..9fb8b6beb7 --- /dev/null +++ b/data/schemas/org.cryptomator.data.db.CryptomatorDatabase/14.json @@ -0,0 +1,211 @@ +{ + "formatVersion": 1, + "database": { + "version": 14, + "identityHash": "2ddff851b0943dea5f3c6586134086a8", + "entities": [ + { + "tableName": "CLOUD_ENTITY", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `TYPE` TEXT NOT NULL, `ACCESS_TOKEN` TEXT, `ACCESS_TOKEN_CRYPTO_MODE` TEXT, `URL` TEXT, `USERNAME` TEXT, `WEBDAV_CERTIFICATE` TEXT, `S3_BUCKET` TEXT, `S3_REGION` TEXT, `S3_SECRET_KEY` TEXT, `S3_SECRET_KEY_CRYPTO_MODE` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "type", + "columnName": "TYPE", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accessToken", + "columnName": "ACCESS_TOKEN", + "affinity": "TEXT" + }, + { + "fieldPath": "accessTokenCryptoMode", + "columnName": "ACCESS_TOKEN_CRYPTO_MODE", + "affinity": "TEXT" + }, + { + "fieldPath": "url", + "columnName": "URL", + "affinity": "TEXT" + }, + { + "fieldPath": "username", + "columnName": "USERNAME", + "affinity": "TEXT" + }, + { + "fieldPath": "webdavCertificate", + "columnName": "WEBDAV_CERTIFICATE", + "affinity": "TEXT" + }, + { + "fieldPath": "s3Bucket", + "columnName": "S3_BUCKET", + "affinity": "TEXT" + }, + { + "fieldPath": "s3Region", + "columnName": "S3_REGION", + "affinity": "TEXT" + }, + { + "fieldPath": "s3SecretKey", + "columnName": "S3_SECRET_KEY", + "affinity": "TEXT" + }, + { + "fieldPath": "s3SecretKeyCryptoMode", + "columnName": "S3_SECRET_KEY_CRYPTO_MODE", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "UPDATE_CHECK_ENTITY", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `RELEASE_NOTE` TEXT, `VERSION` TEXT, `URL_TO_APK` TEXT, `APK_SHA256` TEXT, `URL_TO_RELEASE_NOTE` TEXT)", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "releaseNote", + "columnName": "RELEASE_NOTE", + "affinity": "TEXT" + }, + { + "fieldPath": "version", + "columnName": "VERSION", + "affinity": "TEXT" + }, + { + "fieldPath": "urlToApk", + "columnName": "URL_TO_APK", + "affinity": "TEXT" + }, + { + "fieldPath": "apkSha256", + "columnName": "APK_SHA256", + "affinity": "TEXT" + }, + { + "fieldPath": "urlToReleaseNote", + "columnName": "URL_TO_RELEASE_NOTE", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + } + }, + { + "tableName": "VAULT_ENTITY", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT, `FOLDER_CLOUD_ID` INTEGER, `FOLDER_PATH` TEXT, `FOLDER_NAME` TEXT, `CLOUD_TYPE` TEXT NOT NULL, `PASSWORD` TEXT, `PASSWORD_CRYPTO_MODE` TEXT, `POSITION` INTEGER, `FORMAT` INTEGER, `SHORTENING_THRESHOLD` INTEGER, FOREIGN KEY(`FOLDER_CLOUD_ID`) REFERENCES `CLOUD_ENTITY`(`_id`) ON UPDATE NO ACTION ON DELETE SET NULL )", + "fields": [ + { + "fieldPath": "id", + "columnName": "_id", + "affinity": "INTEGER" + }, + { + "fieldPath": "folderCloudId", + "columnName": "FOLDER_CLOUD_ID", + "affinity": "INTEGER" + }, + { + "fieldPath": "folderPath", + "columnName": "FOLDER_PATH", + "affinity": "TEXT" + }, + { + "fieldPath": "folderName", + "columnName": "FOLDER_NAME", + "affinity": "TEXT" + }, + { + "fieldPath": "cloudType", + "columnName": "CLOUD_TYPE", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "PASSWORD", + "affinity": "TEXT" + }, + { + "fieldPath": "passwordCryptoMode", + "columnName": "PASSWORD_CRYPTO_MODE", + "affinity": "TEXT" + }, + { + "fieldPath": "position", + "columnName": "POSITION", + "affinity": "INTEGER" + }, + { + "fieldPath": "format", + "columnName": "FORMAT", + "affinity": "INTEGER" + }, + { + "fieldPath": "shorteningThreshold", + "columnName": "SHORTENING_THRESHOLD", + "affinity": "INTEGER" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "_id" + ] + }, + "indices": [ + { + "name": "IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID", + "unique": true, + "columnNames": [ + "FOLDER_PATH", + "FOLDER_CLOUD_ID" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID` ON `${TABLE_NAME}` (`FOLDER_PATH`, `FOLDER_CLOUD_ID`)" + } + ], + "foreignKeys": [ + { + "table": "CLOUD_ENTITY", + "onDelete": "SET NULL", + "onUpdate": "NO ACTION", + "columns": [ + "FOLDER_CLOUD_ID" + ], + "referencedColumns": [ + "_id" + ] + } + ] + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2ddff851b0943dea5f3c6586134086a8')" + ] + } +} \ No newline at end of file diff --git a/data/src/androidTest/java/org/cryptomator/data/db/CryptomatorDatabaseMigrationTest.kt b/data/src/androidTest/java/org/cryptomator/data/db/CryptomatorDatabaseMigrationTest.kt new file mode 100644 index 0000000000..9d1f79be1c --- /dev/null +++ b/data/src/androidTest/java/org/cryptomator/data/db/CryptomatorDatabaseMigrationTest.kt @@ -0,0 +1,164 @@ +package org.cryptomator.data.db + +import androidx.sqlite.db.SupportSQLiteDatabase +import androidx.sqlite.db.SupportSQLiteOpenHelper +import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import org.cryptomator.domain.CloudType +import org.cryptomator.util.SharedPreferencesHandler +import org.cryptomator.util.crypto.CredentialCryptor +import org.cryptomator.util.crypto.CryptoMode +import org.hamcrest.CoreMatchers +import org.junit.After +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Opens databases as greenDAO left them behind with Room, which is what happens on every device that + * updates to the first release built on Room. + */ +@RunWith(AndroidJUnit4::class) +@SmallTest +class CryptomatorDatabaseMigrationTest { + + private val context = InstrumentationRegistry.getInstrumentation().context + private lateinit var sharedPreferencesHandler: SharedPreferencesHandler + private lateinit var database: CryptomatorDatabase + + @Before + fun setup() { + context.deleteDatabase(CryptomatorDatabase.NAME) + sharedPreferencesHandler = SharedPreferencesHandler(context) + } + + @After + fun tearDown() { + if (this::database.isInitialized) { + database.close() + } + context.deleteDatabase(CryptomatorDatabase.NAME) + sharedPreferencesHandler.removeAllEntries() + } + + @Test + fun upgradesADatabaseFromTheOldestVersionStillInTheField() { + val accessToken = "accessToken" + + createGreenDaoDatabase(1) { db -> + LegacyDatabaseV1.createOn(db) + addWebDavVaultTo(db, accessToken = CredentialCryptor.getInstance(context, CryptoMode.CBC).encrypt(accessToken)) + } + + database = openWithRoom() + + assertWebDavVaultSurvived(accessToken) + } + + @Test + fun adoptsADatabaseLeftBehindAtTheLastGreenDaoVersion() { + val accessToken = "accessToken" + + createGreenDaoDatabase(CryptomatorDatabase.VERSION) { db -> + LegacyDatabaseV1.createOn(db) + addWebDavVaultTo(db, accessToken = CredentialCryptor.getInstance(context, CryptoMode.CBC).encrypt(accessToken)) + upgrades().forEach { it.migrate(db) } + } + + database = openWithRoom() + + assertWebDavVaultSurvived(accessToken) + } + + @Test + fun createsTheCloudsAndUpdateCheckRowAFreshInstallStartsOutWith() { + database = openWithRoom() + + val clouds = database.cloudDao().loadAll().sortedBy { it.id } + Assert.assertThat(clouds.map { it.id }, CoreMatchers.`is`(listOf(1L, 2L))) + Assert.assertThat(clouds.map { it.type }, CoreMatchers.`is`(listOf(CloudType.DROPBOX.name, CloudType.GOOGLE_DRIVE.name))) + + Assert.assertThat(database.vaultDao().loadAll().isEmpty(), CoreMatchers.`is`(true)) + Assert.assertThat(database.updateCheckDao().load(1L), CoreMatchers.notNullValue()) + } + + private fun assertWebDavVaultSurvived(accessToken: String) { + val vaults = database.vaultDao().loadAll() + Assert.assertThat(vaults.size, CoreMatchers.`is`(1)) + + val vault = vaults[0].vault + Assert.assertThat(vault.id, CoreMatchers.`is`(25L)) + Assert.assertThat(vault.folderPath, CoreMatchers.`is`("path")) + Assert.assertThat(vault.folderName, CoreMatchers.`is`("name")) + Assert.assertThat(vault.cloudType, CoreMatchers.`is`(CloudType.WEBDAV.name)) + Assert.assertThat(vault.password, CoreMatchers.`is`("password")) + + val cloud = vaults[0].folderCloud + Assert.assertThat(cloud.id, CoreMatchers.`is`(15L)) + Assert.assertThat(cloud.type, CoreMatchers.`is`(CloudType.WEBDAV.name)) + Assert.assertThat(cloud.username, CoreMatchers.`is`("username")) + Assert.assertThat(cloud.url, CoreMatchers.`is`("https://example.org/webdav")) + Assert.assertThat(cloud.accessTokenCryptoMode, CoreMatchers.`is`(CryptoMode.GCM.name)) + Assert.assertThat(CredentialCryptor.getInstance(context, CryptoMode.GCM).decrypt(cloud.accessToken), CoreMatchers.`is`(accessToken)) + + Assert.assertThat(database.updateCheckDao().load(1L), CoreMatchers.notNullValue()) + } + + private fun addWebDavVaultTo(db: SupportSQLiteDatabase, accessToken: String) { + Sql.insertInto("CLOUD_ENTITY") // + .integer("_id", 15) // + .text("TYPE", CloudType.WEBDAV.name) // + .text("USERNAME", "username") // + .text("ACCESS_TOKEN", accessToken) // + .text("WEBDAV_URL", "https://example.org/webdav") // + .executeOn(db) + + Sql.insertInto("VAULT_ENTITY") // + .integer("_id", 25) // + .integer("FOLDER_CLOUD_ID", 15) // + .text("FOLDER_PATH", "path") // + .text("FOLDER_NAME", "name") // + .text("CLOUD_TYPE", CloudType.WEBDAV.name) // + .text("PASSWORD", "password") // + .executeOn(db) + } + + private fun createGreenDaoDatabase(version: Int, create: (SupportSQLiteDatabase) -> Unit) { + val helper = FrameworkSQLiteOpenHelperFactory().create( + SupportSQLiteOpenHelper.Configuration.builder(context) // + .name(CryptomatorDatabase.NAME) // + .callback(object : SupportSQLiteOpenHelper.Callback(version) { + override fun onCreate(db: SupportSQLiteDatabase) = create(db) + override fun onUpgrade(db: SupportSQLiteDatabase, oldVersion: Int, newVersion: Int) = Unit + }) // + .build() + ) + helper.writableDatabase + helper.close() + } + + private fun openWithRoom(): CryptomatorDatabase { + return DatabaseModule().provideCryptomatorDatabase(context, databaseUpgrades()) + } + + private fun upgrades() = databaseUpgrades().all().toList() + + private fun databaseUpgrades() = DatabaseUpgrades( // + Upgrade1To2(), // + Upgrade2To3(context), // + Upgrade3To4(), // + Upgrade4To5(), // + Upgrade5To6(), // + Upgrade6To7(), // + Upgrade7To8(), // + Upgrade8To9(sharedPreferencesHandler), // + Upgrade9To10(sharedPreferencesHandler), // + Upgrade10To11(), // + Upgrade11To12(sharedPreferencesHandler), // + Upgrade12To13(context), // + Upgrade13To14(sharedPreferencesHandler) + ) +} diff --git a/data/src/androidTest/java/org/cryptomator/data/db/CryptomatorDatabaseTest.kt b/data/src/androidTest/java/org/cryptomator/data/db/CryptomatorDatabaseTest.kt new file mode 100644 index 0000000000..e619280b0c --- /dev/null +++ b/data/src/androidTest/java/org/cryptomator/data/db/CryptomatorDatabaseTest.kt @@ -0,0 +1,103 @@ +package org.cryptomator.data.db + +import android.database.sqlite.SQLiteConstraintException +import androidx.room.Room +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import org.cryptomator.data.db.entities.CloudEntity +import org.cryptomator.data.db.entities.VaultEntity +import org.cryptomator.data.db.entities.VaultWithCloud +import org.cryptomator.domain.CloudType +import org.hamcrest.CoreMatchers +import org.junit.After +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class CryptomatorDatabaseTest { + + private val context = InstrumentationRegistry.getInstrumentation().context + private lateinit var database: CryptomatorDatabase + + @Before + fun setup() { + database = Room.inMemoryDatabaseBuilder(context, CryptomatorDatabase::class.java) // + .allowMainThreadQueries() // + .build() + } + + @After + fun tearDown() { + database.close() + } + + @Test + fun storingACloudWithoutIdInsertsItAndStoringItAgainUpdatesIt() { + val stored = database.cloudDao().store(webDavCloud()) + Assert.assertThat(stored.id, CoreMatchers.notNullValue()) + Assert.assertThat(stored.url, CoreMatchers.`is`("https://example.org/webdav")) + + stored.url = "https://example.com/webdav" + val updated = database.cloudDao().store(stored) + + Assert.assertThat(updated.id, CoreMatchers.`is`(stored.id)) + Assert.assertThat(updated.url, CoreMatchers.`is`("https://example.com/webdav")) + Assert.assertThat(database.cloudDao().loadAll().size, CoreMatchers.`is`(1)) + } + + @Test + fun storingAVaultResolvesItsCloudOnLoad() { + val cloud = database.cloudDao().store(webDavCloud()) + + val stored = database.vaultDao().store(vaultIn(cloud)) + + Assert.assertThat(stored.vault.id, CoreMatchers.notNullValue()) + Assert.assertThat(stored.vault.folderName, CoreMatchers.`is`("name")) + Assert.assertThat(stored.folderCloud.id, CoreMatchers.`is`(cloud.id)) + Assert.assertThat(stored.folderCloud.type, CoreMatchers.`is`(CloudType.WEBDAV.name)) + + database.vaultDao().delete(stored) + + Assert.assertThat(database.vaultDao().loadAll().isEmpty(), CoreMatchers.`is`(true)) + } + + @Test(expected = SQLiteConstraintException::class) + fun storingTwoVaultsForTheSamePathInTheSameCloudIsRejected() { + val cloud = database.cloudDao().store(webDavCloud()) + + database.vaultDao().store(vaultIn(cloud)) + database.vaultDao().store(vaultIn(cloud)) + } + + @Test + fun deletingACloudDetachesItsVaults() { + val cloud = database.cloudDao().store(webDavCloud()) + database.vaultDao().store(vaultIn(cloud)) + + database.cloudDao().delete(cloud) + + val vault = database.vaultDao().loadAll().single() + Assert.assertThat(vault.vault.folderCloudId, CoreMatchers.nullValue()) + Assert.assertThat(vault.folderCloud, CoreMatchers.nullValue()) + } + + private fun webDavCloud() = CloudEntity().apply { + type = CloudType.WEBDAV.name + url = "https://example.org/webdav" + username = "username" + } + + private fun vaultIn(cloud: CloudEntity) = VaultWithCloud().apply { + vault = VaultEntity().apply { + folderCloudId = cloud.id + folderPath = "path" + folderName = "name" + cloudType = CloudType.WEBDAV.name + } + folderCloud = cloud + } +} diff --git a/data/src/androidTest/java/org/cryptomator/data/db/LegacyDatabaseV1.kt b/data/src/androidTest/java/org/cryptomator/data/db/LegacyDatabaseV1.kt new file mode 100644 index 0000000000..69e8be21e4 --- /dev/null +++ b/data/src/androidTest/java/org/cryptomator/data/db/LegacyDatabaseV1.kt @@ -0,0 +1,61 @@ +package org.cryptomator.data.db + +import androidx.sqlite.db.SupportSQLiteDatabase +import org.cryptomator.data.db.Sql.SqlCreateTableBuilder.ForeignKeyBehaviour +import org.cryptomator.domain.CloudType + +/** + * The schema greenDAO created for v1, which the app itself no longer creates: Room creates the current + * schema directly and only the upgrades from v1 onwards are still needed. Migration tests use this to + * build a database as old as the oldest one still in the field. + */ +internal object LegacyDatabaseV1 { + + fun createOn(db: SupportSQLiteDatabase) { + createCloudEntityTable(db) + createVaultEntityTable(db) + createCloud(db, 1, CloudType.DROPBOX) + createCloud(db, 2, CloudType.GOOGLE_DRIVE) + createCloud(db, 3, CloudType.ONEDRIVE) + createCloud(db, 4, CloudType.LOCAL) + } + + private fun createCloudEntityTable(db: SupportSQLiteDatabase) { + Sql.createTable("CLOUD_ENTITY") // + .id() // + .requiredText("TYPE") // + .optionalText("ACCESS_TOKEN") // + .optionalText("WEBDAV_URL") // + .optionalText("USERNAME") // + .optionalText("WEBDAV_CERTIFICATE") // + .executeOn(db) + } + + private fun createVaultEntityTable(db: SupportSQLiteDatabase) { + Sql.createTable("VAULT_ENTITY") // + .id() // + .optionalInt("FOLDER_CLOUD_ID") // + .optionalText("FOLDER_PATH") // + .optionalText("FOLDER_NAME") // + .requiredText("CLOUD_TYPE") // + .optionalText("PASSWORD") // + .foreignKey("FOLDER_CLOUD_ID", "CLOUD_ENTITY", ForeignKeyBehaviour.ON_DELETE_SET_NULL) // + .executeOn(db) + Sql.createUniqueIndex("IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID") // + .on("VAULT_ENTITY") // + .asc("FOLDER_PATH") // + .asc("FOLDER_CLOUD_ID") // + .executeOn(db) + } + + private fun createCloud(db: SupportSQLiteDatabase, id: Int, type: CloudType) { + Sql.insertInto("CLOUD_ENTITY") // + .integer("_id", id) // + .text("TYPE", type.name) // + .text("ACCESS_TOKEN", null) // + .text("WEBDAV_URL", null) // + .text("USERNAME", null) // + .text("WEBDAV_CERTIFICATE", null) // + .executeOn(db) + } +} diff --git a/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt b/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt index 6c57345f1a..2d42b4f910 100644 --- a/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt +++ b/data/src/androidTest/java/org/cryptomator/data/db/UpgradeDatabaseTest.kt @@ -1,23 +1,18 @@ package org.cryptomator.data.db import android.content.Context -import android.database.sqlite.SQLiteDatabase +import androidx.sqlite.db.SupportSQLiteDatabase +import androidx.sqlite.db.SupportSQLiteOpenHelper +import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import com.google.common.base.Optional -import org.cryptomator.data.BuildConfig -import org.cryptomator.data.db.entities.CloudEntityDao -import org.cryptomator.data.db.entities.UpdateCheckEntityDao -import org.cryptomator.data.db.entities.VaultEntityDao import org.cryptomator.domain.CloudType import org.cryptomator.util.FlavorConfig import org.cryptomator.util.SharedPreferencesHandler import org.cryptomator.util.crypto.CredentialCryptor import org.cryptomator.util.crypto.CryptoMode -import org.greenrobot.greendao.database.Database -import org.greenrobot.greendao.database.StandardDatabase -import org.greenrobot.greendao.internal.DaoConfig import org.hamcrest.CoreMatchers import org.junit.After import org.junit.Assert @@ -30,48 +25,68 @@ import org.junit.runner.RunWith class UpgradeDatabaseTest { private val context = InstrumentationRegistry.getInstrumentation().context - private lateinit var db: Database + private lateinit var openHelper: SupportSQLiteOpenHelper + private lateinit var db: SupportSQLiteDatabase private lateinit var sharedPreferencesHandler: SharedPreferencesHandler @Before fun setup() { - db = StandardDatabase(SQLiteDatabase.create(null)) + openHelper = inMemoryDatabase(context) + db = openHelper.writableDatabase sharedPreferencesHandler = SharedPreferencesHandler(context) } @After fun tearDown() { - db.close() + openHelper.close() sharedPreferencesHandler.removeAllEntries() } + private fun inMemoryDatabase(context: Context): SupportSQLiteOpenHelper { + return FrameworkSQLiteOpenHelperFactory().create( + SupportSQLiteOpenHelper.Configuration.builder(context) // + .callback(object : SupportSQLiteOpenHelper.Callback(1) { + override fun onCreate(db: SupportSQLiteDatabase) = Unit + override fun onUpgrade(db: SupportSQLiteDatabase, oldVersion: Int, newVersion: Int) = Unit + }) // + .build() + ) + } + @Test fun upgradeAll() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) - Upgrade12To13(context).applyTo(db, 12) - Upgrade13To14(sharedPreferencesHandler).applyTo(db, 13) - - CloudEntityDao(DaoConfig(db, CloudEntityDao::class.java)).loadAll() - VaultEntityDao(DaoConfig(db, VaultEntityDao::class.java)).loadAll() - UpdateCheckEntityDao(DaoConfig(db, UpdateCheckEntityDao::class.java)).loadAll() + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) + Upgrade11To12(sharedPreferencesHandler).migrate(db) + Upgrade12To13(context).migrate(db) + Upgrade13To14(sharedPreferencesHandler).migrate(db) + + // the clouds seeded for v1 that no later upgrade removes, and the single update check row + Sql.query("CLOUD_ENTITY").executeOn(db).use { + Assert.assertThat(it.count, CoreMatchers.`is`(2)) + } + Sql.query("VAULT_ENTITY").executeOn(db).use { + Assert.assertThat(it.count, CoreMatchers.`is`(0)) + } + Sql.query("UPDATE_CHECK_ENTITY").executeOn(db).use { + Assert.assertThat(it.count, CoreMatchers.`is`(1)) + } } @Test fun upgrade2To3() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) val url = "url" val username = "username" @@ -96,7 +111,7 @@ class UpgradeDatabaseTest { context.getSharedPreferences("com.microsoft.live", Context.MODE_PRIVATE).edit().putString("refresh_token", accessToken).commit() - Upgrade2To3(context).applyTo(db, 2) + Upgrade2To3(context).migrate(db) checkUpgrade2to3ResultForCloud("DROPBOX", accessToken, url, username, webdavCertificate) checkUpgrade2to3ResultForCloud("ONEDRIVE", accessToken, url, username, webdavCertificate) @@ -116,9 +131,9 @@ class UpgradeDatabaseTest { @Test fun upgrade3To4() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) val ids = arrayOf("10", "20", "31", "32", "51") @@ -133,7 +148,7 @@ class UpgradeDatabaseTest { .executeOn(db) } - Upgrade3To4().applyTo(db, 3) + Upgrade3To4().migrate(db) Sql.query("VAULT_ENTITY").where("CLOUD_TYPE", Sql.eq(CloudType.DROPBOX.name)).executeOn(db).use { Assert.assertThat(it.count, CoreMatchers.`is`(ids.size)) @@ -151,10 +166,10 @@ class UpgradeDatabaseTest { @Test fun upgrade4To5() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) val cloudId = 15 val cloudUrl = "url" @@ -187,7 +202,7 @@ class UpgradeDatabaseTest { .integer("POSITION", position) // .executeOn(db) - Upgrade4To5().applyTo(db, 4) + Upgrade4To5().migrate(db) Sql.query("CLOUD_ENTITY").where("TYPE", Sql.eq(CloudType.WEBDAV.name)).executeOn(db).use { it.moveToFirst() @@ -213,11 +228,11 @@ class UpgradeDatabaseTest { @Test fun upgrade5To6() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) val cloudId = 15 val cloudUrl = "url" @@ -250,7 +265,7 @@ class UpgradeDatabaseTest { .integer("POSITION", position) // .executeOn(db) - Upgrade5To6().applyTo(db, 5) + Upgrade5To6().migrate(db) Sql.query("CLOUD_ENTITY").where("TYPE", Sql.eq(CloudType.WEBDAV.name)).executeOn(db).use { it.moveToFirst() @@ -276,12 +291,12 @@ class UpgradeDatabaseTest { @Test fun upgrade6To7() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) val licenseToken = "licenseToken" val releaseNote = "releaseNote" @@ -297,7 +312,7 @@ class UpgradeDatabaseTest { .set("URL_TO_RELEASE_NOTE", Sql.toString(urlReleaseNote)) .executeOn(db) - Upgrade6To7().applyTo(db, 6) + Upgrade6To7().migrate(db) Sql.query("UPDATE_CHECK_ENTITY").executeOn(db).use { it.moveToFirst() @@ -312,12 +327,12 @@ class UpgradeDatabaseTest { @Test fun upgrade6To7DueToSQLiteExceptionThrown() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) val licenseToken = "licenseToken" @@ -356,13 +371,13 @@ class UpgradeDatabaseTest { @Test fun upgrade7To8() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) Sql.insertInto("CLOUD_ENTITY") // .integer("_id", 15) // @@ -390,7 +405,7 @@ class UpgradeDatabaseTest { Assert.assertThat(it.count, CoreMatchers.`is`(5)) } - Upgrade7To8().applyTo(db, 7) + Upgrade7To8().migrate(db) Sql.query("CLOUD_ENTITY").executeOn(db).use { Assert.assertThat(it.count, CoreMatchers.`is`(4)) @@ -403,33 +418,33 @@ class UpgradeDatabaseTest { @Test fun upgrade8To9() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) sharedPreferencesHandler.setBetaScreenDialogAlreadyShown(true) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) + Upgrade8To9(sharedPreferencesHandler).migrate(db) Assert.assertThat(sharedPreferencesHandler.isBetaModeAlreadyShown(), CoreMatchers.`is`(false)) } @Test fun upgrade9To10() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) Sql.insertInto("CLOUD_ENTITY") // .integer("_id", 15) // @@ -467,7 +482,7 @@ class UpgradeDatabaseTest { Assert.assertThat(it.count, CoreMatchers.`is`(5)) } - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) + Upgrade9To10(sharedPreferencesHandler).migrate(db) Sql.query("VAULT_ENTITY").executeOn(db).use { Assert.assertThat(it.count, CoreMatchers.`is`(1)) @@ -482,16 +497,16 @@ class UpgradeDatabaseTest { @Test fun upgrade10To11EmptyOnedriveCloudRemovesCloud() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) Sql.insertInto("VAULT_ENTITY") // .integer("_id", 25) // @@ -507,7 +522,7 @@ class UpgradeDatabaseTest { Assert.assertThat(it.count, CoreMatchers.`is`(3)) } - Upgrade10To11().applyTo(db, 10) + Upgrade10To11().migrate(db) Sql.query("VAULT_ENTITY").executeOn(db).use { Assert.assertThat(it.count, CoreMatchers.`is`(1)) @@ -532,16 +547,16 @@ class UpgradeDatabaseTest { @Test fun upgrade10To11UsedOnedriveCloudPreservesCloud() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) Sql.insertInto("VAULT_ENTITY") // .integer("_id", 25) // @@ -566,7 +581,7 @@ class UpgradeDatabaseTest { Assert.assertThat(it.count, CoreMatchers.`is`(3)) } - Upgrade10To11().applyTo(db, 10) + Upgrade10To11().migrate(db) Sql.query("VAULT_ENTITY").executeOn(db).use { Assert.assertThat(it.count, CoreMatchers.`is`(1)) @@ -591,81 +606,81 @@ class UpgradeDatabaseTest { @Test fun upgrade11To12IfOldDefaultSet() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) sharedPreferencesHandler.setUpdateIntervalInDays(Optional.of(7)) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) + Upgrade11To12(sharedPreferencesHandler).migrate(db) Assert.assertThat(sharedPreferencesHandler.updateIntervalInDays(), CoreMatchers.`is`(Optional.of(1))) } @Test fun upgrade11To12MonthlySet() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) sharedPreferencesHandler.setUpdateIntervalInDays(Optional.of(30)) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) + Upgrade11To12(sharedPreferencesHandler).migrate(db) Assert.assertThat(sharedPreferencesHandler.updateIntervalInDays(), CoreMatchers.`is`(Optional.of(1))) } @Test fun upgrade11To12MonthlyNever() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) sharedPreferencesHandler.setUpdateIntervalInDays(Optional.absent()) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) + Upgrade11To12(sharedPreferencesHandler).migrate(db) Assert.assertThat(sharedPreferencesHandler.updateIntervalInDays(), CoreMatchers.`is`(Optional.absent())) } @Test fun upgrade12To13BaseTests() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) + Upgrade11To12(sharedPreferencesHandler).migrate(db) val gcmCryptor = CredentialCryptor.getInstance(context, CryptoMode.GCM) val cbcCryptor = CredentialCryptor.getInstance(context, CryptoMode.CBC) @@ -710,7 +725,7 @@ class UpgradeDatabaseTest { .integer("SHORTENING_THRESHOLD", 4) .executeOn(db) - Upgrade12To13(context).applyTo(db, 12) + Upgrade12To13(context).migrate(db) Sql.query("CLOUD_ENTITY").where("_id", Sql.eq(15)).executeOn(db).use { it.moveToFirst() @@ -749,18 +764,18 @@ class UpgradeDatabaseTest { @Test fun upgrade12To13DropGoogleDriveUsernameInAccessToken() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) + Upgrade11To12(sharedPreferencesHandler).migrate(db) Sql.insertInto("CLOUD_ENTITY") // .integer("_id", 15) // @@ -769,7 +784,7 @@ class UpgradeDatabaseTest { .text("ACCESS_TOKEN", "username") // .executeOn(db) - Upgrade12To13(context).applyTo(db, 12) + Upgrade12To13(context).migrate(db) Sql.query("CLOUD_ENTITY").where("_id", Sql.eq(15)).executeOn(db).use { it.moveToFirst() @@ -779,18 +794,18 @@ class UpgradeDatabaseTest { @Test fun upgrade12To13MovingAccessTokenToUrlInLocalStorage() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) + Upgrade11To12(sharedPreferencesHandler).migrate(db) Sql.insertInto("CLOUD_ENTITY") // .integer("_id", 15) // @@ -798,7 +813,7 @@ class UpgradeDatabaseTest { .text("ACCESS_TOKEN", "testUrl3000") // .executeOn(db) - Upgrade12To13(context).applyTo(db, 12) + Upgrade12To13(context).migrate(db) Sql.query("CLOUD_ENTITY").where("_id", Sql.eq(15)).executeOn(db).use { it.moveToFirst() @@ -809,18 +824,18 @@ class UpgradeDatabaseTest { @Test fun upgrade12To13Dropbox() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) + Upgrade11To12(sharedPreferencesHandler).migrate(db) val gcmCryptor = CredentialCryptor.getInstance(context, CryptoMode.GCM) val cbcCryptor = CredentialCryptor.getInstance(context, CryptoMode.CBC) @@ -835,7 +850,7 @@ class UpgradeDatabaseTest { .text("ACCESS_TOKEN", accessTokenCiphertext) // .executeOn(db) - Upgrade12To13(context).applyTo(db, 12) + Upgrade12To13(context).migrate(db) Sql.query("CLOUD_ENTITY").where("_id", Sql.eq(15)).executeOn(db).use { it.moveToFirst() @@ -846,18 +861,18 @@ class UpgradeDatabaseTest { @Test fun upgrade12To13OneDrive() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) + Upgrade11To12(sharedPreferencesHandler).migrate(db) val gcmCryptor = CredentialCryptor.getInstance(context, CryptoMode.GCM) val cbcCryptor = CredentialCryptor.getInstance(context, CryptoMode.CBC) @@ -872,7 +887,7 @@ class UpgradeDatabaseTest { .text("ACCESS_TOKEN", accessTokenCiphertext) // .executeOn(db) - Upgrade12To13(context).applyTo(db, 12) + Upgrade12To13(context).migrate(db) Sql.query("CLOUD_ENTITY").where("_id", Sql.eq(15)).executeOn(db).use { it.moveToFirst() @@ -883,18 +898,18 @@ class UpgradeDatabaseTest { @Test fun upgrade12To13PCloud() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) + Upgrade11To12(sharedPreferencesHandler).migrate(db) val gcmCryptor = CredentialCryptor.getInstance(context, CryptoMode.GCM) val cbcCryptor = CredentialCryptor.getInstance(context, CryptoMode.CBC) @@ -910,7 +925,7 @@ class UpgradeDatabaseTest { .text("URL", "url") // .executeOn(db) - Upgrade12To13(context).applyTo(db, 12) + Upgrade12To13(context).migrate(db) Sql.query("CLOUD_ENTITY").where("_id", Sql.eq(15)).executeOn(db).use { it.moveToFirst() @@ -921,7 +936,7 @@ class UpgradeDatabaseTest { @Test fun upgrade12To13Webdav() { - Upgrade0To1().applyTo(db, 0) + LegacyDatabaseV1.createOn(db) val gcmCryptor = CredentialCryptor.getInstance(context, CryptoMode.GCM) val cbcCryptor = CredentialCryptor.getInstance(context, CryptoMode.CBC) @@ -936,18 +951,18 @@ class UpgradeDatabaseTest { .text("ACCESS_TOKEN", accessTokenCiphertext) // .executeOn(db) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) - Upgrade12To13(context).applyTo(db, 12) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) + Upgrade11To12(sharedPreferencesHandler).migrate(db) + Upgrade12To13(context).migrate(db) Sql.query("CLOUD_ENTITY").where("_id", Sql.eq(15)).executeOn(db).use { it.moveToFirst() @@ -958,19 +973,19 @@ class UpgradeDatabaseTest { @Test fun upgrade13To14ExistingLicense() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) - Upgrade12To13(context).applyTo(db, 12) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) + Upgrade11To12(sharedPreferencesHandler).migrate(db) + Upgrade12To13(context).migrate(db) val licenseToken = "licenseToken" val releaseNote = "releaseNote" @@ -988,7 +1003,7 @@ class UpgradeDatabaseTest { .set("URL_TO_RELEASE_NOTE", Sql.toString(urlReleaseNote)) .executeOn(db) - Upgrade13To14(sharedPreferencesHandler).applyTo(db, 13) + Upgrade13To14(sharedPreferencesHandler).migrate(db) Assert.assertThat(sharedPreferencesHandler.hasCompletedWelcomeFlow(), CoreMatchers.`is`(true)) if (!FlavorConfig.isPremiumFlavor) { @@ -1008,19 +1023,19 @@ class UpgradeDatabaseTest { @Test fun upgrade13To14NoLicense() { - Upgrade0To1().applyTo(db, 0) - Upgrade1To2().applyTo(db, 1) - Upgrade2To3(context).applyTo(db, 2) - Upgrade3To4().applyTo(db, 3) - Upgrade4To5().applyTo(db, 4) - Upgrade5To6().applyTo(db, 5) - Upgrade6To7().applyTo(db, 6) - Upgrade7To8().applyTo(db, 7) - Upgrade8To9(sharedPreferencesHandler).applyTo(db, 8) - Upgrade9To10(sharedPreferencesHandler).applyTo(db, 9) - Upgrade10To11().applyTo(db, 10) - Upgrade11To12(sharedPreferencesHandler).applyTo(db, 11) - Upgrade12To13(context).applyTo(db, 12) + LegacyDatabaseV1.createOn(db) + Upgrade1To2().migrate(db) + Upgrade2To3(context).migrate(db) + Upgrade3To4().migrate(db) + Upgrade4To5().migrate(db) + Upgrade5To6().migrate(db) + Upgrade6To7().migrate(db) + Upgrade7To8().migrate(db) + Upgrade8To9(sharedPreferencesHandler).migrate(db) + Upgrade9To10(sharedPreferencesHandler).migrate(db) + Upgrade10To11().migrate(db) + Upgrade11To12(sharedPreferencesHandler).migrate(db) + Upgrade12To13(context).migrate(db) val releaseNote = "releaseNote" val version = "version" @@ -1036,7 +1051,7 @@ class UpgradeDatabaseTest { .set("URL_TO_RELEASE_NOTE", Sql.toString(urlReleaseNote)) .executeOn(db) - Upgrade13To14(sharedPreferencesHandler).applyTo(db, 13) + Upgrade13To14(sharedPreferencesHandler).migrate(db) Assert.assertThat(sharedPreferencesHandler.hasCompletedWelcomeFlow(), CoreMatchers.`is`(true)) Assert.assertThat(sharedPreferencesHandler.licenseToken(), CoreMatchers.`is`("")) diff --git a/data/src/main/java/org/cryptomator/data/db/CompoundDatabaseUpgrade.java b/data/src/main/java/org/cryptomator/data/db/CompoundDatabaseUpgrade.java deleted file mode 100755 index a4ab1f2209..0000000000 --- a/data/src/main/java/org/cryptomator/data/db/CompoundDatabaseUpgrade.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.cryptomator.data.db; - -import java.util.List; - -class CompoundDatabaseUpgrade extends DatabaseUpgrade { - - private final List upgrades; - - public CompoundDatabaseUpgrade(List upgrades) { - super(upgrades.get(0).from(), upgrades.get(upgrades.size() - 1).to()); - this.upgrades = upgrades; - } - - @Override - protected void internalApplyTo(org.greenrobot.greendao.database.Database db, int origin) { - for (DatabaseUpgrade upgrade : upgrades) { - upgrade.applyTo(db, origin); - } - } - -} diff --git a/data/src/main/java/org/cryptomator/data/db/CryptomatorDatabase.java b/data/src/main/java/org/cryptomator/data/db/CryptomatorDatabase.java new file mode 100644 index 0000000000..08935c952e --- /dev/null +++ b/data/src/main/java/org/cryptomator/data/db/CryptomatorDatabase.java @@ -0,0 +1,31 @@ +package org.cryptomator.data.db; + +import androidx.room.Database; +import androidx.room.RoomDatabase; + +import org.cryptomator.data.db.dao.CloudDao; +import org.cryptomator.data.db.dao.UpdateCheckDao; +import org.cryptomator.data.db.dao.VaultDao; +import org.cryptomator.data.db.entities.CloudEntity; +import org.cryptomator.data.db.entities.UpdateCheckEntity; +import org.cryptomator.data.db.entities.VaultEntity; + +@Database(entities = {CloudEntity.class, UpdateCheckEntity.class, VaultEntity.class}, version = CryptomatorDatabase.VERSION) +public abstract class CryptomatorDatabase extends RoomDatabase { + + static final String NAME = "Cryptomator"; + + /** + * Deliberately the schema version greenDAO left behind. The tables it created for v14 already match the + * entities of this database, so Room adopts an existing v14 file as is instead of rewriting it. Databases + * from older app versions are brought up to v14 by the upgrades in {@link DatabaseUpgrades}, which are + * therefore the only migrations Room ever has to run. + */ + static final int VERSION = 14; + + public abstract CloudDao cloudDao(); + + public abstract UpdateCheckDao updateCheckDao(); + + public abstract VaultDao vaultDao(); +} diff --git a/data/src/main/java/org/cryptomator/data/db/Database.java b/data/src/main/java/org/cryptomator/data/db/Database.java deleted file mode 100644 index 7f24da91d5..0000000000 --- a/data/src/main/java/org/cryptomator/data/db/Database.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.cryptomator.data.db; - -import org.cryptomator.data.db.entities.DaoMaster; -import org.cryptomator.data.db.entities.DaoSession; -import org.cryptomator.data.db.entities.DatabaseEntity; - -import java.util.List; - -import javax.inject.Inject; -import javax.inject.Singleton; - -@Singleton -public class Database { - - private final DaoSession daoSession; - - @Inject - public Database(DatabaseFactory databaseFactory) { - DaoMaster daoMaster = new DaoMaster(databaseFactory.getWritableDatabase()); - daoSession = daoMaster.newSession(); - } - - public T load(Class type, long id) { - return daoSession.load(type, id); - } - - public void delete(T entity) { - daoSession.delete(entity); - } - - public List loadAll(Class type) { - return daoSession.loadAll(type); - } - - public T create(T entity) { - long id = daoSession.insert(entity); - return load((Class) entity.getClass(), id); - } - - public T store(T entity) { - Long id = entity.getId(); - if (id == null) { - id = daoSession.insert(entity); - } else { - daoSession.update(entity); - } - return load((Class) entity.getClass(), id); - } - - public void clearCache() { - daoSession.clear(); - } -} diff --git a/data/src/main/java/org/cryptomator/data/db/DatabaseFactory.java b/data/src/main/java/org/cryptomator/data/db/DatabaseFactory.java deleted file mode 100644 index 36cea49ae0..0000000000 --- a/data/src/main/java/org/cryptomator/data/db/DatabaseFactory.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.cryptomator.data.db; - -import android.content.Context; -import android.database.sqlite.SQLiteDatabase; - -import org.cryptomator.data.db.entities.DaoMaster; -import org.greenrobot.greendao.database.Database; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import timber.log.Timber; - -import static org.cryptomator.data.db.entities.DaoMaster.SCHEMA_VERSION; - -@Singleton -class DatabaseFactory extends DaoMaster.OpenHelper { - - private static final String DATABASE_NAME = "Cryptomator"; - - private final DatabaseUpgrades databaseUpgrades; - - @Inject - public DatabaseFactory(Context context, DatabaseUpgrades databaseUpgrades) { - super(context, DATABASE_NAME); - this.databaseUpgrades = databaseUpgrades; - } - - @Override - public void onConfigure(SQLiteDatabase db) { - super.onConfigure(db); - - Timber.tag("Database").i("Configure v%d", db.getVersion()); - - if (!db.isReadOnly()) { - db.setForeignKeyConstraintsEnabled(true); - } - } - - @Override - public void onCreate(Database db) { - Timber.tag("Database").i("Create v%s", SCHEMA_VERSION); - databaseUpgrades.getUpgrade(0, SCHEMA_VERSION).applyTo(db, 0); - } - - @Override - public void onUpgrade(Database db, int oldVersion, int newVersion) { - Timber.tag("Database").i("Upgrade v" + oldVersion + " to v" + newVersion); - databaseUpgrades.getUpgrade(oldVersion, newVersion).applyTo(db, oldVersion); - } - - @Override - public void onOpen(SQLiteDatabase db) { - super.onOpen(db); - Timber.tag("Database").i("Open v%s", db.getVersion()); - } -} diff --git a/data/src/main/java/org/cryptomator/data/db/DatabaseModule.java b/data/src/main/java/org/cryptomator/data/db/DatabaseModule.java new file mode 100644 index 0000000000..edc56be1ec --- /dev/null +++ b/data/src/main/java/org/cryptomator/data/db/DatabaseModule.java @@ -0,0 +1,45 @@ +package org.cryptomator.data.db; + +import android.content.Context; + +import androidx.room.Room; + +import org.cryptomator.data.db.dao.CloudDao; +import org.cryptomator.data.db.dao.UpdateCheckDao; +import org.cryptomator.data.db.dao.VaultDao; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +@Module +public class DatabaseModule { + + @Singleton + @Provides + public CryptomatorDatabase provideCryptomatorDatabase(Context context, DatabaseUpgrades databaseUpgrades) { + return Room.databaseBuilder(context, CryptomatorDatabase.class, CryptomatorDatabase.NAME) // + .addMigrations(databaseUpgrades.all()) // + .addCallback(new InitialDataCallback()) // + // the database holds a handful of rows and is read from the main thread in places such as + // PhotoContentJob#onStartJob, which greenDAO allowed and moving off it is its own change + .allowMainThreadQueries() // + .build(); + } + + @Provides + public CloudDao provideCloudDao(CryptomatorDatabase database) { + return database.cloudDao(); + } + + @Provides + public UpdateCheckDao provideUpdateCheckDao(CryptomatorDatabase database) { + return database.updateCheckDao(); + } + + @Provides + public VaultDao provideVaultDao(CryptomatorDatabase database) { + return database.vaultDao(); + } +} diff --git a/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrade.java b/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrade.java index da2fb34df6..8a8d57c38f 100644 --- a/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrade.java +++ b/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrade.java @@ -1,41 +1,23 @@ package org.cryptomator.data.db; -import org.greenrobot.greendao.database.Database; +import androidx.annotation.NonNull; +import androidx.room.migration.Migration; +import androidx.sqlite.db.SupportSQLiteDatabase; import timber.log.Timber; -abstract class DatabaseUpgrade implements Comparable { - - private final int from; - private final int to; +abstract class DatabaseUpgrade extends Migration { DatabaseUpgrade(int from, int to) { - this.from = from; - this.to = to; - } - - public int from() { - return from; - } - - public int to() { - return to; + super(from, to); } @Override - public int compareTo(DatabaseUpgrade other) { - int compareByFrom = from - other.from; - if (compareByFrom != 0) { - return compareByFrom; - } - return to - other.to; - } - - final void applyTo(Database db, int origin) { - Timber.tag("DatabaseUpgrade").i("Running %s (%d -> %d)", getClass().getSimpleName(), from, to); - internalApplyTo(db, origin); + public final void migrate(@NonNull SupportSQLiteDatabase db) { + Timber.tag("DatabaseUpgrade").i("Running %s (%d -> %d)", getClass().getSimpleName(), startVersion, endVersion); + internalMigrate(db); } - protected abstract void internalApplyTo(Database db, int origin); + protected abstract void internalMigrate(SupportSQLiteDatabase db); } diff --git a/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java b/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java index 57cef31acd..a34ab49e14 100644 --- a/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java +++ b/data/src/main/java/org/cryptomator/data/db/DatabaseUpgrades.java @@ -1,25 +1,17 @@ package org.cryptomator.data.db; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import androidx.room.migration.Migration; import javax.inject.Inject; import javax.inject.Singleton; -import static java.lang.String.format; - @Singleton class DatabaseUpgrades { - private final Map> availableUpgrades; + private final Migration[] upgrades; @Inject public DatabaseUpgrades( // - Upgrade0To1 upgrade0To1, // Upgrade1To2 upgrade1To2, // Upgrade2To3 upgrade2To3, // Upgrade3To4 upgrade3To4, // @@ -32,11 +24,9 @@ public DatabaseUpgrades( // Upgrade10To11 upgrade10To11, // Upgrade11To12 upgrade11To12, // Upgrade12To13 upgrade12To13, // - Upgrade13To14 upgrade13To14 + Upgrade13To14 upgrade13To14 // ) { - - availableUpgrades = defineUpgrades( // - upgrade0To1, // + upgrades = new Migration[] { // upgrade1To2, // upgrade2To3, // upgrade3To4, // @@ -49,50 +39,10 @@ public DatabaseUpgrades( // upgrade10To11, // upgrade11To12, // upgrade12To13, // - upgrade13To14); - } - - private Map> defineUpgrades(DatabaseUpgrade... upgrades) { - Map> result = new HashMap<>(); - for (DatabaseUpgrade upgrade : upgrades) { - if (!result.containsKey(upgrade.from())) { - result.put(upgrade.from(), new ArrayList<>()); - } - result.get(upgrade.from()).add(upgrade); - } - for (List list : result.values()) { - Collections.sort(list, Comparator.reverseOrder()); - } - return result; + upgrade13To14}; } - public DatabaseUpgrade getUpgrade(int oldVersion, int newVersion) { - List upgrades = new ArrayList<>(10); - if (!findUpgrades(upgrades, oldVersion, newVersion)) { - throw new IllegalStateException(format("No upgrade path from %d to %d", oldVersion, newVersion)); - } - return new CompoundDatabaseUpgrade(upgrades); - } - - private boolean findUpgrades(List upgrades, int oldVersion, int newVersion) { - if (oldVersion == newVersion) { - return true; - } - - List upgradesFromOldVersion = availableUpgrades.get(oldVersion); - if (upgradesFromOldVersion == null) { - return false; - } - for (DatabaseUpgrade upgrade : upgradesFromOldVersion) { - if (upgrade.to() > newVersion) { - continue; - } - upgrades.add(upgrade); - if (findUpgrades(upgrades, upgrade.to(), newVersion)) { - return true; - } - upgrades.remove(upgrades.size() - 1); - } - return false; + public Migration[] all() { + return upgrades.clone(); } } diff --git a/data/src/main/java/org/cryptomator/data/db/InitialDataCallback.java b/data/src/main/java/org/cryptomator/data/db/InitialDataCallback.java new file mode 100644 index 0000000000..c49289e1c6 --- /dev/null +++ b/data/src/main/java/org/cryptomator/data/db/InitialDataCallback.java @@ -0,0 +1,36 @@ +package org.cryptomator.data.db; + +import androidx.annotation.NonNull; +import androidx.room.RoomDatabase; +import androidx.sqlite.db.SupportSQLiteDatabase; + +import org.cryptomator.domain.CloudType; + +import timber.log.Timber; + +/** + * Seeds a freshly created database with the rows every installation starts out with. Under greenDAO these + * were inserted by the upgrade from v0 to v1 and partly deleted again by later upgrades, so this is the state + * an install that walked the whole upgrade chain ended up in. + */ +class InitialDataCallback extends RoomDatabase.Callback { + + @Override + public void onCreate(@NonNull SupportSQLiteDatabase db) { + Timber.tag("Database").i("Create v%d", CryptomatorDatabase.VERSION); + + createCloud(db, 1, CloudType.DROPBOX); + createCloud(db, 2, CloudType.GOOGLE_DRIVE); + + Sql.insertInto("UPDATE_CHECK_ENTITY") // + .integer("_id", 1) // + .executeOn(db); + } + + private void createCloud(SupportSQLiteDatabase db, int id, CloudType type) { + Sql.insertInto("CLOUD_ENTITY") // + .integer("_id", id) // + .text("TYPE", type.name()) // + .executeOn(db); + } +} diff --git a/data/src/main/java/org/cryptomator/data/db/Sql.java b/data/src/main/java/org/cryptomator/data/db/Sql.java index 1d961e1460..2772343aff 100644 --- a/data/src/main/java/org/cryptomator/data/db/Sql.java +++ b/data/src/main/java/org/cryptomator/data/db/Sql.java @@ -4,7 +4,8 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; -import org.greenrobot.greendao.database.Database; +import androidx.sqlite.db.SupportSQLiteDatabase; +import androidx.sqlite.db.SupportSQLiteQueryBuilder; import java.util.ArrayList; import java.util.List; @@ -89,10 +90,6 @@ public static ValueHolder toNull() { return (column, contentValues) -> contentValues.putNull(column); } - private static SQLiteDatabase unwrap(Database wrapped) { - return (SQLiteDatabase) wrapped.getRawDatabase(); - } - public interface ValueHolder { void put(String column, ContentValues contentValues); @@ -111,9 +108,6 @@ public static class SqlQueryBuilder { private final List whereArgs = new ArrayList<>(); private List columns = new ArrayList<>(); - private String groupBy; - private String having; - private String limit; public SqlQueryBuilder(String tableName) { this.tableName = tableName; @@ -132,24 +126,15 @@ public SqlQueryBuilder where(String column, Criterion criterion) { return this; } - public SqlQueryBuilder groupBy(String groupBy) { - this.groupBy = groupBy; - return this; - } - - public SqlQueryBuilder having(String having) { - this.having = having; - return this; - } - - public SqlQueryBuilder limit(String limit) { - this.limit = limit; - return this; - } - - public Cursor executeOn(Database wrapped) { - SQLiteDatabase db = unwrap(wrapped); - return db.query(tableName, columns.toArray(new String[columns.size()]), whereClause.toString(), whereArgs.toArray(new String[whereArgs.size()]), groupBy, having, limit); + public Cursor executeOn(SupportSQLiteDatabase db) { + SupportSQLiteQueryBuilder query = SupportSQLiteQueryBuilder.builder(tableName); + if (!columns.isEmpty()) { + query.columns(columns.toArray(new String[0])); + } + if (whereClause.length() > 0) { + query.selection(whereClause.toString(), whereArgs.toArray(new String[0])); + } + return db.query(query.create()); } } @@ -179,12 +164,11 @@ public SqlUpdateBuilder where(String column, Criterion criterion) { return this; } - public void executeOn(Database wrapped) { + public void executeOn(SupportSQLiteDatabase db) { if (contentValues.size() == 0) { throw new IllegalStateException("At least one value must be set"); } - SQLiteDatabase db = unwrap(wrapped); - db.update(tableName, contentValues, whereClause.toString(), whereArgs.toArray(new String[whereArgs.size()])); + db.update(tableName, SQLiteDatabase.CONFLICT_NONE, contentValues, whereClause.toString(), whereArgs.toArray(new String[0])); } } @@ -197,8 +181,7 @@ private SqlDropIndexBuilder(String index) { this.index = index; } - public void executeOn(Database wrapped) { - SQLiteDatabase db = unwrap(wrapped); + public void executeOn(SupportSQLiteDatabase db) { db.execSQL(format("DROP INDEX \"%s\"", index)); } @@ -227,8 +210,7 @@ public SqlUniqueIndexBuilder asc(String column) { return this; } - public void executeOn(Database wrapped) { - SQLiteDatabase db = unwrap(wrapped); + public void executeOn(SupportSQLiteDatabase db) { db.execSQL(format("CREATE UNIQUE INDEX \"%s\" ON \"%s\" (%s)", indexName, table, columns)); } } @@ -241,8 +223,7 @@ private SqlDropTableBuilder(String table) { this.table = table; } - public void executeOn(Database wrapped) { - SQLiteDatabase db = unwrap(wrapped); + public void executeOn(SupportSQLiteDatabase db) { db.execSQL(format("DROP TABLE \"%s\"", table)); } @@ -262,8 +243,7 @@ public SqlAlterTableBuilder renameTo(String newName) { return this; } - public void executeOn(Database wrapped) { - SQLiteDatabase db = unwrap(wrapped); + public void executeOn(SupportSQLiteDatabase db) { db.execSQL(format("ALTER TABLE \"%s\" RENAME TO \"%s\"", table, newName)); } } @@ -288,8 +268,7 @@ public SqlInsertSelectBuilder from(String sourceTableName) { return this; } - public void executeOn(Database wrapped) { - SQLiteDatabase db = unwrap(wrapped); + public void executeOn(SupportSQLiteDatabase db) { StringBuilder query = new StringBuilder().append("INSERT INTO \"").append(table).append("\" ("); appendColumns(query, columns, false); query.append(") SELECT "); @@ -400,8 +379,7 @@ public SqlCreateTableBuilder column(String name, ColumnType type, ColumnConstrai return this; } - public void executeOn(Database wrapped) { - SQLiteDatabase db = unwrap(wrapped); + public void executeOn(SupportSQLiteDatabase db) { db.execSQL(format("CREATE TABLE \"%s\" (%s%s)", table, columns, foreignKeys)); } @@ -496,9 +474,8 @@ public SqlInsertBuilder bool(String column, Boolean value) { return this; } - public Long executeOn(Database wrapped) { - SQLiteDatabase db = unwrap(wrapped); - return db.insertOrThrow(table, null, contentValues); + public Long executeOn(SupportSQLiteDatabase db) { + return db.insert(table, SQLiteDatabase.CONFLICT_NONE, contentValues); } } @@ -521,9 +498,8 @@ public SqlDeleteBuilder where(String column, Criterion criterion) { return this; } - public void executeOn(Database wrapped) { - SQLiteDatabase db = unwrap(wrapped); - db.delete(tableName, whereClause.toString(), whereArgs.toArray(new String[whereArgs.size()])); + public void executeOn(SupportSQLiteDatabase db) { + db.delete(tableName, whereClause.toString(), whereArgs.toArray(new String[0])); } } diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade0To1.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade0To1.kt deleted file mode 100644 index a8f7849fb7..0000000000 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade0To1.kt +++ /dev/null @@ -1,92 +0,0 @@ -package org.cryptomator.data.db - -import org.cryptomator.data.db.Sql.SqlCreateTableBuilder.ForeignKeyBehaviour -import org.cryptomator.domain.CloudType -import org.greenrobot.greendao.database.Database -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -internal class Upgrade0To1 @Inject constructor() : DatabaseUpgrade(0, 1) { - - override fun internalApplyTo(db: Database, origin: Int) { - createCloudEntityTable(db) - createVaultEntityTable(db) - createDropboxCloud(db) - createGoogleDriveCloud(db) - createLocalStorageCloud(db) - createOnedriveCloud(db) - } - - private fun createCloudEntityTable(db: Database) { - Sql.createTable("CLOUD_ENTITY") // - .id() // - .requiredText("TYPE") // - .optionalText("ACCESS_TOKEN") // - .optionalText("WEBDAV_URL") // - .optionalText("USERNAME") // - .optionalText("WEBDAV_CERTIFICATE") // - .executeOn(db) - } - - private fun createVaultEntityTable(db: Database) { - Sql.createTable("VAULT_ENTITY") // - .id() // - .optionalInt("FOLDER_CLOUD_ID") // - .optionalText("FOLDER_PATH") // - .optionalText("FOLDER_NAME") // - .requiredText("CLOUD_TYPE") // - .optionalText("PASSWORD") // - .foreignKey("FOLDER_CLOUD_ID", "CLOUD_ENTITY", ForeignKeyBehaviour.ON_DELETE_SET_NULL) // - .executeOn(db) - Sql.createUniqueIndex("IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID") // - .on("VAULT_ENTITY") // - .asc("FOLDER_PATH") // - .asc("FOLDER_CLOUD_ID") // - .executeOn(db) - } - - private fun createDropboxCloud(db: Database) { - Sql.insertInto("CLOUD_ENTITY") // - .integer("_id", 1) // - .text("TYPE", CloudType.DROPBOX.name) // - .text("ACCESS_TOKEN", null) // - .text("WEBDAV_URL", null) // - .text("USERNAME", null) // - .text("WEBDAV_CERTIFICATE", null) // - .executeOn(db) - } - - private fun createGoogleDriveCloud(db: Database) { - Sql.insertInto("CLOUD_ENTITY") // - .integer("_id", 2) // - .text("TYPE", CloudType.GOOGLE_DRIVE.name) // - .text("ACCESS_TOKEN", null) // - .text("WEBDAV_URL", null) // - .text("USERNAME", null) // - .text("WEBDAV_CERTIFICATE", null) // - .executeOn(db) - } - - private fun createOnedriveCloud(db: Database) { - Sql.insertInto("CLOUD_ENTITY") // - .integer("_id", 3) // - .text("TYPE", CloudType.ONEDRIVE.name) // - .text("ACCESS_TOKEN", null) // - .text("WEBDAV_URL", null) // - .text("USERNAME", null) // - .text("WEBDAV_CERTIFICATE", null) // - .executeOn(db) - } - - private fun createLocalStorageCloud(db: Database) { - Sql.insertInto("CLOUD_ENTITY") // - .integer("_id", 4) // - .text("TYPE", CloudType.LOCAL.name) // - .text("ACCESS_TOKEN", null) // - .text("WEBDAV_URL", null) // - .text("USERNAME", null) // - .text("WEBDAV_CERTIFICATE", null) // - .executeOn(db) - } -} diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade10To11.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade10To11.kt index 263f18fd33..22f4e79494 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade10To11.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade10To11.kt @@ -1,6 +1,6 @@ package org.cryptomator.data.db -import org.greenrobot.greendao.database.Database +import androidx.sqlite.db.SupportSQLiteDatabase import javax.inject.Inject import javax.inject.Singleton @@ -10,7 +10,7 @@ internal class Upgrade10To11 @Inject constructor() : DatabaseUpgrade(10, 11) { private val defaultVaultFormat = 8 private val onedriveCloudId = 3L - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { db.beginTransaction() try { addFormatAndShorteningToDbEntity(db) @@ -24,7 +24,7 @@ internal class Upgrade10To11 @Inject constructor() : DatabaseUpgrade(10, 11) { } } - private fun addFormatAndShorteningToDbEntity(db: Database) { + private fun addFormatAndShorteningToDbEntity(db: SupportSQLiteDatabase) { Sql.alterTable("VAULT_ENTITY").renameTo("VAULT_ENTITY_OLD").executeOn(db) Sql.createTable("VAULT_ENTITY") // .id() // @@ -58,14 +58,14 @@ internal class Upgrade10To11 @Inject constructor() : DatabaseUpgrade(10, 11) { } - private fun addDefaultFormatAndShorteningThresholdToVaults(db: Database) { + private fun addDefaultFormatAndShorteningThresholdToVaults(db: SupportSQLiteDatabase) { Sql.update("VAULT_ENTITY") .set("FORMAT", Sql.toInteger(defaultVaultFormat)) .set("SHORTENING_THRESHOLD", Sql.toInteger(defaultThreshold)) .executeOn(db) } - private fun deleteOnedriveCloudIfNotSetUp(db: Database) { + private fun deleteOnedriveCloudIfNotSetUp(db: SupportSQLiteDatabase) { Sql.deleteFrom("CLOUD_ENTITY") .where("_id", Sql.eq(onedriveCloudId)) .where("TYPE", Sql.eq("ONEDRIVE")) diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade11To12.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade11To12.kt index 2ec8464430..6266c55eb6 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade11To12.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade11To12.kt @@ -1,15 +1,15 @@ package org.cryptomator.data.db +import androidx.sqlite.db.SupportSQLiteDatabase import com.google.common.base.Optional import org.cryptomator.util.SharedPreferencesHandler -import org.greenrobot.greendao.database.Database import javax.inject.Inject import javax.inject.Singleton @Singleton internal class Upgrade11To12 @Inject constructor(private val sharedPreferencesHandler: SharedPreferencesHandler) : DatabaseUpgrade(11, 12) { - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { when (sharedPreferencesHandler.updateIntervalInDays()) { Optional.of(7), Optional.of(30) -> sharedPreferencesHandler.setUpdateIntervalInDays(Optional.of(1)) } diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade12To13.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade12To13.kt index a6b99a32f5..5515d684cc 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade12To13.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade12To13.kt @@ -1,16 +1,16 @@ package org.cryptomator.data.db import android.content.Context +import androidx.sqlite.db.SupportSQLiteDatabase import org.cryptomator.util.crypto.CredentialCryptor import org.cryptomator.util.crypto.CryptoMode -import org.greenrobot.greendao.database.Database import javax.inject.Inject import javax.inject.Singleton @Singleton internal class Upgrade12To13 @Inject constructor(private val context: Context) : DatabaseUpgrade(12, 13) { - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { db.beginTransaction() try { moveLocalStorageUrlToUrlProperty(db) @@ -24,7 +24,7 @@ internal class Upgrade12To13 @Inject constructor(private val context: Context) : } } - private fun moveLocalStorageUrlToUrlProperty(db: Database) { + private fun moveLocalStorageUrlToUrlProperty(db: SupportSQLiteDatabase) { Sql.query("CLOUD_ENTITY").where("TYPE", Sql.eq("LOCAL")).executeOn(db).use { while (it.moveToNext()) { Sql.update("CLOUD_ENTITY") // @@ -36,14 +36,14 @@ internal class Upgrade12To13 @Inject constructor(private val context: Context) : } } - private fun dropGoogleDriveUsernameInAccessToken(db: Database) { + private fun dropGoogleDriveUsernameInAccessToken(db: SupportSQLiteDatabase) { Sql.update("CLOUD_ENTITY") .set("ACCESS_TOKEN", Sql.toNull()) // .where("TYPE", Sql.eq("GOOGLE_DRIVE")) .executeOn(db) } - private fun addCryptoModeToDbEntities(db: Database) { + private fun addCryptoModeToDbEntities(db: SupportSQLiteDatabase) { Sql.alterTable("CLOUD_ENTITY").renameTo("CLOUD_ENTITY_OLD").executeOn(db) Sql.createTable("CLOUD_ENTITY") // @@ -72,7 +72,7 @@ internal class Upgrade12To13 @Inject constructor(private val context: Context) : Sql.dropTable("CLOUD_ENTITY_OLD").executeOn(db) } - private fun addPasswordCryptoModeToVaultDbEntity(db: Database) { + private fun addPasswordCryptoModeToVaultDbEntity(db: SupportSQLiteDatabase) { Sql.alterTable("VAULT_ENTITY").renameTo("VAULT_ENTITY_OLD").executeOn(db) Sql.createTable("VAULT_ENTITY") // .id() // @@ -106,14 +106,14 @@ internal class Upgrade12To13 @Inject constructor(private val context: Context) : Sql.dropTable("VAULT_ENTITY_OLD").executeOn(db) } - private fun applyVaultPasswordCryptoModeToDb(db: Database) { + private fun applyVaultPasswordCryptoModeToDb(db: SupportSQLiteDatabase) { Sql.update("VAULT_ENTITY") .set("PASSWORD_CRYPTO_MODE", Sql.toString(CryptoMode.CBC.name)) // .where("PASSWORD", Sql.isNotNull()) .executeOn(db) } - private fun upgradeCloudCryptoModeToGCM(db: Database) { + private fun upgradeCloudCryptoModeToGCM(db: SupportSQLiteDatabase) { val gcmCryptor = CredentialCryptor.getInstance(context, CryptoMode.GCM) val cbcCryptor = CredentialCryptor.getInstance(context, CryptoMode.CBC) diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade13To14.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade13To14.kt index 85a18951c3..d7f7b7a73b 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade13To14.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade13To14.kt @@ -1,8 +1,8 @@ package org.cryptomator.data.db +import androidx.sqlite.db.SupportSQLiteDatabase import org.cryptomator.util.FlavorConfig import org.cryptomator.util.SharedPreferencesHandler -import org.greenrobot.greendao.database.Database import javax.inject.Inject import javax.inject.Singleton import timber.log.Timber @@ -10,15 +10,13 @@ import timber.log.Timber @Singleton internal class Upgrade13To14 @Inject constructor(private val sharedPreferencesHandler: SharedPreferencesHandler) : DatabaseUpgrade(13, 14) { - override fun internalApplyTo(db: Database, origin: Int) { - if (origin > 0) { - // Any user going through a schema migration is an existing user — skip welcome - setWelcomeFlowCompleted() - if (!nonLicenseKeyVariant()) { - val licenseToken = getExistingLicenseToken(db) - if (licenseToken != null) { - sharedPreferencesHandler.setLicenseToken(licenseToken) - } + override fun internalMigrate(db: SupportSQLiteDatabase) { + // Only an existing database is ever migrated, so this is an existing user — skip welcome + setWelcomeFlowCompleted() + if (!nonLicenseKeyVariant()) { + val licenseToken = getExistingLicenseToken(db) + if (licenseToken != null) { + sharedPreferencesHandler.setLicenseToken(licenseToken) } } removeLicenseFromDb(db) @@ -28,7 +26,7 @@ internal class Upgrade13To14 @Inject constructor(private val sharedPreferencesHa return FlavorConfig.isPremiumFlavor } - private fun removeLicenseFromDb(db: Database) { + private fun removeLicenseFromDb(db: SupportSQLiteDatabase) { db.beginTransaction() try { Sql.alterTable("UPDATE_CHECK_ENTITY").renameTo("UPDATE_CHECK_ENTITY_OLD").executeOn(db) @@ -55,7 +53,7 @@ internal class Upgrade13To14 @Inject constructor(private val sharedPreferencesHa } } - private fun getExistingLicenseToken(db: Database): String? { + private fun getExistingLicenseToken(db: SupportSQLiteDatabase): String? { Sql.query("UPDATE_CHECK_ENTITY") .columns(listOf("LICENSE_TOKEN")) .executeOn(db).use { diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade1To2.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade1To2.kt index b4541bfef6..791a321a8c 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade1To2.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade1To2.kt @@ -1,18 +1,18 @@ package org.cryptomator.data.db -import org.greenrobot.greendao.database.Database +import androidx.sqlite.db.SupportSQLiteDatabase import javax.inject.Inject import javax.inject.Singleton @Singleton internal class Upgrade1To2 @Inject constructor() : DatabaseUpgrade(1, 2) { - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { createUpdateCheckTable(db) createInitialUpdateStatus(db) } - private fun createUpdateCheckTable(db: Database) { + private fun createUpdateCheckTable(db: SupportSQLiteDatabase) { db.beginTransaction() try { Sql.createTable("UPDATE_CHECK_ENTITY") // @@ -29,7 +29,7 @@ internal class Upgrade1To2 @Inject constructor() : DatabaseUpgrade(1, 2) { } } - private fun createInitialUpdateStatus(db: Database) { + private fun createInitialUpdateStatus(db: SupportSQLiteDatabase) { Sql.insertInto("UPDATE_CHECK_ENTITY") // .integer("_id", 1) // .text("LICENSE_TOKEN", null) // diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade2To3.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade2To3.kt index 680dbdda4f..36b77b9acf 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade2To3.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade2To3.kt @@ -2,16 +2,16 @@ package org.cryptomator.data.db import android.content.Context import android.content.SharedPreferences +import androidx.sqlite.db.SupportSQLiteDatabase import org.cryptomator.util.crypto.CredentialCryptor import org.cryptomator.util.crypto.CryptoMode -import org.greenrobot.greendao.database.Database import javax.inject.Inject import javax.inject.Singleton @Singleton internal class Upgrade2To3 @Inject constructor(private val context: Context) : DatabaseUpgrade(2, 3) { - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { db.beginTransaction() try { Sql.query("CLOUD_ENTITY") diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt index fd443ec8f8..41dfb094d4 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade3To4.kt @@ -1,14 +1,14 @@ package org.cryptomator.data.db +import androidx.sqlite.db.SupportSQLiteDatabase import org.cryptomator.data.db.Sql.SqlCreateTableBuilder.ForeignKeyBehaviour -import org.greenrobot.greendao.database.Database import javax.inject.Inject import javax.inject.Singleton @Singleton internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { db.beginTransaction() try { addPositionToVaultSchema(db) @@ -19,7 +19,7 @@ internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { } } - private fun addPositionToVaultSchema(db: Database) { + private fun addPositionToVaultSchema(db: SupportSQLiteDatabase) { Sql.alterTable("VAULT_ENTITY").renameTo("VAULT_ENTITY_OLD").executeOn(db) Sql.createTable("VAULT_ENTITY") // .id() // @@ -50,7 +50,7 @@ internal class Upgrade3To4 @Inject constructor() : DatabaseUpgrade(3, 4) { Sql.dropTable("VAULT_ENTITY_OLD").executeOn(db) } - private fun initVaultPositionUsingCurrentSortOrder(db: Database) { + private fun initVaultPositionUsingCurrentSortOrder(db: SupportSQLiteDatabase) { Sql.query("VAULT_ENTITY").executeOn(db).use { while (it.moveToNext()) { Sql.update("VAULT_ENTITY") diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade4To5.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade4To5.kt index 84baee3307..569bb40004 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade4To5.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade4To5.kt @@ -1,13 +1,13 @@ package org.cryptomator.data.db -import org.greenrobot.greendao.database.Database +import androidx.sqlite.db.SupportSQLiteDatabase import javax.inject.Inject import javax.inject.Singleton @Singleton internal class Upgrade4To5 @Inject constructor() : DatabaseUpgrade(4, 5) { - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { db.beginTransaction() try { changeWebdavUrlInCloudEntityToUrl(db) @@ -17,7 +17,7 @@ internal class Upgrade4To5 @Inject constructor() : DatabaseUpgrade(4, 5) { } } - private fun changeWebdavUrlInCloudEntityToUrl(db: Database) { + private fun changeWebdavUrlInCloudEntityToUrl(db: SupportSQLiteDatabase) { Sql.alterTable("CLOUD_ENTITY").renameTo("CLOUD_ENTITY_OLD").executeOn(db) Sql.createTable("CLOUD_ENTITY") // @@ -40,7 +40,7 @@ internal class Upgrade4To5 @Inject constructor() : DatabaseUpgrade(4, 5) { Sql.dropTable("CLOUD_ENTITY_OLD").executeOn(db) } - private fun recreateVaultEntity(db: Database) { + private fun recreateVaultEntity(db: SupportSQLiteDatabase) { Sql.alterTable("VAULT_ENTITY").renameTo("VAULT_ENTITY_OLD").executeOn(db) Sql.createTable("VAULT_ENTITY") // .id() // diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade5To6.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade5To6.kt index 75fb443a0d..47daddd09b 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade5To6.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade5To6.kt @@ -1,13 +1,13 @@ package org.cryptomator.data.db -import org.greenrobot.greendao.database.Database +import androidx.sqlite.db.SupportSQLiteDatabase import javax.inject.Inject import javax.inject.Singleton @Singleton internal class Upgrade5To6 @Inject constructor() : DatabaseUpgrade(5, 6) { - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { db.beginTransaction() try { changeCloudEntityToSupportS3(db) @@ -17,7 +17,7 @@ internal class Upgrade5To6 @Inject constructor() : DatabaseUpgrade(5, 6) { } } - private fun changeCloudEntityToSupportS3(db: Database) { + private fun changeCloudEntityToSupportS3(db: SupportSQLiteDatabase) { Sql.alterTable("CLOUD_ENTITY").renameTo("CLOUD_ENTITY_OLD").executeOn(db) Sql.createTable("CLOUD_ENTITY") // @@ -43,7 +43,7 @@ internal class Upgrade5To6 @Inject constructor() : DatabaseUpgrade(5, 6) { Sql.dropTable("CLOUD_ENTITY_OLD").executeOn(db) } - private fun recreateVaultEntity(db: Database) { + private fun recreateVaultEntity(db: SupportSQLiteDatabase) { Sql.alterTable("VAULT_ENTITY").renameTo("VAULT_ENTITY_OLD").executeOn(db) Sql.createTable("VAULT_ENTITY") // .id() // diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade6To7.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade6To7.kt index 8e625516b5..8be7bedbab 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade6To7.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade6To7.kt @@ -1,7 +1,7 @@ package org.cryptomator.data.db import android.database.sqlite.SQLiteException -import org.greenrobot.greendao.database.Database +import androidx.sqlite.db.SupportSQLiteDatabase import javax.inject.Inject import javax.inject.Singleton import timber.log.Timber @@ -9,7 +9,7 @@ import timber.log.Timber @Singleton internal class Upgrade6To7 @Inject constructor() : DatabaseUpgrade(6, 7) { - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { db.beginTransaction() try { changeUpdateEntityToSupportSha256Verification(db) @@ -19,7 +19,7 @@ internal class Upgrade6To7 @Inject constructor() : DatabaseUpgrade(6, 7) { } } - private fun changeUpdateEntityToSupportSha256Verification(db: Database) { + private fun changeUpdateEntityToSupportSha256Verification(db: SupportSQLiteDatabase) { Sql.alterTable("UPDATE_CHECK_ENTITY").renameTo("UPDATE_CHECK_ENTITY_OLD").executeOn(db) Sql.createTable("UPDATE_CHECK_ENTITY") // @@ -46,7 +46,7 @@ internal class Upgrade6To7 @Inject constructor() : DatabaseUpgrade(6, 7) { Sql.dropTable("UPDATE_CHECK_ENTITY_OLD").executeOn(db) } - fun tryToRecoverFromSQLiteException(db: Database) { + fun tryToRecoverFromSQLiteException(db: SupportSQLiteDatabase) { var licenseToken: String? = null try { diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade7To8.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade7To8.kt index 5f1a65cc1a..ff91f7ff80 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade7To8.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade7To8.kt @@ -1,13 +1,13 @@ package org.cryptomator.data.db -import org.greenrobot.greendao.database.Database +import androidx.sqlite.db.SupportSQLiteDatabase import javax.inject.Inject import javax.inject.Singleton @Singleton internal class Upgrade7To8 @Inject constructor() : DatabaseUpgrade(7, 8) { - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { db.beginTransaction() try { dropS3Vaults(db) @@ -18,13 +18,13 @@ internal class Upgrade7To8 @Inject constructor() : DatabaseUpgrade(7, 8) { } } - private fun dropS3Vaults(db: Database) { + private fun dropS3Vaults(db: SupportSQLiteDatabase) { Sql.deleteFrom("VAULT_ENTITY") // .where("CLOUD_TYPE", Sql.eq("S3")) .executeOn(db) } - private fun dropS3Clouds(db: Database) { + private fun dropS3Clouds(db: SupportSQLiteDatabase) { Sql.deleteFrom("CLOUD_ENTITY") // .where("TYPE", Sql.eq("S3")) .executeOn(db) diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade8To9.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade8To9.kt index a3fa283bcb..310d3c4cbf 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade8To9.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade8To9.kt @@ -1,14 +1,14 @@ package org.cryptomator.data.db +import androidx.sqlite.db.SupportSQLiteDatabase import org.cryptomator.util.SharedPreferencesHandler -import org.greenrobot.greendao.database.Database import javax.inject.Inject import javax.inject.Singleton @Singleton internal class Upgrade8To9 @Inject constructor(private val sharedPreferencesHandler: SharedPreferencesHandler) : DatabaseUpgrade(8, 9) { - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { // toggle beta screen dialog already shown to display it again in this beta sharedPreferencesHandler.setBetaScreenDialogAlreadyShown(false) } diff --git a/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt b/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt index 01cf79fa52..aac8d9eba5 100644 --- a/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt +++ b/data/src/main/java/org/cryptomator/data/db/Upgrade9To10.kt @@ -1,8 +1,8 @@ package org.cryptomator.data.db +import androidx.sqlite.db.SupportSQLiteDatabase import org.cryptomator.domain.CloudType import org.cryptomator.util.SharedPreferencesHandler -import org.greenrobot.greendao.database.Database import javax.inject.Inject import javax.inject.Singleton import timber.log.Timber @@ -12,7 +12,7 @@ internal class Upgrade9To10 @Inject constructor(private val sharedPreferencesHan private val defaultLocalStorageCloudId = 4L - override fun internalApplyTo(db: Database, origin: Int) { + override fun internalMigrate(db: SupportSQLiteDatabase) { db.beginTransaction() try { diff --git a/data/src/main/java/org/cryptomator/data/db/dao/CloudDao.java b/data/src/main/java/org/cryptomator/data/db/dao/CloudDao.java new file mode 100644 index 0000000000..60b0802a3c --- /dev/null +++ b/data/src/main/java/org/cryptomator/data/db/dao/CloudDao.java @@ -0,0 +1,42 @@ +package org.cryptomator.data.db.dao; + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.Query; +import androidx.room.Transaction; +import androidx.room.Update; + +import org.cryptomator.data.db.entities.CloudEntity; + +import java.util.List; + +@Dao +public interface CloudDao { + + @Query("SELECT * FROM CLOUD_ENTITY") + List loadAll(); + + @Query("SELECT * FROM CLOUD_ENTITY WHERE _id = :id") + CloudEntity load(Long id); + + @Insert + long insert(CloudEntity entity); + + @Update + void update(CloudEntity entity); + + @Delete + void delete(CloudEntity entity); + + @Transaction + default CloudEntity store(CloudEntity entity) { + Long id = entity.getId(); + if (id == null) { + id = insert(entity); + } else { + update(entity); + } + return load(id); + } +} diff --git a/data/src/main/java/org/cryptomator/data/db/dao/UpdateCheckDao.java b/data/src/main/java/org/cryptomator/data/db/dao/UpdateCheckDao.java new file mode 100644 index 0000000000..3faafb12f7 --- /dev/null +++ b/data/src/main/java/org/cryptomator/data/db/dao/UpdateCheckDao.java @@ -0,0 +1,17 @@ +package org.cryptomator.data.db.dao; + +import androidx.room.Dao; +import androidx.room.Query; +import androidx.room.Update; + +import org.cryptomator.data.db.entities.UpdateCheckEntity; + +@Dao +public interface UpdateCheckDao { + + @Query("SELECT * FROM UPDATE_CHECK_ENTITY WHERE _id = :id") + UpdateCheckEntity load(Long id); + + @Update + void update(UpdateCheckEntity entity); +} diff --git a/data/src/main/java/org/cryptomator/data/db/dao/VaultDao.java b/data/src/main/java/org/cryptomator/data/db/dao/VaultDao.java new file mode 100644 index 0000000000..104798faa6 --- /dev/null +++ b/data/src/main/java/org/cryptomator/data/db/dao/VaultDao.java @@ -0,0 +1,51 @@ +package org.cryptomator.data.db.dao; + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.Query; +import androidx.room.Transaction; +import androidx.room.Update; + +import org.cryptomator.data.db.entities.VaultEntity; +import org.cryptomator.data.db.entities.VaultWithCloud; + +import java.util.List; + +@Dao +public interface VaultDao { + + @Transaction + @Query("SELECT * FROM VAULT_ENTITY") + List loadAll(); + + @Transaction + @Query("SELECT * FROM VAULT_ENTITY WHERE _id = :id") + VaultWithCloud load(Long id); + + @Insert + long insert(VaultEntity entity); + + @Update + void update(VaultEntity entity); + + @Delete + void delete(VaultEntity entity); + + @Transaction + default VaultWithCloud store(VaultWithCloud entity) { + VaultEntity vault = entity.getVault(); + Long id = vault.getId(); + if (id == null) { + id = insert(vault); + } else { + update(vault); + } + return load(id); + } + + @Transaction + default void delete(VaultWithCloud entity) { + delete(entity.getVault()); + } +} diff --git a/data/src/main/java/org/cryptomator/data/db/entities/CloudEntity.java b/data/src/main/java/org/cryptomator/data/db/entities/CloudEntity.java index 385898bc98..0ee0569a37 100644 --- a/data/src/main/java/org/cryptomator/data/db/entities/CloudEntity.java +++ b/data/src/main/java/org/cryptomator/data/db/entities/CloudEntity.java @@ -1,79 +1,79 @@ package org.cryptomator.data.db.entities; -import org.greenrobot.greendao.annotation.Entity; -import org.greenrobot.greendao.annotation.Generated; -import org.greenrobot.greendao.annotation.Id; -import org.greenrobot.greendao.annotation.NotNull; +import androidx.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.PrimaryKey; -@Entity -public class CloudEntity extends DatabaseEntity { +@Entity(tableName = "CLOUD_ENTITY") +public class CloudEntity { - @Id + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "_id") private Long id; - @NotNull + @NonNull + @ColumnInfo(name = "TYPE") private String type; + @ColumnInfo(name = "ACCESS_TOKEN") private String accessToken; + @ColumnInfo(name = "ACCESS_TOKEN_CRYPTO_MODE") private String accessTokenCryptoMode; + @ColumnInfo(name = "URL") private String url; + @ColumnInfo(name = "USERNAME") private String username; + @ColumnInfo(name = "WEBDAV_CERTIFICATE") private String webdavCertificate; + @ColumnInfo(name = "S3_BUCKET") private String s3Bucket; + @ColumnInfo(name = "S3_REGION") private String s3Region; + @ColumnInfo(name = "S3_SECRET_KEY") private String s3SecretKey; + @ColumnInfo(name = "S3_SECRET_KEY_CRYPTO_MODE") private String s3SecretKeyCryptoMode; - @Generated(hash = 930663276) - public CloudEntity(Long id, @NotNull String type, String accessToken, String accessTokenCryptoMode, String url, String username, String webdavCertificate, String s3Bucket, - String s3Region, String s3SecretKey, String s3SecretKeyCryptoMode) { - this.id = id; - this.type = type; - this.accessToken = accessToken; - this.accessTokenCryptoMode = accessTokenCryptoMode; - this.url = url; - this.username = username; - this.webdavCertificate = webdavCertificate; - this.s3Bucket = s3Bucket; - this.s3Region = s3Region; - this.s3SecretKey = s3SecretKey; - this.s3SecretKeyCryptoMode = s3SecretKeyCryptoMode; + public Long getId() { + return id; } - @Generated(hash = 1354152224) - public CloudEntity() { + public void setId(Long id) { + this.id = id; } - public String getAccessToken() { - return this.accessToken; + @NonNull + public String getType() { + return type; } - public void setAccessToken(String accessToken) { - this.accessToken = accessToken; + public void setType(@NonNull String type) { + this.type = type; } - public String getType() { - return this.type; + public String getAccessToken() { + return accessToken; } - public void setType(String type) { - this.type = type; + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; } - public Long getId() { - return this.id; + public String getAccessTokenCryptoMode() { + return accessTokenCryptoMode; } - public void setId(Long id) { - this.id = id; + public void setAccessTokenCryptoMode(String accessTokenCryptoMode) { + this.accessTokenCryptoMode = accessTokenCryptoMode; } public String getUrl() { @@ -101,7 +101,7 @@ public void setWebdavCertificate(String webdavCertificate) { } public String getS3Bucket() { - return this.s3Bucket; + return s3Bucket; } public void setS3Bucket(String s3Bucket) { @@ -109,7 +109,7 @@ public void setS3Bucket(String s3Bucket) { } public String getS3Region() { - return this.s3Region; + return s3Region; } public void setS3Region(String s3Region) { @@ -117,23 +117,15 @@ public void setS3Region(String s3Region) { } public String getS3SecretKey() { - return this.s3SecretKey; + return s3SecretKey; } public void setS3SecretKey(String s3SecretKey) { this.s3SecretKey = s3SecretKey; } - public String getAccessTokenCryptoMode() { - return this.accessTokenCryptoMode; - } - - public void setAccessTokenCryptoMode(String accessTokenCryptoMode) { - this.accessTokenCryptoMode = accessTokenCryptoMode; - } - public String getS3SecretKeyCryptoMode() { - return this.s3SecretKeyCryptoMode; + return s3SecretKeyCryptoMode; } public void setS3SecretKeyCryptoMode(String s3SecretKeyCryptoMode) { diff --git a/data/src/main/java/org/cryptomator/data/db/entities/DatabaseEntity.java b/data/src/main/java/org/cryptomator/data/db/entities/DatabaseEntity.java deleted file mode 100755 index c40978e34a..0000000000 --- a/data/src/main/java/org/cryptomator/data/db/entities/DatabaseEntity.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.cryptomator.data.db.entities; - -public abstract class DatabaseEntity { - - DatabaseEntity() { - } - - public abstract Long getId(); - -} diff --git a/data/src/main/java/org/cryptomator/data/db/entities/UpdateCheckEntity.java b/data/src/main/java/org/cryptomator/data/db/entities/UpdateCheckEntity.java index 2d82b8c9e0..7202526c70 100644 --- a/data/src/main/java/org/cryptomator/data/db/entities/UpdateCheckEntity.java +++ b/data/src/main/java/org/cryptomator/data/db/entities/UpdateCheckEntity.java @@ -1,49 +1,49 @@ package org.cryptomator.data.db.entities; -import org.greenrobot.greendao.annotation.Entity; -import org.greenrobot.greendao.annotation.Generated; -import org.greenrobot.greendao.annotation.Id; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.PrimaryKey; -@Entity -public class UpdateCheckEntity extends DatabaseEntity { +@Entity(tableName = "UPDATE_CHECK_ENTITY") +public class UpdateCheckEntity { - @Id + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "_id") private Long id; + @ColumnInfo(name = "RELEASE_NOTE") private String releaseNote; + @ColumnInfo(name = "VERSION") private String version; + @ColumnInfo(name = "URL_TO_APK") private String urlToApk; + @ColumnInfo(name = "APK_SHA256") private String apkSha256; + @ColumnInfo(name = "URL_TO_RELEASE_NOTE") private String urlToReleaseNote; - public UpdateCheckEntity() { + public Long getId() { + return id; } - @Generated(hash = 867488251) - public UpdateCheckEntity(Long id, String releaseNote, String version, String urlToApk, String apkSha256, String urlToReleaseNote) { + public void setId(Long id) { this.id = id; - this.releaseNote = releaseNote; - this.version = version; - this.urlToApk = urlToApk; - this.apkSha256 = apkSha256; - this.urlToReleaseNote = urlToReleaseNote; } - @Override - public Long getId() { - return id; + public String getReleaseNote() { + return releaseNote; } - public void setId(Long id) { - this.id = id; + public void setReleaseNote(String releaseNote) { + this.releaseNote = releaseNote; } public String getVersion() { - return this.version; + return version; } public void setVersion(String version) { @@ -51,34 +51,26 @@ public void setVersion(String version) { } public String getUrlToApk() { - return this.urlToApk; + return urlToApk; } public void setUrlToApk(String urlToApk) { this.urlToApk = urlToApk; } - public String getReleaseNote() { - return this.releaseNote; + public String getApkSha256() { + return apkSha256; } - public void setReleaseNote(String releaseNote) { - this.releaseNote = releaseNote; + public void setApkSha256(String apkSha256) { + this.apkSha256 = apkSha256; } public String getUrlToReleaseNote() { - return this.urlToReleaseNote; + return urlToReleaseNote; } public void setUrlToReleaseNote(String urlToReleaseNote) { this.urlToReleaseNote = urlToReleaseNote; } - - public String getApkSha256() { - return this.apkSha256; - } - - public void setApkSha256(String apkSha256) { - this.apkSha256 = apkSha256; - } } diff --git a/data/src/main/java/org/cryptomator/data/db/entities/VaultEntity.java b/data/src/main/java/org/cryptomator/data/db/entities/VaultEntity.java index e23220c600..9be35a5d93 100644 --- a/data/src/main/java/org/cryptomator/data/db/entities/VaultEntity.java +++ b/data/src/main/java/org/cryptomator/data/db/entities/VaultEntity.java @@ -1,145 +1,80 @@ package org.cryptomator.data.db.entities; -import org.greenrobot.greendao.DaoException; -import org.greenrobot.greendao.annotation.Entity; -import org.greenrobot.greendao.annotation.Generated; -import org.greenrobot.greendao.annotation.Id; -import org.greenrobot.greendao.annotation.Index; -import org.greenrobot.greendao.annotation.NotNull; -import org.greenrobot.greendao.annotation.ToOne; - -@Entity(indexes = {@Index(value = "folderPath,folderCloudId", unique = true)}) -public class VaultEntity extends DatabaseEntity { - - @Id +import androidx.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.ForeignKey; +import androidx.room.Index; +import androidx.room.PrimaryKey; +import androidx.room.RoomWarnings; + +/** + * The index on {@code FOLDER_CLOUD_ID} that Room asks for would only speed up cascading deletes of a + * handful of rows, so the index inherited from the greenDAO schema is kept as the only one. + */ +@SuppressWarnings(RoomWarnings.MISSING_INDEX_ON_FOREIGN_KEY_CHILD) +@Entity(tableName = "VAULT_ENTITY", // + foreignKeys = @ForeignKey( // + entity = CloudEntity.class, // + parentColumns = "_id", // + childColumns = "FOLDER_CLOUD_ID", // + onDelete = ForeignKey.SET_NULL), // + indices = @Index( // + name = "IDX_VAULT_ENTITY_FOLDER_PATH_FOLDER_CLOUD_ID", // + value = {"FOLDER_PATH", "FOLDER_CLOUD_ID"}, // + unique = true)) +public class VaultEntity { + + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = "_id") private Long id; + @ColumnInfo(name = "FOLDER_CLOUD_ID") private Long folderCloudId; - @ToOne(joinProperty = "folderCloudId") - private CloudEntity folderCloud; - + @ColumnInfo(name = "FOLDER_PATH") private String folderPath; + @ColumnInfo(name = "FOLDER_NAME") private String folderName; - @NotNull + @NonNull + @ColumnInfo(name = "CLOUD_TYPE") private String cloudType; + @ColumnInfo(name = "PASSWORD") private String password; + @ColumnInfo(name = "PASSWORD_CRYPTO_MODE") private String passwordCryptoMode; + @ColumnInfo(name = "POSITION") private Integer position; + @ColumnInfo(name = "FORMAT") private Integer format; + @ColumnInfo(name = "SHORTENING_THRESHOLD") private Integer shorteningThreshold; - /** - * Used for active entity operations. - */ - @Generated(hash = 941685503) - private transient VaultEntityDao myDao; - /** - * Used to resolve relations - */ - @Generated(hash = 2040040024) - private transient DaoSession daoSession; - - @Generated(hash = 229273163) - private transient Long folderCloud__resolvedKey; - - @Generated(hash = 1663458645) - public VaultEntity(Long id, Long folderCloudId, String folderPath, String folderName, @NotNull String cloudType, String password, String passwordCryptoMode, Integer position, Integer format, - Integer shorteningThreshold) { + public Long getId() { + return id; + } + + public void setId(Long id) { this.id = id; - this.folderCloudId = folderCloudId; - this.folderPath = folderPath; - this.folderName = folderName; - this.cloudType = cloudType; - this.password = password; - this.passwordCryptoMode = passwordCryptoMode; - this.position = position; - this.format = format; - this.shorteningThreshold = shorteningThreshold; } - @Generated(hash = 691253864) - public VaultEntity() { - } - - /** - * Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}. - * Entity must attached to an entity context. - */ - @Generated(hash = 1942392019) - public void refresh() { - if (myDao == null) { - throw new DaoException("Entity is detached from DAO context"); - } - myDao.refresh(this); - } - - /** - * Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}. - * Entity must attached to an entity context. - */ - @Generated(hash = 713229351) - public void update() { - if (myDao == null) { - throw new DaoException("Entity is detached from DAO context"); - } - myDao.update(this); - } - - /** - * Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}. - * Entity must attached to an entity context. - */ - @Generated(hash = 128553479) - public void delete() { - if (myDao == null) { - throw new DaoException("Entity is detached from DAO context"); - } - myDao.delete(this); - } - - /** - * To-one relationship, resolved on first access. - */ - @Generated(hash = 1508817413) - public CloudEntity getFolderCloud() { - Long __key = this.folderCloudId; - if (folderCloud__resolvedKey == null || !folderCloud__resolvedKey.equals(__key)) { - final DaoSession daoSession = this.daoSession; - if (daoSession == null) { - throw new DaoException("Entity is detached from DAO context"); - } - CloudEntityDao targetDao = daoSession.getCloudEntityDao(); - CloudEntity folderCloudNew = targetDao.load(__key); - synchronized (this) { - folderCloud = folderCloudNew; - folderCloud__resolvedKey = __key; - } - } - return folderCloud; - } - - /** - * called by internal mechanisms, do not call yourself. - */ - @Generated(hash = 1482096330) - public void setFolderCloud(CloudEntity folderCloud) { - synchronized (this) { - this.folderCloud = folderCloud; - folderCloudId = folderCloud == null ? null : folderCloud.getId(); - folderCloud__resolvedKey = folderCloudId; - } + public Long getFolderCloudId() { + return folderCloudId; + } + + public void setFolderCloudId(Long folderCloudId) { + this.folderCloudId = folderCloudId; } public String getFolderPath() { - return this.folderPath; + return folderPath; } public void setFolderPath(String folderPath) { @@ -154,40 +89,33 @@ public void setFolderName(String folderName) { this.folderName = folderName; } - public Long getId() { - return this.id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getFolderCloudId() { - return this.folderCloudId; - } - - public void setFolderCloudId(Long folderCloudId) { - this.folderCloudId = folderCloudId; - } - + @NonNull public String getCloudType() { - return this.cloudType; + return cloudType; } - public void setCloudType(String cloudType) { + public void setCloudType(@NonNull String cloudType) { this.cloudType = cloudType; } public String getPassword() { - return this.password; + return password; } public void setPassword(String password) { this.password = password; } + public String getPasswordCryptoMode() { + return passwordCryptoMode; + } + + public void setPasswordCryptoMode(String passwordCryptoMode) { + this.passwordCryptoMode = passwordCryptoMode; + } + public Integer getPosition() { - return this.position; + return position; } public void setPosition(Integer position) { @@ -195,7 +123,7 @@ public void setPosition(Integer position) { } public Integer getFormat() { - return this.format; + return format; } public void setFormat(Integer format) { @@ -203,26 +131,10 @@ public void setFormat(Integer format) { } public Integer getShorteningThreshold() { - return this.shorteningThreshold; + return shorteningThreshold; } public void setShorteningThreshold(Integer shorteningThreshold) { this.shorteningThreshold = shorteningThreshold; } - - public String getPasswordCryptoMode() { - return this.passwordCryptoMode; - } - - public void setPasswordCryptoMode(String passwordCryptoMode) { - this.passwordCryptoMode = passwordCryptoMode; - } - - /** called by internal mechanisms, do not call yourself. */ - @Generated(hash = 674742652) - public void __setDaoSession(DaoSession daoSession) { - this.daoSession = daoSession; - myDao = daoSession != null ? daoSession.getVaultEntityDao() : null; - } - } diff --git a/data/src/main/java/org/cryptomator/data/db/entities/VaultWithCloud.java b/data/src/main/java/org/cryptomator/data/db/entities/VaultWithCloud.java new file mode 100644 index 0000000000..9f9e1f5b2e --- /dev/null +++ b/data/src/main/java/org/cryptomator/data/db/entities/VaultWithCloud.java @@ -0,0 +1,33 @@ +package org.cryptomator.data.db.entities; + +import androidx.room.Embedded; +import androidx.room.Relation; + +/** + * A vault together with the cloud it is stored in, which greenDAO used to resolve lazily through the + * {@code FOLDER_CLOUD_ID} to-one relation. + */ +public class VaultWithCloud { + + @Embedded + private VaultEntity vault; + + @Relation(parentColumn = "FOLDER_CLOUD_ID", entityColumn = "_id") + private CloudEntity folderCloud; + + public VaultEntity getVault() { + return vault; + } + + public void setVault(VaultEntity vault) { + this.vault = vault; + } + + public CloudEntity getFolderCloud() { + return folderCloud; + } + + public void setFolderCloud(CloudEntity folderCloud) { + this.folderCloud = folderCloud; + } +} diff --git a/data/src/main/java/org/cryptomator/data/db/mappers/EntityMapper.java b/data/src/main/java/org/cryptomator/data/db/mappers/EntityMapper.java index 63135bcc17..37d200a1c5 100644 --- a/data/src/main/java/org/cryptomator/data/db/mappers/EntityMapper.java +++ b/data/src/main/java/org/cryptomator/data/db/mappers/EntityMapper.java @@ -1,12 +1,11 @@ package org.cryptomator.data.db.mappers; -import org.cryptomator.data.db.entities.DatabaseEntity; import org.cryptomator.domain.exception.BackendException; import java.util.ArrayList; import java.util.List; -public abstract class EntityMapper { +public abstract class EntityMapper { EntityMapper() { } @@ -19,14 +18,6 @@ public List fromEntities(Iterable entities) throws BackendException { return result; } - public List toEntities(Iterable domainObjects) { - List result = new ArrayList<>(); - for (D domainObject : domainObjects) { - result.add(toEntity(domainObject)); - } - return result; - } - protected abstract D fromEntity(E entity) throws BackendException; protected abstract E toEntity(D domainObject); diff --git a/data/src/main/java/org/cryptomator/data/db/mappers/VaultEntityMapper.java b/data/src/main/java/org/cryptomator/data/db/mappers/VaultEntityMapper.java index 3cd19471fa..ab9f810acb 100644 --- a/data/src/main/java/org/cryptomator/data/db/mappers/VaultEntityMapper.java +++ b/data/src/main/java/org/cryptomator/data/db/mappers/VaultEntityMapper.java @@ -1,6 +1,7 @@ package org.cryptomator.data.db.mappers; import org.cryptomator.data.db.entities.VaultEntity; +import org.cryptomator.data.db.entities.VaultWithCloud; import org.cryptomator.domain.Cloud; import org.cryptomator.domain.CloudType; import org.cryptomator.domain.Vault; @@ -13,7 +14,7 @@ import static org.cryptomator.domain.Vault.aVault; @Singleton -public class VaultEntityMapper extends EntityMapper { +public class VaultEntityMapper extends EntityMapper { private final CloudEntityMapper cloudEntityMapper; @@ -23,21 +24,22 @@ public VaultEntityMapper(CloudEntityMapper cloudEntityMapper) { } @Override - public Vault fromEntity(VaultEntity entity) throws BackendException { + public Vault fromEntity(VaultWithCloud entity) throws BackendException { + VaultEntity vault = entity.getVault(); return aVault() // - .withId(entity.getId()) // - .withName(entity.getFolderName()) // - .withPath(entity.getFolderPath()) // + .withId(vault.getId()) // + .withName(vault.getFolderName()) // + .withPath(vault.getFolderPath()) // .withCloud(cloudFrom(entity)) // - .withCloudType(CloudType.valueOf(entity.getCloudType())) // - .withSavedPassword(entity.getPassword(), cryptoModeFrom(entity)) // - .withPosition(entity.getPosition()) // - .withFormat(entity.getFormat()) // - .withShorteningThreshold(entity.getShorteningThreshold()) // + .withCloudType(CloudType.valueOf(vault.getCloudType())) // + .withSavedPassword(vault.getPassword(), cryptoModeFrom(vault)) // + .withPosition(vault.getPosition()) // + .withFormat(vault.getFormat()) // + .withShorteningThreshold(vault.getShorteningThreshold()) // .build(); } - private Cloud cloudFrom(VaultEntity entity) { + private Cloud cloudFrom(VaultWithCloud entity) { if (entity.getFolderCloud() == null) { return null; } @@ -49,22 +51,26 @@ private CryptoMode cryptoModeFrom(VaultEntity entity) { } @Override - public VaultEntity toEntity(Vault domainObject) { - VaultEntity entity = new VaultEntity(); - entity.setId(domainObject.getId()); - entity.setFolderPath(domainObject.getPath()); - entity.setFolderName(domainObject.getName()); - if (domainObject.getCloud() != null) { - entity.setFolderCloud(cloudEntityMapper.toEntity(domainObject.getCloud())); - } - entity.setCloudType(domainObject.getCloudType().name()); - entity.setPassword(domainObject.getPassword()); + public VaultWithCloud toEntity(Vault domainObject) { + VaultEntity vault = new VaultEntity(); + vault.setId(domainObject.getId()); + vault.setFolderPath(domainObject.getPath()); + vault.setFolderName(domainObject.getName()); + vault.setCloudType(domainObject.getCloudType().name()); + vault.setPassword(domainObject.getPassword()); if (domainObject.getPasswordCryptoMode() != null) { - entity.setPasswordCryptoMode(domainObject.getPasswordCryptoMode().name()); + vault.setPasswordCryptoMode(domainObject.getPasswordCryptoMode().name()); + } + vault.setPosition(domainObject.getPosition()); + vault.setFormat(domainObject.getFormat()); + vault.setShorteningThreshold(domainObject.getShorteningThreshold()); + + VaultWithCloud result = new VaultWithCloud(); + result.setVault(vault); + if (domainObject.getCloud() != null) { + result.setFolderCloud(cloudEntityMapper.toEntity(domainObject.getCloud())); + vault.setFolderCloudId(result.getFolderCloud().getId()); } - entity.setPosition(domainObject.getPosition()); - entity.setFormat(domainObject.getFormat()); - entity.setShorteningThreshold(domainObject.getShorteningThreshold()); - return entity; + return result; } } diff --git a/data/src/main/java/org/cryptomator/data/repository/CloudRepositoryImpl.java b/data/src/main/java/org/cryptomator/data/repository/CloudRepositoryImpl.java index bcda1f3a2f..140fa00fbe 100644 --- a/data/src/main/java/org/cryptomator/data/repository/CloudRepositoryImpl.java +++ b/data/src/main/java/org/cryptomator/data/repository/CloudRepositoryImpl.java @@ -3,8 +3,7 @@ import com.google.common.base.Optional; import org.cryptomator.data.cloud.crypto.CryptoCloudFactory; -import org.cryptomator.data.db.Database; -import org.cryptomator.data.db.entities.CloudEntity; +import org.cryptomator.data.db.dao.CloudDao; import org.cryptomator.data.db.mappers.CloudEntityMapper; import org.cryptomator.domain.Cloud; import org.cryptomator.domain.CloudFolder; @@ -25,7 +24,7 @@ @Singleton class CloudRepositoryImpl implements CloudRepository { - private final Database database; + private final CloudDao cloudDao; private final CryptoCloudFactory cryptoCloudFactory; private final CloudEntityMapper mapper; private final DispatchingCloudContentRepository dispatchingCloudContentRepository; @@ -33,9 +32,9 @@ class CloudRepositoryImpl implements CloudRepository { @Inject public CloudRepositoryImpl(CloudEntityMapper mapper, // CryptoCloudFactory cryptoCloudFactory, // - Database database, // + CloudDao cloudDao, // DispatchingCloudContentRepository dispatchingCloudContentRepository) { - this.database = database; + this.cloudDao = cloudDao; this.cryptoCloudFactory = cryptoCloudFactory; this.mapper = mapper; this.dispatchingCloudContentRepository = dispatchingCloudContentRepository; @@ -44,7 +43,7 @@ public CloudRepositoryImpl(CloudEntityMapper mapper, // @Override public List clouds(CloudType cloudType) throws BackendException { List cloudsFromType = new ArrayList<>(); - List allClouds = mapper.fromEntities(database.loadAll(CloudEntity.class)); + List allClouds = mapper.fromEntities(cloudDao.loadAll()); for (Cloud cloud : allClouds) { if (cloud.type().equals(cloudType)) { @@ -57,7 +56,7 @@ public List clouds(CloudType cloudType) throws BackendException { @Override public List allClouds() throws BackendException { - return mapper.fromEntities(database.loadAll(CloudEntity.class)); + return mapper.fromEntities(cloudDao.loadAll()); } @Override @@ -66,8 +65,7 @@ public Cloud store(Cloud cloud) { throw new IllegalArgumentException("Can not store non persistent cloud"); } - Cloud storedCloud = mapper.fromEntity(database.store(mapper.toEntity(cloud))); - database.clearCache(); + Cloud storedCloud = mapper.fromEntity(cloudDao.store(mapper.toEntity(cloud))); dispatchingCloudContentRepository.updateCloudContentRepositoryFor(storedCloud); @@ -79,7 +77,7 @@ public void delete(Cloud cloud) { if (!cloud.persistent()) { throw new IllegalArgumentException("Can not delete non persistent cloud"); } - database.delete(mapper.toEntity(cloud)); + cloudDao.delete(mapper.toEntity(cloud)); dispatchingCloudContentRepository.removeCloudContentRepositoryFor(cloud); } diff --git a/data/src/main/java/org/cryptomator/data/repository/UpdateCheckRepositoryImpl.java b/data/src/main/java/org/cryptomator/data/repository/UpdateCheckRepositoryImpl.java index a84d916ff8..17af292624 100644 --- a/data/src/main/java/org/cryptomator/data/repository/UpdateCheckRepositoryImpl.java +++ b/data/src/main/java/org/cryptomator/data/repository/UpdateCheckRepositoryImpl.java @@ -11,7 +11,7 @@ import com.google.common.io.BaseEncoding; import org.apache.commons.codec.binary.Hex; -import org.cryptomator.data.db.Database; +import org.cryptomator.data.db.dao.UpdateCheckDao; import org.cryptomator.data.db.entities.UpdateCheckEntity; import org.cryptomator.data.util.UserAgentInterceptor; import org.cryptomator.domain.exception.BackendException; @@ -47,14 +47,14 @@ public class UpdateCheckRepositoryImpl implements UpdateCheckRepository { private static final String HOSTNAME_LATEST_VERSION = "https://api.cryptomator.org/android/latest-version.json"; - private final Database database; + private final UpdateCheckDao updateCheckDao; private final OkHttpClient httpClient; private final Context context; @Inject - UpdateCheckRepositoryImpl(Database database, Context context) { + UpdateCheckRepositoryImpl(UpdateCheckDao updateCheckDao, Context context) { this.httpClient = httpClient(); - this.database = database; + this.updateCheckDao = updateCheckDao; this.context = context; } @@ -72,7 +72,7 @@ public Optional getUpdateCheck(final String appVersion) throws Back return Optional.absent(); } - final UpdateCheckEntity entity = database.load(UpdateCheckEntity.class, 1L); + final UpdateCheckEntity entity = updateCheckDao.load(1L); if (entity.getVersion() != null && entity.getVersion().equals(latestVersion.version) && entity.getApkSha256() != null) { return Optional.of(new UpdateCheckImpl("", entity)); @@ -83,7 +83,7 @@ public Optional getUpdateCheck(final String appVersion) throws Back entity.setVersion(updateCheck.getVersion()); entity.setApkSha256(updateCheck.getApkSha256()); - database.store(entity); + updateCheckDao.update(entity); return Optional.of(updateCheck); } @@ -91,7 +91,7 @@ public Optional getUpdateCheck(final String appVersion) throws Back @Override public void update(File file) throws GeneralUpdateErrorException { try { - final UpdateCheckEntity entity = database.load(UpdateCheckEntity.class, 1L); + final UpdateCheckEntity entity = updateCheckDao.load(1L); final Request request = new Request // .Builder() // diff --git a/data/src/main/java/org/cryptomator/data/repository/VaultRepositoryImpl.java b/data/src/main/java/org/cryptomator/data/repository/VaultRepositoryImpl.java index 2c4e179349..c9bf79b227 100644 --- a/data/src/main/java/org/cryptomator/data/repository/VaultRepositoryImpl.java +++ b/data/src/main/java/org/cryptomator/data/repository/VaultRepositoryImpl.java @@ -4,8 +4,7 @@ import org.cryptomator.data.cloud.crypto.CryptoCloudContentRepositoryFactory; import org.cryptomator.data.cloud.crypto.CryptoCloudFactory; -import org.cryptomator.data.db.Database; -import org.cryptomator.data.db.entities.VaultEntity; +import org.cryptomator.data.db.dao.VaultDao; import org.cryptomator.data.db.mappers.VaultEntityMapper; import org.cryptomator.domain.Vault; import org.cryptomator.domain.exception.BackendException; @@ -23,7 +22,7 @@ @Singleton class VaultRepositoryImpl implements VaultRepository { - private final Database database; + private final VaultDao vaultDao; private final VaultEntityMapper mapper; private final CryptoCloudContentRepositoryFactory cryptoCloudContentRepositoryFactory; private final DispatchingCloudContentRepository dispatchingCloudContentRepository; @@ -35,9 +34,9 @@ public VaultRepositoryImpl( // CryptoCloudContentRepositoryFactory cryptoCloudContentRepositoryFactory, // CryptoCloudFactory cryptoCloudFactory, // DispatchingCloudContentRepository dispatchingCloudContentRepository, // - Database database) { + VaultDao vaultDao) { this.mapper = mapper; - this.database = database; + this.vaultDao = vaultDao; this.cryptoCloudContentRepositoryFactory = cryptoCloudContentRepositoryFactory; this.cryptoCloudFactory = cryptoCloudFactory; this.dispatchingCloudContentRepository = dispatchingCloudContentRepository; @@ -46,7 +45,7 @@ public VaultRepositoryImpl( // @Override public List vaults() throws BackendException { List result = new ArrayList<>(); - for (Vault vault : mapper.fromEntities(database.loadAll(VaultEntity.class))) { + for (Vault vault : mapper.fromEntities(vaultDao.loadAll())) { result.add(aCopyOf(vault).withUnlocked(isUnlocked(vault)).build()); } return result; @@ -55,7 +54,7 @@ public List vaults() throws BackendException { @Override public Vault store(Vault vault) throws BackendException { try { - return mapper.fromEntity(database.store(mapper.toEntity(vault))); + return mapper.fromEntity(vaultDao.store(mapper.toEntity(vault))); } catch (SQLiteConstraintException e) { throw new VaultAlreadyExistException(); } @@ -65,13 +64,13 @@ public Vault store(Vault vault) throws BackendException { public Long delete(Vault vault) throws BackendException { deregisterUnlocked(vault); dispatchingCloudContentRepository.removeCloudContentRepositoryFor(cryptoCloudFactory.decryptedViewOf(vault)); - database.delete(mapper.toEntity(vault)); + vaultDao.delete(mapper.toEntity(vault)); return vault.getId(); } @Override public Vault load(Long id) throws BackendException { - Vault vault = mapper.fromEntity(database.load(VaultEntity.class, id)); + Vault vault = mapper.fromEntity(vaultDao.load(id)); return aCopyOf(vault).withUnlocked(isUnlocked(vault)).build(); } diff --git a/presentation/src/main/java/org/cryptomator/presentation/di/component/ApplicationComponent.java b/presentation/src/main/java/org/cryptomator/presentation/di/component/ApplicationComponent.java index ca02320285..183e7c6b66 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/di/component/ApplicationComponent.java +++ b/presentation/src/main/java/org/cryptomator/presentation/di/component/ApplicationComponent.java @@ -3,6 +3,7 @@ import android.content.Context; import org.cryptomator.data.cloud.crypto.CryptorsModule; +import org.cryptomator.data.db.DatabaseModule; import org.cryptomator.data.repository.RepositoryModule; import org.cryptomator.data.util.NetworkConnectionCheck; import org.cryptomator.domain.executor.PostExecutionThread; @@ -22,7 +23,7 @@ import dagger.Component; @Singleton -@Component(modules = {ApplicationModule.class, ThreadModule.class, RepositoryModule.class, CryptorsModule.class}) +@Component(modules = {ApplicationModule.class, ThreadModule.class, DatabaseModule.class, RepositoryModule.class, CryptorsModule.class}) public interface ApplicationComponent { Context context();