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

Commit 3bbc08f2 authored by Jonathan Klee's avatar Jonathan Klee
Browse files

feat: introduce SyncAdapterComponentManager

parent 94f2bdf3
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.syncadapter.AccountsUpdatedListener
import at.bitfire.davdroid.syncadapter.SyncAdapterComponentManager
import at.bitfire.davdroid.syncadapter.SyncUtils
import at.bitfire.davdroid.ui.DebugInfoActivity
import at.bitfire.davdroid.ui.NotificationUtils
@@ -100,6 +101,8 @@ class App: Application(), Thread.UncaughtExceptionHandler, Configuration.Provide

        // don't block UI for some background checks
        thread {
            SyncAdapterComponentManager.updateComponents(this)

            // watch for account changes/deletions
            accountsUpdatedListener.listen()

+3 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import at.bitfire.davdroid.murenasso.MurenaSsoMigrationService
import at.bitfire.davdroid.murenasso.MurenaSsoMigrationService.Companion.NOTIFICATION_TAG_MURENA_SSO
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.syncadapter.AccountUtils
import at.bitfire.davdroid.syncadapter.SyncAdapterComponentManager
import at.bitfire.davdroid.ui.NotificationUtils
import at.bitfire.davdroid.ui.NotificationUtils.CHANNEL_GENERAL
import at.bitfire.davdroid.ui.NotificationUtils.NOTIFY_MIGRATE_TO_MURENA_SSO
@@ -55,6 +56,8 @@ class BootCompletedReceiver: BroadcastReceiver() {
    }

    private fun initializeSync(context: Context) {
        SyncAdapterComponentManager.updateComponents(context)

        AccountUtils.getMainAccounts(context)
            .forEach {
                // sync intervals are checked in App.onCreate()
+79 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2026 e Foundation
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

package at.bitfire.davdroid.syncadapter

import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import java.util.logging.Level

object SyncAdapterComponentManager {

    private data class SyncServiceSpec(
        val serviceClass: Class<*>,
        val authorityResId: Int
    )

    private val optionalSyncServices = listOf(
        SyncServiceSpec(MurenaTasksSyncAdapterService::class.java, R.string.task_authority),
        SyncServiceSpec(MurenaNotesSyncAdapterService::class.java, R.string.notes_authority),
        SyncServiceSpec(MurenaEmailSyncAdapterService::class.java, R.string.email_authority),
        SyncServiceSpec(MurenaMediaSyncAdapterService::class.java, R.string.media_authority),
        SyncServiceSpec(MurenaAppDataSyncAdapterService::class.java, R.string.app_data_authority),
        SyncServiceSpec(MurenaMeteredEdriveSyncAdapterService::class.java, R.string.metered_edrive_authority),
        SyncServiceSpec(MurenaPasswordSyncAdapterService::class.java, R.string.password_authority),
        SyncServiceSpec(GoogleTasksSyncAdapterService::class.java, R.string.task_authority),
        SyncServiceSpec(GoogleEmailSyncAdapterService::class.java, R.string.email_authority),
        SyncServiceSpec(YahooTasksSyncAdapterService::class.java, R.string.task_authority),
        SyncServiceSpec(YahooEmailSyncAdapterService::class.java, R.string.email_authority)
    )

    fun updateComponents(context: Context) {
        val packageManager = context.packageManager

        for (syncService in optionalSyncServices) {
            val authority = context.getString(syncService.authorityResId)
            val isProviderAvailable = hasProvider(packageManager, authority)
            setComponentEnabled(packageManager, context, syncService.serviceClass, isProviderAvailable, authority)
        }
    }

    private fun hasProvider(packageManager: PackageManager, authority: String): Boolean =
        packageManager.resolveContentProvider(authority, 0) != null

    private fun setComponentEnabled(
        packageManager: PackageManager,
        context: Context,
        serviceClass: Class<*>,
        enabled: Boolean,
        authority: String
    ) {
        val component = ComponentName(context, serviceClass)
        val desiredState = if (enabled) PackageManager.COMPONENT_ENABLED_STATE_ENABLED else PackageManager.COMPONENT_ENABLED_STATE_DISABLED

        if (packageManager.getComponentEnabledSetting(component) == desiredState) {
            return
        }

        packageManager.setComponentEnabledSetting(component, desiredState, PackageManager.DONT_KILL_APP)
        Logger.log.log(Level.INFO, "Set ${serviceClass.simpleName} to ${if (enabled) "ENABLED" else "DISABLED"} (authority=$authority)")
    }
}