From e7694924b48dc17bf08e3e8f42f5f236069f1b08 Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Fri, 24 Mar 2017 15:22:26 +0000 Subject: [PATCH] Automatically fix non-dirty entries with null etag on upgrade Commit 5d1c90dcbac4e4a21e63c8fbc762a453d9bf0491 fixed a bug where entries added from the server were marked as "local only" (null etag) which was causing issues. That commit fixes it for newly added resources, but existing resources remained broken. This commit goes through the database and fixes all of the existing broken resources. It skips dirty entries because figuring out if they were just created or updated is complex, and the chances of doing an update at exactly the same time there are dirty entries is quite low, so the complexity involved is just not worth it. --- .../java/com/etesync/syncadapter/App.java | 31 +++++++++++++++++++ .../resource/LocalAddressBook.java | 16 ++++++++++ .../syncadapter/resource/LocalCalendar.java | 17 ++++++++++ 3 files changed, 64 insertions(+) diff --git a/app/src/main/java/com/etesync/syncadapter/App.java b/app/src/main/java/com/etesync/syncadapter/App.java index 3d9adf39..299ab0df 100644 --- a/app/src/main/java/com/etesync/syncadapter/App.java +++ b/app/src/main/java/com/etesync/syncadapter/App.java @@ -8,6 +8,8 @@ package com.etesync.syncadapter; +import android.accounts.Account; +import android.accounts.AccountManager; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Application; @@ -25,6 +27,8 @@ import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Process; import android.os.StrictMode; +import android.provider.CalendarContract; +import android.provider.ContactsContract; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.NotificationManagerCompat; @@ -38,6 +42,8 @@ import com.etesync.syncadapter.model.JournalEntity; import com.etesync.syncadapter.model.Models; import com.etesync.syncadapter.model.ServiceDB; import com.etesync.syncadapter.model.Settings; +import com.etesync.syncadapter.resource.LocalAddressBook; +import com.etesync.syncadapter.resource.LocalCalendar; import org.apache.commons.lang3.time.DateFormatUtils; @@ -53,6 +59,8 @@ import java.util.logging.Logger; import javax.net.ssl.HostnameVerifier; import at.bitfire.cert4android.CustomCertManager; +import at.bitfire.ical4android.CalendarStorageException; +import at.bitfire.vcard4android.ContactsStorageException; import io.requery.Persistable; import io.requery.android.sqlite.DatabaseSource; import io.requery.sql.Configuration; @@ -239,6 +247,29 @@ public class App extends Application { @Cleanup SQLiteDatabase db = dbHelper.getWritableDatabase(); db.delete(ServiceDB.Collections._TABLE, null, null); } + + if (fromVersion < 7) { + /* Fix all of the etags to be non-null */ + AccountManager am = AccountManager.get(this); + for (Account account : am.getAccountsByType(Constants.ACCOUNT_TYPE)) { + try { + LocalCalendar calendars[] = (LocalCalendar[]) LocalCalendar.find(account, this.getContentResolver().acquireContentProviderClient(CalendarContract.CONTENT_URI), + LocalCalendar.Factory.INSTANCE, null, null); + for (LocalCalendar calendar : calendars) { + calendar.fixEtags(); + } + } catch (CalendarStorageException e) { + e.printStackTrace(); + } + + LocalAddressBook addressBook = new LocalAddressBook(account, this.getContentResolver().acquireContentProviderClient(ContactsContract.Contacts.CONTENT_URI)); + try { + addressBook.fixEtags(); + } catch (ContactsStorageException e) { + e.printStackTrace(); + } + } + } } public static class AppUpdatedReceiver extends BroadcastReceiver { diff --git a/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.java b/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.java index 83798399..e0d8de84 100644 --- a/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.java +++ b/app/src/main/java/com/etesync/syncadapter/resource/LocalAddressBook.java @@ -301,4 +301,20 @@ public class LocalAddressBook extends AndroidAddressBook implements LocalCollect } } + /** Fix all of the etags of all of the non-dirty contacts to be non-null. + * Currently set to the ctag. */ + public void fixEtags() throws ContactsStorageException { + String newEtag = getCTag(); + String where = ContactsContract.RawContacts.DIRTY + "=0 AND " + AndroidContact.COLUMN_ETAG + " IS NULL"; + + ContentValues values = new ContentValues(1); + values.put(AndroidContact.COLUMN_ETAG, newEtag); + try { + int fixed = provider.update(syncAdapterURI(RawContacts.CONTENT_URI), + values, where, null); + App.log.info("Fixed entries: " + String.valueOf(fixed)); + } catch (RemoteException e) { + throw new ContactsStorageException("Couldn't query contacts", e); + } + } } diff --git a/app/src/main/java/com/etesync/syncadapter/resource/LocalCalendar.java b/app/src/main/java/com/etesync/syncadapter/resource/LocalCalendar.java index 536e2250..11c11841 100644 --- a/app/src/main/java/com/etesync/syncadapter/resource/LocalCalendar.java +++ b/app/src/main/java/com/etesync/syncadapter/resource/LocalCalendar.java @@ -280,4 +280,21 @@ public class LocalCalendar extends AndroidCalendar implements LocalCollection { } } + /** Fix all of the etags of all of the non-dirty events to be non-null. + * Currently set to the ctag. */ + public void fixEtags() throws CalendarStorageException { + String newEtag = getCTag(); + String where = Events.CALENDAR_ID + "=? AND " + Events.DIRTY + "=0 AND " + LocalEvent.COLUMN_ETAG + " IS NULL"; + String whereArgs[] = {String.valueOf(id)}; + + ContentValues values = new ContentValues(1); + values.put(LocalEvent.COLUMN_ETAG, newEtag); + try { + int fixed = provider.update(syncAdapterURI(Events.CONTENT_URI), + values, where, whereArgs); + App.log.info("Fixed entries: " + String.valueOf(fixed)); + } catch (RemoteException e) { + throw new CalendarStorageException("Couldn't fix etags", e); + } + } }