From c54baccdc7ec7933455031705709e85639e3d5ca Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Tue, 16 May 2017 11:54:55 +0100 Subject: [PATCH] SyncManager: add back support for contact groups Groups are saved as separate vCards. We removed support for groups to speed up development and deferred adding them back until there was demand. There is demand now, and also, not having this support resulted in the sync not working, not just groups not supported. Many thanks to "359" (this user's preferred alias) for investigating and reporting this issue. --- app/build.gradle | 1 + .../syncadapter/resource/LocalGroup.java | 16 ++++++++-- .../syncadapter/ContactsSyncManager.java | 31 ++++++++++++++++--- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 401a6ea4..f5e66b50 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -138,6 +138,7 @@ dependencies { compile group: 'com.madgag.spongycastle', name: 'prov', version: '1.54.0.0' compile group: 'com.google.code.gson', name: 'gson', version: '1.7.2' compile 'com.squareup.okhttp3:logging-interceptor:3.8.0' + compile 'org.apache.commons:commons-collections4:4.1' provided 'org.projectlombok:lombok:1.16.16' // for tests diff --git a/app/src/main/java/com/etesync/syncadapter/resource/LocalGroup.java b/app/src/main/java/com/etesync/syncadapter/resource/LocalGroup.java index 5918ba00..5dd00b21 100644 --- a/app/src/main/java/com/etesync/syncadapter/resource/LocalGroup.java +++ b/app/src/main/java/com/etesync/syncadapter/resource/LocalGroup.java @@ -25,6 +25,7 @@ import com.etesync.syncadapter.App; import org.apache.commons.lang3.ArrayUtils; +import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashSet; @@ -41,10 +42,13 @@ import at.bitfire.vcard4android.BatchOperation; import at.bitfire.vcard4android.CachedGroupMembership; import at.bitfire.vcard4android.Contact; import at.bitfire.vcard4android.ContactsStorageException; +import ezvcard.VCardVersion; import lombok.Cleanup; import lombok.Getter; import lombok.ToString; +import static at.bitfire.vcard4android.GroupMethod.GROUP_VCARDS; + @ToString(callSuper=true) public class LocalGroup extends AndroidGroup implements LocalResource { @Getter @@ -62,7 +66,15 @@ public class LocalGroup extends AndroidGroup implements LocalResource { @Override public String getContent() throws IOException, ContactsStorageException { - return null; + final Contact contact; + contact = getContact(); + + App.log.log(Level.FINE, "Preparing upload of VCard " + getUuid(), contact); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + contact.write(VCardVersion.V4_0, GROUP_VCARDS, os); + + return os.toString(); } @Override @@ -107,7 +119,7 @@ public class LocalGroup extends AndroidGroup implements LocalResource { @Override public void prepareForUpload() throws ContactsStorageException { final String uid = UUID.randomUUID().toString(); - final String newFileName = uid + ".vcf"; + final String newFileName = uid; ContentValues values = new ContentValues(2); values.put(COLUMN_FILENAME, newFileName); diff --git a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java index 98b57c34..e49c36cf 100644 --- a/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java +++ b/app/src/main/java/com/etesync/syncadapter/syncadapter/ContactsSyncManager.java @@ -10,7 +10,9 @@ package com.etesync.syncadapter.syncadapter; import android.accounts.Account; import android.content.ContentProviderClient; +import android.content.ContentProviderOperation; import android.content.ContentResolver; +import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.SyncResult; @@ -33,14 +35,18 @@ import com.etesync.syncadapter.resource.LocalGroup; import com.etesync.syncadapter.resource.LocalResource; import org.apache.commons.codec.Charsets; +import org.apache.commons.collections4.SetUtils; import org.apache.commons.io.IOUtils; import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.Set; import java.util.logging.Level; import at.bitfire.ical4android.CalendarStorageException; +import at.bitfire.vcard4android.BatchOperation; import at.bitfire.vcard4android.Contact; import at.bitfire.vcard4android.ContactsStorageException; import lombok.Cleanup; @@ -100,6 +106,8 @@ public class ContactsSyncManager extends SyncManager { journal = new JournalEntryManager(httpClient, remote, localAddressBook.getURL()); + localAddressBook.includeGroups = true; + return true; } @@ -109,12 +117,27 @@ public class ContactsSyncManager extends SyncManager { LocalAddressBook addressBook = localAddressBook(); - /* groups as separate VCards: thtere are group contacts and individual contacts */ + /* groups as separate VCards: there are group contacts and individual contacts */ // mark groups with changed members as dirty - - // FIXME: add back - + BatchOperation batch = new BatchOperation(addressBook.provider); + for (LocalContact contact : addressBook.getDirtyContacts()) { + try { + App.log.fine("Looking for changed group memberships of contact " + contact.getFileName()); + Set cachedGroups = contact.getCachedGroupMemberships(), + currentGroups = contact.getGroupMemberships(); + for (Long groupID : SetUtils.disjunction(cachedGroups, currentGroups)) { + App.log.fine("Marking group as dirty: " + groupID); + batch.enqueue(new BatchOperation.Operation( + ContentProviderOperation.newUpdate(addressBook.syncAdapterURI(ContentUris.withAppendedId(ContactsContract.Groups.CONTENT_URI, groupID))) + .withValue(ContactsContract.Groups.DIRTY, 1) + .withYieldAllowed(true) + )); + } + } catch (FileNotFoundException ignored) { + } + } + batch.commit(); } @Override