From 8faae52c0d012b47171ae270f4af84c43cac45f7 Mon Sep 17 00:00:00 2001 From: Andy Stadler Date: Fri, 25 Mar 2011 16:18:06 -0700 Subject: [PATCH] DO NOT MERGE - Clear cached CalendarObservers after Calendar wipe * This fix may resolve the bugs referenced below; the issue fixed could cause pandemonium after the server commands a wipe of calendar data and most likely explains these issues (via Occam's Razor) * Also backport a SQL fix to more reliably delete calendar data Bug: 4077499 Bug: 4064237 Backport from: I628fb14ea2c04150d4f27341751f0eab61ee33d1 Change-Id: I7667a11663d8720a92b9eba0748f60256a25edba --- src/com/android/exchange/SyncManager.java | 23 +++++++++++-------- .../exchange/adapter/CalendarSyncAdapter.java | 18 ++++++++++----- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/com/android/exchange/SyncManager.java b/src/com/android/exchange/SyncManager.java index 3defdc5e3..c096c5077 100644 --- a/src/com/android/exchange/SyncManager.java +++ b/src/com/android/exchange/SyncManager.java @@ -69,21 +69,21 @@ import android.database.ContentObserver; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.net.Uri; import android.net.NetworkInfo.State; +import android.net.Uri; import android.os.Bundle; import android.os.Debug; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; -import android.os.PowerManager.WakeLock; import android.provider.Calendar; -import android.provider.ContactsContract; import android.provider.Calendar.Calendars; import android.provider.Calendar.Events; +import android.provider.ContactsContract; import android.util.Log; import java.io.BufferedReader; @@ -95,6 +95,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; /** * The SyncManager handles all aspects of starting, maintaining, and stopping the various sync @@ -210,8 +211,9 @@ public class SyncManager extends Service implements Runnable { private Object mStatusChangeListener; private EasAccountsUpdatedListener mAccountsUpdatedListener; - private HashMap mCalendarObservers = - new HashMap(); + // Concurrent because CalendarSyncAdapter can modify the map during a wipe + private ConcurrentHashMap mCalendarObservers = + new ConcurrentHashMap(); private ContentResolver mResolver; @@ -659,11 +661,14 @@ public class SyncManager extends Service implements Runnable { /** * Unregister all CalendarObserver's */ - private void unregisterCalendarObservers() { - for (CalendarObserver observer: mCalendarObservers.values()) { - mResolver.unregisterContentObserver(observer); + static public void unregisterCalendarObservers() { + SyncManager syncManager = INSTANCE; + if (syncManager == null) return; + ContentResolver resolver = syncManager.mResolver; + for (CalendarObserver observer: syncManager.mCalendarObservers.values()) { + resolver.unregisterContentObserver(observer); } - mCalendarObservers.clear(); + syncManager.mCalendarObservers.clear(); } /** diff --git a/src/com/android/exchange/adapter/CalendarSyncAdapter.java b/src/com/android/exchange/adapter/CalendarSyncAdapter.java index 317f22576..97074cabc 100644 --- a/src/com/android/exchange/adapter/CalendarSyncAdapter.java +++ b/src/com/android/exchange/adapter/CalendarSyncAdapter.java @@ -25,6 +25,7 @@ import com.android.email.provider.EmailContent.Message; import com.android.exchange.Eas; import com.android.exchange.EasOutboxService; import com.android.exchange.EasSyncService; +import com.android.exchange.SyncManager; import com.android.exchange.utility.CalendarUtilities; import com.android.exchange.utility.Duration; @@ -35,14 +36,14 @@ import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Entity; +import android.content.Entity.NamedContentValues; import android.content.EntityIterator; import android.content.OperationApplicationException; -import android.content.Entity.NamedContentValues; import android.database.Cursor; +import android.database.DatabaseUtils; import android.net.Uri; import android.os.RemoteException; import android.provider.Calendar; -import android.provider.SyncStateContract; import android.provider.Calendar.Attendees; import android.provider.Calendar.Calendars; import android.provider.Calendar.Events; @@ -51,6 +52,7 @@ import android.provider.Calendar.ExtendedProperties; import android.provider.Calendar.Reminders; import android.provider.Calendar.SyncState; import android.provider.ContactsContract.RawContacts; +import android.provider.SyncStateContract; import android.text.TextUtils; import android.util.Log; @@ -59,10 +61,10 @@ import java.io.InputStream; import java.text.ParseException; import java.util.ArrayList; import java.util.GregorianCalendar; +import java.util.Map.Entry; import java.util.StringTokenizer; import java.util.TimeZone; import java.util.UUID; -import java.util.Map.Entry; /** * Sync adapter class for EAS calendars @@ -282,9 +284,13 @@ public class CalendarSyncAdapter extends AbstractSyncAdapter { @Override public void wipe() { // Delete the calendar associated with this account - // TODO Make sure the Events, etc. are also deleted - mContentResolver.delete(Calendars.CONTENT_URI, CALENDAR_SELECTION, - new String[] {mEmailAddress, Email.EXCHANGE_ACCOUNT_MANAGER_TYPE}); + // CalendarProvider2 does NOT handle selection arguments in deletions + mContentResolver.delete(Calendars.CONTENT_URI, Calendars._SYNC_ACCOUNT + + "=" + DatabaseUtils.sqlEscapeString(mEmailAddress) + " AND " + + Calendars._SYNC_ACCOUNT_TYPE + "=" + + DatabaseUtils.sqlEscapeString(Email.EXCHANGE_ACCOUNT_MANAGER_TYPE), null); + // Invalidate our calendar observers + SyncManager.unregisterCalendarObservers(); } private void addOrganizerToAttendees(CalendarOperations ops, long eventId,