Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 904c8ba2 authored by Sunik Kupfer's avatar Sunik Kupfer Committed by GitHub
Browse files

[Sync framework] Disable contacts content change triggered syncs if sync...


[Sync framework] Disable contacts content change triggered syncs if sync interval set to manual only (#1569)

* Fix lint error

Signed-off-by: default avatarSunik Kupfer <kupfer@bitfire.at>

* Show manual sync interval setting in UI

Signed-off-by: default avatarSunik Kupfer <kupfer@bitfire.at>

* Disable contacts content change triggered syncs if set to manual; update kdoc

Signed-off-by: default avatarSunik Kupfer <kupfer@bitfire.at>

* Update comments and kdoc

Signed-off-by: default avatarSunik Kupfer <kupfer@bitfire.at>

* Automatically close provider

Signed-off-by: default avatarSunik Kupfer <kupfer@bitfire.at>

* Explicitly handle special case

* Rename updateAutomaticSync to updateSyncFrameworkSetting; adjust comments

Signed-off-by: default avatarSunik Kupfer <kupfer@bitfire.at>

---------

Signed-off-by: default avatarSunik Kupfer <kupfer@bitfire.at>
Co-authored-by: default avatarRicki Hirner <hirner@bitfire.at>
parent 62dc73c2
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import at.bitfire.davdroid.repository.DavServiceRepository
import at.bitfire.davdroid.resource.LocalAddressBook.Companion.USER_DATA_READ_ONLY
import at.bitfire.davdroid.resource.workaround.ContactDirtyVerifier
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.sync.SyncDataType
import at.bitfire.davdroid.sync.SyncFrameworkIntegration
import at.bitfire.davdroid.sync.account.SystemAccountUtils
import at.bitfire.davdroid.sync.account.setAndVerifyUserData
@@ -223,15 +224,18 @@ open class LocalAddressBook @AssistedInject constructor(


    /**
     * Makes contacts of this address book available to be synced and activates synchronization upon
     * contact data changes.
     * Enables or disables sync on content changes for the address book account based on the current sync
     * interval account setting.
     */
    fun updateSyncFrameworkSettings() {
        // Enable sync-ability of contacts
        syncFramework.enableSyncAbility(addressBookAccount, ContactsContract.AUTHORITY)
        val accountSettings = accountSettingsFactory.create(account)
        val syncInterval = accountSettings.getSyncInterval(SyncDataType.CONTACTS)

        // Changes in contact data should trigger syncs
        // Enable/Disable content triggered syncs for the address book account.
        if (syncInterval != null)
            syncFramework.enableSyncOnContentChange(addressBookAccount, ContactsContract.AUTHORITY)
        else
            syncFramework.disableSyncAbility(addressBookAccount, ContactsContract.AUTHORITY)
    }


+1 −1
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ class LocalAddressBookStore @Inject constructor(
            localCollection.readOnly = nowReadOnly
        }

        // make sure it will still be synchronized when contacts are updated
        // Update automatic synchronization
        localCollection.updateSyncFrameworkSettings()
    }

+1 −1
Original line number Diff line number Diff line
@@ -177,7 +177,7 @@ class AccountSettings @AssistedInject constructor(
            SyncDataType.EVENTS -> KEY_SYNC_INTERVAL_CALENDARS
            SyncDataType.TASKS -> KEY_SYNC_INTERVAL_TASKS
        }
        val newValue = if (seconds == null) SYNC_INTERVAL_MANUALLY else seconds
        val newValue = seconds ?: SYNC_INTERVAL_MANUALLY
        accountManager.setAndVerifyUserData(account, key, newValue.toString())

        automaticSyncManager.updateAutomaticSync(account, dataType)
+43 −23
Original line number Diff line number Diff line
@@ -6,8 +6,10 @@ package at.bitfire.davdroid.sync

import android.accounts.Account
import android.provider.CalendarContract
import android.provider.ContactsContract
import at.bitfire.davdroid.db.Service
import at.bitfire.davdroid.repository.DavServiceRepository
import at.bitfire.davdroid.resource.LocalAddressBookStore
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.sync.worker.SyncWorkerManager
import kotlinx.coroutines.runBlocking
@@ -27,6 +29,7 @@ import javax.inject.Provider
 */
class AutomaticSyncManager @Inject constructor(
    private val accountSettingsFactory: AccountSettings.Factory,
    private val localAddressBookStore: LocalAddressBookStore,
    private val serviceRepository: DavServiceRepository,
    private val syncFramework: SyncFrameworkIntegration,
    private val tasksAppManager: Provider<TasksAppManager>,
@@ -39,15 +42,18 @@ class AutomaticSyncManager @Inject constructor(
    private fun disableAutomaticSync(account: Account, dataType: SyncDataType) {
        workerManager.disablePeriodic(account, dataType)

        for (authority in dataType.possibleAuthorities())
        for (authority in dataType.possibleAuthorities()) {
            syncFramework.disableSyncAbility(account, authority)
            // no need to disable content-triggered sync, as it can't be active when sync-ability is disabled
        }
    }

    /**
     * Enables automatic synchronization for the given account and data type and sets it to the given interval:
     * Enables/Disables automatic synchronization for the given account and data type and sets it to the given interval,
     * based on sync interval setting in account settings:
     *
     * 1. Sets up periodic sync for the given data type with the given interval.
     * 2. Enables sync in the sync framework for the given data type and sets up periodic sync with the given interval.
     * 1. Enables/Disables periodic sync worker for the given data type with the given interval.
     * 2. Enables/Disables sync in the sync framework and enables or disables content-triggered syncs for the given data type
     *
     * @param account   the account to synchronize
     * @param dataType  the data type to synchronize
@@ -58,19 +64,31 @@ class AutomaticSyncManager @Inject constructor(
    ) {
        val accountSettings = accountSettingsFactory.create(account)
        val syncInterval = accountSettings.getSyncInterval(dataType)

        // 1. Update sync workers (needs already updated sync interval in AccountSettings).
        if (syncInterval != null) {
            // update sync workers (needs already updated sync interval in AccountSettings)
            val wifiOnly = accountSettings.getSyncWifiOnly()
            workerManager.enablePeriodic(account, dataType, syncInterval, wifiOnly)
        } else
            workerManager.disablePeriodic(account, dataType)

        // also enable/disable content-triggered syncs
        // 2. Enable/disable content-triggered syncs.
        if (dataType == SyncDataType.CONTACTS) {
            // Contact updates are handled by their respective address book accounts, so we must always
            // disable the content-triggered sync for the main account.
            syncFramework.disableSyncAbility(account, ContactsContract.AUTHORITY)

            // pass through request to update all existing address books
            localAddressBookStore.acquireContentProvider()?.use { provider ->
                for (addressBookAccount in localAddressBookStore.getAll(account, provider))
                    addressBookAccount.updateSyncFrameworkSettings()
            }

        } else {
            // everything but contacts
            val possibleAuthorities = dataType.possibleAuthorities()
            val authority: String? = when (dataType) {
            // Content triggered sync of contacts is handled per address book account in
            // [LocalAddressBook.updateSyncFrameworkSettings()]
            SyncDataType.CONTACTS -> null
                SyncDataType.CONTACTS -> throw IllegalStateException()  // handled above
                SyncDataType.EVENTS -> CalendarContract.AUTHORITY
                SyncDataType.TASKS -> tasksAppManager.get().currentProvider()?.authority
            }
@@ -84,6 +102,7 @@ class AutomaticSyncManager @Inject constructor(
                for (authority in possibleAuthorities)
                    syncFramework.disableSyncOnContentChange(account, authority)
        }
    }

    /**
     * Updates automatic synchronization of the given account and all data types according to the account settings.
@@ -101,7 +120,8 @@ class AutomaticSyncManager @Inject constructor(
    /**
     * Updates automatic synchronization of the given account and data type according to the account services and settings.
     *
     * If there's a [Service] for the given account and data type, automatic sync is enabled (with details from [AccountSettings]).
     * If there's a [Service] for the given account and data type, automatic sync may be enabled if sync interval is set
     * in [AccountSettings].
     * Otherwise, automatic synchronization is disabled.
     *
     * @param account   account for which automatic synchronization shall be updated
+5 −0
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@ class SyncFrameworkIntegration @Inject constructor(

    /**
     * Disable this account/provider to be syncable.
     *
     * If an authority is not syncable, this implies that there's no sync on content changes, too.
     */
    fun disableSyncAbility(account: Account, authority: String) {
        logger.fine("Disabling sync framework for account=$account, authority=$authority")
@@ -72,6 +74,9 @@ class SyncFrameworkIntegration @Inject constructor(

    /**
     * Enable syncing on content (contact, calendar event or task) changes.
     *
     * This implies that the [authority] is syncable, so this method makes the [authority]
     * syncable if required.
     */
    fun enableSyncOnContentChange(account: Account, authority: String) {
        if (!isSyncable(account, authority))
Loading