From bc7cd650485bdbbd24935da3e4b5fc6e71900fff Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Mon, 6 Feb 2017 11:55:18 +0100 Subject: [PATCH] Android 7 workaround bugfix * use local version of contact before calculating hash code * don't stop upload sync if there are deleted contacts --- .../at/bitfire/davdroid/resource/LocalAddressBook.java | 9 +++++++++ .../at/bitfire/davdroid/resource/LocalContact.java | 10 ++++++---- .../davdroid/syncadapter/ContactsSyncManager.java | 7 ++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java index 71f01f54..e9e1e859 100644 --- a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java +++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java @@ -57,6 +57,7 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect super(account, provider, LocalGroup.Factory.INSTANCE, LocalContact.Factory.INSTANCE); } + @NonNull public LocalContact findContactByUID(String uid) throws ContactsStorageException, FileNotFoundException { LocalContact[] contacts = (LocalContact[])queryContacts(LocalContact.COLUMN_UID + "=?", new String[] { uid }); if (contacts.length == 0) @@ -65,6 +66,7 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect } @Override + @NonNull public LocalResource[] getAll() throws ContactsStorageException { List all = new LinkedList<>(); Collections.addAll(all, (LocalResource[])queryContacts(null, null)); @@ -77,6 +79,7 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect * Returns an array of local contacts/groups which have been deleted locally. (DELETED != 0). */ @Override + @NonNull public LocalResource[] getDeleted() throws ContactsStorageException { List deleted = new LinkedList<>(); Collections.addAll(deleted, getDeletedContacts()); @@ -124,6 +127,7 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect * Returns an array of local contacts/groups which have been changed locally (DIRTY != 0). */ @Override + @NonNull public LocalResource[] getDirty() throws ContactsStorageException { List dirty = new LinkedList<>(); Collections.addAll(dirty, getDirtyContacts()); @@ -136,6 +140,7 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect * Returns an array of local contacts which don't have a file name yet. */ @Override + @NonNull public LocalResource[] getWithoutFileName() throws ContactsStorageException { List nameless = new LinkedList<>(); Collections.addAll(nameless, (LocalContact[])queryContacts(AndroidContact.COLUMN_FILENAME + " IS NULL", null)); @@ -154,18 +159,22 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect } + @NonNull public LocalContact[] getDeletedContacts() throws ContactsStorageException { return (LocalContact[])queryContacts(RawContacts.DELETED + "!= 0", null); } + @NonNull public LocalContact[] getDirtyContacts() throws ContactsStorageException { return (LocalContact[])queryContacts(RawContacts.DIRTY + "!= 0 AND " + RawContacts.DELETED + "== 0", null); } + @NonNull public LocalGroup[] getDeletedGroups() throws ContactsStorageException { return (LocalGroup[])queryGroups(Groups.DELETED + "!= 0", null); } + @NonNull public LocalGroup[] getDirtyGroups() throws ContactsStorageException { return (LocalGroup[])queryGroups(Groups.DIRTY + "!= 0 AND " + Groups.DELETED + "== 0", null); } diff --git a/app/src/main/java/at/bitfire/davdroid/resource/LocalContact.java b/app/src/main/java/at/bitfire/davdroid/resource/LocalContact.java index 2e483a73..353cb329 100644 --- a/app/src/main/java/at/bitfire/davdroid/resource/LocalContact.java +++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalContact.java @@ -166,10 +166,9 @@ public class LocalContact extends AndroidContact implements LocalResource { public int update(Contact contact) throws ContactsStorageException { int result = super.update(contact); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) // workaround for Android 7 which sets DIRTY flag when only meta-data is changed updateHashCode(); - } return result; } @@ -178,10 +177,9 @@ public class LocalContact extends AndroidContact implements LocalResource { public Uri create() throws ContactsStorageException { Uri uri = super.create(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) // workaround for Android 7 which sets DIRTY flag when only meta-data is changed updateHashCode(); - } return uri; } @@ -202,6 +200,10 @@ public class LocalContact extends AndroidContact implements LocalResource { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) App.log.severe("updateHashCode() should not be called on Android <7"); + // re-read from provider before calculating the hash because the Contact as parsed from + // the VCard is not the same as when read from the database + contact = null; + ContentValues values = new ContentValues(1); try { int hashCode = dataHashCode(); diff --git a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.java b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.java index 2fa973a3..62308d1a 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.java +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.java @@ -85,9 +85,10 @@ public class ContactsSyncManager extends SyncManager { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // workaround for Android 7 which sets DIRTY flag when only meta-data is changed - int reallyDirty = localAddressBook.verifyDirty(); - if (extras.containsKey(ContentResolver.SYNC_EXTRAS_UPLOAD) && reallyDirty == 0) { - App.log.info("This sync was called to upload dirty contacts, but no contact data have been changed"); + int reallyDirty = localAddressBook.verifyDirty(), + deleted = localAddressBook.getDeleted().length; + if (extras.containsKey(ContentResolver.SYNC_EXTRAS_UPLOAD) && reallyDirty == 0 && deleted == 0) { + App.log.info("This sync was called to up-sync dirty/deleted contacts, but no contacts have been changed"); return false; } }