mirror of
https://github.com/bitfireAT/davx5-ose
synced 2024-07-23 11:39:15 +00:00
Check sync workers properly (closes bitfireAT/davx5#217) (bitfireAT/davx5#220)
* check sync workers properly * Move utils around * Merge live data, instead of observing in view, to recalculate account list. * Update LiveData with same value * Remove unused context property. --------- Co-authored-by: Ricki Hirner <hirner@bitfire.at>
This commit is contained in:
parent
fe7a928064
commit
9fee782968
|
@ -12,11 +12,11 @@ import at.bitfire.dav4jvm.DavCollection
|
|||
import at.bitfire.dav4jvm.MultiResponseCallback
|
||||
import at.bitfire.dav4jvm.Response
|
||||
import at.bitfire.dav4jvm.property.GetCTag
|
||||
import at.bitfire.davdroid.util.DavUtils
|
||||
import at.bitfire.davdroid.HttpClient
|
||||
import at.bitfire.davdroid.db.SyncState
|
||||
import at.bitfire.davdroid.resource.LocalResource
|
||||
import at.bitfire.davdroid.settings.AccountSettings
|
||||
import at.bitfire.davdroid.util.DavUtils
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
|
|
|
@ -14,14 +14,14 @@ import android.provider.ContactsContract.CommonDataKinds.GroupMembership
|
|||
import android.provider.ContactsContract.Groups
|
||||
import android.provider.ContactsContract.RawContacts
|
||||
import android.util.Base64
|
||||
import at.bitfire.davdroid.util.DavUtils
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.db.Collection
|
||||
import at.bitfire.davdroid.db.SyncState
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.settings.AccountSettings
|
||||
import at.bitfire.davdroid.syncadapter.AccountUtils
|
||||
import at.bitfire.davdroid.syncadapter.SyncUtils
|
||||
import at.bitfire.davdroid.syncadapter.SyncUtils.removePeriodicSyncs
|
||||
import at.bitfire.davdroid.util.DavUtils
|
||||
import at.bitfire.vcard4android.*
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.util.*
|
||||
|
@ -287,7 +287,7 @@ open class LocalAddressBook(
|
|||
ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1)
|
||||
if (!ContentResolver.getSyncAutomatically(account, ContactsContract.AUTHORITY))
|
||||
ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true)
|
||||
SyncUtils.removePeriodicSyncs(account, ContactsContract.AUTHORITY)
|
||||
removePeriodicSyncs(account, ContactsContract.AUTHORITY)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.preference.PreferenceManager
|
||||
import at.bitfire.davdroid.InvalidAccountException
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.util.closeCompat
|
||||
import at.bitfire.davdroid.db.AppDatabase
|
||||
import at.bitfire.davdroid.db.Collection
|
||||
import at.bitfire.davdroid.db.Credentials
|
||||
|
@ -33,6 +32,7 @@ import at.bitfire.davdroid.resource.LocalAddressBook
|
|||
import at.bitfire.davdroid.resource.LocalTask
|
||||
import at.bitfire.davdroid.resource.TaskUtils
|
||||
import at.bitfire.davdroid.syncadapter.SyncUtils
|
||||
import at.bitfire.davdroid.util.closeCompat
|
||||
import at.bitfire.ical4android.AndroidCalendar
|
||||
import at.bitfire.ical4android.AndroidEvent
|
||||
import at.bitfire.ical4android.TaskProvider
|
||||
|
|
|
@ -13,7 +13,6 @@ import android.content.SyncResult
|
|||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import at.bitfire.davdroid.HttpClient
|
||||
import at.bitfire.davdroid.db.AppDatabase
|
||||
import at.bitfire.davdroid.db.Collection
|
||||
import at.bitfire.davdroid.db.Service
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/***************************************************************************************************
|
||||
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
|
||||
**************************************************************************************************/
|
||||
|
||||
package at.bitfire.davdroid.syncadapter
|
||||
|
||||
import android.accounts.Account
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.provider.ContactsContract
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkQuery
|
||||
import at.bitfire.davdroid.resource.LocalAddressBook
|
||||
|
||||
enum class SyncStatus {
|
||||
ACTIVE, PENDING, IDLE;
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Returns the sync status of a given account. Checks the account itself and possible
|
||||
* sub-accounts (address book accounts).
|
||||
*
|
||||
* @param authorities sync authorities to check (usually taken from [syncAuthorities])
|
||||
*
|
||||
* @return sync status of the given account
|
||||
*/
|
||||
fun fromAccount(context: Context, authorities: Iterable<String>, account: Account): SyncStatus {
|
||||
// check sync framework syncs are active or pending
|
||||
if (authorities.any { ContentResolver.isSyncActive(account, it) })
|
||||
return SyncStatus.ACTIVE
|
||||
val addrBookAccounts = LocalAddressBook.findAll(context, null, account).map { it.account }
|
||||
if (addrBookAccounts.any { ContentResolver.isSyncActive(it, ContactsContract.AUTHORITY) })
|
||||
return SyncStatus.ACTIVE
|
||||
if (authorities.any { ContentResolver.isSyncPending(account, it) } ||
|
||||
addrBookAccounts.any { ContentResolver.isSyncPending(it, ContactsContract.AUTHORITY) })
|
||||
return SyncStatus.PENDING
|
||||
|
||||
// Also check SyncWorkers
|
||||
val workerNames = authorities.map { authority ->
|
||||
SyncWorker.workerName(account, authority)
|
||||
}
|
||||
val workQuery = WorkQuery.Builder
|
||||
.fromUniqueWorkNames(workerNames)
|
||||
.addStates(listOf(WorkInfo.State.RUNNING, WorkInfo.State.ENQUEUED))
|
||||
.build()
|
||||
val workInfos = WorkManager.getInstance(context).getWorkInfos(workQuery).get()
|
||||
when {
|
||||
workInfos.any { workInfo ->
|
||||
workInfo.state == WorkInfo.State.RUNNING
|
||||
} -> return SyncStatus.ACTIVE
|
||||
|
||||
workInfos.any { workInfo ->
|
||||
workInfo.state == WorkInfo.State.ENQUEUED
|
||||
} -> return SyncStatus.PENDING
|
||||
}
|
||||
|
||||
// None active or pending? Then we're idle ..
|
||||
return SyncStatus.IDLE
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -14,11 +14,11 @@ import android.content.pm.PackageManager
|
|||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.CalendarContract
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import at.bitfire.davdroid.InvalidAccountException
|
||||
import at.bitfire.davdroid.util.PermissionUtils
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.db.AppDatabase
|
||||
import at.bitfire.davdroid.db.Service
|
||||
|
@ -29,12 +29,16 @@ import at.bitfire.davdroid.settings.Settings
|
|||
import at.bitfire.davdroid.settings.SettingsManager
|
||||
import at.bitfire.davdroid.ui.NotificationUtils
|
||||
import at.bitfire.davdroid.ui.NotificationUtils.notifyIfPossible
|
||||
import at.bitfire.davdroid.util.PermissionUtils
|
||||
import at.bitfire.ical4android.TaskProvider
|
||||
import dagger.hilt.EntryPoint
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
/**
|
||||
* Utility methods related to synchronization management (authorities, workers etc.)
|
||||
*/
|
||||
object SyncUtils {
|
||||
|
||||
@EntryPoint
|
||||
|
@ -89,6 +93,29 @@ object SyncUtils {
|
|||
ContentResolver.removePeriodicSync(sync.account, sync.authority, sync.extras)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all available sync authorities for main accounts (!= address book accounts):
|
||||
*
|
||||
* 1. address books authority (not [ContactsContract.AUTHORITY], but the one which manages address book accounts)
|
||||
* 1. calendar authority
|
||||
* 1. tasks authority (if available)
|
||||
*
|
||||
* Checking the availability of authorities may be relatively expensive, so the
|
||||
* result should be cached for the current operation.
|
||||
*
|
||||
* @return list of available sync authorities for main accounts
|
||||
*/
|
||||
fun syncAuthorities(context: Context): List<String> {
|
||||
val result = mutableListOf(
|
||||
context.getString(R.string.address_books_authority),
|
||||
CalendarContract.AUTHORITY
|
||||
)
|
||||
TaskUtils.currentProvider(context)?.let { taskProvider ->
|
||||
result += taskProvider.authority
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
// task sync utils
|
||||
|
||||
|
|
|
@ -15,12 +15,12 @@ import android.provider.ContactsContract
|
|||
import androidx.concurrent.futures.CallbackToFutureAdapter
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.hilt.work.HiltWorker
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import androidx.work.*
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.ui.NotificationUtils
|
||||
import at.bitfire.davdroid.util.DavUtils
|
||||
import at.bitfire.davdroid.util.LiveDataUtils
|
||||
import at.bitfire.davdroid.util.closeCompat
|
||||
import at.bitfire.ical4android.TaskProvider
|
||||
|
@ -55,7 +55,7 @@ class SyncWorker @AssistedInject constructor(
|
|||
* @param account account to sync
|
||||
*/
|
||||
fun requestSync(context: Context, account: Account) {
|
||||
for (authority in DavUtils.syncAuthorities(context))
|
||||
for (authority in SyncUtils.syncAuthorities(context))
|
||||
requestSync(context, account, authority)
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ class SyncWorker @AssistedInject constructor(
|
|||
* @param authorities type of sync work
|
||||
* @return boolean *true* if at least one worker with matching state was found; *false* otherwise
|
||||
*/
|
||||
fun isSomeWorkerInState(context: Context, workState: WorkInfo.State, account: Account, authorities: List<String>) =
|
||||
fun existsForAccount(context: Context, workState: WorkInfo.State, account: Account, authorities: List<String>) =
|
||||
LiveDataUtils.liveDataLogicOr(
|
||||
authorities.map { authority -> isWorkerInState(context, workState, account, authority) }
|
||||
)
|
||||
|
@ -107,6 +107,21 @@ class SyncWorker @AssistedInject constructor(
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds out whether SyncWorkers with given statuses exist
|
||||
*
|
||||
* @param statuses statuses to check
|
||||
* @return whether SyncWorkers matching the statuses were found
|
||||
*/
|
||||
fun existsWithStatuses(context: Context, statuses: List<WorkInfo.State>): LiveData<Boolean> {
|
||||
val workQuery = WorkQuery.Builder
|
||||
.fromStates(statuses)
|
||||
.build()
|
||||
return Transformations.map(
|
||||
WorkManager.getInstance(context).getWorkInfosLiveData(workQuery)
|
||||
) { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ import android.content.SyncResult
|
|||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import at.bitfire.davdroid.HttpClient
|
||||
import at.bitfire.davdroid.db.AppDatabase
|
||||
import at.bitfire.davdroid.db.Collection
|
||||
import at.bitfire.davdroid.db.Service
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
|
|
|
@ -10,27 +10,33 @@ import android.accounts.AccountManager
|
|||
import android.accounts.OnAccountsUpdateListener
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.content.*
|
||||
import android.content.ContentResolver
|
||||
import android.content.Intent
|
||||
import android.content.SyncStatusObserver
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.*
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.view.*
|
||||
import androidx.annotation.AnyThread
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import at.bitfire.davdroid.util.DavUtils
|
||||
import at.bitfire.davdroid.util.DavUtils.SyncStatus
|
||||
import androidx.work.WorkInfo
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.databinding.AccountListBinding
|
||||
import at.bitfire.davdroid.databinding.AccountListItemBinding
|
||||
import at.bitfire.davdroid.syncadapter.SyncStatus
|
||||
import at.bitfire.davdroid.syncadapter.SyncUtils
|
||||
import at.bitfire.davdroid.syncadapter.SyncWorker
|
||||
import at.bitfire.davdroid.ui.account.AccountActivity
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
|
@ -108,6 +114,7 @@ class AccountListFragment: Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
// Accounts adapter
|
||||
val accountAdapter = AccountAdapter(requireActivity())
|
||||
binding.list.apply {
|
||||
layoutManager = LinearLayoutManager(requireActivity())
|
||||
|
@ -222,9 +229,39 @@ class AccountListFragment: Fragment() {
|
|||
val storageLow = warnings.storageLow
|
||||
|
||||
// Accounts
|
||||
val accounts = MutableLiveData<List<AccountInfo>>()
|
||||
private val accountsUpdated = MutableLiveData<Boolean>()
|
||||
private val syncFrameworkStatusChanged = MutableLiveData<Boolean>()
|
||||
private val syncWorkersActive = SyncWorker.existsWithStatuses(
|
||||
application.applicationContext, listOf(WorkInfo.State.RUNNING))
|
||||
|
||||
val accounts = object : MediatorLiveData<List<AccountInfo>>() {
|
||||
init {
|
||||
addSource(accountsUpdated) { recalculate() }
|
||||
addSource(syncFrameworkStatusChanged) { recalculate() }
|
||||
addSource(syncWorkersActive) { recalculate() }
|
||||
}
|
||||
|
||||
fun recalculate() {
|
||||
val context = getApplication<Application>()
|
||||
val collator = Collator.getInstance()
|
||||
|
||||
val sortedAccounts = accountManager
|
||||
.getAccountsByType(context.getString(R.string.account_type))
|
||||
.sortedArrayWith { a, b ->
|
||||
collator.compare(a.name, b.name)
|
||||
}
|
||||
val accountsWithInfo = sortedAccounts.map { account ->
|
||||
AccountInfo(
|
||||
account,
|
||||
SyncStatus.fromAccount(context, syncAuthorities, account)
|
||||
)
|
||||
}
|
||||
value = accountsWithInfo
|
||||
}
|
||||
}
|
||||
|
||||
private val accountManager = AccountManager.get(application)!!
|
||||
private val syncAuthorities by lazy { DavUtils.syncAuthorities(application) }
|
||||
private val syncAuthorities by lazy { SyncUtils.syncAuthorities(application) }
|
||||
|
||||
init {
|
||||
// watch accounts
|
||||
|
@ -237,30 +274,14 @@ class AccountListFragment: Fragment() {
|
|||
)
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
override fun onAccountsUpdated(newAccounts: Array<out Account>) {
|
||||
reloadAccounts()
|
||||
accountsUpdated.postValue(true)
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
override fun onStatusChanged(which: Int) {
|
||||
reloadAccounts()
|
||||
}
|
||||
|
||||
private fun reloadAccounts() {
|
||||
val context = getApplication<Application>()
|
||||
val collator = Collator.getInstance()
|
||||
|
||||
val sortedAccounts = accountManager
|
||||
.getAccountsByType(context.getString(R.string.account_type))
|
||||
.sortedArrayWith { a, b ->
|
||||
collator.compare(a.name, b.name)
|
||||
}
|
||||
val accountsWithInfo = sortedAccounts.map { account ->
|
||||
AccountInfo(
|
||||
account,
|
||||
DavUtils.accountSyncStatus(context, syncAuthorities, account)
|
||||
)
|
||||
}
|
||||
accounts.postValue(accountsWithInfo)
|
||||
syncFrameworkStatusChanged.postValue(true)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
|
|
|
@ -316,11 +316,11 @@ abstract class CollectionsFragment: Fragment(), SwipeRefreshLayout.OnRefreshList
|
|||
listOf(context.getString(R.string.address_books_authority), ContactsContract.AUTHORITY)
|
||||
else
|
||||
listOf(CalendarContract.AUTHORITY, taskProvider?.authority).filterNotNull()
|
||||
private val isSyncWorkerRunning = SyncWorker.isSomeWorkerInState(context,
|
||||
private val isSyncWorkerRunning = SyncWorker.existsForAccount(context,
|
||||
WorkInfo.State.RUNNING,
|
||||
accountModel.account,
|
||||
authorities)
|
||||
private val isSyncWorkerEnqueued = SyncWorker.isSomeWorkerInState(context,
|
||||
private val isSyncWorkerEnqueued = SyncWorker.existsForAccount(context,
|
||||
WorkInfo.State.ENQUEUED,
|
||||
accountModel.account,
|
||||
authorities)
|
||||
|
|
|
@ -4,21 +4,12 @@
|
|||
|
||||
package at.bitfire.davdroid.util
|
||||
|
||||
import android.accounts.Account
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.Build
|
||||
import android.provider.CalendarContract
|
||||
import android.provider.ContactsContract
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.work.WorkInfo
|
||||
import at.bitfire.davdroid.Android10Resolver
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.resource.LocalAddressBook
|
||||
import at.bitfire.davdroid.resource.TaskUtils
|
||||
import at.bitfire.davdroid.syncadapter.SyncWorker
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
|
@ -27,14 +18,10 @@ import java.net.InetAddress
|
|||
import java.util.*
|
||||
|
||||
/**
|
||||
* Some WebDAV and related network utility methods
|
||||
*/
|
||||
* Some WebDAV and HTTP network utility methods.
|
||||
*/
|
||||
object DavUtils {
|
||||
|
||||
enum class SyncStatus {
|
||||
ACTIVE, PENDING, IDLE
|
||||
}
|
||||
|
||||
val DNS_QUAD9 = InetAddress.getByAddress(byteArrayOf(9,9,9,9))
|
||||
|
||||
const val MIME_TYPE_ACCEPT_ALL = "*/*"
|
||||
|
@ -51,7 +38,6 @@ object DavUtils {
|
|||
return String.format(Locale.ROOT, "#%06X%02X", color, alpha)
|
||||
}
|
||||
|
||||
|
||||
fun lastSegmentOfUrl(url: HttpUrl): String {
|
||||
// the list returned by HttpUrl.pathSegments() is unmodifiable, so we have to create a copy
|
||||
val segments = LinkedList(url.pathSegments)
|
||||
|
@ -60,7 +46,6 @@ object DavUtils {
|
|||
return segments.firstOrNull { it.isNotEmpty() } ?: "/"
|
||||
}
|
||||
|
||||
|
||||
fun prepareLookup(context: Context, lookup: Lookup) {
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
/* Since Android 10, there's a native DnsResolver API that allows to send SRV queries without
|
||||
|
@ -164,66 +149,6 @@ object DavUtils {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sync status of a given account. Checks the account itself and possible
|
||||
* sub-accounts (address book accounts).
|
||||
*
|
||||
* @param authorities sync authorities to check (usually taken from [syncAuthorities])
|
||||
*
|
||||
* @return sync status of the given account
|
||||
*/
|
||||
fun accountSyncStatus(context: Context, authorities: Iterable<String>, account: Account): SyncStatus {
|
||||
// check active syncs
|
||||
if (authorities.any { ContentResolver.isSyncActive(account, it) })
|
||||
return SyncStatus.ACTIVE
|
||||
|
||||
val addrBookAccounts = LocalAddressBook.findAll(context, null, account).map { it.account }
|
||||
if (addrBookAccounts.any { ContentResolver.isSyncActive(it, ContactsContract.AUTHORITY) })
|
||||
return SyncStatus.ACTIVE
|
||||
|
||||
// check pending syncs
|
||||
if (authorities.any { ContentResolver.isSyncPending(account, it) } ||
|
||||
addrBookAccounts.any { ContentResolver.isSyncPending(it, ContactsContract.AUTHORITY) })
|
||||
return SyncStatus.PENDING
|
||||
|
||||
// Also check SyncWorkers
|
||||
val pending = SyncWorker.isSomeWorkerInState(context, WorkInfo.State.ENQUEUED, account, authorities.toList()).value
|
||||
if (pending != null && pending == true)
|
||||
return SyncStatus.PENDING
|
||||
val running = SyncWorker.isSomeWorkerInState(context, WorkInfo.State.RUNNING, account, authorities.toList()).value
|
||||
if (running != null && running == true)
|
||||
return SyncStatus.ACTIVE
|
||||
|
||||
return SyncStatus.IDLE
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of all available sync authorities for main accounts (!= address book accounts):
|
||||
*
|
||||
* 1. address books authority (not [ContactsContract.AUTHORITY], but the one which manages address book accounts)
|
||||
* 1. calendar authority
|
||||
* 1. tasks authority (if available)
|
||||
*
|
||||
* Checking the availability of authorities may be relatively expensive, so the
|
||||
* result should be cached for the current operation.
|
||||
*
|
||||
* @return list of available sync authorities for main accounts
|
||||
*/
|
||||
fun syncAuthorities(context: Context): List<String> {
|
||||
val result = mutableListOf(
|
||||
context.getString(R.string.address_books_authority),
|
||||
CalendarContract.AUTHORITY
|
||||
)
|
||||
|
||||
TaskUtils.currentProvider(context)?.let { taskProvider ->
|
||||
result += taskProvider.authority
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
// extension methods
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue