Loading src/androidTest/java/at/bitfire/ical4android/AndroidEventTest.kt +8 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import at.bitfire.ical4android.impl.TestEvent import net.fortuna.ical4j.model.Date import net.fortuna.ical4j.model.DateList import net.fortuna.ical4j.model.Dur import net.fortuna.ical4j.model.Property import net.fortuna.ical4j.model.component.VAlarm import net.fortuna.ical4j.model.parameter.Value import net.fortuna.ical4j.model.property.* Loading Loading @@ -115,6 +116,10 @@ class AndroidEventTest { // add EXDATE event.exDates += ExDate(DateList("20150502T120000", Value.DATE_TIME, tzVienna)) // add special properties event.unknownProperties.add(Categories("CAT1,CAT2")) event.unknownProperties.add(XProperty("X-NAME", "X-Value")) // add to calendar val uri = TestEvent(calendar, event).add() assertNotNull(uri) Loading Loading @@ -172,6 +177,9 @@ class AndroidEventTest { // compare EXDATE assertEquals(1, event2.exDates.size) assertEquals(event.exDates.first, event2.exDates.first) // compare unknown properties assertArrayEquals(event.unknownProperties.toArray(), event2.unknownProperties.toArray()) } finally { testEvent.delete() } Loading src/androidTest/java/at/bitfire/ical4android/AndroidTaskTest.kt +7 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import net.fortuna.ical4j.model.TimeZone import net.fortuna.ical4j.model.property.DtStart import net.fortuna.ical4j.model.property.Due import net.fortuna.ical4j.model.property.Organizer import net.fortuna.ical4j.model.property.XProperty import org.dmfs.tasks.contract.TaskContract import org.junit.After import org.junit.Assert.* Loading Loading @@ -77,6 +78,10 @@ class AndroidTaskTest { task.organizer = Organizer("mailto:organizer@example.com") assertFalse(task.isAllDay()) // extended properties task.categories.addAll(arrayOf("Cat1", "Cat2")) task.unknownProperties += XProperty("X-UNKNOWN-PROP", "Unknown Value") // add to task list val uri = TestTask(taskList!!, task).add() assertNotNull("Couldn't add task", uri) Loading @@ -93,6 +98,8 @@ class AndroidTaskTest { assertEquals(task.description, task2.description) assertEquals(task.location, task2.location) assertEquals(task.dtStart, task2.dtStart) assertEquals(task.categories, task2.categories) assertEquals(task.unknownProperties, task2.unknownProperties) } finally { testTask.delete() } Loading src/androidTest/java/at/bitfire/ical4android/UnknownPropertyTest.kt +7 −7 Original line number Diff line number Diff line Loading @@ -14,8 +14,8 @@ class UnknownPropertyTest { @Test @SmallTest fun testFromExtendedProperty() { val prop = AndroidEvent.UnknownProperty.fromExtendedProperty("[ \"UID\", \"PropValue\" ]") fun testFromJsonString() { val prop = UnknownProperty.fromJsonString("[ \"UID\", \"PropValue\" ]") assertTrue(prop is Uid) assertEquals("UID", prop.name) assertEquals("PropValue", prop.value) Loading @@ -23,8 +23,8 @@ class UnknownPropertyTest { @Test @SmallTest fun testFromExtendedPropertyWithParameters() { val prop = AndroidEvent.UnknownProperty.fromExtendedProperty("[ \"ATTENDEE\", \"PropValue\", { \"x-param1\": \"value1\", \"x-param2\": \"value2\" } ]") fun testFromJsonStringWithParameters() { val prop = UnknownProperty.fromJsonString("[ \"ATTENDEE\", \"PropValue\", { \"x-param1\": \"value1\", \"x-param2\": \"value2\" } ]") assertTrue(prop is Attendee) assertEquals("ATTENDEE", prop.name) assertEquals("PropValue", prop.value) Loading @@ -35,14 +35,14 @@ class UnknownPropertyTest { @Test(expected = JSONException::class) @SmallTest fun testFromInvalidExtendedProperty() { AndroidEvent.UnknownProperty.fromExtendedProperty("This isn't JSON") fun testFromInvalidJsonString() { UnknownProperty.fromJsonString("This isn't JSON") } @Test @SmallTest fun testToExtendedProperty() { fun testToJsonString() { val attendee = Attendee("mailto:test@test.at") assertEquals( "ATTENDEE:mailto:test@test.at", Loading src/main/java/at/bitfire/ical4android/AndroidEvent.kt +11 −71 Original line number Diff line number Diff line Loading @@ -25,8 +25,6 @@ import net.fortuna.ical4j.model.component.VAlarm import net.fortuna.ical4j.model.parameter.* import net.fortuna.ical4j.model.property.* import net.fortuna.ical4j.util.TimeZones import org.json.JSONArray import org.json.JSONObject import java.io.ByteArrayInputStream import java.io.FileNotFoundException import java.io.ObjectInputStream Loading @@ -52,13 +50,15 @@ abstract class AndroidEvent( companion object { /** [ExtendedProperties.NAME] for unknown iCal properties */ @Deprecated("New serialization format", ReplaceWith("EXT_UNKNOWN_PROPERTY2")) const val EXT_UNKNOWN_PROPERTY = "unknown-property" @Deprecated("New content item MIME type", ReplaceWith("UnknownProperty.CONTENT_ITEM_TYPE")) const val EXT_UNKNOWN_PROPERTY2 = "unknown-property.v2" const val MAX_UNKNOWN_PROPERTY_SIZE = 25000 // not declared in ical4j Parameters class yet /** * EMAIL parameter name (as used for ORGANIZER). Not declared in ical4j Parameters class yet. */ private const val PARAMETER_EMAIL = "EMAIL" } Loading Loading @@ -329,17 +329,15 @@ abstract class AndroidEvent( try { when (row.getAsString(ExtendedProperties.NAME)) { EXT_UNKNOWN_PROPERTY -> { // deserialize unknown property v1 (deprecated) // deserialize unknown property (deprecated format) val stream = ByteArrayInputStream(Base64.decode(row.getAsString(ExtendedProperties.VALUE), Base64.NO_WRAP)) ObjectInputStream(stream).use { event.unknownProperties += it.readObject() as Property } } EXT_UNKNOWN_PROPERTY2 -> { // deserialize unknown property v2 event.unknownProperties += UnknownProperty.fromExtendedProperty(row.getAsString(ExtendedProperties.VALUE)) } EXT_UNKNOWN_PROPERTY2, UnknownProperty.CONTENT_ITEM_TYPE -> event.unknownProperties += UnknownProperty.fromJsonString(row.getAsString(ExtendedProperties.VALUE)) } } catch(e: Exception) { Constants.log.log(Level.WARNING, "Couldn't parse extended property", e) Loading Loading @@ -694,14 +692,14 @@ abstract class AndroidEvent( } protected open fun insertUnknownProperty(batch: BatchOperation, idxEvent: Int, property: Property) { if (property.value.length > MAX_UNKNOWN_PROPERTY_SIZE) { if (property.value.length > UnknownProperty.MAX_UNKNOWN_PROPERTY_SIZE) { Constants.log.warning("Ignoring unknown property with ${property.value.length} octets (too long)") return } val builder = ContentProviderOperation.newInsert(calendar.syncAdapterURI(ExtendedProperties.CONTENT_URI)) builder .withValue(ExtendedProperties.NAME, EXT_UNKNOWN_PROPERTY2) .withValue(ExtendedProperties.VALUE, UnknownProperty.toExtendedProperty(property)) .withValue(ExtendedProperties.NAME, UnknownProperty.CONTENT_ITEM_TYPE) .withValue(ExtendedProperties.VALUE, UnknownProperty.toJsonString(property)) batch.enqueue(BatchOperation.Operation(builder, ExtendedProperties.EVENT_ID, idxEvent)) } Loading Loading @@ -735,62 +733,4 @@ abstract class AndroidEvent( override fun toString() = MiscUtils.reflectionToString(this) /** * Helpers to (de)serialize unknown properties as JSON to store it in an Android ExtendedProperty row. * * Format: `{ propertyName, propertyValue, { param1Name: param1Value, ... } }`, with the third * array (parameters) being optional. */ object UnknownProperty { private val parameterFactory = ParameterFactoryRegistry() private val propertyFactory = PropertyFactoryRegistry() /** * Deserializes a JSON string from an ExtendedProperty value to an ical4j property. * * @param jsonString JSON representation of an ical4j property * @return ical4j property, generated from [jsonString] * @throws org.json.JSONException when the input value can't be parsed */ fun fromExtendedProperty(jsonString: String): Property { val json = JSONArray(jsonString) val name = json.getString(0) val value = json.getString(1) val params = ParameterList() json.optJSONObject(2)?.let { jsonParams -> for (paramName in jsonParams.keys()) params.add(parameterFactory.createParameter( paramName, jsonParams.getString(paramName) )) } return propertyFactory.createProperty(name, params, value) } /** * Serializes an ical4j property to a JSON string that can be stored in an ExtendedProperty. * * @param prop property to serialize as JSON * @return JSON representation of [prop] */ fun toExtendedProperty(prop: Property): String { val json = JSONArray() json.put(prop.name) json.put(prop.value) if (!prop.parameters.isEmpty) { val jsonParams = JSONObject() for (param in prop.parameters) jsonParams.put(param.name, param.value) json.put(jsonParams) } return json.toString() } } } src/main/java/at/bitfire/ical4android/AndroidTask.kt +35 −14 Original line number Diff line number Diff line Loading @@ -46,6 +46,10 @@ abstract class AndroidTask( val taskList: AndroidTaskList<AndroidTask> ) { companion object { const val UNKNOWN_PROPERTY_DATA = Properties.DATA0 } var id: Long? = null Loading Loading @@ -84,11 +88,8 @@ abstract class AndroidTask( client.query(taskList.tasksPropertiesSyncUri(), null, "${Properties.TASK_ID}=?", arrayOf(id.toString()), null)?.use { propCursor -> while (propCursor.moveToNext()) { val propValues = propCursor.toValues(true) Constants.log.log(Level.FINER, "Found property", propValues) populateProperty(propValues) } while (propCursor.moveToNext()) populateProperty(propCursor.toValues(true)) } return task Loading Loading @@ -180,12 +181,16 @@ abstract class AndroidTask( } protected open fun populateProperty(row: ContentValues) { Constants.log.log(Level.FINER, "Found property", row) val task = requireNotNull(task) when (val type = row.getAsString(Properties.MIMETYPE)) { Alarm.CONTENT_ITEM_TYPE -> populateAlarm(row) Category.CONTENT_ITEM_TYPE -> task.categories += row.getAsString(Category.CATEGORY_NAME) UnknownProperty.CONTENT_ITEM_TYPE -> task.unknownProperties += UnknownProperty.fromJsonString(row.getAsString(UNKNOWN_PROPERTY_DATA)) else -> Constants.log.warning("Found unknown property of type $type") } Loading Loading @@ -259,6 +264,7 @@ abstract class AndroidTask( private fun insertProperties(batch: BatchOperation) { insertAlarms(batch) insertCategories(batch) insertUnknownProperties(batch) } private fun insertAlarms(batch: BatchOperation) { Loading @@ -282,7 +288,7 @@ abstract class AndroidTask( } val builder = ContentProviderOperation.newInsert(taskList.tasksPropertiesSyncUri()) builder .withValue(Alarm.TASK_ID, id) .withValue(Alarm.TASK_ID, id) .withValue(Alarm.MIMETYPE, Alarm.CONTENT_ITEM_TYPE) .withValue(Alarm.MINUTES_BEFORE, ICalendar.alarmMinBefore(alarm)) .withValue(Alarm.REFERENCE, alarmRef) Loading @@ -297,7 +303,7 @@ abstract class AndroidTask( private fun insertCategories(batch: BatchOperation) { for (category in requireNotNull(task).categories) { val builder = ContentProviderOperation.newInsert(taskList.tasksPropertiesSyncUri()) builder .withValue(Category.TASK_ID, id) .withValue(Category.TASK_ID, id) .withValue(Category.MIMETYPE, Category.CONTENT_ITEM_TYPE) .withValue(Category.CATEGORY_NAME, category) Constants.log.log(Level.FINE, "Inserting category", builder.build()) Loading @@ -305,6 +311,22 @@ abstract class AndroidTask( } } private fun insertUnknownProperties(batch: BatchOperation) { for (property in requireNotNull(task).unknownProperties) { if (property.value.length > UnknownProperty.MAX_UNKNOWN_PROPERTY_SIZE) { Constants.log.warning("Ignoring unknown property with ${property.value.length} octets (too long)") return } val builder = ContentProviderOperation.newInsert(taskList.tasksPropertiesSyncUri()) .withValue(Properties.TASK_ID, id) .withValue(Properties.MIMETYPE, UnknownProperty.CONTENT_ITEM_TYPE) .withValue(UNKNOWN_PROPERTY_DATA, UnknownProperty.toJsonString(property)) Constants.log.log(Level.FINE, "Inserting unknown property", builder.build()) batch.enqueue(BatchOperation.Operation(builder)) } } fun delete(): Int { try { return taskList.provider.client.delete(taskSyncURI(), null, null) Loading @@ -318,16 +340,15 @@ abstract class AndroidTask( builder .withValue(Tasks.LIST_ID, taskList.id) val task = requireNotNull(task) builder .withValue(Tasks._UID, task.uid) builder .withValue(Tasks._UID, task.uid) .withValue(Tasks._DIRTY, 0) .withValue(Tasks.SYNC_VERSION, task.sequence) .withValue(Tasks.TITLE, task.summary) .withValue(Tasks.LOCATION, task.location) builder .withValue(Tasks.GEO, task.geoPosition?.value) .withValue(Tasks.GEO, task.geoPosition?.value) builder .withValue(Tasks.DESCRIPTION, task.description) .withValue(Tasks.DESCRIPTION, task.description) .withValue(Tasks.TASK_COLOR, task.color) .withValue(Tasks.URL, task.url) Loading Loading @@ -379,14 +400,14 @@ abstract class AndroidTask( builder .withValue(Tasks.CREATED, task.createdAt) .withValue(Tasks.LAST_MODIFIED, task.lastModified) builder .withValue(Tasks.DTSTART, task.dtStart?.date?.time) .withValue(Tasks.DTSTART, task.dtStart?.date?.time) .withValue(Tasks.DUE, task.due?.date?.time) .withValue(Tasks.DURATION, task.duration?.value) builder .withValue(Tasks.RDATE, if (task.rDates.isEmpty()) null else DateUtils.recurrenceSetsToAndroidString(task.rDates, allDay)) .withValue(Tasks.RDATE, if (task.rDates.isEmpty()) null else DateUtils.recurrenceSetsToAndroidString(task.rDates, allDay)) .withValue(Tasks.RRULE, task.rRule?.value) builder .withValue(Tasks.EXDATE, if (task.exDates.isEmpty()) null else DateUtils.recurrenceSetsToAndroidString(task.exDates, allDay)) .withValue(Tasks.EXDATE, if (task.exDates.isEmpty()) null else DateUtils.recurrenceSetsToAndroidString(task.exDates, allDay)) Constants.log.log(Level.FINE, "Built task object", builder.build()) } Loading Loading
src/androidTest/java/at/bitfire/ical4android/AndroidEventTest.kt +8 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import at.bitfire.ical4android.impl.TestEvent import net.fortuna.ical4j.model.Date import net.fortuna.ical4j.model.DateList import net.fortuna.ical4j.model.Dur import net.fortuna.ical4j.model.Property import net.fortuna.ical4j.model.component.VAlarm import net.fortuna.ical4j.model.parameter.Value import net.fortuna.ical4j.model.property.* Loading Loading @@ -115,6 +116,10 @@ class AndroidEventTest { // add EXDATE event.exDates += ExDate(DateList("20150502T120000", Value.DATE_TIME, tzVienna)) // add special properties event.unknownProperties.add(Categories("CAT1,CAT2")) event.unknownProperties.add(XProperty("X-NAME", "X-Value")) // add to calendar val uri = TestEvent(calendar, event).add() assertNotNull(uri) Loading Loading @@ -172,6 +177,9 @@ class AndroidEventTest { // compare EXDATE assertEquals(1, event2.exDates.size) assertEquals(event.exDates.first, event2.exDates.first) // compare unknown properties assertArrayEquals(event.unknownProperties.toArray(), event2.unknownProperties.toArray()) } finally { testEvent.delete() } Loading
src/androidTest/java/at/bitfire/ical4android/AndroidTaskTest.kt +7 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import net.fortuna.ical4j.model.TimeZone import net.fortuna.ical4j.model.property.DtStart import net.fortuna.ical4j.model.property.Due import net.fortuna.ical4j.model.property.Organizer import net.fortuna.ical4j.model.property.XProperty import org.dmfs.tasks.contract.TaskContract import org.junit.After import org.junit.Assert.* Loading Loading @@ -77,6 +78,10 @@ class AndroidTaskTest { task.organizer = Organizer("mailto:organizer@example.com") assertFalse(task.isAllDay()) // extended properties task.categories.addAll(arrayOf("Cat1", "Cat2")) task.unknownProperties += XProperty("X-UNKNOWN-PROP", "Unknown Value") // add to task list val uri = TestTask(taskList!!, task).add() assertNotNull("Couldn't add task", uri) Loading @@ -93,6 +98,8 @@ class AndroidTaskTest { assertEquals(task.description, task2.description) assertEquals(task.location, task2.location) assertEquals(task.dtStart, task2.dtStart) assertEquals(task.categories, task2.categories) assertEquals(task.unknownProperties, task2.unknownProperties) } finally { testTask.delete() } Loading
src/androidTest/java/at/bitfire/ical4android/UnknownPropertyTest.kt +7 −7 Original line number Diff line number Diff line Loading @@ -14,8 +14,8 @@ class UnknownPropertyTest { @Test @SmallTest fun testFromExtendedProperty() { val prop = AndroidEvent.UnknownProperty.fromExtendedProperty("[ \"UID\", \"PropValue\" ]") fun testFromJsonString() { val prop = UnknownProperty.fromJsonString("[ \"UID\", \"PropValue\" ]") assertTrue(prop is Uid) assertEquals("UID", prop.name) assertEquals("PropValue", prop.value) Loading @@ -23,8 +23,8 @@ class UnknownPropertyTest { @Test @SmallTest fun testFromExtendedPropertyWithParameters() { val prop = AndroidEvent.UnknownProperty.fromExtendedProperty("[ \"ATTENDEE\", \"PropValue\", { \"x-param1\": \"value1\", \"x-param2\": \"value2\" } ]") fun testFromJsonStringWithParameters() { val prop = UnknownProperty.fromJsonString("[ \"ATTENDEE\", \"PropValue\", { \"x-param1\": \"value1\", \"x-param2\": \"value2\" } ]") assertTrue(prop is Attendee) assertEquals("ATTENDEE", prop.name) assertEquals("PropValue", prop.value) Loading @@ -35,14 +35,14 @@ class UnknownPropertyTest { @Test(expected = JSONException::class) @SmallTest fun testFromInvalidExtendedProperty() { AndroidEvent.UnknownProperty.fromExtendedProperty("This isn't JSON") fun testFromInvalidJsonString() { UnknownProperty.fromJsonString("This isn't JSON") } @Test @SmallTest fun testToExtendedProperty() { fun testToJsonString() { val attendee = Attendee("mailto:test@test.at") assertEquals( "ATTENDEE:mailto:test@test.at", Loading
src/main/java/at/bitfire/ical4android/AndroidEvent.kt +11 −71 Original line number Diff line number Diff line Loading @@ -25,8 +25,6 @@ import net.fortuna.ical4j.model.component.VAlarm import net.fortuna.ical4j.model.parameter.* import net.fortuna.ical4j.model.property.* import net.fortuna.ical4j.util.TimeZones import org.json.JSONArray import org.json.JSONObject import java.io.ByteArrayInputStream import java.io.FileNotFoundException import java.io.ObjectInputStream Loading @@ -52,13 +50,15 @@ abstract class AndroidEvent( companion object { /** [ExtendedProperties.NAME] for unknown iCal properties */ @Deprecated("New serialization format", ReplaceWith("EXT_UNKNOWN_PROPERTY2")) const val EXT_UNKNOWN_PROPERTY = "unknown-property" @Deprecated("New content item MIME type", ReplaceWith("UnknownProperty.CONTENT_ITEM_TYPE")) const val EXT_UNKNOWN_PROPERTY2 = "unknown-property.v2" const val MAX_UNKNOWN_PROPERTY_SIZE = 25000 // not declared in ical4j Parameters class yet /** * EMAIL parameter name (as used for ORGANIZER). Not declared in ical4j Parameters class yet. */ private const val PARAMETER_EMAIL = "EMAIL" } Loading Loading @@ -329,17 +329,15 @@ abstract class AndroidEvent( try { when (row.getAsString(ExtendedProperties.NAME)) { EXT_UNKNOWN_PROPERTY -> { // deserialize unknown property v1 (deprecated) // deserialize unknown property (deprecated format) val stream = ByteArrayInputStream(Base64.decode(row.getAsString(ExtendedProperties.VALUE), Base64.NO_WRAP)) ObjectInputStream(stream).use { event.unknownProperties += it.readObject() as Property } } EXT_UNKNOWN_PROPERTY2 -> { // deserialize unknown property v2 event.unknownProperties += UnknownProperty.fromExtendedProperty(row.getAsString(ExtendedProperties.VALUE)) } EXT_UNKNOWN_PROPERTY2, UnknownProperty.CONTENT_ITEM_TYPE -> event.unknownProperties += UnknownProperty.fromJsonString(row.getAsString(ExtendedProperties.VALUE)) } } catch(e: Exception) { Constants.log.log(Level.WARNING, "Couldn't parse extended property", e) Loading Loading @@ -694,14 +692,14 @@ abstract class AndroidEvent( } protected open fun insertUnknownProperty(batch: BatchOperation, idxEvent: Int, property: Property) { if (property.value.length > MAX_UNKNOWN_PROPERTY_SIZE) { if (property.value.length > UnknownProperty.MAX_UNKNOWN_PROPERTY_SIZE) { Constants.log.warning("Ignoring unknown property with ${property.value.length} octets (too long)") return } val builder = ContentProviderOperation.newInsert(calendar.syncAdapterURI(ExtendedProperties.CONTENT_URI)) builder .withValue(ExtendedProperties.NAME, EXT_UNKNOWN_PROPERTY2) .withValue(ExtendedProperties.VALUE, UnknownProperty.toExtendedProperty(property)) .withValue(ExtendedProperties.NAME, UnknownProperty.CONTENT_ITEM_TYPE) .withValue(ExtendedProperties.VALUE, UnknownProperty.toJsonString(property)) batch.enqueue(BatchOperation.Operation(builder, ExtendedProperties.EVENT_ID, idxEvent)) } Loading Loading @@ -735,62 +733,4 @@ abstract class AndroidEvent( override fun toString() = MiscUtils.reflectionToString(this) /** * Helpers to (de)serialize unknown properties as JSON to store it in an Android ExtendedProperty row. * * Format: `{ propertyName, propertyValue, { param1Name: param1Value, ... } }`, with the third * array (parameters) being optional. */ object UnknownProperty { private val parameterFactory = ParameterFactoryRegistry() private val propertyFactory = PropertyFactoryRegistry() /** * Deserializes a JSON string from an ExtendedProperty value to an ical4j property. * * @param jsonString JSON representation of an ical4j property * @return ical4j property, generated from [jsonString] * @throws org.json.JSONException when the input value can't be parsed */ fun fromExtendedProperty(jsonString: String): Property { val json = JSONArray(jsonString) val name = json.getString(0) val value = json.getString(1) val params = ParameterList() json.optJSONObject(2)?.let { jsonParams -> for (paramName in jsonParams.keys()) params.add(parameterFactory.createParameter( paramName, jsonParams.getString(paramName) )) } return propertyFactory.createProperty(name, params, value) } /** * Serializes an ical4j property to a JSON string that can be stored in an ExtendedProperty. * * @param prop property to serialize as JSON * @return JSON representation of [prop] */ fun toExtendedProperty(prop: Property): String { val json = JSONArray() json.put(prop.name) json.put(prop.value) if (!prop.parameters.isEmpty) { val jsonParams = JSONObject() for (param in prop.parameters) jsonParams.put(param.name, param.value) json.put(jsonParams) } return json.toString() } } }
src/main/java/at/bitfire/ical4android/AndroidTask.kt +35 −14 Original line number Diff line number Diff line Loading @@ -46,6 +46,10 @@ abstract class AndroidTask( val taskList: AndroidTaskList<AndroidTask> ) { companion object { const val UNKNOWN_PROPERTY_DATA = Properties.DATA0 } var id: Long? = null Loading Loading @@ -84,11 +88,8 @@ abstract class AndroidTask( client.query(taskList.tasksPropertiesSyncUri(), null, "${Properties.TASK_ID}=?", arrayOf(id.toString()), null)?.use { propCursor -> while (propCursor.moveToNext()) { val propValues = propCursor.toValues(true) Constants.log.log(Level.FINER, "Found property", propValues) populateProperty(propValues) } while (propCursor.moveToNext()) populateProperty(propCursor.toValues(true)) } return task Loading Loading @@ -180,12 +181,16 @@ abstract class AndroidTask( } protected open fun populateProperty(row: ContentValues) { Constants.log.log(Level.FINER, "Found property", row) val task = requireNotNull(task) when (val type = row.getAsString(Properties.MIMETYPE)) { Alarm.CONTENT_ITEM_TYPE -> populateAlarm(row) Category.CONTENT_ITEM_TYPE -> task.categories += row.getAsString(Category.CATEGORY_NAME) UnknownProperty.CONTENT_ITEM_TYPE -> task.unknownProperties += UnknownProperty.fromJsonString(row.getAsString(UNKNOWN_PROPERTY_DATA)) else -> Constants.log.warning("Found unknown property of type $type") } Loading Loading @@ -259,6 +264,7 @@ abstract class AndroidTask( private fun insertProperties(batch: BatchOperation) { insertAlarms(batch) insertCategories(batch) insertUnknownProperties(batch) } private fun insertAlarms(batch: BatchOperation) { Loading @@ -282,7 +288,7 @@ abstract class AndroidTask( } val builder = ContentProviderOperation.newInsert(taskList.tasksPropertiesSyncUri()) builder .withValue(Alarm.TASK_ID, id) .withValue(Alarm.TASK_ID, id) .withValue(Alarm.MIMETYPE, Alarm.CONTENT_ITEM_TYPE) .withValue(Alarm.MINUTES_BEFORE, ICalendar.alarmMinBefore(alarm)) .withValue(Alarm.REFERENCE, alarmRef) Loading @@ -297,7 +303,7 @@ abstract class AndroidTask( private fun insertCategories(batch: BatchOperation) { for (category in requireNotNull(task).categories) { val builder = ContentProviderOperation.newInsert(taskList.tasksPropertiesSyncUri()) builder .withValue(Category.TASK_ID, id) .withValue(Category.TASK_ID, id) .withValue(Category.MIMETYPE, Category.CONTENT_ITEM_TYPE) .withValue(Category.CATEGORY_NAME, category) Constants.log.log(Level.FINE, "Inserting category", builder.build()) Loading @@ -305,6 +311,22 @@ abstract class AndroidTask( } } private fun insertUnknownProperties(batch: BatchOperation) { for (property in requireNotNull(task).unknownProperties) { if (property.value.length > UnknownProperty.MAX_UNKNOWN_PROPERTY_SIZE) { Constants.log.warning("Ignoring unknown property with ${property.value.length} octets (too long)") return } val builder = ContentProviderOperation.newInsert(taskList.tasksPropertiesSyncUri()) .withValue(Properties.TASK_ID, id) .withValue(Properties.MIMETYPE, UnknownProperty.CONTENT_ITEM_TYPE) .withValue(UNKNOWN_PROPERTY_DATA, UnknownProperty.toJsonString(property)) Constants.log.log(Level.FINE, "Inserting unknown property", builder.build()) batch.enqueue(BatchOperation.Operation(builder)) } } fun delete(): Int { try { return taskList.provider.client.delete(taskSyncURI(), null, null) Loading @@ -318,16 +340,15 @@ abstract class AndroidTask( builder .withValue(Tasks.LIST_ID, taskList.id) val task = requireNotNull(task) builder .withValue(Tasks._UID, task.uid) builder .withValue(Tasks._UID, task.uid) .withValue(Tasks._DIRTY, 0) .withValue(Tasks.SYNC_VERSION, task.sequence) .withValue(Tasks.TITLE, task.summary) .withValue(Tasks.LOCATION, task.location) builder .withValue(Tasks.GEO, task.geoPosition?.value) .withValue(Tasks.GEO, task.geoPosition?.value) builder .withValue(Tasks.DESCRIPTION, task.description) .withValue(Tasks.DESCRIPTION, task.description) .withValue(Tasks.TASK_COLOR, task.color) .withValue(Tasks.URL, task.url) Loading Loading @@ -379,14 +400,14 @@ abstract class AndroidTask( builder .withValue(Tasks.CREATED, task.createdAt) .withValue(Tasks.LAST_MODIFIED, task.lastModified) builder .withValue(Tasks.DTSTART, task.dtStart?.date?.time) .withValue(Tasks.DTSTART, task.dtStart?.date?.time) .withValue(Tasks.DUE, task.due?.date?.time) .withValue(Tasks.DURATION, task.duration?.value) builder .withValue(Tasks.RDATE, if (task.rDates.isEmpty()) null else DateUtils.recurrenceSetsToAndroidString(task.rDates, allDay)) .withValue(Tasks.RDATE, if (task.rDates.isEmpty()) null else DateUtils.recurrenceSetsToAndroidString(task.rDates, allDay)) .withValue(Tasks.RRULE, task.rRule?.value) builder .withValue(Tasks.EXDATE, if (task.exDates.isEmpty()) null else DateUtils.recurrenceSetsToAndroidString(task.exDates, allDay)) .withValue(Tasks.EXDATE, if (task.exDates.isEmpty()) null else DateUtils.recurrenceSetsToAndroidString(task.exDates, allDay)) Constants.log.log(Level.FINE, "Built task object", builder.build()) } Loading