diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 985eced2..85836024 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -106,6 +106,19 @@
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_calendars" />
+
+
+
+
+
+
+
+
data, String account, CollectionInfo.Type type) {
- return data.select(ServiceEntity.class).where(ServiceEntity.ACCOUNT.eq(account).and(ServiceEntity.TYPE.eq(type))).limit(1).get().firstOrNull();
+ ServiceEntity service = data.select(ServiceEntity.class).where(ServiceEntity.ACCOUNT.eq(account).and(ServiceEntity.TYPE.eq(type))).limit(1).get().firstOrNull();
+ if (service == null) {
+ // If our first time, create service and a journal
+ ServiceEntity serviceEntity = new ServiceEntity();
+ serviceEntity.account = account;
+ serviceEntity.type = CollectionInfo.Type.TASKS;
+ service = data.insert(serviceEntity);
+ }
+ return service;
}
}
diff --git a/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.kt b/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.kt
index 0518b3e0..efdaeab3 100644
--- a/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.kt
+++ b/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.kt
@@ -151,7 +151,7 @@ class LocalAddressBook(
_mainAccount = newMainAccount
}
- var url: String
+ override var url: String
get() = AccountManager.get(context).getUserData(account, USER_DATA_URL)
?: throw IllegalStateException("Address book has no URL")
set(url) = AccountManager.get(context).setUserData(account, USER_DATA_URL, url)
diff --git a/app/src/main/java/com/etesync/syncadapter/resource/LocalCalendar.kt b/app/src/main/java/com/etesync/syncadapter/resource/LocalCalendar.kt
index 44ee06e7..fb3cee13 100644
--- a/app/src/main/java/com/etesync/syncadapter/resource/LocalCalendar.kt
+++ b/app/src/main/java/com/etesync/syncadapter/resource/LocalCalendar.kt
@@ -88,6 +88,9 @@ class LocalCalendar private constructor(
}
}
+ override val url: String?
+ get() = name
+
fun update(journalEntity: JournalEntity, updateColor: Boolean) =
update(valuesFromCollectionInfo(journalEntity, updateColor))
diff --git a/app/src/main/java/com/etesync/syncadapter/resource/LocalCollection.kt b/app/src/main/java/com/etesync/syncadapter/resource/LocalCollection.kt
index fc2c77b1..38bfcc94 100644
--- a/app/src/main/java/com/etesync/syncadapter/resource/LocalCollection.kt
+++ b/app/src/main/java/com/etesync/syncadapter/resource/LocalCollection.kt
@@ -9,6 +9,8 @@
package com.etesync.syncadapter.resource
interface LocalCollection> {
+ val url: String?
+
fun findDeleted(): List
fun findDirty(): List
fun findWithoutFileName(): List
diff --git a/app/src/main/java/com/etesync/syncadapter/resource/LocalTask.kt b/app/src/main/java/com/etesync/syncadapter/resource/LocalTask.kt
index 9ddd0b7a..24e67995 100644
--- a/app/src/main/java/com/etesync/syncadapter/resource/LocalTask.kt
+++ b/app/src/main/java/com/etesync/syncadapter/resource/LocalTask.kt
@@ -48,7 +48,7 @@ class LocalTask : AndroidTask, LocalResource {
val uuid: String?
get() = fileName
- constructor(taskList: AndroidTaskList<*>, task: Task, fileName: String?, eTag: String?, flags: Int)
+ constructor(taskList: AndroidTaskList<*>, task: Task, fileName: String?, eTag: String?)
: super(taskList, task) {
this.fileName = fileName
this.eTag = eTag
@@ -63,6 +63,15 @@ class LocalTask : AndroidTask, LocalResource {
/* process LocalTask-specific fields */
+ override fun populateTask(values: ContentValues) {
+ super.populateTask(values)
+ fileName = values.getAsString(TaskContract.Tasks._SYNC_ID)
+ eTag = values.getAsString(COLUMN_ETAG)
+ task?.uid = values.getAsString(COLUMN_UID)
+
+ task?.sequence = values.getAsInteger(COLUMN_SEQUENCE)
+ }
+
override fun buildTask(builder: ContentProviderOperation.Builder, update: Boolean) {
super.buildTask(builder, update)
builder.withValue(TaskContract.Tasks._SYNC_ID, fileName)
@@ -75,7 +84,14 @@ class LocalTask : AndroidTask, LocalResource {
/* custom queries */
override fun prepareForUpload() {
- val uid = UUID.randomUUID().toString()
+ var uid: String? = null
+ val c = taskList.provider.client.query(taskSyncURI(), arrayOf(COLUMN_UID), null, null, null)
+ if (c.moveToNext())
+ uid = c.getString(0)
+ if (uid == null)
+ uid = UUID.randomUUID().toString()
+
+ c.close()
val values = ContentValues(2)
values.put(TaskContract.Tasks._SYNC_ID, uid)
diff --git a/app/src/main/java/com/etesync/syncadapter/resource/LocalTaskList.kt b/app/src/main/java/com/etesync/syncadapter/resource/LocalTaskList.kt
index 24a51e87..d2425271 100644
--- a/app/src/main/java/com/etesync/syncadapter/resource/LocalTaskList.kt
+++ b/app/src/main/java/com/etesync/syncadapter/resource/LocalTaskList.kt
@@ -62,6 +62,9 @@ class LocalTaskList private constructor(
}
+ override val url: String?
+ get() = syncId
+
fun update(journalEntity: JournalEntity, updateColor: Boolean) =
update(valuesFromCollectionInfo(journalEntity, updateColor))
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.kt b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.kt
index 2fce6e9f..e7d63666 100644
--- a/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.kt
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/SyncManager.kt
@@ -10,9 +10,7 @@ package com.etesync.syncadapter.syncadapter
import android.accounts.Account
import android.annotation.TargetApi
import android.content.Context
-import android.content.Intent
import android.content.SyncResult
-import android.content.res.Resources
import android.os.Bundle
import com.etesync.syncadapter.AccountSettings
@@ -40,7 +38,6 @@ import com.etesync.syncadapter.ui.ViewCollectionActivity
import java.io.FileNotFoundException
import java.io.IOException
import java.util.ArrayList
-import java.util.Arrays
import java.util.LinkedList
import java.util.Locale
import java.util.logging.Level
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/TasksSyncAdapterService.kt b/app/src/main/java/com/etesync/syncadapter/syncadapter/TasksSyncAdapterService.kt
new file mode 100644
index 00000000..168a4195
--- /dev/null
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/TasksSyncAdapterService.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright © 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.syncadapter
+
+import android.accounts.Account
+import android.accounts.AccountManager
+import android.content.ContentProviderClient
+import android.content.ContentResolver
+import android.content.Context
+import android.content.SyncResult
+import android.database.sqlite.SQLiteException
+import android.os.Build
+import android.os.Bundle
+import at.bitfire.ical4android.AndroidTaskList
+import at.bitfire.ical4android.TaskProvider
+import com.etesync.syncadapter.*
+import com.etesync.syncadapter.journalmanager.Exceptions
+import com.etesync.syncadapter.model.CollectionInfo
+import com.etesync.syncadapter.model.JournalEntity
+import com.etesync.syncadapter.model.JournalModel
+import com.etesync.syncadapter.model.ServiceEntity
+import com.etesync.syncadapter.resource.LocalTaskList
+import com.etesync.syncadapter.ui.DebugInfoActivity
+import okhttp3.HttpUrl
+import org.dmfs.tasks.contract.TaskContract
+import java.util.*
+import java.util.logging.Level
+
+/**
+ * Synchronization manager for CalDAV collections; handles tasks ({@code VTODO}).
+ */
+class TasksSyncAdapterService: SyncAdapterService() {
+
+ override fun syncAdapter() = TasksSyncAdapter(this)
+
+
+ class TasksSyncAdapter(
+ context: Context
+ ): SyncAdapter(context) {
+
+ override fun onPerformSync(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
+ super.onPerformSync(account, extras, authority, provider, syncResult)
+
+ val notificationManager = NotificationHelper(context, "journals-tasks", Constants.NOTIFICATION_TASK_SYNC)
+ notificationManager.cancel()
+
+ try {
+ val taskProvider = TaskProvider.fromProviderClient(context, provider)
+
+ // make sure account can be seen by OpenTasks
+ if (Build.VERSION.SDK_INT >= 26)
+ AccountManager.get(context).setAccountVisibility(account, taskProvider.name.packageName, AccountManager.VISIBILITY_VISIBLE)
+
+ val accountSettings = AccountSettings(context, account)
+ /* don't run sync if
+ - sync conditions (e.g. "sync only in WiFi") are not met AND
+ - this is is an automatic sync (i.e. manual syncs are run regardless of sync conditions)
+ */
+ if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(accountSettings))
+ return
+
+ RefreshCollections(account, CollectionInfo.Type.TASKS).run()
+
+ updateLocalTaskLists(taskProvider, account, accountSettings)
+
+ val principal = HttpUrl.get(accountSettings.uri!!)!!
+
+ for (taskList in AndroidTaskList.find(account, taskProvider, LocalTaskList.Factory, "${TaskContract.TaskLists.SYNC_ENABLED}!=0", null)) {
+ App.log.info("Synchronizing task list #${taskList.id} [${taskList.syncId}]")
+ val tasksSyncManager = TasksSyncManager(context, account, accountSettings, extras, authority, syncResult, taskList, principal);
+ tasksSyncManager.performSync()
+ }
+ } catch (e: Exceptions.ServiceUnavailableException) {
+ syncResult.stats.numIoExceptions++
+ syncResult.delayUntil = if (e.retryAfter > 0) e.retryAfter else Constants.DEFAULT_RETRY_DELAY
+ } catch (e: Exception) {
+ if (e is SQLiteException) {
+ App.log.log(Level.SEVERE, "Couldn't prepare local task list", e)
+ syncResult.databaseError = true
+ }
+
+ val syncPhase = R.string.sync_phase_journals
+ val title = context.getString(R.string.sync_error_tasks, account.name)
+
+ notificationManager.setThrowable(e)
+
+ val detailsIntent = notificationManager.detailsIntent
+ detailsIntent.putExtra(Constants.KEY_ACCOUNT, account)
+ if (e !is Exceptions.UnauthorizedException) {
+ detailsIntent.putExtra(DebugInfoActivity.KEY_AUTHORITY, authority)
+ detailsIntent.putExtra(DebugInfoActivity.KEY_PHASE, syncPhase)
+ }
+
+ notificationManager.notify(title, context.getString(syncPhase))
+ } catch (e: OutOfMemoryError) {
+ val syncPhase = R.string.sync_phase_journals
+ val title = context.getString(R.string.sync_error_tasks, account.name)
+ notificationManager.setThrowable(e)
+ val detailsIntent = notificationManager.detailsIntent
+ detailsIntent.putExtra(Constants.KEY_ACCOUNT, account)
+ notificationManager.notify(title, context.getString(syncPhase))
+ }
+
+ App.log.info("Task sync complete")
+ }
+
+ private fun updateLocalTaskLists(provider: TaskProvider, account: Account, settings: AccountSettings) {
+ val data = (context.applicationContext as App).data
+ var service = JournalModel.Service.fetch(data, account.name, CollectionInfo.Type.TASKS)
+
+ val remote = HashMap()
+ val remoteJournals = JournalEntity.getJournals(data, service)
+ for (journalEntity in remoteJournals) {
+ remote[journalEntity.uid] = journalEntity
+ }
+
+ val local = AndroidTaskList.find(account, provider, LocalTaskList.Factory, null, null)
+
+ val updateColors = settings.manageCalendarColors
+
+ // delete obsolete local TaskList
+ for (taskList in local) {
+ val url = taskList.url
+ val journalEntity = remote[url]
+ if (journalEntity == null) {
+ App.log.fine("Deleting obsolete local task list $url")
+ taskList.delete()
+ } else {
+ // remote CollectionInfo found for this local collection, update data
+ App.log.fine("Updating local task list $url with $journalEntity")
+ taskList.update(journalEntity, updateColors)
+ // we already have a local tasks for this remote collection, don't take into consideration anymore
+ remote.remove(url)
+ }
+ }
+
+ // create new local taskss
+ for (url in remote.keys) {
+ val journalEntity = remote[url]!!
+ App.log.info("Adding local task list $journalEntity")
+ LocalTaskList.create(account, provider, journalEntity)
+ }
+ }
+
+ }
+
+}
diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/TasksSyncManager.kt b/app/src/main/java/com/etesync/syncadapter/syncadapter/TasksSyncManager.kt
new file mode 100644
index 00000000..8e36e9f2
--- /dev/null
+++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/TasksSyncManager.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 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.syncadapter
+
+import android.accounts.Account
+import android.content.Context
+import android.content.SyncResult
+import android.os.Bundle
+import at.bitfire.ical4android.Event
+import at.bitfire.ical4android.InvalidCalendarException
+import at.bitfire.ical4android.Task
+import com.etesync.syncadapter.AccountSettings
+import com.etesync.syncadapter.App
+import com.etesync.syncadapter.Constants
+import com.etesync.syncadapter.R
+import com.etesync.syncadapter.journalmanager.JournalEntryManager
+import com.etesync.syncadapter.model.CollectionInfo
+import com.etesync.syncadapter.model.SyncEntry
+import com.etesync.syncadapter.resource.LocalEvent
+import com.etesync.syncadapter.resource.LocalTask
+import com.etesync.syncadapter.resource.LocalTaskList
+import okhttp3.HttpUrl
+import java.io.Reader
+import java.io.StringReader
+import java.util.logging.Level
+
+/**
+ * Synchronization manager for CalDAV collections; handles tasks (VTODO)
+ */
+class TasksSyncManager(
+ context: Context,
+ account: Account,
+ accountSettings: AccountSettings,
+ extras: Bundle,
+ authority: String,
+ syncResult: SyncResult,
+ taskList: LocalTaskList,
+ private val remote: HttpUrl
+): SyncManager(context, account, accountSettings, extras, authority, syncResult, taskList.url!!, CollectionInfo.Type.TASKS, account.name) {
+
+ override val syncErrorTitle: String
+ get() = context.getString(R.string.sync_error_tasks, account.name)
+
+ override val syncSuccessfullyTitle: String
+ get() = context.getString(R.string.sync_successfully_tasks, info.displayName,
+ account.name)
+
+ init {
+ localCollection = taskList
+ }
+
+ override fun notificationId(): Int {
+ return Constants.NOTIFICATION_TASK_SYNC
+ }
+
+ override fun prepare(): Boolean {
+ if (!super.prepare())
+ return false
+
+ journal = JournalEntryManager(httpClient, remote, localTaskList().url!!)
+ return true
+ }
+
+ // helpers
+
+ private fun localTaskList(): LocalTaskList {
+ return localCollection as LocalTaskList
+ }
+
+ override fun processSyncEntry(cEntry: SyncEntry) {
+ val inputReader = StringReader(cEntry.content)
+
+ val tasks = Task.fromReader(inputReader)
+ if (tasks.size == 0) {
+ App.log.warning("Received VCard without data, ignoring")
+ return
+ } else if (tasks.size > 1) {
+ App.log.warning("Received multiple VCALs, using first one")
+ }
+
+ val event = tasks[0]
+ val local = localCollection!!.findByUid(event.uid!!)
+
+ if (cEntry.isAction(SyncEntry.Actions.ADD) || cEntry.isAction(SyncEntry.Actions.CHANGE)) {
+ processTask(event, local)
+ } else {
+ if (local != null) {
+ App.log.info("Removing local record #" + local.id + " which has been deleted on the server")
+ local.delete()
+ } else {
+ App.log.warning("Tried deleting a non-existent record: " + event.uid)
+ }
+ }
+ }
+
+ private fun processTask(newData: Task, localTask: LocalTask?): LocalTask {
+ var localTask = localTask
+ // delete local Task, if it exists
+ if (localTask != null) {
+ App.log.info("Updating " + newData.uid + " in local calendar")
+ localTask.eTag = newData.uid
+ localTask.update(newData)
+ syncResult.stats.numUpdates++
+ } else {
+ App.log.info("Adding " + newData.uid + " to local calendar")
+ localTask = LocalTask(localTaskList(), newData, newData.uid, newData.uid)
+ localTask.add()
+ syncResult.stats.numInserts++
+ }
+
+ return localTask
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.kt b/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.kt
index 089e0616..303c3cc3 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.kt
+++ b/app/src/main/java/com/etesync/syncadapter/ui/AccountActivity.kt
@@ -278,29 +278,32 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
for (serviceEntity in data.select(ServiceEntity::class.java).where(ServiceEntity.ACCOUNT.eq(account.name)).get()) {
val id = serviceEntity.id.toLong()
val service = serviceEntity.type
- if (service == CollectionInfo.Type.ADDRESS_BOOK) {
- info.carddav = AccountInfo.ServiceInfo()
- info.carddav!!.id = id
- info.carddav!!.refreshing = davService != null && davService!!.isRefreshing(id) || ContentResolver.isSyncActive(account, App.addressBooksAuthority)
- info.carddav!!.journals = JournalEntity.getJournals(data, serviceEntity)
-
- val accountManager = AccountManager.get(context)
- for (addrBookAccount in accountManager.getAccountsByType(App.addressBookAccountType)) {
- val addressBook = LocalAddressBook(context, addrBookAccount, null)
- try {
- if (account == addressBook.mainAccount)
- info.carddav!!.refreshing = info.carddav!!.refreshing or ContentResolver.isSyncActive(addrBookAccount, ContactsContract.AUTHORITY)
- } catch (e: ContactsStorageException) {
- }
+ when (service) {
+ CollectionInfo.Type.ADDRESS_BOOK -> {
+ info.carddav = AccountInfo.ServiceInfo()
+ info.carddav!!.id = id
+ info.carddav!!.refreshing = davService != null && davService!!.isRefreshing(id) || ContentResolver.isSyncActive(account, App.addressBooksAuthority)
+ info.carddav!!.journals = JournalEntity.getJournals(data, serviceEntity)
+
+ val accountManager = AccountManager.get(context)
+ for (addrBookAccount in accountManager.getAccountsByType(App.addressBookAccountType)) {
+ val addressBook = LocalAddressBook(context, addrBookAccount, null)
+ try {
+ if (account == addressBook.mainAccount)
+ info.carddav!!.refreshing = info.carddav!!.refreshing or ContentResolver.isSyncActive(addrBookAccount, ContactsContract.AUTHORITY)
+ } catch (e: ContactsStorageException) {
+ }
+ }
+ }
+ CollectionInfo.Type.CALENDAR -> {
+ info.caldav = AccountInfo.ServiceInfo()
+ info.caldav!!.id = id
+ info.caldav!!.refreshing = davService != null && davService!!.isRefreshing(id) ||
+ ContentResolver.isSyncActive(account, CalendarContract.AUTHORITY) ||
+ ContentResolver.isSyncActive(account, TaskProvider.ProviderName.OpenTasks.authority)
+ info.caldav!!.journals = JournalEntity.getJournals(data, serviceEntity)
}
- } else if (service == CollectionInfo.Type.CALENDAR) {
- info.caldav = AccountInfo.ServiceInfo()
- info.caldav!!.id = id
- info.caldav!!.refreshing = davService != null && davService!!.isRefreshing(id) ||
- ContentResolver.isSyncActive(account, CalendarContract.AUTHORITY) ||
- ContentResolver.isSyncActive(account, TaskProvider.ProviderName.OpenTasks.authority)
- info.caldav!!.journals = JournalEntity.getJournals(data, serviceEntity)
}
}
return info
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionActivity.kt b/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionActivity.kt
index a85e7fdd..43901e8d 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionActivity.kt
+++ b/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionActivity.kt
@@ -43,26 +43,29 @@ open class CreateCollectionActivity : BaseActivity() {
setContentView(R.layout.activity_create_collection)
val displayName = findViewById(R.id.display_name) as EditText
- if (info!!.type == CollectionInfo.Type.CALENDAR) {
- setTitle(R.string.create_calendar)
- displayName.setHint(R.string.create_calendar_display_name_hint)
-
- val colorSquare = findViewById(R.id.color)
- colorSquare.setOnClickListener {
- AmbilWarnaDialog(this@CreateCollectionActivity, (colorSquare.background as ColorDrawable).color, true, object : AmbilWarnaDialog.OnAmbilWarnaListener {
- override fun onCancel(dialog: AmbilWarnaDialog) {}
-
- override fun onOk(dialog: AmbilWarnaDialog, color: Int) {
- colorSquare.setBackgroundColor(color)
- }
- }).show()
+ when (info.type) {
+ CollectionInfo.Type.CALENDAR, CollectionInfo.Type.TASKS -> {
+ setTitle(R.string.create_calendar)
+ displayName.setHint(R.string.create_calendar_display_name_hint)
+
+ val colorSquare = findViewById(R.id.color)
+ colorSquare.setOnClickListener {
+ AmbilWarnaDialog(this@CreateCollectionActivity, (colorSquare.background as ColorDrawable).color, true, object : AmbilWarnaDialog.OnAmbilWarnaListener {
+ override fun onCancel(dialog: AmbilWarnaDialog) {}
+
+ override fun onOk(dialog: AmbilWarnaDialog, color: Int) {
+ colorSquare.setBackgroundColor(color)
+ }
+ }).show()
+ }
}
- } else {
- setTitle(R.string.create_addressbook)
- displayName.setHint(R.string.create_addressbook_display_name_hint)
+ CollectionInfo.Type.ADDRESS_BOOK -> {
+ setTitle(R.string.create_addressbook)
+ displayName.setHint(R.string.create_addressbook_display_name_hint)
- val colorGroup = findViewById(R.id.color_group)
- colorGroup.visibility = View.GONE
+ val colorGroup = findViewById(R.id.color_group)
+ colorGroup.visibility = View.GONE
+ }
}
}
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.kt
index b5ad7386..8da65548 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.kt
+++ b/app/src/main/java/com/etesync/syncadapter/ui/CreateCollectionFragment.kt
@@ -19,6 +19,7 @@ import android.support.v4.app.DialogFragment
import android.support.v4.app.LoaderManager
import android.support.v4.content.AsyncTaskLoader
import android.support.v4.content.Loader
+import at.bitfire.ical4android.TaskProvider
import com.etesync.syncadapter.*
import com.etesync.syncadapter.journalmanager.Crypto
import com.etesync.syncadapter.journalmanager.Exceptions
@@ -83,17 +84,15 @@ class CreateCollectionFragment : DialogFragment(), LoaderManager.LoaderCallbacks
override fun loadInBackground(): Exception? {
try {
- var authority: String
+ var authority: String = ""
val data = (context.applicationContext as App).data
// 1. find service ID
- if (info.type == CollectionInfo.Type.ADDRESS_BOOK) {
- authority = App.addressBooksAuthority
- } else if (info.type == CollectionInfo.Type.CALENDAR) {
- authority = CalendarContract.AUTHORITY
- } else {
- throw IllegalArgumentException("Collection must be an address book or calendar")
+ when (info.type){
+ CollectionInfo.Type.ADDRESS_BOOK -> authority = App.addressBooksAuthority
+ CollectionInfo.Type.CALENDAR -> authority = CalendarContract.AUTHORITY
+ CollectionInfo.Type.TASKS -> authority = TaskProvider.ProviderName.OpenTasks.authority
}
val serviceEntity = JournalModel.Service.fetch(data, account.name, info.type)
diff --git a/app/src/main/java/com/etesync/syncadapter/ui/PermissionsActivity.kt b/app/src/main/java/com/etesync/syncadapter/ui/PermissionsActivity.kt
index d616f85e..61ec0b4a 100644
--- a/app/src/main/java/com/etesync/syncadapter/ui/PermissionsActivity.kt
+++ b/app/src/main/java/com/etesync/syncadapter/ui/PermissionsActivity.kt
@@ -80,7 +80,7 @@ class PermissionsActivity : BaseActivity() {
val PERMISSION_WRITE_TASKS = "org.dmfs.permission.WRITE_TASKS"
fun requestAllPermissions(activity: Activity) {
- ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS), REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS)
+ ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS, PERMISSION_READ_TASKS, PERMISSION_WRITE_TASKS), REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS)
}
}
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a641e263..ee10083a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -306,6 +306,7 @@
Additional permissions required
Calendar sync failed (%s)
Contacts sync failed (%s)
+ Tasks sync failed (%s)
Error while %s
Integrity error while %s
Server error while %s
@@ -325,6 +326,7 @@
User is inactive
Calendar \"%s\" modified (%s)
Contacts modified (%s)
+ Tasks \"%s\" modified (%s)
%s modified.
%s added.\n%s updated.\n%s deleted.
diff --git a/app/src/main/res/xml/sync_tasks.xml b/app/src/main/res/xml/sync_tasks.xml
new file mode 100644
index 00000000..d5436d28
--- /dev/null
+++ b/app/src/main/res/xml/sync_tasks.xml
@@ -0,0 +1,12 @@
+
+
+