1
0
mirror of https://github.com/etesync/android synced 2024-11-15 20:38:58 +00:00

CalendarSyncAdapter: implement syncing etebase calendars.

This commit is contained in:
Tom Hacohen 2020-08-26 07:34:51 +03:00
parent 2069e9b215
commit 1c284bce91
2 changed files with 95 additions and 6 deletions

View File

@ -13,11 +13,13 @@ import android.content.ContentProviderClient
import android.content.ContentProviderOperation
import android.content.ContentUris
import android.content.ContentValues
import android.graphics.Color.parseColor
import android.net.Uri
import android.os.RemoteException
import android.provider.CalendarContract
import android.provider.CalendarContract.*
import at.bitfire.ical4android.*
import com.etesync.syncadapter.CachedCollection
import com.etesync.syncadapter.log.Logger
import com.etesync.syncadapter.model.JournalEntity
import org.apache.commons.lang3.StringUtils
@ -50,6 +52,21 @@ class LocalCalendar private constructor(
return AndroidCalendar.create(account, provider, values)
}
fun create(account: Account, provider: ContentProviderClient, cachedCollection: CachedCollection): Uri {
val values = valuesFromCachedCollection(cachedCollection, true)
// ACCOUNT_NAME and ACCOUNT_TYPE are required (see docs)! If it's missing, other apps will crash.
values.put(Calendars.ACCOUNT_NAME, account.name)
values.put(Calendars.ACCOUNT_TYPE, account.type)
values.put(Calendars.OWNER_ACCOUNT, account.name)
// flag as visible & synchronizable at creation, might be changed by user at any time
values.put(Calendars.VISIBLE, 1)
values.put(Calendars.SYNC_EVENTS, 1)
return AndroidCalendar.create(account, provider, values)
}
fun findByName(account: Account, provider: ContentProviderClient, factory: Factory, name: String): LocalCalendar?
= AndroidCalendar.find(account, provider, factory, Calendars.NAME + "==?", arrayOf(name)).firstOrNull()
@ -85,6 +102,30 @@ class LocalCalendar private constructor(
values.put(Calendars.ALLOWED_ATTENDEE_TYPES, StringUtils.join(intArrayOf(CalendarContract.Attendees.TYPE_OPTIONAL, CalendarContract.Attendees.TYPE_REQUIRED, CalendarContract.Attendees.TYPE_RESOURCE), ", "))
return values
}
private fun valuesFromCachedCollection(cachedCollection: CachedCollection, withColor: Boolean): ContentValues {
val values = ContentValues()
val col = cachedCollection.col
val meta = cachedCollection.meta
values.put(Calendars.NAME, col.uid)
values.put(Calendars.CALENDAR_DISPLAY_NAME, meta.name)
if (withColor)
values.put(Calendars.CALENDAR_COLOR, if (!meta.color.isNullOrBlank()) parseColor(meta.color) else defaultColor)
if (col.accessLevel == "ro")
values.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_READ)
else {
values.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER)
values.put(Calendars.CAN_MODIFY_TIME_ZONE, 1)
values.put(Calendars.CAN_ORGANIZER_RESPOND, 1)
}
values.put(Calendars.ALLOWED_REMINDERS, Reminders.METHOD_ALERT)
values.put(Calendars.ALLOWED_AVAILABILITY, StringUtils.join(intArrayOf(Reminders.AVAILABILITY_TENTATIVE, Reminders.AVAILABILITY_FREE, Reminders.AVAILABILITY_BUSY), ","))
values.put(Calendars.ALLOWED_ATTENDEE_TYPES, StringUtils.join(intArrayOf(CalendarContract.Attendees.TYPE_OPTIONAL, CalendarContract.Attendees.TYPE_REQUIRED, CalendarContract.Attendees.TYPE_RESOURCE), ", "))
return values
}
}
override val url: String?
@ -93,6 +134,9 @@ class LocalCalendar private constructor(
fun update(journalEntity: JournalEntity, updateColor: Boolean) =
update(valuesFromCollectionInfo(journalEntity, updateColor))
fun update(cachedCollection: CachedCollection, updateColor: Boolean) =
update(valuesFromCachedCollection(cachedCollection, updateColor))
override fun findDeleted() =
queryEvents("${Events.DELETED}!=0 AND ${Events.ORIGINAL_ID} IS NULL", null)

View File

@ -13,10 +13,7 @@ import android.os.Bundle
import android.provider.CalendarContract
import at.bitfire.ical4android.AndroidCalendar
import at.bitfire.ical4android.CalendarStorageException
import com.etesync.syncadapter.AccountSettings
import com.etesync.syncadapter.App
import com.etesync.syncadapter.Constants
import com.etesync.syncadapter.R
import com.etesync.syncadapter.*
import com.etesync.syncadapter.log.Logger
import com.etesync.syncadapter.model.CollectionInfo
import com.etesync.syncadapter.model.JournalEntity
@ -42,7 +39,11 @@ class CalendarsSyncAdapterService : SyncAdapterService() {
RefreshCollections(account, CollectionInfo.Type.CALENDAR).run()
updateLocalCalendars(provider, account, settings)
if (settings.isLegacy) {
legacyUpdateLocalCalendars(provider, account, settings)
} else {
updateLocalCalendars(provider, account, settings)
}
val principal = settings.uri?.toHttpUrlOrNull()!!
@ -56,8 +57,52 @@ class CalendarsSyncAdapterService : SyncAdapterService() {
Logger.log.info("Calendar sync complete")
}
@Throws(CalendarStorageException::class)
private fun updateLocalCalendars(provider: ContentProviderClient, account: Account, settings: AccountSettings) {
val remote = HashMap<String, CachedCollection>()
val etebaseLocalCache = EtebaseLocalCache.getInstance(context, account.name)
val collections: List<CachedCollection>
synchronized(etebaseLocalCache) {
val httpClient = HttpClient.Builder(context, settings).setForeground(false).build()
val etebase = EtebaseLocalCache.getEtebase(context, httpClient.okHttpClient, settings)
val colMgr = etebase.collectionManager
collections = etebaseLocalCache.collectionList(colMgr).filter { it.meta.collectionType == Constants.ETEBASE_TYPE_CALENDAR }
}
for (collection in collections) {
remote[collection.col.uid] = collection
}
val local = AndroidCalendar.find(account, provider, LocalCalendar.Factory, null, null)
val updateColors = settings.manageCalendarColors
// delete obsolete local calendar
for (calendar in local) {
val url = calendar.name
val collection = remote[url]
if (collection == null) {
Logger.log.fine("Deleting obsolete local calendar $url")
calendar.delete()
} else {
// remote CollectionInfo found for this local collection, update data
Logger.log.fine("Updating local calendar $url")
calendar.update(collection, updateColors)
// we already have a local calendar for this remote collection, don't take into consideration anymore
remote.remove(url)
}
}
// create new local calendars
for (url in remote.keys) {
val cachedCollection = remote[url]!!
Logger.log.info("Adding local calendar list $cachedCollection")
LocalCalendar.create(account, provider, cachedCollection)
}
}
@Throws(CalendarStorageException::class)
private fun legacyUpdateLocalCalendars(provider: ContentProviderClient, account: Account, settings: AccountSettings) {
val data = (context.applicationContext as App).data
val service = JournalModel.Service.fetchOrCreate(data, account.name, CollectionInfo.Type.CALENDAR)