From 59f8305ba53bd969d4d926831a2c1ec2dede08ec Mon Sep 17 00:00:00 2001 From: Ricki Hirner Date: Sun, 5 Feb 2017 17:12:31 +0100 Subject: [PATCH] Use contact hash codes only on Android 7+ (workaround) vcard4android: don't hash CATEGORIES, more verbose logging --- .../davdroid/resource/LocalAddressBook.java | 12 +++++-- .../davdroid/resource/LocalContact.java | 33 ++++++++++++++++--- .../syncadapter/ContactsSyncManager.java | 12 ++++--- 3 files changed, 46 insertions(+), 11 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 1fdb0926..71f01f54 100644 --- a/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java +++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalAddressBook.java @@ -14,6 +14,7 @@ import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.RemoteException; @@ -92,15 +93,22 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect * @return number of "really dirty" contacts */ public int verifyDirty() throws ContactsStorageException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) + App.log.severe("verifyDirty() should not be called on Android <7"); + int reallyDirty = 0; for (LocalContact contact : getDirtyContacts()) { try { - if (contact.getLastHashCode() == contact.dataHashCode()) { + int lastHash = contact.getLastHashCode(), + currentHash = contact.dataHashCode(); + if (lastHash == currentHash) { // hash is code still the same, contact is not "really dirty" (only metadata been have changed) App.log.log(Level.FINE, "Contact data hash has not changed, resetting dirty flag", contact); contact.resetDirty(); - } else + } else { + App.log.log(Level.FINE, "Contact data has changed from hash " + lastHash + " to " + currentHash, contact); reallyDirty++; + } } catch(FileNotFoundException e) { throw new ContactsStorageException("Couldn't calculate hash code", e); } 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 7a399b08..2e483a73 100644 --- a/app/src/main/java/at/bitfire/davdroid/resource/LocalContact.java +++ b/app/src/main/java/at/bitfire/davdroid/resource/LocalContact.java @@ -12,6 +12,7 @@ import android.content.ContentProviderOperation; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.os.RemoteException; import android.provider.ContactsContract; import android.provider.ContactsContract.CommonDataKinds.GroupMembership; @@ -82,9 +83,12 @@ public class LocalContact extends AndroidContact implements LocalResource { values.put(COLUMN_ETAG, eTag); values.put(ContactsContract.RawContacts.DIRTY, 0); - int hashCode = dataHashCode(); - values.put(COLUMN_HASHCODE, hashCode); - App.log.finer("Clearing dirty flag with eTag = " + eTag + ", contact hash = " + hashCode); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + // workaround for Android 7 which sets DIRTY flag when only meta-data is changed + int hashCode = dataHashCode(); + values.put(COLUMN_HASHCODE, hashCode); + App.log.finer("Clearing dirty flag with eTag = " + eTag + ", contact hash = " + hashCode); + } addressBook.provider.update(rawContactSyncURI(), values, null, null); @@ -161,14 +165,24 @@ public class LocalContact extends AndroidContact implements LocalResource { @Override public int update(Contact contact) throws ContactsStorageException { int result = super.update(contact); - updateHashCode(); + + 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; } @Override public Uri create() throws ContactsStorageException { Uri uri = super.create(); - updateHashCode(); + + 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; } @@ -177,11 +191,17 @@ public class LocalContact extends AndroidContact implements LocalResource { * @return hash code of contact data (including group memberships) */ public int dataHashCode() throws FileNotFoundException, ContactsStorageException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) + App.log.severe("dataHashCode() should not be called on Android <7"); + // groupMemberships is filled by getContact() return getContact().hashCode() ^ groupMemberships.hashCode(); } protected void updateHashCode() throws ContactsStorageException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) + App.log.severe("updateHashCode() should not be called on Android <7"); + ContentValues values = new ContentValues(1); try { int hashCode = dataHashCode(); @@ -194,6 +214,9 @@ public class LocalContact extends AndroidContact implements LocalResource { } int getLastHashCode() throws ContactsStorageException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) + App.log.severe("getLastHashCode() should not be called on Android <7"); + try { @Cleanup Cursor c = addressBook.provider.query(rawContactSyncURI(), new String[] { COLUMN_HASHCODE }, null, null, null); if (c == null || !c.moveToNext() || c.isNull(0)) 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 3a617ca1..2fa973a3 100644 --- a/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.java +++ b/app/src/main/java/at/bitfire/davdroid/syncadapter/ContactsSyncManager.java @@ -14,6 +14,7 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.SyncResult; +import android.os.Build; import android.os.Bundle; import android.provider.ContactsContract; @@ -82,10 +83,13 @@ public class ContactsSyncManager extends SyncManager { LocalAddressBook localAddressBook = localAddressBook(); localAddressBook.setURL(info.url); - 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"); - return false; + 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"); + return false; + } } // set up Contacts Provider Settings