From f32493986b9bd4b86085c4e08ef1662a95c80647 Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Wed, 20 Jan 2016 15:22:58 +0100 Subject: [PATCH] Update local calendars according to ServiceDB at sync --- .../davdroid/resource/LocalCalendar.java | 19 ++-- .../CalendarsSyncAdapterService.java | 96 ++++++++++++++++--- .../syncadapter/TasksSyncAdapterService.java | 4 +- .../bitfire/davdroid/ui/AccountActivity.java | 3 + .../main/res/layout/account_calendar_item.xml | 7 ++ 5 files changed, 109 insertions(+), 20 deletions(-) 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 6e970a63..1dd05897 100644 --- a/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java +++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalCalendar.java @@ -42,6 +42,7 @@ import at.bitfire.ical4android.CalendarStorageException; import at.bitfire.ical4android.DateUtils; import at.bitfire.vcard4android.ContactsStorageException; import lombok.Cleanup; +import lombok.NonNull; public class LocalCalendar extends AndroidCalendar implements LocalCollection { @@ -69,12 +70,17 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection { super(account, provider, LocalEvent.Factory.INSTANCE, id); } - @TargetApi(15) - public static Uri create(Account account, ContentResolver resolver, CollectionInfo info) throws CalendarStorageException { - @Cleanup("release") ContentProviderClient provider = resolver.acquireContentProviderClient(CalendarContract.AUTHORITY); - if (provider == null) - throw new CalendarStorageException("Couldn't acquire ContentProviderClient for " + CalendarContract.AUTHORITY); + public static Uri create(@NonNull Account account, @NonNull ContentProviderClient provider, @NonNull CollectionInfo info) throws CalendarStorageException { + ContentValues values = valuesFromCollectionInfo(info); + values.put(Calendars.OWNER_ACCOUNT, account.name); + return create(account, provider, values); + } + public void update(CollectionInfo info) throws CalendarStorageException { + update(valuesFromCollectionInfo(info)); + } + + private static ContentValues valuesFromCollectionInfo(CollectionInfo info) { ContentValues values = new ContentValues(); values.put(Calendars.NAME, info.url); values.put(Calendars.CALENDAR_DISPLAY_NAME, info.displayName); @@ -88,7 +94,6 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection { values.put(Calendars.CAN_ORGANIZER_RESPOND, 1); } - values.put(Calendars.OWNER_ACCOUNT, account.name); values.put(Calendars.SYNC_EVENTS, 1); values.put(Calendars.VISIBLE, 1); if (!TextUtils.isEmpty(info.timeZone)) { @@ -101,7 +106,7 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection { values.put(Calendars.ALLOWED_AVAILABILITY, StringUtils.join(new int[] { Reminders.AVAILABILITY_TENTATIVE, Reminders.AVAILABILITY_FREE, Reminders.AVAILABILITY_BUSY }, ",")); values.put(Calendars.ALLOWED_ATTENDEE_TYPES, StringUtils.join(new int[] { CalendarContract.Attendees.TYPE_OPTIONAL, CalendarContract.Attendees.TYPE_REQUIRED, CalendarContract.Attendees.TYPE_RESOURCE }, ", ")); } - return create(account, provider, values); + return values; } diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java index f05e6cfd..4ef2016e 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/CalendarsSyncAdapterService.java @@ -11,30 +11,42 @@ import android.accounts.Account; import android.app.Service; import android.content.AbstractThreadedSyncAdapter; import android.content.ContentProviderClient; +import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.SyncResult; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.os.IBinder; import android.provider.CalendarContract; +import java.util.LinkedHashMap; +import java.util.Map; + import at.bitfire.davdroid.Constants; +import at.bitfire.davdroid.model.CollectionInfo; +import at.bitfire.davdroid.model.ServiceDB; +import at.bitfire.davdroid.model.ServiceDB.OpenHelper; import at.bitfire.davdroid.resource.LocalCalendar; import at.bitfire.ical4android.CalendarStorageException; +import lombok.Cleanup; public class CalendarsSyncAdapterService extends Service { - private static SyncAdapter syncAdapter; + private static SyncAdapter syncAdapter; + OpenHelper dbHelper; - @Override - public void onCreate() { - if (syncAdapter == null) - syncAdapter = new SyncAdapter(getApplicationContext()); - } + @Override + public void onCreate() { + dbHelper = new OpenHelper(this); + syncAdapter = new SyncAdapter(this, dbHelper); + } - @Override - public void onDestroy() { - syncAdapter = null; - } + @Override + public void onDestroy() { + dbHelper.close(); + } @Override public IBinder onBind(Intent intent) { @@ -43,8 +55,14 @@ public class CalendarsSyncAdapterService extends Service { private static class SyncAdapter extends AbstractThreadedSyncAdapter { - public SyncAdapter(Context context) { + private final OpenHelper dbHelper; + private final SQLiteDatabase db; + + public SyncAdapter(Context context, OpenHelper dbHelper) { super(context, false); + + this.dbHelper = dbHelper; + db = dbHelper.getReadableDatabase(); } @Override @@ -52,6 +70,8 @@ public class CalendarsSyncAdapterService extends Service { Constants.log.info("Starting calendar sync (" + authority + ")"); try { + updateLocalCalendars(provider, account); + for (LocalCalendar calendar : (LocalCalendar[])LocalCalendar.find(account, provider, LocalCalendar.Factory.INSTANCE, CalendarContract.Calendars.SYNC_EVENTS + "!=0", null)) { Constants.log.info("Synchronizing calendar #" + calendar.getId() + ", URL: " + calendar.getName()); CalendarSyncManager syncManager = new CalendarSyncManager(getContext(), account, extras, authority, syncResult, calendar); @@ -59,10 +79,64 @@ public class CalendarsSyncAdapterService extends Service { } } catch (CalendarStorageException e) { Constants.log.error("Couldn't enumerate local calendars", e); + } finally { + dbHelper.close(); } Constants.log.info("Calendar sync complete"); } + + private void updateLocalCalendars(ContentProviderClient provider, Account account) throws CalendarStorageException { + long service = getService(account); + + // enumerate remote and local calendars + Map remote = remoteCalendars(service); + LocalCalendar[] local = (LocalCalendar[])LocalCalendar.find(account, provider, LocalCalendar.Factory.INSTANCE, null, null); + + // delete obsolete local calendar + for (LocalCalendar calendar : local) { + String url = calendar.getName(); + if (!remote.containsKey(url)) { + Constants.log.debug("Deleting obsolete local calendar {}", url); + calendar.delete(); + } else { + // remote CollectionInfo found for this local collection, update data + CollectionInfo info = remote.get(url); + Constants.log.debug("Updating local calendar {} with {}", url, info); + calendar.update(info); + // we already have a local calendar for this remote collection, don't take into consideration anymore + remote.remove(url); + } + } + + // create new local calendars + for (String url : remote.keySet()) { + CollectionInfo info = remote.get(url); + Constants.log.info("Adding local calendar list {}", info); + LocalCalendar.create(account, provider, info); + } + } + + long getService(Account account) { + @Cleanup Cursor c = db.query(ServiceDB.Services._TABLE, new String[]{ServiceDB.Services.ID}, + ServiceDB.Services.ACCOUNT_NAME + "=? AND " + ServiceDB.Services.SERVICE + "=?", new String[]{account.name, ServiceDB.Services.SERVICE_CALDAV}, null, null, null); + c.moveToNext(); + return c.getLong(0); + } + + private Map remoteCalendars(long service) { + Map collections = new LinkedHashMap<>(); + @Cleanup Cursor cursor = db.query(ServiceDB.Collections._TABLE, ServiceDB.Collections._COLUMNS, + ServiceDB.Collections.SERVICE_ID + "=? AND " + ServiceDB.Collections.SUPPORTS_VEVENT + "!=0", + new String[] { String.valueOf(service) }, null, null, null); + while (cursor.moveToNext()) { + ContentValues values = new ContentValues(); + DatabaseUtils.cursorRowToContentValues(cursor, values); + CollectionInfo info = CollectionInfo.fromDB(values); + collections.put(info.url, info); + } + return collections; + } } } diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.java b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.java index fb812e00..56a69b42 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.java +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/TasksSyncAdapterService.java @@ -54,8 +54,8 @@ public class TasksSyncAdapterService extends Service { private static class SyncAdapter extends AbstractThreadedSyncAdapter { - final OpenHelper dbHelper; - final SQLiteDatabase db; + private final OpenHelper dbHelper; + private final SQLiteDatabase db; public SyncAdapter(Context context, OpenHelper dbHelper) { super(context, false); diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java b/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java index d30fe830..8bf6bdba 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java +++ b/app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.java @@ -323,6 +323,9 @@ public class AccountActivity extends AppCompatActivity implements Toolbar.OnMenu CollectionInfo info = getItem(position); + View vColor = v.findViewById(R.id.color); + vColor.setBackgroundColor(info.color); + TextView tv = (TextView)v.findViewById(R.id.title); tv.setText(TextUtils.isEmpty(info.displayName) ? info.url : info.displayName); diff --git a/app/src/main/res/layout/account_calendar_item.xml b/app/src/main/res/layout/account_calendar_item.xml index 04b6f8da..0a19d662 100644 --- a/app/src/main/res/layout/account_calendar_item.xml +++ b/app/src/main/res/layout/account_calendar_item.xml @@ -20,6 +20,13 @@ android:layout_height="wrap_content" android:layout_marginRight="4dp"/> + +