diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 24c5405e..072c30ad 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -127,15 +127,21 @@ android:name=".DavService" android:enabled="true"> </service> - <receiver - android:name=".AccountsChangedReceiver" - android:enabled="true" - android:exported="true"> + + <receiver android:name=".AccountsChangedReceiver"> <intent-filter> <action android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED"/> </intent-filter> </receiver> - + + <receiver android:name=".PackageChangedReceiver"> + <intent-filter> + <action android:name="android.intent.action.PACKAGE_ADDED"/> + <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED"/> + <data android:scheme="package"/> + </intent-filter> + </receiver> + <activity android:name=".ui.AccountsActivity" android:label="@string/app_name" diff --git a/app/src/main/java/at/bitfire/davdroid/Constants.java b/app/src/main/java/at/bitfire/davdroid/Constants.java index 5adc720c..22543d17 100644 --- a/app/src/main/java/at/bitfire/davdroid/Constants.java +++ b/app/src/main/java/at/bitfire/davdroid/Constants.java @@ -26,4 +26,6 @@ public class Constants { public static final Uri webUri = Uri.parse("https://davdroid.bitfire.at/?pk_campaign=davdroid-app"); + public static final int DEFAULT_SYNC_INTERVAL = 4 * 3600; // 4 hours + } diff --git a/app/src/main/java/at/bitfire/davdroid/PackageChangedReceiver.java b/app/src/main/java/at/bitfire/davdroid/PackageChangedReceiver.java new file mode 100644 index 00000000..dd076a59 --- /dev/null +++ b/app/src/main/java/at/bitfire/davdroid/PackageChangedReceiver.java @@ -0,0 +1,61 @@ +/* + * 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 at.bitfire.davdroid; + +import android.accounts.Account; +import android.annotation.SuppressLint; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; + +import at.bitfire.davdroid.model.ServiceDB; +import at.bitfire.davdroid.model.ServiceDB.Services; +import at.bitfire.davdroid.resource.LocalTaskList; +import at.bitfire.ical4android.TaskProvider; +import lombok.Cleanup; + +public class PackageChangedReceiver extends BroadcastReceiver { + + @Override + @SuppressLint("MissingPermission") + public void onReceive(Context context, Intent intent) { + if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction()) || + Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(intent.getAction())) { + + boolean tasksInstalled = LocalTaskList.tasksProviderAvailable(context); + App.log.info("Package (un)installed; OpenTasks provider now available = " + tasksInstalled); + + // check all accounts and (de)activate OpenTasks if a CalDAV service is defined + @Cleanup ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(context); + SQLiteDatabase db = dbHelper.getReadableDatabase(); + + @Cleanup Cursor cursor = db.query(Services._TABLE, new String[] { Services.ACCOUNT_NAME }, + Services.SERVICE + "=?", new String[] { Services.SERVICE_CALDAV }, null, null, null); + while (cursor.moveToNext()) { + Account account = new Account(cursor.getString(0), Constants.ACCOUNT_TYPE); + + if (tasksInstalled) { + ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 1); + try { + AccountSettings settings = new AccountSettings(context, account); + settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, Constants.DEFAULT_SYNC_INTERVAL); + } catch(InvalidAccountException ignored) { + } + } else + ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 0); + + } + + } + } + +} diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalTaskList.java b/app/src/main/java/at/bitfire/davdroid/resource/LocalTaskList.java index a6b1414f..b293a7fa 100644 --- a/app/src/main/java/at/bitfire/davdroid/resource/LocalTaskList.java +++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalTaskList.java @@ -45,9 +45,6 @@ public class LocalTaskList extends AndroidTaskList implements LocalCollection { LocalTask.COLUMN_ETAG }; - // can be cached, because after installing OpenTasks, you have to re-install DAVdroid anyway - private static Boolean tasksProviderAvailable; - @Override protected String[] taskBaseInfoColumns() { @@ -140,15 +137,11 @@ public class LocalTaskList extends AndroidTaskList implements LocalCollection { // helpers public static boolean tasksProviderAvailable(@NonNull Context context) { - if (tasksProviderAvailable != null) - return tasksProviderAvailable; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + return context.getPackageManager().resolveContentProvider(TaskProvider.ProviderName.OpenTasks.authority, 0) != null; else { - if (Build.VERSION.SDK_INT >= 23) - return context.getPackageManager().resolveContentProvider(TaskProvider.ProviderName.OpenTasks.authority, 0) != null; - else { - @Cleanup TaskProvider provider = TaskProvider.acquire(context.getContentResolver(), TaskProvider.ProviderName.OpenTasks); - return tasksProviderAvailable = (provider != null); - } + @Cleanup TaskProvider provider = TaskProvider.acquire(context.getContentResolver(), TaskProvider.ProviderName.OpenTasks); + return provider != null; } } diff --git a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.java b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.java index 7a5fb9b7..b2d787b6 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/setup/AccountDetailsFragment.java @@ -15,7 +15,6 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; import android.database.sqlite.SQLiteDatabase; -import android.os.Build; import android.os.Bundle; import android.provider.CalendarContract; import android.provider.ContactsContract; @@ -50,7 +49,6 @@ import lombok.Cleanup; public class AccountDetailsFragment extends Fragment { private static final String KEY_CONFIG = "config"; - private static final int DEFAULT_SYNC_INTERVAL = 4 * 3600; // 4 hours Spinner spnrGroupMethod; @@ -141,7 +139,7 @@ public class AccountDetailsFragment extends Fragment { // enable contact sync ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 1); - settings.setSyncInterval(ContactsContract.AUTHORITY, DEFAULT_SYNC_INTERVAL); + settings.setSyncInterval(ContactsContract.AUTHORITY, Constants.DEFAULT_SYNC_INTERVAL); } else // disable contact sync when CardDAV is not available ContentResolver.setIsSyncable(account, ContactsContract.AUTHORITY, 0); @@ -156,26 +154,16 @@ public class AccountDetailsFragment extends Fragment { // enable calendar sync ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 1); - settings.setSyncInterval(CalendarContract.AUTHORITY, DEFAULT_SYNC_INTERVAL); + settings.setSyncInterval(CalendarContract.AUTHORITY, Constants.DEFAULT_SYNC_INTERVAL); - // enable task sync, if possible - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - /* Android >=6, it's possible to gain OpenTasks permissions dynamically, so - * OpenTasks sync will be enabled by default. Setting the sync interval to "manually" - * if OpenTasks is not installed avoids the "sync error" in Android settings / Accounts. */ + // enable task sync if OpenTasks is installed + // further changes will be handled by PackageChangedReceiver + if (LocalTaskList.tasksProviderAvailable(getContext())) { ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 1); - settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, - LocalTaskList.tasksProviderAvailable(getContext()) ? DEFAULT_SYNC_INTERVAL : AccountSettings.SYNC_INTERVAL_MANUALLY); - } else { - // Android <6: enable task sync according to whether OpenTasks is accessible - if (LocalTaskList.tasksProviderAvailable(getContext())) { - ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 1); - settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, DEFAULT_SYNC_INTERVAL); - } else - // Android <6 only: disable OpenTasks sync forever when OpenTasks is not installed - // because otherwise, there will be a non-catchable SecurityException as soon as OpenTasks is installed - ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 0); - } + settings.setSyncInterval(TaskProvider.ProviderName.OpenTasks.authority, Constants.DEFAULT_SYNC_INTERVAL); + } else + ContentResolver.setIsSyncable(account, TaskProvider.ProviderName.OpenTasks.authority, 0); + } else { // disable calendar and task sync when CalDAV is not available ContentResolver.setIsSyncable(account, CalendarContract.AUTHORITY, 0); diff --git a/app/src/main/res/xml/sync_calendars.xml b/app/src/main/res/xml/sync_calendars.xml index 7adc91e9..1579537e 100644 --- a/app/src/main/res/xml/sync_calendars.xml +++ b/app/src/main/res/xml/sync_calendars.xml @@ -11,5 +11,4 @@ android:contentAuthority="com.android.calendar" android:allowParallelSyncs="true" android:supportsUploading="true" - android:isAlwaysSyncable="true" android:userVisible="true" /> diff --git a/app/src/main/res/xml/sync_contacts.xml b/app/src/main/res/xml/sync_contacts.xml index 1cd55f2f..ceb54f49 100644 --- a/app/src/main/res/xml/sync_contacts.xml +++ b/app/src/main/res/xml/sync_contacts.xml @@ -11,5 +11,4 @@ android:contentAuthority="com.android.contacts" android:allowParallelSyncs="true" android:supportsUploading="true" - android:isAlwaysSyncable="true" android:userVisible="true" /> diff --git a/app/src/main/res/xml/sync_tasks.xml b/app/src/main/res/xml/sync_tasks.xml index 76c6866a..1c2ec6db 100644 --- a/app/src/main/res/xml/sync_tasks.xml +++ b/app/src/main/res/xml/sync_tasks.xml @@ -11,5 +11,4 @@ android:contentAuthority="org.dmfs.tasks" android:allowParallelSyncs="true" android:supportsUploading="true" - android:isAlwaysSyncable="true" android:userVisible="true" />