Loading README.md +9 −7 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ # ical4android ical4android is an Android library that brings together iCalendar and Android. ical4android is a library for Android that brings together iCalendar and Android. It's a framework for * parsing and generating iCalendar resources (using [ical4j](https://github.com/ical4j/ical4j)) Loading @@ -14,11 +14,16 @@ It's a framework for It has been primarily developed for: * [DAVdroid](https://www.davdroid.com) * [ICSdroid](https://icsdroid.bitfire.at) * [DAVx⁵](https://www.davx5.com) * [ICSx⁵](https://icsx5.bitfire.at) _This software is not affiliated to, nor has it been authorized, sponsored or otherwise approved by Google LLC. Android is a trademark of Google LLC._ Generated KDoc: https://bitfireAT.gitlab.io/ical4android/dokka/ical4android/ Discussion: https://forums.bitfire.at/category/18/libraries ## Contact Loading @@ -30,13 +35,10 @@ Florastraße 27 Email: [play@bitfire.at](mailto:play@bitfire.at) (do not use this) For questions, suggestions etc. please use the DAVdroid forum: https://www.davdroid.com/forums/ ## License Copyright (C) bitfire web engineering (Ricki Hirner, Bernhard Stockmann). Copyright (C) bitfire web engineering (Ricki Hirner, Bernhard Stockmann) and contributors. This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under the conditions of the [GNU GPL v3](https://www.gnu.org/licenses/gpl-3.0.html). Loading build.gradle +29 −15 Original line number Diff line number Diff line buildscript { ext.versions = [ kotlin: '1.3.31', dokka: '0.9.17', ical4j: '2.2.4' kotlin: '1.3.60', dokka: '0.10.0', ical4j: '2.2.6' ] repositories { Loading @@ -12,9 +12,9 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.4.1' classpath 'com.android.tools.build:gradle:3.5.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:${versions.dokka}" classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}" } } Loading @@ -25,20 +25,21 @@ repositories { apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'org.jetbrains.dokka-android' apply plugin: 'org.jetbrains.dokka' android { compileSdkVersion 27 buildToolsVersion '27.1.1' compileSdkVersion 29 buildToolsVersion '29.0.2' defaultConfig { minSdkVersion 24 targetSdkVersion 27 targetSdkVersion 29 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" buildConfigField "String", "version_ical4j", "\"${versions.ical4j}\"" } lintOptions { disable 'AllowBackup' disable 'InvalidPackage' Loading @@ -51,18 +52,31 @@ android { sourceSets { main.java.srcDirs = [ "src/main/java", "opentasks-contract/src/main/java" ] } dokka.configuration { sourceLink { url = "https://gitlab.com/bitfireAT/ical4android/tree/master/" lineSuffix = "#L" } jdkVersion = 7 } } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}" api "org.mnode.ical4j:ical4j:${versions.ical4j}" implementation 'org.slf4j:slf4j-jdk14:1.7.25' implementation 'androidx.core:core-ktx:1.0.2' implementation 'org.slf4j:slf4j-jdk14:1.7.26' implementation 'androidx.core:core-ktx:1.1.0' androidTestImplementation 'androidx.test:core:1.2.0' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:rules:1.2.0' androidTestImplementation 'androidx.test:core:1.1.0' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:rules:1.1.1' // This very old Groovy version is not actually used, but it's needed // so that ical4j doesn't crash when testing: https://github.com/ical4j/ical4j/issues/315 //noinspection GradleDependency androidTestImplementation 'org.codehaus.groovy:groovy:2.2.2' testImplementation 'junit:junit:4.12' } gradle/wrapper/gradle-wrapper.properties +1 −1 Original line number Diff line number Diff line Loading @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip src/androidTest/java/foundation/e/ical4android/AndroidEventTest.kt +7 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,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 +176,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/foundation/e/ical4android/AndroidTaskListTest.kt +82 −20 Original line number Diff line number Diff line Loading @@ -11,13 +11,17 @@ package foundation.e.ical4android import android.accounts.Account import android.content.ContentUris import android.content.ContentValues import androidx.test.filters.MediumTest import android.database.DatabaseUtils import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import foundation.e.ical4android.impl.TestTaskList import foundation.e.ical4android.impl.TestTask import net.fortuna.ical4j.model.property.RelatedTo import org.dmfs.tasks.contract.TaskContract import org.dmfs.tasks.contract.TaskContract.Properties import org.dmfs.tasks.contract.TaskContract.Property.Relation import org.dmfs.tasks.contract.TaskContract.Tasks import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.* import org.junit.Assume.assumeNotNull import org.junit.Before import org.junit.Test Loading @@ -43,24 +47,26 @@ class AndroidTaskListTest { provider?.close() } @MediumTest @Test fun testManageTaskLists() { // create task list private fun createTaskList(): TestTaskList { val info = ContentValues() info.put(TaskContract.TaskLists.LIST_NAME, "Test Task List") info.put(TaskContract.TaskLists.LIST_COLOR, 0xffff0000) info.put(TaskContract.TaskLists.OWNER, "test@example.com") info.put(TaskContract.TaskLists.SYNC_ENABLED, 1) info.put(TaskContract.TaskLists.VISIBLE, 1) val uri = AndroidTaskList.create(testAccount, provider!!, info) assertNotNull(uri) // query task list val taskList = AndroidTaskList.findByID(testAccount, provider!!, TestTaskList.Factory, ContentUris.parseId(uri)) assertNotNull(taskList) return AndroidTaskList.findByID(testAccount, provider!!, TestTaskList.Factory, ContentUris.parseId(uri)) } @Test fun testManageTaskLists() { val taskList = createTaskList() try { // sync URIs assertEquals("true", taskList.taskListSyncUri().getQueryParameter(TaskContract.CALLER_IS_SYNCADAPTER)) assertEquals(testAccount.type, taskList.taskListSyncUri().getQueryParameter(TaskContract.ACCOUNT_TYPE)) Loading @@ -69,9 +75,65 @@ class AndroidTaskListTest { assertEquals("true", taskList.tasksSyncUri().getQueryParameter(TaskContract.CALLER_IS_SYNCADAPTER)) assertEquals(testAccount.type, taskList.tasksSyncUri().getQueryParameter(TaskContract.ACCOUNT_TYPE)) assertEquals(testAccount.name, taskList.tasksSyncUri().getQueryParameter(TaskContract.ACCOUNT_NAME)) } finally { // delete task list assertEquals(1, taskList.delete()) } } @Test fun testTouchRelations() { val taskList = createTaskList() try { val parent = Task() parent.uid = "parent" parent.summary = "Parent task" val child = Task() child.uid = "child" child.summary = "Child task" child.relatedTo.add(RelatedTo(parent.uid)) // insert child before parent val childContentUri = TestTask(taskList, child).add() val childId = ContentUris.parseId(childContentUri) val parentContentUri = TestTask(taskList, parent).add() val parentId = ContentUris.parseId(parentContentUri) // OpenTasks should provide the correct relation… taskList.provider.client.query(taskList.tasksPropertiesSyncUri(), null, "${Properties.TASK_ID}=?", arrayOf(childId.toString()), null, null)!!.use { cursor -> assertEquals(1, cursor.count) cursor.moveToNext() val row = ContentValues() DatabaseUtils.cursorRowToContentValues(cursor, row) assertEquals(Relation.CONTENT_ITEM_TYPE, row.getAsString(Properties.MIMETYPE)) assertEquals(parentId, row.getAsLong(Relation.RELATED_ID)) assertEquals(parent.uid, row.getAsString(Relation.RELATED_UID)) assertEquals(Relation.RELTYPE_PARENT, row.getAsInteger(Relation.RELATED_TYPE)) } // … BUT the parent_id is not updated (https://github.com/dmfs/opentasks/issues/877) taskList.provider.client.query(childContentUri, arrayOf(Tasks.PARENT_ID), null, null, null)!!.use { cursor -> assertTrue(cursor.moveToNext()) assertTrue(cursor.isNull(0)) } // touch the relations to update parent_id values taskList.touchRelations() // now parent_id should bet set taskList.provider.client.query(childContentUri, arrayOf(Tasks.PARENT_ID), null, null, null)!!.use { cursor -> assertTrue(cursor.moveToNext()) assertEquals(parentId, cursor.getLong(0)) } } finally { taskList.delete() } } } Loading
README.md +9 −7 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ # ical4android ical4android is an Android library that brings together iCalendar and Android. ical4android is a library for Android that brings together iCalendar and Android. It's a framework for * parsing and generating iCalendar resources (using [ical4j](https://github.com/ical4j/ical4j)) Loading @@ -14,11 +14,16 @@ It's a framework for It has been primarily developed for: * [DAVdroid](https://www.davdroid.com) * [ICSdroid](https://icsdroid.bitfire.at) * [DAVx⁵](https://www.davx5.com) * [ICSx⁵](https://icsx5.bitfire.at) _This software is not affiliated to, nor has it been authorized, sponsored or otherwise approved by Google LLC. Android is a trademark of Google LLC._ Generated KDoc: https://bitfireAT.gitlab.io/ical4android/dokka/ical4android/ Discussion: https://forums.bitfire.at/category/18/libraries ## Contact Loading @@ -30,13 +35,10 @@ Florastraße 27 Email: [play@bitfire.at](mailto:play@bitfire.at) (do not use this) For questions, suggestions etc. please use the DAVdroid forum: https://www.davdroid.com/forums/ ## License Copyright (C) bitfire web engineering (Ricki Hirner, Bernhard Stockmann). Copyright (C) bitfire web engineering (Ricki Hirner, Bernhard Stockmann) and contributors. This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under the conditions of the [GNU GPL v3](https://www.gnu.org/licenses/gpl-3.0.html). Loading
build.gradle +29 −15 Original line number Diff line number Diff line buildscript { ext.versions = [ kotlin: '1.3.31', dokka: '0.9.17', ical4j: '2.2.4' kotlin: '1.3.60', dokka: '0.10.0', ical4j: '2.2.6' ] repositories { Loading @@ -12,9 +12,9 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.4.1' classpath 'com.android.tools.build:gradle:3.5.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:${versions.dokka}" classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}" } } Loading @@ -25,20 +25,21 @@ repositories { apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'org.jetbrains.dokka-android' apply plugin: 'org.jetbrains.dokka' android { compileSdkVersion 27 buildToolsVersion '27.1.1' compileSdkVersion 29 buildToolsVersion '29.0.2' defaultConfig { minSdkVersion 24 targetSdkVersion 27 targetSdkVersion 29 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" buildConfigField "String", "version_ical4j", "\"${versions.ical4j}\"" } lintOptions { disable 'AllowBackup' disable 'InvalidPackage' Loading @@ -51,18 +52,31 @@ android { sourceSets { main.java.srcDirs = [ "src/main/java", "opentasks-contract/src/main/java" ] } dokka.configuration { sourceLink { url = "https://gitlab.com/bitfireAT/ical4android/tree/master/" lineSuffix = "#L" } jdkVersion = 7 } } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}" api "org.mnode.ical4j:ical4j:${versions.ical4j}" implementation 'org.slf4j:slf4j-jdk14:1.7.25' implementation 'androidx.core:core-ktx:1.0.2' implementation 'org.slf4j:slf4j-jdk14:1.7.26' implementation 'androidx.core:core-ktx:1.1.0' androidTestImplementation 'androidx.test:core:1.2.0' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:rules:1.2.0' androidTestImplementation 'androidx.test:core:1.1.0' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:rules:1.1.1' // This very old Groovy version is not actually used, but it's needed // so that ical4j doesn't crash when testing: https://github.com/ical4j/ical4j/issues/315 //noinspection GradleDependency androidTestImplementation 'org.codehaus.groovy:groovy:2.2.2' testImplementation 'junit:junit:4.12' }
gradle/wrapper/gradle-wrapper.properties +1 −1 Original line number Diff line number Diff line Loading @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip
src/androidTest/java/foundation/e/ical4android/AndroidEventTest.kt +7 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,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 +176,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/foundation/e/ical4android/AndroidTaskListTest.kt +82 −20 Original line number Diff line number Diff line Loading @@ -11,13 +11,17 @@ package foundation.e.ical4android import android.accounts.Account import android.content.ContentUris import android.content.ContentValues import androidx.test.filters.MediumTest import android.database.DatabaseUtils import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import foundation.e.ical4android.impl.TestTaskList import foundation.e.ical4android.impl.TestTask import net.fortuna.ical4j.model.property.RelatedTo import org.dmfs.tasks.contract.TaskContract import org.dmfs.tasks.contract.TaskContract.Properties import org.dmfs.tasks.contract.TaskContract.Property.Relation import org.dmfs.tasks.contract.TaskContract.Tasks import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.* import org.junit.Assume.assumeNotNull import org.junit.Before import org.junit.Test Loading @@ -43,24 +47,26 @@ class AndroidTaskListTest { provider?.close() } @MediumTest @Test fun testManageTaskLists() { // create task list private fun createTaskList(): TestTaskList { val info = ContentValues() info.put(TaskContract.TaskLists.LIST_NAME, "Test Task List") info.put(TaskContract.TaskLists.LIST_COLOR, 0xffff0000) info.put(TaskContract.TaskLists.OWNER, "test@example.com") info.put(TaskContract.TaskLists.SYNC_ENABLED, 1) info.put(TaskContract.TaskLists.VISIBLE, 1) val uri = AndroidTaskList.create(testAccount, provider!!, info) assertNotNull(uri) // query task list val taskList = AndroidTaskList.findByID(testAccount, provider!!, TestTaskList.Factory, ContentUris.parseId(uri)) assertNotNull(taskList) return AndroidTaskList.findByID(testAccount, provider!!, TestTaskList.Factory, ContentUris.parseId(uri)) } @Test fun testManageTaskLists() { val taskList = createTaskList() try { // sync URIs assertEquals("true", taskList.taskListSyncUri().getQueryParameter(TaskContract.CALLER_IS_SYNCADAPTER)) assertEquals(testAccount.type, taskList.taskListSyncUri().getQueryParameter(TaskContract.ACCOUNT_TYPE)) Loading @@ -69,9 +75,65 @@ class AndroidTaskListTest { assertEquals("true", taskList.tasksSyncUri().getQueryParameter(TaskContract.CALLER_IS_SYNCADAPTER)) assertEquals(testAccount.type, taskList.tasksSyncUri().getQueryParameter(TaskContract.ACCOUNT_TYPE)) assertEquals(testAccount.name, taskList.tasksSyncUri().getQueryParameter(TaskContract.ACCOUNT_NAME)) } finally { // delete task list assertEquals(1, taskList.delete()) } } @Test fun testTouchRelations() { val taskList = createTaskList() try { val parent = Task() parent.uid = "parent" parent.summary = "Parent task" val child = Task() child.uid = "child" child.summary = "Child task" child.relatedTo.add(RelatedTo(parent.uid)) // insert child before parent val childContentUri = TestTask(taskList, child).add() val childId = ContentUris.parseId(childContentUri) val parentContentUri = TestTask(taskList, parent).add() val parentId = ContentUris.parseId(parentContentUri) // OpenTasks should provide the correct relation… taskList.provider.client.query(taskList.tasksPropertiesSyncUri(), null, "${Properties.TASK_ID}=?", arrayOf(childId.toString()), null, null)!!.use { cursor -> assertEquals(1, cursor.count) cursor.moveToNext() val row = ContentValues() DatabaseUtils.cursorRowToContentValues(cursor, row) assertEquals(Relation.CONTENT_ITEM_TYPE, row.getAsString(Properties.MIMETYPE)) assertEquals(parentId, row.getAsLong(Relation.RELATED_ID)) assertEquals(parent.uid, row.getAsString(Relation.RELATED_UID)) assertEquals(Relation.RELTYPE_PARENT, row.getAsInteger(Relation.RELATED_TYPE)) } // … BUT the parent_id is not updated (https://github.com/dmfs/opentasks/issues/877) taskList.provider.client.query(childContentUri, arrayOf(Tasks.PARENT_ID), null, null, null)!!.use { cursor -> assertTrue(cursor.moveToNext()) assertTrue(cursor.isNull(0)) } // touch the relations to update parent_id values taskList.touchRelations() // now parent_id should bet set taskList.provider.client.query(childContentUri, arrayOf(Tasks.PARENT_ID), null, null, null)!!.use { cursor -> assertTrue(cursor.moveToNext()) assertEquals(parentId, cursor.getLong(0)) } } finally { taskList.delete() } } }