diff --git a/app/src/androidTest/kotlin/at/bitfire/davdroid/sync/SyncerTest.kt b/app/src/androidTest/kotlin/at/bitfire/davdroid/sync/SyncerTest.kt index a41e8aa34..58cd4968e 100644 --- a/app/src/androidTest/kotlin/at/bitfire/davdroid/sync/SyncerTest.kt +++ b/app/src/androidTest/kotlin/at/bitfire/davdroid/sync/SyncerTest.kt @@ -165,9 +165,6 @@ class SyncerTest { override val dataStore: LocalTestStore = theDataStore - override val authority: String - get() = throw NotImplementedError() - override val serviceType: String get() = throw NotImplementedError() @@ -189,6 +186,13 @@ class SyncerTest { class LocalTestStore : LocalDataStore { + override val authority: String + get() = throw NotImplementedError() + + override fun acquireContentProvider(): ContentProviderClient? { + throw NotImplementedError() + } + override fun create( provider: ContentProviderClient, fromCollection: Collection diff --git a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalAddressBookStore.kt b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalAddressBookStore.kt index 42e81a861..5dd01bed7 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalAddressBookStore.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalAddressBookStore.kt @@ -34,6 +34,9 @@ class LocalAddressBookStore @Inject constructor( private val settings: SettingsManager ): LocalDataStore { + override val authority: String + get() = ContactsContract.AUTHORITY + /** whether a (usually managed) setting wants all address-books to be read-only **/ val forceAllReadOnly: Boolean get() = settings.getBoolean(Settings.FORCE_READ_ONLY_ADDRESSBOOKS) @@ -67,6 +70,8 @@ class LocalAddressBookStore @Inject constructor( return sb.toString() } + override fun acquireContentProvider() = + context.contentResolver.acquireContentProviderClient(authority) override fun create(provider: ContentProviderClient, fromCollection: Collection): LocalAddressBook? { val service = serviceRepository.get(fromCollection.serviceId) ?: throw IllegalArgumentException("Couldn't fetch DB service from collection") @@ -106,7 +111,6 @@ class LocalAddressBookStore @Inject constructor( return addressBookAccount } - override fun getAll(account: Account, provider: ContentProviderClient): List { val accountManager = AccountManager.get(context) return accountManager.getAccountsByType(context.getString(R.string.account_type_address_book)) @@ -119,7 +123,6 @@ class LocalAddressBookStore @Inject constructor( } } - override fun update(provider: ContentProviderClient, localCollection: LocalAddressBook, fromCollection: Collection) { var currentAccount = localCollection.addressBookAccount logger.log(Level.INFO, "Updating local address book $currentAccount from collection $fromCollection") @@ -171,7 +174,6 @@ class LocalAddressBookStore @Inject constructor( } } - override fun delete(localCollection: LocalAddressBook) { val accountManager = AccountManager.get(context) accountManager.removeAccountExplicitly(localCollection.addressBookAccount) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalCalendarStore.kt b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalCalendarStore.kt index ac1edaff3..4931486f4 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalCalendarStore.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalCalendarStore.kt @@ -34,6 +34,12 @@ class LocalCalendarStore @Inject constructor( private val serviceRepository: DavServiceRepository ): LocalDataStore { + override val authority: String + get() = CalendarContract.AUTHORITY + + override fun acquireContentProvider() = + context.contentResolver.acquireContentProviderClient(authority) + override fun create(provider: ContentProviderClient, fromCollection: Collection): LocalCalendar? { val service = serviceRepository.get(fromCollection.serviceId) ?: throw IllegalArgumentException("Couldn't fetch DB service from collection") val account = Account(service.accountName, context.getString(R.string.account_type)) @@ -67,11 +73,9 @@ class LocalCalendarStore @Inject constructor( return AndroidCalendar.findByID(account, provider, LocalCalendar.Factory, ContentUris.parseId(uri)) } - override fun getAll(account: Account, provider: ContentProviderClient) = AndroidCalendar.find(account, provider, LocalCalendar.Factory, "${Calendars.SYNC_EVENTS}!=0", null) - override fun update(provider: ContentProviderClient, localCollection: LocalCalendar, fromCollection: Collection) { val accountSettings = accountSettingsFactory.create(localCollection.account) val values = valuesFromCollectionInfo(fromCollection, withColor = accountSettings.getManageCalendarColors()) @@ -114,10 +118,9 @@ class LocalCalendarStore @Inject constructor( } } - override fun delete(localCollection: LocalCalendar) { logger.log(Level.INFO, "Deleting local calendar", localCollection) localCollection.delete() } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalDataStore.kt b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalDataStore.kt index 4f35592f7..c8685a75e 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalDataStore.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalDataStore.kt @@ -14,6 +14,23 @@ import at.bitfire.davdroid.db.Collection */ interface LocalDataStore> { + /** + * Content provider authority for the data store. + */ + val authority: String + + /** + * Acquires a content provider client for the data store. The result of this call + * should be passed to all other methods of this class. + * + * **The caller is responsible for closing the content provider client!** + * + * @return the content provider client, or `null` if the content provider could not be acquired + * + * @throws SecurityException on missing permissions + */ + fun acquireContentProvider(): ContentProviderClient? + /** * Creates a new local collection from the given (remote) collection info. * diff --git a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalJtxCollectionStore.kt b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalJtxCollectionStore.kt index 47956859d..6523d1e92 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalJtxCollectionStore.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalJtxCollectionStore.kt @@ -34,6 +34,12 @@ class LocalJtxCollectionStore @Inject constructor( private val serviceDao = db.serviceDao() + override val authority: String + get() = JtxContract.AUTHORITY + + override fun acquireContentProvider() = + context.contentResolver.acquireContentProviderClient(JtxContract.AUTHORITY) + override fun create(provider: ContentProviderClient, fromCollection: Collection): LocalJtxCollection? { val service = serviceDao.get(fromCollection.serviceId) ?: throw IllegalArgumentException("Couldn't fetch DB service from collection") val account = Account(service.accountName, context.getString(R.string.account_type)) @@ -82,22 +88,15 @@ class LocalJtxCollectionStore @Inject constructor( } } - override fun getAll(account: Account, provider: ContentProviderClient): List = JtxCollection.find(account, provider, context, LocalJtxCollection.Factory, null, null) - override fun update(provider: ContentProviderClient, localCollection: LocalJtxCollection, fromCollection: Collection) { val accountSettings = accountSettingsFactory.create(localCollection.account) val values = valuesFromCollection(fromCollection, account = localCollection.account, withColor = accountSettings.getManageCalendarColors()) localCollection.update(values) } - - override fun delete(localCollection: LocalJtxCollection) { - localCollection.delete() - } - override fun updateAccount(oldAccount: Account, newAccount: Account) { TaskProvider.acquire(context, TaskProvider.ProviderName.JtxBoard)?.use { provider -> val values = contentValuesOf(JtxContract.JtxCollection.ACCOUNT_NAME to newAccount.name) @@ -106,4 +105,8 @@ class LocalJtxCollectionStore @Inject constructor( } } + override fun delete(localCollection: LocalJtxCollection) { + localCollection.delete() + } + } \ No newline at end of file diff --git a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTaskListStore.kt b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTaskListStore.kt index 2460dce86..f45c86f4d 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTaskListStore.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTaskListStore.kt @@ -44,6 +44,11 @@ class LocalTaskListStore @AssistedInject constructor( private val serviceDao = db.serviceDao() + override val authority: String + get() = providerName.authority + + override fun acquireContentProvider() = + context.contentResolver.acquireContentProviderClient(authority) override fun create(provider: ContentProviderClient, fromCollection: Collection): LocalTaskList? { val service = serviceDao.get(fromCollection.serviceId) ?: throw IllegalArgumentException("Couldn't fetch DB service from collection") @@ -89,22 +94,15 @@ class LocalTaskListStore @AssistedInject constructor( return values } - override fun getAll(account: Account, provider: ContentProviderClient) = DmfsTaskList.find(account, LocalTaskList.Factory, provider, providerName, null, null) - override fun update(provider: ContentProviderClient, localCollection: LocalTaskList, fromCollection: Collection) { logger.log(Level.FINE, "Updating local task list ${fromCollection.url}", fromCollection) val accountSettings = accountSettingsFactory.create(localCollection.account) localCollection.update(valuesFromCollectionInfo(fromCollection, withColor = accountSettings.getManageCalendarColors())) } - - override fun delete(localCollection: LocalTaskList) { - localCollection.delete() - } - override fun updateAccount(oldAccount: Account, newAccount: Account) { TaskProvider.acquire(context, providerName)?.use { provider -> val values = contentValuesOf(Tasks.ACCOUNT_NAME to newAccount.name) @@ -113,4 +111,8 @@ class LocalTaskListStore @AssistedInject constructor( } } + override fun delete(localCollection: LocalTaskList) { + localCollection.delete() + } + } \ No newline at end of file diff --git a/app/src/main/kotlin/at/bitfire/davdroid/sync/AddressBookSyncer.kt b/app/src/main/kotlin/at/bitfire/davdroid/sync/AddressBookSyncer.kt index 4067d6b57..fb0ddba5c 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/sync/AddressBookSyncer.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/sync/AddressBookSyncer.kt @@ -41,8 +41,6 @@ class AddressBookSyncer @AssistedInject constructor( override val serviceType: String get() = Service.TYPE_CARDDAV - override val authority: String - get() = ContactsContract.AUTHORITY // Address books use the contacts authority for sync override fun getDbSyncCollections(serviceId: Long): List = @@ -100,7 +98,16 @@ class AddressBookSyncer @AssistedInject constructor( } accountManager.setAndVerifyUserData(addressBook.addressBookAccount, PREVIOUS_GROUP_METHOD, groupMethod) - val syncManager = contactsSyncManagerFactory.contactsSyncManager(account, httpClient.value, extras, authority, syncResult, provider, addressBook, collection) + val syncManager = contactsSyncManagerFactory.contactsSyncManager( + account, + httpClient.value, + extras, + dataStore.authority, + syncResult, + provider, + addressBook, + collection + ) syncManager.performSync() } catch(e: Exception) { diff --git a/app/src/main/kotlin/at/bitfire/davdroid/sync/CalendarSyncer.kt b/app/src/main/kotlin/at/bitfire/davdroid/sync/CalendarSyncer.kt index d74f2a566..a8a26abf9 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/sync/CalendarSyncer.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/sync/CalendarSyncer.kt @@ -6,7 +6,6 @@ package at.bitfire.davdroid.sync import android.accounts.Account import android.content.ContentProviderClient -import android.provider.CalendarContract import at.bitfire.davdroid.db.Collection import at.bitfire.davdroid.db.Service import at.bitfire.davdroid.resource.LocalCalendar @@ -38,8 +37,6 @@ class CalendarSyncer @AssistedInject constructor( override val serviceType: String get() = Service.TYPE_CALDAV - override val authority: String - get() = CalendarContract.AUTHORITY override fun prepare(provider: ContentProviderClient): Boolean { @@ -62,7 +59,7 @@ class CalendarSyncer @AssistedInject constructor( account, extras, httpClient.value, - authority, + dataStore.authority, syncResult, localCollection, remoteCollection diff --git a/app/src/main/kotlin/at/bitfire/davdroid/sync/JtxSyncer.kt b/app/src/main/kotlin/at/bitfire/davdroid/sync/JtxSyncer.kt index 21a66ce48..9ad390994 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/sync/JtxSyncer.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/sync/JtxSyncer.kt @@ -38,8 +38,6 @@ class JtxSyncer @AssistedInject constructor( override val serviceType: String get() = Service.TYPE_CALDAV - override val authority: String - get() = TaskProvider.ProviderName.JtxBoard.authority override fun prepare(provider: ContentProviderClient): Boolean { @@ -74,7 +72,7 @@ class JtxSyncer @AssistedInject constructor( account, extras, httpClient.value, - authority, + dataStore.authority, syncResult, localCollection, remoteCollection diff --git a/app/src/main/kotlin/at/bitfire/davdroid/sync/Syncer.kt b/app/src/main/kotlin/at/bitfire/davdroid/sync/Syncer.kt index fe5f84056..054a5acf4 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/sync/Syncer.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/sync/Syncer.kt @@ -77,7 +77,6 @@ abstract class Syncer, CollectionType: @Inject lateinit var serviceRepository: DavServiceRepository - abstract val authority: String @ServiceType abstract val serviceType: String @@ -214,7 +213,8 @@ abstract class Syncer, CollectionType: /** * For collection specific sync preparations. * - * @param provider Content provider for syncer specific authority + * @param provider Content provider for data store + * * @return *true* to run the sync; *false* to abort */ open fun prepare(provider: ContentProviderClient): Boolean = true @@ -223,6 +223,7 @@ abstract class Syncer, CollectionType: * Get the local database collections which are sync-enabled (should by synchronized). * * @param serviceId The CalDAV or CardDAV service (account) to be synchronized + * * @return Database collections to be synchronized */ abstract fun getDbSyncCollections(serviceId: Long): List @@ -244,13 +245,12 @@ abstract class Syncer, CollectionType: * - handle occurring sync errors */ operator fun invoke() { - logger.log(Level.INFO, "$authority sync of $account initiated", extras.joinToString(", ")) + logger.log(Level.INFO, "${dataStore.authority} sync of $account initiated", extras.joinToString(", ")) - // Acquire ContentProviderClient try { - context.contentResolver.acquireContentProviderClient(authority) + dataStore.acquireContentProvider() } catch (e: SecurityException) { - logger.log(Level.WARNING, "Missing permissions for authority $authority", e) + logger.log(Level.WARNING, "Missing permissions for content provider authority ${dataStore.authority}", e) notificationRegistry.notifyPermissions() null }.use { provider -> @@ -259,7 +259,7 @@ abstract class Syncer, CollectionType: - we're not allowed to access the content provider, or - the content provider is not available at all, for instance because the tasks app has been uninstalled or the respective system app (like "calendar storage") is disabled */ - logger.warning("Couldn't connect to content provider of authority $authority") + logger.warning("Couldn't connect to content provider of authority ${dataStore.authority}") syncResult.contentProviderError = true return // Don't continue without provider @@ -281,7 +281,7 @@ abstract class Syncer, CollectionType: logger.log(Level.WARNING, "Account was removed during synchronization", e) } catch (e: Exception) { - logger.log(Level.SEVERE, "Couldn't sync $authority", e) + logger.log(Level.SEVERE, "Couldn't sync ${dataStore.authority}", e) syncResult.numUnclassifiedErrors++ // Hard sync error } finally { @@ -289,7 +289,7 @@ abstract class Syncer, CollectionType: httpClient.value.close() logger.log( Level.INFO, - "$authority sync of $account finished", + "${dataStore.authority} sync of $account finished", extras.joinToString(", ")) } } diff --git a/app/src/main/kotlin/at/bitfire/davdroid/sync/TaskSyncer.kt b/app/src/main/kotlin/at/bitfire/davdroid/sync/TaskSyncer.kt index c56ade01d..9632a67b0 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/sync/TaskSyncer.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/sync/TaskSyncer.kt @@ -22,7 +22,7 @@ import dagger.assisted.AssistedInject */ class TaskSyncer @AssistedInject constructor( @Assisted account: Account, - @Assisted override val authority: String, + @Assisted val providerName: TaskProvider.ProviderName, @Assisted extras: Array, @Assisted syncResult: SyncResult, localTaskListStoreFactory: LocalTaskListStore.Factory, @@ -32,11 +32,9 @@ class TaskSyncer @AssistedInject constructor( @AssistedFactory interface Factory { - fun create(account: Account, authority: String, extras: Array, syncResult: SyncResult): TaskSyncer + fun create(account: Account, providerName: TaskProvider.ProviderName, extras: Array, syncResult: SyncResult): TaskSyncer } - private val providerName = TaskProvider.ProviderName.fromAuthority(authority) - override val dataStore = localTaskListStoreFactory.create(providerName) override val serviceType: String @@ -75,7 +73,7 @@ class TaskSyncer @AssistedInject constructor( account, httpClient.value, extras, - authority, + dataStore.authority, syncResult, localCollection, remoteCollection diff --git a/app/src/main/kotlin/at/bitfire/davdroid/sync/worker/BaseSyncWorker.kt b/app/src/main/kotlin/at/bitfire/davdroid/sync/worker/BaseSyncWorker.kt index dd3f27d90..83900fb44 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/sync/worker/BaseSyncWorker.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/sync/worker/BaseSyncWorker.kt @@ -169,7 +169,7 @@ abstract class BaseSyncWorker( jtxSyncer.create(account, extras, syncResult) TaskProvider.ProviderName.OpenTasks, TaskProvider.ProviderName.TasksOrg -> - taskSyncer.create(account, currentProvider.authority, extras, syncResult) + taskSyncer.create(account, currentProvider, extras, syncResult) else -> { logger.warning("No valid tasks provider found, aborting sync") return@withContext Result.failure()