/* * Copyright © 2013 – 2015 Ricki Hirner (bitfire web engineering). * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package com.etesync.syncadapter.resource import android.content.ContentProviderOperation import android.content.ContentValues import android.net.Uri import android.provider.CalendarContract import android.provider.CalendarContract.Events import android.text.TextUtils import at.bitfire.ical4android.* import at.bitfire.ical4android.Ical4Android.ical4jVersion import com.etesync.syncadapter.Constants import com.etesync.syncadapter.log.Logger import net.fortuna.ical4j.model.component.VAlarm import net.fortuna.ical4j.model.property.Action import net.fortuna.ical4j.model.property.ProdId import java.io.ByteArrayOutputStream import java.util.* import java.util.logging.Level class LocalEvent : AndroidEvent, LocalResource { companion object { init { ICalendar.prodId = ProdId(Constants.PRODID_BASE + " ical4j/" + ical4jVersion) } internal const val COLUMN_ETAG = CalendarContract.Events.SYNC_DATA1 internal const val COLUMN_UID = Events.UID_2445 internal const val COLUMN_SEQUENCE = CalendarContract.Events.SYNC_DATA3 } private var saveAsDirty = false // When true, the resource will be saved as dirty override var fileName: String? = null var eTag: String? = null var weAreOrganizer = true override val content: String get() { Logger.log.log(Level.FINE, "Preparing upload of event $fileName} ${event}") val os = ByteArrayOutputStream() event?.write(os) return os.toString() } override val isLocalOnly: Boolean get() = TextUtils.isEmpty(eTag) override// Now the same val uuid: String? get() = event?.uid constructor(calendar: AndroidCalendar<*>, event: Event, fileName: String?, eTag: String?) : super(calendar, event) { this.fileName = fileName this.eTag = eTag } protected constructor(calendar: AndroidCalendar<*>, baseInfo: ContentValues) : super(calendar, baseInfo) { fileName = baseInfo.getAsString(Events._SYNC_ID) eTag = baseInfo.getAsString(COLUMN_ETAG) } /* process LocalEvent-specific fields */ override fun populateEvent(row: ContentValues, groupScheduled: Boolean) { super.populateEvent(row, groupScheduled) fileName = row.getAsString(Events._SYNC_ID) eTag = row.getAsString(COLUMN_ETAG) event?.uid = row.getAsString(COLUMN_UID) event?.sequence = row.getAsInteger(COLUMN_SEQUENCE) val isOrganizer = row.getAsInteger(Events.IS_ORGANIZER) weAreOrganizer = isOrganizer != null && isOrganizer != 0 } override fun buildEvent(recurrence: Event?, builder: ContentProviderOperation.Builder) { super.buildEvent(recurrence, builder) val buildException = recurrence != null val eventToBuild = if (buildException) recurrence else event builder.withValue(COLUMN_UID, event?.uid) .withValue(COLUMN_SEQUENCE, eventToBuild?.sequence) .withValue(CalendarContract.Events.DIRTY, if (saveAsDirty) 1 else 0) .withValue(CalendarContract.Events.DELETED, 0) if (buildException) builder.withValue(Events.ORIGINAL_SYNC_ID, fileName) else builder.withValue(Events._SYNC_ID, fileName) .withValue(COLUMN_ETAG, eTag) } override fun insertReminder(batch: BatchOperation, idxEvent: Int, alarm: VAlarm) { // We only support DISPLAY and AUDIO alarms so modify when inserting val action = alarm.action val modifiedAlarm = when (action?.value) { Action.DISPLAY.value, Action.AUDIO.value -> alarm Action.EMAIL.value -> { val tmp = VAlarm(alarm.trigger?.duration) tmp.properties += Action.DISPLAY tmp.properties += alarm.description tmp } else -> alarm } super.insertReminder(batch, idxEvent, modifiedAlarm) } fun addAsDirty(): Uri { saveAsDirty = true return this.add() } fun updateAsDirty(event: Event): Uri { saveAsDirty = true return this.update(event) } /* custom queries */ override fun legacyPrepareForUpload(fileName_: String?) { var uid: String? = null val c = calendar.provider.query(eventSyncURI(), arrayOf(COLUMN_UID), null, null, null) if (c.moveToNext()) uid = c.getString(0) if (uid == null) uid = UUID.randomUUID().toString() c.close() val fileName = fileName_ ?: uid val values = ContentValues(2) values.put(Events._SYNC_ID, fileName) values.put(COLUMN_UID, uid) calendar.provider.update(eventSyncURI(), values, null, null) this.fileName = fileName val event = this.event if (event != null) event.uid = uid } override fun prepareForUpload(fileName: String, uid: String) { val values = ContentValues(2) values.put(Events._SYNC_ID, fileName) values.put(COLUMN_UID, uid) calendar.provider.update(eventSyncURI(), values, null, null) event?.uid = uid this.fileName = fileName } override fun resetDeleted() { val values = ContentValues(1) values.put(CalendarContract.Events.DELETED, 0) calendar.provider.update(eventSyncURI(), values, null, null) } override fun clearDirty(eTag: String?) { val values = ContentValues(2) values.put(CalendarContract.Events.DIRTY, 0) if (eTag != null) { values.put(COLUMN_ETAG, eTag) } if (event != null) values.put(COLUMN_SEQUENCE, event?.sequence) calendar.provider.update(eventSyncURI(), values, null, null) this.eTag = eTag } object Factory: AndroidEventFactory { override fun fromProvider(calendar: AndroidCalendar, values: ContentValues): LocalEvent = LocalEvent(calendar, values) } }