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

Verified Commit cac30678 authored by Fahim M. Choudhury's avatar Fahim M. Choudhury
Browse files

fix: preserve sync enabled/disabled state and sync intervals during SSO migration

When migrating a non-SSO Murena account to use SSO, the sync settings for eDrive, Mail, Notes, Contacts, Calendar, and Tasks were not fully preserved. The sync intervals for Contacts, Calendar and Tasks were also being reset.

To fix this, when an account is migrated to SSO, the following settings are now carried over from the old account to the new one:
- Sync enabled/disabled status for eDrive, Mail, Notes, Contacts, Calendar, and Tasks
- Sync interval for Contacts, Calendar, and Tasks.
- Group method for Contacts.

If it's a new account setup, default sync settings will be applied.

Additionally, the logic for handling CardDAV and CalDAV services during account setup has been updated to:
- For existing accounts being migrated: Update the existing service record in the database with the new authentication state and principal.
- For new accounts: Create a new service record.

This commit also fixed the issue where the sync settings for Contacts, Calendar and Tasks were reset after a device reboot.
parent 7bdc8381
Loading
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -342,7 +342,7 @@ class AccountSettings(
     * @throws IllegalArgumentException when [seconds] is not [SYNC_INTERVAL_MANUALLY] but less than 15 min
     */
    @WorkerThread
    fun setSyncInterval(authority: String, argSeconds: Long): Boolean {
    fun setSyncInterval(authority: String, argSeconds: Long, setAutomaticSync: Boolean = true): Boolean {
        var seconds = argSeconds

        if (seconds != SYNC_INTERVAL_MANUALLY && seconds < 60*15) {
@@ -369,7 +369,9 @@ class AccountSettings(

        // Also enable/disable content change triggered syncs (SyncFramework automatic sync).
        // We could make this a separate user adjustable setting later on.
        if (setAutomaticSync) {
            setSyncOnContentChange(authority, seconds != SYNC_INTERVAL_MANUALLY)
        }

        return true
    }
@@ -626,6 +628,10 @@ class AccountSettings(
            return
        }

        if (!ContentResolver.getSyncAutomatically(account, authority)) {
            return
        }

        if (authority !in getPeriodicSyncEnableAuthorities()) {
            return
        }
+197 −46
Original line number Diff line number Diff line
@@ -406,23 +406,148 @@ class AccountDetailsFragment : Fragment() {
                    accountManager.setPassword(account, credentials?.password)
                }

                // Account sync settings for eDrive
                var mediaSyncEnabled = true
                var appDataSyncEnabled = true
                var meteredEdriveSyncEnabled = true

                ContentResolver.setSyncAutomatically(account, context.getString(R.string.notes_authority), true)
                ContentResolver.setSyncAutomatically(account, context.getString(R.string.email_authority), true)
                ContentResolver.setSyncAutomatically(account, context.getString(R.string.media_authority), true)
                ContentResolver.setSyncAutomatically(account, context.getString(R.string.app_data_authority), true)
                ContentResolver.setSyncAutomatically(account, context.getString(R.string.metered_edrive_authority), true)
                // Account sync settings for other apps
                var notesSyncEnabled = true
                var emailSyncEnabled = true
                var contactsSyncable = 1
                var calendarSyncable = 1
                var tasksSyncable = 1

                var contactsGroupMethod = groupMethod

                // Sync interval
                val defaultSyncInterval = Constants.DEFAULT_CALENDAR_SYNC_INTERVAL
                var contactsSyncInterval = defaultSyncInterval
                var calendarSyncInterval = defaultSyncInterval
                var tasksSyncInterval = defaultSyncInterval

                var contactsSyncEnabled = true
                var calendarSyncEnabled = true
                var tasksSyncEnabled = true

                if (accountToUpdate != null) {
                    val oldSettings = AccountSettings(context, accountToUpdate)
                    val addressBookAuthority = context.getString(R.string.address_books_authority)
                    val taskProvider = TaskUtils.currentProvider(context)

                    mediaSyncEnabled = ContentResolver.getSyncAutomatically(
                        accountToUpdate,
                        context.getString(R.string.media_authority)
                    )
                    appDataSyncEnabled = ContentResolver.getSyncAutomatically(
                        accountToUpdate,
                        context.getString(R.string.app_data_authority)
                    )
                    meteredEdriveSyncEnabled = ContentResolver.getSyncAutomatically(
                        accountToUpdate,
                        context.getString(R.string.metered_edrive_authority)
                    )

                    notesSyncEnabled = ContentResolver.getSyncAutomatically(
                        accountToUpdate,
                        context.getString(R.string.notes_authority)
                    )
                    emailSyncEnabled = ContentResolver.getSyncAutomatically(
                        accountToUpdate,
                        context.getString(R.string.email_authority)
                    )

                    // --- Contacts sync logic ---
                    contactsSyncable =
                        ContentResolver.getIsSyncable(accountToUpdate, addressBookAuthority)
                    val oldContactsSyncInterval = oldSettings.getSyncInterval(addressBookAuthority)
                    contactsSyncEnabled =
                        ContentResolver.getSyncAutomatically(accountToUpdate, addressBookAuthority)

                    contactsSyncInterval = when {
                        contactsSyncEnabled -> oldContactsSyncInterval ?: defaultSyncInterval
                        oldContactsSyncInterval != null -> oldContactsSyncInterval
                        else -> AccountSettings.SYNC_INTERVAL_MANUALLY
                    }
                    contactsGroupMethod = oldSettings.getGroupMethod()

                    // --- Calendar sync logic ---
                    calendarSyncable =
                        ContentResolver.getIsSyncable(accountToUpdate, CalendarContract.AUTHORITY)
                    val oldCalendarSyncInterval =
                        oldSettings.getSyncInterval(CalendarContract.AUTHORITY)
                    calendarSyncEnabled = ContentResolver.getSyncAutomatically(
                        accountToUpdate,
                        CalendarContract.AUTHORITY
                    )
                    calendarSyncInterval = when {
                        calendarSyncEnabled -> oldCalendarSyncInterval ?: defaultSyncInterval
                        oldCalendarSyncInterval != null -> oldCalendarSyncInterval
                        else -> AccountSettings.SYNC_INTERVAL_MANUALLY
                    }

                    // --- Tasks sync logic ---
                    if (taskProvider != null) {
                        tasksSyncable =
                            ContentResolver.getIsSyncable(accountToUpdate, taskProvider.authority)
                        tasksSyncEnabled =
                            ContentResolver.getSyncAutomatically(accountToUpdate, taskProvider.authority)
                        val oldTasksSyncInterval =
                            oldSettings.getSyncInterval(taskProvider.authority)

                        tasksSyncInterval = when {
                            tasksSyncEnabled -> oldTasksSyncInterval ?: defaultSyncInterval
                            oldTasksSyncInterval != null -> oldTasksSyncInterval
                            else -> AccountSettings.SYNC_INTERVAL_MANUALLY
                        }
                    }
                }

                ContentResolver.setSyncAutomatically(
                    account,
                    context.getString(R.string.notes_authority),
                    notesSyncEnabled
                )
                ContentResolver.setSyncAutomatically(
                    account,
                    context.getString(R.string.email_authority),
                    emailSyncEnabled
                )
                ContentResolver.setSyncAutomatically(
                    account,
                    context.getString(R.string.media_authority),
                    mediaSyncEnabled
                )
                ContentResolver.setSyncAutomatically(
                    account,
                    context.getString(R.string.app_data_authority),
                    appDataSyncEnabled
                )
                ContentResolver.setSyncAutomatically(
                    account,
                    context.getString(R.string.metered_edrive_authority),
                    meteredEdriveSyncEnabled
                )

                // add entries for account to service DB
                Logger.log.log(Level.INFO, "Writing account configuration to database", config)
                try {
                    val accountSettings = AccountSettings(context, account)
                    val defaultSyncInterval = Constants.DEFAULT_CALENDAR_SYNC_INTERVAL

                    // Configure CardDAV service
                    val addrBookAuthority = context.getString(R.string.address_books_authority)
                    val addressBookAuthority = context.getString(R.string.address_books_authority)
                    if (config.cardDAV != null) {
                        // insert CardDAV service
                        if (accountToUpdate != null) {
                            // Migration: update existing service
                            val service = db.serviceDao().getByAccountAndType(accountToUpdate.name, Service.TYPE_CARDDAV)
                            service?.let {
                                it.authState = credentials?.authState?.jsonSerializeString()
                                it.principal = config.cardDAV.principal
                                db.serviceDao().insertOrReplace(it)
                                RefreshCollectionsWorker.refreshCollections(context, it.id)
                            }
                        } else {
                            // New account: create new service
                            val id = insertService(
                                credentials?.userName ?: "",
                                credentials?.authState?.jsonSerializeString(),
@@ -431,22 +556,36 @@ class AccountDetailsFragment : Fragment() {
                                Service.TYPE_CARDDAV,
                                config.cardDAV
                            )

                        // initial CardDAV account settings
                        accountSettings.setGroupMethod(groupMethod)

                        // start CardDAV service detection (refresh collections)
                            accountSettings.setGroupMethod(contactsGroupMethod)
                            ContentResolver.setIsSyncable(account, addressBookAuthority, contactsSyncable)
                            RefreshCollectionsWorker.refreshCollections(context, id)
                        }

                        // set default sync interval and enable sync regardless of permissions
                        ContentResolver.setIsSyncable(account, addrBookAuthority, 1)
                        accountSettings.setSyncInterval(addrBookAuthority, defaultSyncInterval)
                    } else
                        ContentResolver.setIsSyncable(account, addrBookAuthority, 0)
                        // set sync settings
                        ContentResolver.setSyncAutomatically(
                            account,
                            addressBookAuthority,
                            contactsSyncEnabled
                        )
                        accountSettings.setSyncInterval(addressBookAuthority, contactsSyncInterval, false)

                    } else {
                        ContentResolver.setIsSyncable(account, addressBookAuthority, 0)
                    }

                    // Configure CalDAV service
                    if (config.calDAV != null) {
                        // insert CalDAV service
                        if (accountToUpdate != null) {
                            // Migration: update existing service
                            val service = db.serviceDao().getByAccountAndType(accountToUpdate.name, Service.TYPE_CALDAV)
                            service?.let {
                                it.authState = credentials?.authState?.jsonSerializeString()
                                it.principal = config.calDAV.principal
                                db.serviceDao().insertOrReplace(it)
                                RefreshCollectionsWorker.refreshCollections(context, it.id)
                            }
                        } else {
                            // New account: create new service
                            val id = insertService(
                                credentials?.userName ?: "",
                                credentials?.authState?.jsonSerializeString(),
@@ -455,25 +594,37 @@ class AccountDetailsFragment : Fragment() {
                                Service.TYPE_CALDAV,
                                config.calDAV
                            )

                        // start CalDAV service detection (refresh collections)
                            ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, calendarSyncable)
                            RefreshCollectionsWorker.refreshCollections(context, id)
                        }

                        // set default sync interval and enable sync regardless of permissions
                        ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 1)
                        accountSettings.setSyncInterval(CalendarContract.AUTHORITY, defaultSyncInterval)
                        // set sync settings
                        ContentResolver.setSyncAutomatically(
                            account,
                            CalendarContract.AUTHORITY,
                            calendarSyncEnabled
                        )
                        accountSettings.setSyncInterval(CalendarContract.AUTHORITY, calendarSyncInterval, false)

                        // if task provider present, set task sync interval and enable sync
                        val taskProvider = TaskUtils.currentProvider(context)
                        if (taskProvider != null) {
                            ContentResolver.setIsSyncable(account, taskProvider.authority, 1)
                            accountSettings.setSyncInterval(taskProvider.authority, defaultSyncInterval)
                            // further changes will be handled by TasksWatcher on app start or when tasks app is (un)installed
                            if (accountToUpdate == null)
                                ContentResolver.setIsSyncable(account, taskProvider.authority, tasksSyncable)

                            ContentResolver.setSyncAutomatically(
                                account,
                                taskProvider.authority,
                                tasksSyncEnabled
                            )
                            accountSettings.setSyncInterval(taskProvider.authority, tasksSyncInterval, false)
                            Logger.log.info("Tasks provider ${taskProvider.authority} found. Tasks sync enabled.")
                        } else
                        } else {
                            Logger.log.info("No tasks provider found. Did not enable tasks sync.")
                    } else
                        }
                    } else {
                        ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 0)
                    }

                } catch(e: InvalidAccountException) {
                    Logger.log.log(Level.SEVERE, "Couldn't access account settings", e)