From 753c4b05a5d94fdfe7810997a250f1d9d82983e4 Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Wed, 16 Mar 2016 18:23:52 +0100 Subject: [PATCH] Allow time-range filtering of events (to the past) * add account setting + GUI: restrict time range in the past * add support for restricted time range VEVENT synchronization * fix bug in handling changed exceptions of recurring events --- app/build.gradle | 4 +-- .../at/bitfire/davdroid/AccountSettings.java | 21 +++++++++++++++ .../main/java/at/bitfire/davdroid/App.java | 16 +---------- .../davdroid/resource/LocalCalendar.java | 7 ++--- .../syncadapter/CalendarSyncManager.java | 14 +++++++++- .../syncadapter/TasksSyncManager.java | 4 ++- .../davdroid/ui/AccountSettingsFragment.java | 27 +++++++++++++++++++ app/src/main/res/values/strings.xml | 7 +++++ app/src/main/res/xml/settings_account.xml | 7 +++++ dav4android | 2 +- ical4android | 2 +- vcard4android | 2 +- 12 files changed, 86 insertions(+), 27 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index cf94ac94..c33deeae 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,7 +18,7 @@ android { targetSdkVersion 22 versionCode 87 - versionName "1.0-alpha1" + versionName "1.0-alpha2" buildConfigField "long", "buildTime", System.currentTimeMillis() + "L" } @@ -71,7 +71,7 @@ dependencies { compile 'com.github.yukuku:ambilwarna:2.0.1' compile project(':MemorizingTrustManager') - androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.1.2' + androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.2.0' compile 'dnsjava:dnsjava:2.1.7' compile 'org.apache.commons:commons-lang3:3.4' } diff --git a/app/src/main/java/at/bitfire/davdroid/AccountSettings.java b/app/src/main/java/at/bitfire/davdroid/AccountSettings.java index 30497c68..0f1484bf 100644 --- a/app/src/main/java/at/bitfire/davdroid/AccountSettings.java +++ b/app/src/main/java/at/bitfire/davdroid/AccountSettings.java @@ -47,6 +47,14 @@ public class AccountSettings { KEY_AUTH_PREEMPTIVE = "auth_preemptive", KEY_LAST_ANDROID_VERSION = "last_android_version"; + /* Time range limitation to the past [days] + value = null default value (DEFAULT_TIME_RANGE_PAST_DAYS) + < 0 (-1) no limit + >= 0 entries more than n days in the past won't be synchronized + */ + private final static String KEY_TIME_RANGE_PAST_DAYS = "time_range_past_days"; + private final static int DEFAULT_TIME_RANGE_PAST_DAYS = 90; + public final static long SYNC_INTERVAL_MANUALLY = -1; final Context context; @@ -152,6 +160,19 @@ public class AccountSettings { } } + public Integer getTimeRangePastDays() { + String strDays = accountManager.getUserData(account, KEY_TIME_RANGE_PAST_DAYS); + if (strDays != null) { + int days = Integer.valueOf(strDays); + return days < 0 ? null : days; + } else + return DEFAULT_TIME_RANGE_PAST_DAYS; + } + + public void setTimeRangePastDays(Integer days) { + accountManager.setUserData(account, KEY_TIME_RANGE_PAST_DAYS, String.valueOf(days == null ? -1 : days)); + } + // update from previous account settings diff --git a/app/src/main/java/at/bitfire/davdroid/App.java b/app/src/main/java/at/bitfire/davdroid/App.java index cbe02cd6..7c36998a 100644 --- a/app/src/main/java/at/bitfire/davdroid/App.java +++ b/app/src/main/java/at/bitfire/davdroid/App.java @@ -29,7 +29,7 @@ import de.duenndns.ssl.MemorizingTrustManager; import lombok.Getter; import okhttp3.internal.tls.OkHostnameVerifier; -public class App extends Application implements SharedPreferences.OnSharedPreferenceChangeListener { +public class App extends Application { public static final String PREF_FILE = "global", PREF_LOG_TO_FILE = "log_to_file"; @@ -57,20 +57,6 @@ public class App extends Application implements SharedPreferences.OnSharedPrefer hostnameVerifier = mtm.wrapHostnameVerifier(OkHostnameVerifier.INSTANCE); reinitLogger(); - preferences.registerOnSharedPreferenceChangeListener(this); - } - - @Override - public void onTerminate() { - // will never be called on production devices - super.onTerminate(); - - preferences.unregisterOnSharedPreferenceChangeListener(this); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - reinitLogger(); } diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java index 76b0a85b..e685c95e 100644 --- a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java +++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java @@ -181,22 +181,19 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection { App.log.fine("Found deleted exception, removing; then re-schuling original event"); long id = cursor.getLong(0), // can't be null (by definition) originalID = cursor.getLong(1); // can't be null (by query) - int sequence = cursor.isNull(2) ? 0 : cursor.getInt(2); - - // FIXME sequence / cursor2 not used // get original event's SEQUENCE @Cleanup Cursor cursor2 = provider.query( syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, originalID)), new String[] { LocalEvent.COLUMN_SEQUENCE }, null, null, null); - int originalSequence = cursor.isNull(0) ? 0 : cursor.getInt(0); + int originalSequence = (cursor2 == null || cursor2.isNull(0)) ? 0 : cursor2.getInt(0); BatchOperation batch = new BatchOperation(provider); // re-schedule original event and set it to DIRTY batch.enqueue(ContentProviderOperation.newUpdate( syncAdapterURI(ContentUris.withAppendedId(Events.CONTENT_URI, originalID))) - .withValue(LocalEvent.COLUMN_SEQUENCE, originalSequence) + .withValue(LocalEvent.COLUMN_SEQUENCE, originalSequence + 1) .withValue(Events.DIRTY, DIRTY_INCREASE_SEQUENCE) .build()); // remove exception diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.java b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.java index e03b0ad4..b21feb9f 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.java +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarSyncManager.java @@ -23,6 +23,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.util.Calendar; +import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -114,8 +116,18 @@ public class CalendarSyncManager extends SyncManager { @Override protected void listRemote() throws IOException, HttpException, DavException { + // calculate time range limits + Date limitStart = null; + Integer pastDays = settings.getTimeRangePastDays(); + if (pastDays != null) { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.DAY_OF_MONTH, -pastDays); + limitStart = calendar.getTime(); + } + // fetch list of remote VEVENTs and build hash table to index file name - davCalendar().calendarQuery("VEVENT"); + davCalendar().calendarQuery("VEVENT", limitStart, null); + remoteResources = new HashMap<>(davCollection.members.size()); for (DavResource iCal : davCollection.members) { String fileName = iCal.fileName(); diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.java b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.java index be1fc40f..cd735723 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.java +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncManager.java @@ -23,6 +23,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.util.Calendar; +import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -112,7 +114,7 @@ public class TasksSyncManager extends SyncManager { @Override protected void listRemote() throws IOException, HttpException, DavException { // fetch list of remote VTODOs and build hash table to index file name - davCalendar().calendarQuery("VTODO"); + davCalendar().calendarQuery("VTODO", null, null); remoteResources = new HashMap<>(davCollection.members.size()); for (DavResource vCard : davCollection.members) { String fileName = vCard.fileName(); diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AccountSettingsFragment.java b/app/src/main/java/at/bitfire/davdroid/ui/AccountSettingsFragment.java index 1cc24a5b..62636586 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/AccountSettingsFragment.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/AccountSettingsFragment.java @@ -17,8 +17,12 @@ import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceFragmentCompat; import android.support.v7.preference.SwitchPreferenceCompat; +import android.util.Log; + +import java.util.logging.Level; import at.bitfire.davdroid.AccountSettings; +import at.bitfire.davdroid.App; import at.bitfire.davdroid.R; import at.bitfire.ical4android.TaskProvider; @@ -134,6 +138,29 @@ public class AccountSettingsFragment extends PreferenceFragmentCompat { prefSyncTasks.setSummary(R.string.settings_sync_summary_not_available); } + final EditTextPreference prefTimeRangePastDays = (EditTextPreference)findPreference("caldav_time_range_past_days"); + Integer pastDays = settings.getTimeRangePastDays(); + if (pastDays != null) { + prefTimeRangePastDays.setText(pastDays.toString()); + prefTimeRangePastDays.setSummary(getResources().getQuantityString(R.plurals.settings_sync_time_range_past_days, pastDays, pastDays)); + } else { + prefTimeRangePastDays.setText(null); + prefTimeRangePastDays.setSummary(R.string.settings_sync_time_range_past_none); + } + prefTimeRangePastDays.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + int days; + try { + days = Integer.parseInt((String)newValue); + } catch(NumberFormatException ignored) { + days = -1; + } + settings.setTimeRangePastDays(days < 0 ? null : days); + refresh(); return false; + } + }); + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4490d844..fd93154f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -169,6 +169,13 @@ Every 4 hours Once a day + Restrict synchronization of past events + All events will be synchronized + + Events more than one day in the past will be ignored + Events more than %d days in the past will be ignored + + Events which are more than this number of days in the past (may be 0) will be ignored. Leave blank to synchronize all events. Create address book diff --git a/app/src/main/res/xml/settings_account.xml b/app/src/main/res/xml/settings_account.xml index 4a287c0a..e71d9e29 100644 --- a/app/src/main/res/xml/settings_account.xml +++ b/app/src/main/res/xml/settings_account.xml @@ -57,6 +57,13 @@ android:entries="@array/settings_sync_interval_names" android:entryValues="@array/settings_sync_interval_seconds" /> + + diff --git a/dav4android b/dav4android index 80f3b060..d3cb90c6 160000 --- a/dav4android +++ b/dav4android @@ -1 +1 @@ -Subproject commit 80f3b060a7d5d240848fc89c5008b91a84046299 +Subproject commit d3cb90c629824e5e95b2c9236c2fc91e9a6dd7c9 diff --git a/ical4android b/ical4android index 343c3b3e..19ef2603 160000 --- a/ical4android +++ b/ical4android @@ -1 +1 @@ -Subproject commit 343c3b3ec03b331202425f377b57a17ef2ec3d85 +Subproject commit 19ef2603edc7a28bce1b9ea1f7fa11ca89234dc0 diff --git a/vcard4android b/vcard4android index 13ee3ada..4eab186a 160000 --- a/vcard4android +++ b/vcard4android @@ -1 +1 @@ -Subproject commit 13ee3ada06635814c80f00b67339a5d51275fe20 +Subproject commit 4eab186a210f7fdb74f17af2b086fc17ba2291c7