mirror of
https://github.com/etesync/android
synced 2024-11-22 16:08:13 +00:00
Add Tasks.org support
This commit is contained in:
parent
a81973f816
commit
e01f54c687
@ -110,6 +110,19 @@
|
|||||||
android:resource="@xml/sync_tasks"/>
|
android:resource="@xml/sync_tasks"/>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".syncadapter.TasksOrgSyncAdapterService"
|
||||||
|
android:exported="true"
|
||||||
|
tools:ignore="ExportedService">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.content.SyncAdapter"/>
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="android.content.SyncAdapter"
|
||||||
|
android:resource="@xml/sync_tasks_org"/>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
|
||||||
<!-- Address book account -->
|
<!-- Address book account -->
|
||||||
<service
|
<service
|
||||||
|
@ -24,6 +24,7 @@ import android.provider.ContactsContract
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import at.bitfire.ical4android.AndroidCalendar
|
import at.bitfire.ical4android.AndroidCalendar
|
||||||
import at.bitfire.ical4android.CalendarStorageException
|
import at.bitfire.ical4android.CalendarStorageException
|
||||||
|
import at.bitfire.ical4android.TaskProvider.Companion.OPENTASK_PROVIDERS
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.log.Logger
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.model.*
|
import com.etesync.syncadapter.model.*
|
||||||
@ -85,8 +86,10 @@ class App : Application() {
|
|||||||
tasksFilter.addDataScheme("package")
|
tasksFilter.addDataScheme("package")
|
||||||
registerReceiver(PackageChangedReceiver(), tasksFilter)
|
registerReceiver(PackageChangedReceiver(), tasksFilter)
|
||||||
|
|
||||||
// check whether a tasks app is currently installed
|
OPENTASK_PROVIDERS.forEach {
|
||||||
PackageChangedReceiver.updateTaskSync(this@App)
|
// check whether a tasks app is currently installed
|
||||||
|
PackageChangedReceiver.updateTaskSync(this@App, it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
|
import at.bitfire.ical4android.TaskProvider.ProviderName
|
||||||
import com.etesync.syncadapter.log.Logger
|
import com.etesync.syncadapter.log.Logger
|
||||||
import com.etesync.syncadapter.resource.LocalTaskList
|
import com.etesync.syncadapter.resource.LocalTaskList
|
||||||
|
|
||||||
@ -23,15 +24,18 @@ class PackageChangedReceiver : BroadcastReceiver() {
|
|||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
if (Intent.ACTION_PACKAGE_ADDED == intent.action || Intent.ACTION_PACKAGE_FULLY_REMOVED == intent.action)
|
if (Intent.ACTION_PACKAGE_ADDED == intent.action || Intent.ACTION_PACKAGE_FULLY_REMOVED == intent.action) {
|
||||||
updateTaskSync(context)
|
TaskProvider.OPENTASK_PROVIDERS.forEach {
|
||||||
|
updateTaskSync(context, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
internal fun updateTaskSync(context: Context) {
|
internal fun updateTaskSync(context: Context, provider: ProviderName) {
|
||||||
val tasksInstalled = LocalTaskList.tasksProviderAvailable(context)
|
val tasksInstalled = LocalTaskList.tasksProviderAvailable(context, provider)
|
||||||
Logger.log.info("Package (un)installed; OpenTasks provider now available = $tasksInstalled")
|
Logger.log.info("Package (un)installed; ${provider.name} provider now available = $tasksInstalled")
|
||||||
|
|
||||||
for (account in AccountManager.get(context).getAccountsByType(App.accountType)) {
|
for (account in AccountManager.get(context).getAccountsByType(App.accountType)) {
|
||||||
val settings = AccountSettings(context, account)
|
val settings = AccountSettings(context, account)
|
||||||
@ -40,12 +44,12 @@ class PackageChangedReceiver : BroadcastReceiver() {
|
|||||||
if (tasksInstalled) {
|
if (tasksInstalled) {
|
||||||
if (calendarSyncInterval == null) {
|
if (calendarSyncInterval == null) {
|
||||||
// do nothing atm
|
// do nothing atm
|
||||||
} else if (ContentResolver.getIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority) <= 0) {
|
} else if (ContentResolver.getIsSyncable(account, provider.authority) <= 0) {
|
||||||
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 1)
|
ContentResolver.setIsSyncable(account, provider.authority, 1)
|
||||||
settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, calendarSyncInterval)
|
settings.setSyncInterval(provider.authority, calendarSyncInterval)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 0)
|
ContentResolver.setIsSyncable(account, provider.authority, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import at.bitfire.ical4android.AndroidTaskList
|
|||||||
import at.bitfire.ical4android.AndroidTaskListFactory
|
import at.bitfire.ical4android.AndroidTaskListFactory
|
||||||
import at.bitfire.ical4android.CalendarStorageException
|
import at.bitfire.ical4android.CalendarStorageException
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
|
import at.bitfire.ical4android.TaskProvider.ProviderName
|
||||||
import com.etesync.syncadapter.model.JournalEntity
|
import com.etesync.syncadapter.model.JournalEntity
|
||||||
import org.dmfs.tasks.contract.TaskContract.TaskLists
|
import org.dmfs.tasks.contract.TaskContract.TaskLists
|
||||||
import org.dmfs.tasks.contract.TaskContract.Tasks
|
import org.dmfs.tasks.contract.TaskContract.Tasks
|
||||||
@ -30,12 +31,12 @@ class LocalTaskList private constructor(
|
|||||||
companion object {
|
companion object {
|
||||||
val defaultColor = -0x743cb6 // light green 500
|
val defaultColor = -0x743cb6 // light green 500
|
||||||
|
|
||||||
fun tasksProviderAvailable(context: Context): Boolean {
|
fun tasksProviderAvailable(context: Context, provider: ProviderName): Boolean {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||||
return context.packageManager.resolveContentProvider(TaskProvider.ProviderName.OpenTasks.authority, 0) != null
|
return context.packageManager.resolveContentProvider(provider.authority, 0) != null
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
TaskProvider.acquire(context, TaskProvider.ProviderName.OpenTasks)?.use {
|
TaskProvider.acquire(context, provider)?.use {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -4,12 +4,13 @@ import android.accounts.Account
|
|||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.CalendarContract
|
import android.provider.CalendarContract
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider.Companion.OPENTASK_PROVIDERS
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.App
|
||||||
|
|
||||||
|
|
||||||
fun requestSync(account: Account?) {
|
fun requestSync(account: Account?) {
|
||||||
val authorities = arrayOf(App.addressBooksAuthority, CalendarContract.AUTHORITY, TaskProvider.ProviderName.OpenTasks.authority)
|
val authorities = arrayOf(App.addressBooksAuthority, CalendarContract.AUTHORITY) +
|
||||||
|
OPENTASK_PROVIDERS.map { it.authority }
|
||||||
|
|
||||||
for (authority in authorities) {
|
for (authority in authorities) {
|
||||||
val extras = Bundle()
|
val extras = Bundle()
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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 at.bitfire.ical4android.TaskProvider
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronization manager for CalDAV collections; handles tasks ({@code VTODO}).
|
||||||
|
*/
|
||||||
|
class TasksOrgSyncAdapterService: SyncAdapterService() {
|
||||||
|
|
||||||
|
override fun syncAdapter() =
|
||||||
|
TasksSyncAdapterService.TasksSyncAdapter(this, TaskProvider.ProviderName.TasksOrg)
|
||||||
|
|
||||||
|
}
|
@ -17,6 +17,7 @@ import android.os.Build
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import at.bitfire.ical4android.AndroidTaskList
|
import at.bitfire.ical4android.AndroidTaskList
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
|
import at.bitfire.ical4android.TaskProvider.ProviderName
|
||||||
import com.etesync.syncadapter.AccountSettings
|
import com.etesync.syncadapter.AccountSettings
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.App
|
||||||
import com.etesync.syncadapter.Constants
|
import com.etesync.syncadapter.Constants
|
||||||
@ -35,18 +36,18 @@ import java.util.*
|
|||||||
*/
|
*/
|
||||||
class TasksSyncAdapterService: SyncAdapterService() {
|
class TasksSyncAdapterService: SyncAdapterService() {
|
||||||
|
|
||||||
override fun syncAdapter() = TasksSyncAdapter(this)
|
override fun syncAdapter() = TasksSyncAdapter(this, ProviderName.OpenTasks)
|
||||||
|
|
||||||
|
|
||||||
class TasksSyncAdapter(
|
class TasksSyncAdapter(
|
||||||
context: Context
|
context: Context,
|
||||||
|
private val name: ProviderName
|
||||||
): SyncAdapter(context) {
|
): SyncAdapter(context) {
|
||||||
override val syncErrorTitle = R.string.sync_error_tasks
|
override val syncErrorTitle = R.string.sync_error_tasks
|
||||||
override val notificationManager = SyncNotification(context, "journals-tasks", Constants.NOTIFICATION_TASK_SYNC)
|
override val notificationManager = SyncNotification(context, "journals-tasks", Constants.NOTIFICATION_TASK_SYNC)
|
||||||
|
|
||||||
override fun onPerformSyncDo(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
|
override fun onPerformSyncDo(account: Account, extras: Bundle, authority: String, provider: ContentProviderClient, syncResult: SyncResult) {
|
||||||
|
|
||||||
val taskProvider = TaskProvider.fromProviderClient(context, provider)
|
val taskProvider = TaskProvider.fromProviderClient(context, provider, name)
|
||||||
|
|
||||||
// make sure account can be seen by OpenTasks
|
// make sure account can be seen by OpenTasks
|
||||||
if (Build.VERSION.SDK_INT >= 26)
|
if (Build.VERSION.SDK_INT >= 26)
|
||||||
|
@ -26,6 +26,7 @@ import androidx.appcompat.app.AlertDialog
|
|||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
|
import at.bitfire.ical4android.TaskProvider.Companion.OPENTASK_PROVIDERS
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.journalmanager.Crypto
|
import com.etesync.journalmanager.Crypto
|
||||||
@ -378,7 +379,9 @@ class AccountActivity : BaseActivity(), Toolbar.OnMenuItemClickListener, PopupMe
|
|||||||
info.taskdav = AccountInfo.ServiceInfo()
|
info.taskdav = AccountInfo.ServiceInfo()
|
||||||
info.taskdav!!.id = id
|
info.taskdav!!.id = id
|
||||||
info.taskdav!!.refreshing = davService != null && davService!!.isRefreshing(id) ||
|
info.taskdav!!.refreshing = davService != null && davService!!.isRefreshing(id) ||
|
||||||
ContentResolver.isSyncActive(account, TaskProvider.ProviderName.OpenTasks.authority)
|
OPENTASK_PROVIDERS.any {
|
||||||
|
ContentResolver.isSyncActive(account, it.authority)
|
||||||
|
}
|
||||||
info.taskdav!!.journals = JournalEntity.getJournals(data, serviceEntity)
|
info.taskdav!!.journals = JournalEntity.getJournals(data, serviceEntity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import androidx.loader.content.AsyncTaskLoader
|
|||||||
import androidx.loader.content.Loader
|
import androidx.loader.content.Loader
|
||||||
import androidx.preference.*
|
import androidx.preference.*
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
|
import at.bitfire.ical4android.TaskProvider.Companion.OPENTASK_PROVIDERS
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
@ -121,7 +122,9 @@ class AccountSettingsActivity : BaseActivity() {
|
|||||||
val newInterval = java.lang.Long.parseLong(newValue as String)
|
val newInterval = java.lang.Long.parseLong(newValue as String)
|
||||||
settings.setSyncInterval(App.addressBooksAuthority, newInterval)
|
settings.setSyncInterval(App.addressBooksAuthority, newInterval)
|
||||||
settings.setSyncInterval(CalendarContract.AUTHORITY, newInterval)
|
settings.setSyncInterval(CalendarContract.AUTHORITY, newInterval)
|
||||||
settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, newInterval)
|
OPENTASK_PROVIDERS.forEach {
|
||||||
|
settings.setSyncInterval(it.authority, newInterval)
|
||||||
|
}
|
||||||
loaderManager.restartLoader(0, arguments, this@AccountSettingsFragment)
|
loaderManager.restartLoader(0, arguments, this@AccountSettingsFragment)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import androidx.loader.app.LoaderManager
|
|||||||
import androidx.loader.content.AsyncTaskLoader
|
import androidx.loader.content.AsyncTaskLoader
|
||||||
import androidx.loader.content.Loader
|
import androidx.loader.content.Loader
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
|
import at.bitfire.ical4android.TaskProvider.Companion.OPENTASK_PROVIDERS
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.journalmanager.Crypto
|
import com.etesync.journalmanager.Crypto
|
||||||
import com.etesync.journalmanager.Exceptions
|
import com.etesync.journalmanager.Exceptions
|
||||||
@ -84,15 +85,14 @@ class CreateCollectionFragment : DialogFragment(), LoaderManager.LoaderCallbacks
|
|||||||
|
|
||||||
override fun loadInBackground(): Exception? {
|
override fun loadInBackground(): Exception? {
|
||||||
try {
|
try {
|
||||||
var authority: String = ""
|
|
||||||
|
|
||||||
val data = (context.applicationContext as App).data
|
val data = (context.applicationContext as App).data
|
||||||
|
|
||||||
// 1. find service ID
|
// 1. find service ID
|
||||||
when (info.enumType){
|
val authorities = when (info.enumType){
|
||||||
CollectionInfo.Type.ADDRESS_BOOK -> authority = App.addressBooksAuthority
|
CollectionInfo.Type.ADDRESS_BOOK -> listOf(App.addressBooksAuthority)
|
||||||
CollectionInfo.Type.CALENDAR -> authority = CalendarContract.AUTHORITY
|
CollectionInfo.Type.CALENDAR -> listOf(CalendarContract.AUTHORITY)
|
||||||
CollectionInfo.Type.TASKS -> authority = TaskProvider.ProviderName.OpenTasks.authority
|
CollectionInfo.Type.TASKS -> OPENTASK_PROVIDERS.map { it.authority }
|
||||||
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
val serviceEntity = JournalModel.Service.fetchOrCreate(data, account.name, info.enumType)
|
val serviceEntity = JournalModel.Service.fetchOrCreate(data, account.name, info.enumType)
|
||||||
@ -127,7 +127,7 @@ class CreateCollectionFragment : DialogFragment(), LoaderManager.LoaderCallbacks
|
|||||||
journalManager.update(journal)
|
journalManager.update(journal)
|
||||||
}
|
}
|
||||||
|
|
||||||
requestSync(authority)
|
authorities.forEach { requestSync(it) }
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
return e
|
return e
|
||||||
} catch (e: Exceptions.HttpException) {
|
} catch (e: Exceptions.HttpException) {
|
||||||
|
@ -25,6 +25,7 @@ import android.view.Menu
|
|||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import at.bitfire.ical4android.TaskProvider.ProviderName
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
import com.etesync.syncadapter.Constants.KEY_ACCOUNT
|
||||||
@ -156,7 +157,7 @@ class DebugInfoActivity : BaseActivity(), LoaderManager.LoaderCallbacks<String>
|
|||||||
.append(if (powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)) "yes" else "no")
|
.append(if (powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)) "yes" else "no")
|
||||||
.append("\n")
|
.append("\n")
|
||||||
// permissions
|
// permissions
|
||||||
for (permission in arrayOf(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR, PermissionsActivity.PERMISSION_READ_TASKS, PermissionsActivity.PERMISSION_WRITE_TASKS))
|
for (permission in arrayOf(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR) + ProviderName.OpenTasks.permissions + ProviderName.TasksOrg.permissions)
|
||||||
report.append(permission).append(" permission: ")
|
report.append(permission).append(" permission: ")
|
||||||
.append(if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) "granted" else "denied")
|
.append(if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) "granted" else "denied")
|
||||||
.append("\n")
|
.append("\n")
|
||||||
@ -169,7 +170,7 @@ class DebugInfoActivity : BaseActivity(), LoaderManager.LoaderCallbacks<String>
|
|||||||
for (acct in accountManager.getAccountsByType(context.getString(R.string.account_type)))
|
for (acct in accountManager.getAccountsByType(context.getString(R.string.account_type)))
|
||||||
try {
|
try {
|
||||||
val settings = AccountSettings(context, acct)
|
val settings = AccountSettings(context, acct)
|
||||||
report.append("Account: ").append(acct.name).append("\n" + " Address book sync. interval: ").append(syncStatus(settings, App.addressBooksAuthority)).append("\n" + " Calendar sync. interval: ").append(syncStatus(settings, CalendarContract.AUTHORITY)).append("\n" + " OpenTasks sync. interval: ").append(syncStatus(settings, "org.dmfs.tasks")).append("\n" + " WiFi only: ").append(settings.syncWifiOnly)
|
report.append("Account: ").append(acct.name).append("\n" + " Address book sync. interval: ").append(syncStatus(settings, App.addressBooksAuthority)).append("\n" + " Calendar sync. interval: ").append(syncStatus(settings, CalendarContract.AUTHORITY)).append("\n" + " OpenTasks sync. interval: ").append(syncStatus(settings, ProviderName.OpenTasks.authority)).append("\n" + " Tasks.org sync. interval: ").append(syncStatus(settings, ProviderName.TasksOrg.authority)).append("\n" + " WiFi only: ").append(settings.syncWifiOnly)
|
||||||
if (settings.syncWifiOnlySSID != null)
|
if (settings.syncWifiOnlySSID != null)
|
||||||
report.append(", SSID: ").append(settings.syncWifiOnlySSID)
|
report.append(", SSID: ").append(settings.syncWifiOnlySSID)
|
||||||
report.append("\n [CardDAV] Contact group method: ").append(settings.groupMethod)
|
report.append("\n [CardDAV] Contact group method: ").append(settings.groupMethod)
|
||||||
|
@ -19,6 +19,7 @@ import at.bitfire.ical4android.Event
|
|||||||
import at.bitfire.ical4android.InvalidCalendarException
|
import at.bitfire.ical4android.InvalidCalendarException
|
||||||
import at.bitfire.ical4android.Task
|
import at.bitfire.ical4android.Task
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
|
import at.bitfire.ical4android.TaskProvider.Companion.OPENTASK_PROVIDERS
|
||||||
import at.bitfire.vcard4android.Contact
|
import at.bitfire.vcard4android.Contact
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.App
|
||||||
import com.etesync.syncadapter.Constants
|
import com.etesync.syncadapter.Constants
|
||||||
@ -116,15 +117,17 @@ class JournalItemActivity : BaseActivity(), Refreshable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
CollectionInfo.Type.TASKS -> {
|
CollectionInfo.Type.TASKS -> {
|
||||||
val provider = TaskProvider.acquire(this, TaskProvider.ProviderName.OpenTasks)!!
|
OPENTASK_PROVIDERS.forEach {
|
||||||
val localTaskList = LocalTaskList.findByName(account, provider, LocalTaskList.Factory, info.uid!!)!!
|
val provider = TaskProvider.acquire(this, it)!!
|
||||||
val task = Task.tasksFromReader(StringReader(syncEntry.content))[0]
|
val localTaskList = LocalTaskList.findByName(account, provider, LocalTaskList.Factory, info.uid!!)!!
|
||||||
var localTask = localTaskList.findByUid(task.uid!!)
|
val task = Task.tasksFromReader(StringReader(syncEntry.content))[0]
|
||||||
if (localTask != null) {
|
var localTask = localTaskList.findByUid(task.uid!!)
|
||||||
localTask.updateAsDirty(task)
|
if (localTask != null) {
|
||||||
} else {
|
localTask.updateAsDirty(task)
|
||||||
localTask = LocalTask(localTaskList, task, task.uid, null)
|
} else {
|
||||||
localTask.addAsDirty()
|
localTask = LocalTask(localTaskList, task, task.uid, null)
|
||||||
|
localTask.addAsDirty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CollectionInfo.Type.ADDRESS_BOOK -> {
|
CollectionInfo.Type.ADDRESS_BOOK -> {
|
||||||
|
@ -13,8 +13,11 @@ import android.app.Activity
|
|||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.annotation.IdRes
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import at.bitfire.ical4android.TaskProvider.Companion.OPENTASK_PROVIDERS
|
||||||
|
import at.bitfire.ical4android.TaskProvider.ProviderName
|
||||||
import com.etesync.syncadapter.Constants
|
import com.etesync.syncadapter.Constants
|
||||||
import com.etesync.syncadapter.R
|
import com.etesync.syncadapter.R
|
||||||
import com.etesync.syncadapter.resource.LocalTaskList
|
import com.etesync.syncadapter.resource.LocalTaskList
|
||||||
@ -38,16 +41,10 @@ class PermissionsActivity : BaseActivity() {
|
|||||||
val noContactsPermissions = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED
|
val noContactsPermissions = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED
|
||||||
findViewById<View>(R.id.contacts_permissions).visibility = if (noContactsPermissions) View.VISIBLE else View.GONE
|
findViewById<View>(R.id.contacts_permissions).visibility = if (noContactsPermissions) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
val noTaskPermissions: Boolean
|
val needOpenTaskPermissions = setupPermissions(ProviderName.OpenTasks, R.id.opentasks_permissions)
|
||||||
if (LocalTaskList.tasksProviderAvailable(this)) {
|
val needTasksOrgPermissions = setupPermissions(ProviderName.TasksOrg, R.id.tasksorg_permissions)
|
||||||
noTaskPermissions = ActivityCompat.checkSelfPermission(this, PERMISSION_READ_TASKS) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, PERMISSION_WRITE_TASKS) != PackageManager.PERMISSION_GRANTED
|
|
||||||
findViewById<View>(R.id.opentasks_permissions).visibility = if (noTaskPermissions) View.VISIBLE else View.GONE
|
|
||||||
} else {
|
|
||||||
findViewById<View>(R.id.opentasks_permissions).visibility = View.GONE
|
|
||||||
noTaskPermissions = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!noCalendarPermissions && !noContactsPermissions && !noTaskPermissions) {
|
if (!noCalendarPermissions && !noContactsPermissions && !(needOpenTaskPermissions || needTasksOrgPermissions)) {
|
||||||
val nm = NotificationManagerCompat.from(this)
|
val nm = NotificationManagerCompat.from(this)
|
||||||
nm.cancel(Constants.NOTIFICATION_PERMISSIONS)
|
nm.cancel(Constants.NOTIFICATION_PERMISSIONS)
|
||||||
|
|
||||||
@ -55,6 +52,15 @@ class PermissionsActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupPermissions(provider: ProviderName, @IdRes id: Int): Boolean {
|
||||||
|
val providerAvailable = LocalTaskList.tasksProviderAvailable(this, provider)
|
||||||
|
val hasPermissions = providerAvailable && provider.permissions.all {
|
||||||
|
ActivityCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
|
||||||
|
}
|
||||||
|
findViewById<View>(id).visibility = if (hasPermissions) View.GONE else View.VISIBLE
|
||||||
|
return providerAvailable && !hasPermissions
|
||||||
|
}
|
||||||
|
|
||||||
fun requestCalendarPermissions(v: View) {
|
fun requestCalendarPermissions(v: View) {
|
||||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR), 0)
|
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR), 0)
|
||||||
}
|
}
|
||||||
@ -64,7 +70,11 @@ class PermissionsActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun requestOpenTasksPermissions(v: View) {
|
fun requestOpenTasksPermissions(v: View) {
|
||||||
ActivityCompat.requestPermissions(this, arrayOf(PERMISSION_READ_TASKS, PERMISSION_WRITE_TASKS), 0)
|
ActivityCompat.requestPermissions(this, ProviderName.OpenTasks.permissions, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requestTasksOrgPermissions(v: View) {
|
||||||
|
ActivityCompat.requestPermissions(this, ProviderName.TasksOrg.permissions, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||||
@ -75,11 +85,8 @@ class PermissionsActivity : BaseActivity() {
|
|||||||
companion object {
|
companion object {
|
||||||
private val REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124
|
private val REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124
|
||||||
|
|
||||||
val PERMISSION_READ_TASKS = "org.dmfs.permission.READ_TASKS"
|
|
||||||
val PERMISSION_WRITE_TASKS = "org.dmfs.permission.WRITE_TASKS"
|
|
||||||
|
|
||||||
fun requestAllPermissions(activity: Activity) {
|
fun requestAllPermissions(activity: Activity) {
|
||||||
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)
|
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS) + OPENTASK_PROVIDERS.flatMap { it.permissions.toList() }, REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import android.widget.TextView
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import at.bitfire.ical4android.CalendarStorageException
|
import at.bitfire.ical4android.CalendarStorageException
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
|
import at.bitfire.ical4android.TaskProvider.Companion.OPENTASK_PROVIDERS
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
import com.etesync.syncadapter.App
|
import com.etesync.syncadapter.App
|
||||||
import com.etesync.syncadapter.Constants
|
import com.etesync.syncadapter.Constants
|
||||||
@ -212,7 +213,9 @@ class ViewCollectionActivity : BaseActivity(), Refreshable {
|
|||||||
}
|
}
|
||||||
CollectionInfo.Type.TASKS -> {
|
CollectionInfo.Type.TASKS -> {
|
||||||
try {
|
try {
|
||||||
val providerClient = TaskProvider.acquire(this@ViewCollectionActivity, TaskProvider.ProviderName.OpenTasks)
|
val providerClient = OPENTASK_PROVIDERS.mapNotNull {
|
||||||
|
TaskProvider.acquire(this@ViewCollectionActivity, it)
|
||||||
|
}.firstOrNull()
|
||||||
if (providerClient == null) {
|
if (providerClient == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import android.provider.CalendarContract
|
|||||||
import android.provider.ContactsContract
|
import android.provider.ContactsContract
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import at.bitfire.ical4android.*
|
import at.bitfire.ical4android.*
|
||||||
|
import at.bitfire.ical4android.TaskProvider.Companion.OPENTASK_PROVIDERS
|
||||||
import at.bitfire.vcard4android.BatchOperation
|
import at.bitfire.vcard4android.BatchOperation
|
||||||
import at.bitfire.vcard4android.Contact
|
import at.bitfire.vcard4android.Contact
|
||||||
import at.bitfire.vcard4android.ContactsStorageException
|
import at.bitfire.vcard4android.ContactsStorageException
|
||||||
@ -282,40 +283,44 @@ class ImportFragment : DialogFragment() {
|
|||||||
|
|
||||||
finishParsingFile(tasks.size)
|
finishParsingFile(tasks.size)
|
||||||
|
|
||||||
val provider = TaskProvider.acquire(context, TaskProvider.ProviderName.OpenTasks)
|
val providers = OPENTASK_PROVIDERS.mapNotNull {
|
||||||
if (provider == null) {
|
TaskProvider.acquire(context, it)
|
||||||
|
}
|
||||||
|
if (providers.isEmpty()) {
|
||||||
result.e = Exception("Failed to acquire tasks content provider.")
|
result.e = Exception("Failed to acquire tasks content provider.")
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
val localTaskList: LocalTaskList?
|
providers.forEach {
|
||||||
try {
|
val localTaskList: LocalTaskList?
|
||||||
localTaskList = LocalTaskList.findByName(account, provider, LocalTaskList.Factory, info.uid!!)
|
|
||||||
if (localTaskList == null) {
|
|
||||||
throw FileNotFoundException("Failed to load local resource.")
|
|
||||||
}
|
|
||||||
} catch (e: FileNotFoundException) {
|
|
||||||
Logger.log.info("Fail" + e.localizedMessage)
|
|
||||||
result.e = e
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
for (task in tasks) {
|
|
||||||
try {
|
try {
|
||||||
var localTask = localTaskList.findByUid(task.uid!!)
|
localTaskList = LocalTaskList.findByName(account, it, LocalTaskList.Factory, info.uid!!)
|
||||||
if (localTask != null) {
|
if (localTaskList == null) {
|
||||||
localTask.updateAsDirty(task)
|
throw FileNotFoundException("Failed to load local resource.")
|
||||||
result.updated++
|
|
||||||
} else {
|
|
||||||
localTask = LocalTask(localTaskList, task, task.uid, null)
|
|
||||||
localTask.addAsDirty()
|
|
||||||
result.added++
|
|
||||||
}
|
}
|
||||||
} catch (e: CalendarStorageException) {
|
} catch (e: FileNotFoundException) {
|
||||||
e.printStackTrace()
|
Logger.log.info("Fail" + e.localizedMessage)
|
||||||
|
result.e = e
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
entryProcessed()
|
for (task in tasks) {
|
||||||
|
try {
|
||||||
|
var localTask = localTaskList.findByUid(task.uid!!)
|
||||||
|
if (localTask != null) {
|
||||||
|
localTask.updateAsDirty(task)
|
||||||
|
result.updated++
|
||||||
|
} else {
|
||||||
|
localTask = LocalTask(localTaskList, task, task.uid, null)
|
||||||
|
localTask.addAsDirty()
|
||||||
|
result.added++
|
||||||
|
}
|
||||||
|
} catch (e: CalendarStorageException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
entryProcessed()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (info.enumType == CollectionInfo.Type.ADDRESS_BOOK) {
|
} else if (info.enumType == CollectionInfo.Type.ADDRESS_BOOK) {
|
||||||
val uidToLocalId = HashMap<String?, Long>()
|
val uidToLocalId = HashMap<String?, Long>()
|
||||||
|
@ -21,6 +21,7 @@ import android.provider.CalendarContract
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import at.bitfire.ical4android.TaskProvider
|
import at.bitfire.ical4android.TaskProvider
|
||||||
|
import at.bitfire.ical4android.TaskProvider.Companion.OPENTASK_PROVIDERS
|
||||||
import com.etesync.syncadapter.*
|
import com.etesync.syncadapter.*
|
||||||
import com.etesync.journalmanager.Crypto
|
import com.etesync.journalmanager.Crypto
|
||||||
import com.etesync.journalmanager.Exceptions
|
import com.etesync.journalmanager.Exceptions
|
||||||
@ -153,11 +154,13 @@ class SetupEncryptionFragment : DialogFragment() {
|
|||||||
// calendar sync is automatically enabled by isAlwaysSyncable="true" in res/xml/sync_contacts.xml
|
// calendar sync is automatically enabled by isAlwaysSyncable="true" in res/xml/sync_contacts.xml
|
||||||
settings.setSyncInterval(CalendarContract.AUTHORITY, Constants.DEFAULT_SYNC_INTERVAL.toLong())
|
settings.setSyncInterval(CalendarContract.AUTHORITY, Constants.DEFAULT_SYNC_INTERVAL.toLong())
|
||||||
|
|
||||||
// enable task sync if OpenTasks is installed
|
OPENTASK_PROVIDERS.forEach {
|
||||||
// further changes will be handled by PackageChangedReceiver
|
// enable task sync if OpenTasks is installed
|
||||||
if (LocalTaskList.tasksProviderAvailable(context!!)) {
|
// further changes will be handled by PackageChangedReceiver
|
||||||
ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 1)
|
if (LocalTaskList.tasksProviderAvailable(context!!, it)) {
|
||||||
settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, Constants.DEFAULT_SYNC_INTERVAL.toLong())
|
ContentResolver.setIsSyncable(account, it.authority, 1)
|
||||||
|
settings.setSyncInterval(it.authority, Constants.DEFAULT_SYNC_INTERVAL.toLong())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 0)
|
ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 0)
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
tools:ignore="UselessParent">
|
tools:ignore="UselessParent">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -98,6 +99,31 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/tasksorg_permissions"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:ignore="UselessParent">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/TextView.Heading"
|
||||||
|
android:text="@string/permissions_tasks_org"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/permissions_tasks_org_details"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/permissions_tasks_org_request"
|
||||||
|
android:onClick="requestTasksOrgPermissions"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
@ -196,6 +196,9 @@
|
|||||||
<string name="permissions_opentasks">OpenTasks permissions</string>
|
<string name="permissions_opentasks">OpenTasks permissions</string>
|
||||||
<string name="permissions_opentasks_details">To synchronize tasks with your local task lists, EteSync needs to access OpenTasks.</string>
|
<string name="permissions_opentasks_details">To synchronize tasks with your local task lists, EteSync needs to access OpenTasks.</string>
|
||||||
<string name="permissions_opentasks_request">Request OpenTasks permissions</string>
|
<string name="permissions_opentasks_request">Request OpenTasks permissions</string>
|
||||||
|
<string name="permissions_tasks_org">Tasks.org permissions</string>
|
||||||
|
<string name="permissions_tasks_org_details">To synchronize tasks with your local task lists, EteSync needs to access Tasks.org.</string>
|
||||||
|
<string name="permissions_tasks_org_request">Request Tasks.org permissions</string>
|
||||||
|
|
||||||
<!-- AddAccountActivity -->
|
<!-- AddAccountActivity -->
|
||||||
<string name="login_title">Add account</string>
|
<string name="login_title">Add account</string>
|
||||||
|
12
app/src/main/res/xml/sync_tasks_org.xml
Normal file
12
app/src/main/res/xml/sync_tasks_org.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<!--
|
||||||
|
~ 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
|
||||||
|
-->
|
||||||
|
|
||||||
|
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:accountType="@string/account_type"
|
||||||
|
android:contentAuthority="org.tasks.opentasks"
|
||||||
|
android:supportsUploading="true" />
|
@ -1 +1 @@
|
|||||||
Subproject commit c0459f905571ab2e08e8af9ac40a96200d8cb862
|
Subproject commit 0a070c7866792756d90be429522127ef9108eff8
|
Loading…
Reference in New Issue
Block a user