Update to support sync only restrictions in provider

Change-Id: I38d7dca8405ac8710dde8c08ee16e1f4c7689fcb
diff --git a/src/com/android/exchange/adapter/CalendarSyncAdapter.java b/src/com/android/exchange/adapter/CalendarSyncAdapter.java
index 5a079af..ec2805c 100644
--- a/src/com/android/exchange/adapter/CalendarSyncAdapter.java
+++ b/src/com/android/exchange/adapter/CalendarSyncAdapter.java
@@ -29,6 +29,7 @@
 import com.android.exchange.utility.CalendarUtilities;
 import com.android.exchange.utility.Duration;
 
+import android.accounts.Account;
 import android.content.ContentProviderClient;
 import android.content.ContentProviderOperation;
 import android.content.ContentProviderResult;
@@ -125,12 +126,6 @@
     private static final ContentProviderOperation PLACEHOLDER_OPERATION =
         ContentProviderOperation.newInsert(Uri.EMPTY).build();
 
-    private static final Uri EVENTS_URI = asSyncAdapter(Events.CONTENT_URI);
-    private static final Uri ATTENDEES_URI = asSyncAdapter(Attendees.CONTENT_URI);
-    private static final Uri EXTENDED_PROPERTIES_URI =
-        asSyncAdapter(ExtendedProperties.CONTENT_URI);
-    private static final Uri REMINDERS_URI = asSyncAdapter(Reminders.CONTENT_URI);
-
     private static final Object sSyncKeyLock = new Object();
 
     private static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("UTC");
@@ -196,10 +191,12 @@
     public void wipe() {
         // Delete the calendar associated with this account
         // 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(AccountManagerTypes.TYPE_EXCHANGE), null);
+        mContentResolver.delete(
+                asSyncAdapter(Calendars.CONTENT_URI, mEmailAddress,
+                        Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE),
+                Calendars._SYNC_ACCOUNT + "=" + DatabaseUtils.sqlEscapeString(mEmailAddress)
+                        + " AND " + Calendars._SYNC_ACCOUNT_TYPE + "="
+                        + DatabaseUtils.sqlEscapeString(AccountManagerTypes.TYPE_EXCHANGE), null);
         // Invalidate our calendar observers
         ExchangeService.unregisterCalendarObservers();
     }
@@ -220,8 +217,10 @@
         return p.parse();
     }
 
-    static Uri asSyncAdapter(Uri uri) {
-        return uri.buildUpon().appendQueryParameter(Calendar.CALLER_IS_SYNCADAPTER, "true").build();
+    static Uri asSyncAdapter(Uri uri, String account, String accountType) {
+        return uri.buildUpon().appendQueryParameter(Calendar.CALLER_IS_SYNCADAPTER, "true")
+                .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
+                .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
     }
 
     /**
@@ -245,8 +244,10 @@
             ContentProviderClient client = mService.mContentResolver
                     .acquireContentProviderClient(Calendar.CONTENT_URI);
             try {
-                byte[] data = SyncStateContract.Helpers.get(client,
-                        asSyncAdapter(Calendar.SyncState.CONTENT_URI), mAccountManagerAccount);
+                byte[] data = SyncStateContract.Helpers.get(
+                        client,
+                        asSyncAdapter(Calendar.SyncState.CONTENT_URI, mEmailAddress,
+                                Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), mAccountManagerAccount);
                 if (data == null || data.length == 0) {
                     // Initialize the SyncKey
                     setSyncKey("0", false);
@@ -273,8 +274,10 @@
                 ContentProviderClient client = mService.mContentResolver
                         .acquireContentProviderClient(Calendar.CONTENT_URI);
                 try {
-                    SyncStateContract.Helpers.set(client,
-                            asSyncAdapter(Calendar.SyncState.CONTENT_URI), mAccountManagerAccount,
+                    SyncStateContract.Helpers.set(
+                            client,
+                            asSyncAdapter(Calendar.SyncState.CONTENT_URI, mEmailAddress,
+                                    Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), mAccountManagerAccount,
                             syncKey.getBytes());
                     userLog("SyncKey set to ", syncKey, " in CalendarProvider");
                 } catch (RemoteException e) {
@@ -433,9 +436,13 @@
                             dtStamp = getValue();
                             continue;
                         } else if (tag == Tags.CALENDAR_ATTENDEES) {
-                            // This is an attendees-only update; just delete/re-add attendees
+                            // This is an attendees-only update; just
+                            // delete/re-add attendees
                             mBindArgument[0] = Long.toString(id);
-                            ops.add(ContentProviderOperation.newDelete(ATTENDEES_URI)
+                            ops.add(ContentProviderOperation
+                                    .newDelete(
+                                            asSyncAdapter(Attendees.CONTENT_URI, mEmailAddress,
+                                                    Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE))
                                     .withSelection(ATTENDEES_EXCEPT_ORGANIZER, mBindArgument)
                                     .build());
                             eventId = id;
@@ -659,8 +666,12 @@
                 }
 
                 if (isValidEventValues(cv)) {
-                    ops.set(eventOffset, ContentProviderOperation
-                            .newInsert(EVENTS_URI).withValues(cv).build());
+                    ops.set(eventOffset,
+                            ContentProviderOperation
+                                    .newInsert(
+                                            asSyncAdapter(Events.CONTENT_URI, mEmailAddress,
+                                                    Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE))
+                                    .withValues(cv).build());
                 } else {
                     // If we can't add this event (it's invalid), remove all of the inserts
                     // we've built for it
@@ -1186,16 +1197,22 @@
                     ContentValues cv = new ContentValues();
                     cv.put(Events._SYNC_DIRTY, 0);
                     cv.put(Events._SYNC_MARK, 0);
-                    for (long eventId: mUploadedIdList) {
-                        mContentResolver.update(ContentUris.withAppendedId(EVENTS_URI, eventId), cv,
+                    for (long eventId : mUploadedIdList) {
+                        mContentResolver.update(
+                                asSyncAdapter(
+                                        ContentUris.withAppendedId(Events.CONTENT_URI, eventId),
+                                        mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), cv,
                                 null, null);
                     }
                 }
                 // Delete events marked for deletion
                 if (!mDeletedIdList.isEmpty()) {
-                    for (long eventId: mDeletedIdList) {
-                        mContentResolver.delete(ContentUris.withAppendedId(EVENTS_URI, eventId),
-                                null, null);
+                    for (long eventId : mDeletedIdList) {
+                        mContentResolver.delete(
+                                asSyncAdapter(
+                                        ContentUris.withAppendedId(Events.CONTENT_URI, eventId),
+                                        mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), null,
+                                null);
                     }
                 }
                 // Send any queued up email (invitations replies, etc.)
@@ -1242,10 +1259,12 @@
                     cv.put(Events._SYNC_DATA, clientId);
                     long id = c.getLong(0);
                     // Write the serverId into the Event
-                    mOps.add(ContentProviderOperation.newUpdate(
-                            ContentUris.withAppendedId(EVENTS_URI, id))
-                                    .withValues(cv)
-                                    .build());
+                    mOps.add(ContentProviderOperation
+                            .newUpdate(
+                                    asSyncAdapter(
+                                            ContentUris.withAppendedId(Events.CONTENT_URI, id),
+                                            mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE))
+                            .withValues(cv).build());
                     userLog("New event " + clientId + " was given serverId: " + serverId);
                 }
             } finally {
@@ -1319,28 +1338,30 @@
 
         public void newAttendee(ContentValues cv, int eventStart) {
             add(ContentProviderOperation
-                    .newInsert(ATTENDEES_URI)
-                    .withValues(cv)
-                    .withValueBackReference(Attendees.EVENT_ID, eventStart)
-                    .build());
+                    .newInsert(asSyncAdapter(Attendees.CONTENT_URI, mEmailAddress,
+                            Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE)).withValues(cv)
+                    .withValueBackReference(Attendees.EVENT_ID, eventStart).build());
         }
 
         public void updatedAttendee(ContentValues cv, long id) {
             cv.put(Attendees.EVENT_ID, id);
-            add(ContentProviderOperation.newInsert(ATTENDEES_URI).withValues(cv).build());
+            add(ContentProviderOperation.newInsert(asSyncAdapter(Attendees.CONTENT_URI,
+                    mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE)).withValues(cv).build());
         }
 
         public void newException(ContentValues cv) {
-            add(ContentProviderOperation.newInsert(EVENTS_URI).withValues(cv).build());
+            add(ContentProviderOperation.newInsert(
+                    asSyncAdapter(Events.CONTENT_URI, mEmailAddress,
+                            Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE)).withValues(cv).build());
         }
 
         public void newExtendedProperty(String name, String value) {
             add(ContentProviderOperation
-                    .newInsert(EXTENDED_PROPERTIES_URI)
+                    .newInsert(asSyncAdapter(ExtendedProperties.CONTENT_URI, mEmailAddress,
+                            Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE))
                     .withValue(ExtendedProperties.NAME, name)
                     .withValue(ExtendedProperties.VALUE, value)
-                    .withValueBackReference(ExtendedProperties.EVENT_ID, mEventStart)
-                    .build());
+                    .withValueBackReference(ExtendedProperties.EVENT_ID, mEventStart).build());
         }
 
         public void updatedExtendedProperty(String name, String value, long id) {
@@ -1359,13 +1380,16 @@
                     c.close();
                 }
             }
-            // Either do an update or an insert, depending on whether one already exists
+            // Either do an update or an insert, depending on whether one
+            // already exists
             if (extendedPropertyId >= 0) {
                 add(ContentProviderOperation
-                        .newUpdate(ContentUris.withAppendedId(EXTENDED_PROPERTIES_URI,
-                                extendedPropertyId))
-                        .withValue(ExtendedProperties.VALUE, value)
-                        .build());
+                        .newUpdate(
+                                ContentUris.withAppendedId(
+                                        asSyncAdapter(ExtendedProperties.CONTENT_URI,
+                                                mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE),
+                                        extendedPropertyId))
+                        .withValue(ExtendedProperties.VALUE, value).build());
             } else {
                 newExtendedProperty(name, value);
             }
@@ -1373,11 +1397,11 @@
 
         public void newReminder(int mins, int eventStart) {
             add(ContentProviderOperation
-                    .newInsert(REMINDERS_URI)
+                    .newInsert(asSyncAdapter(Reminders.CONTENT_URI, mEmailAddress,
+                            Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE))
                     .withValue(Reminders.MINUTES, mins)
                     .withValue(Reminders.METHOD, Reminders.METHOD_ALERT)
-                    .withValueBackReference(ExtendedProperties.EVENT_ID, eventStart)
-                    .build());
+                    .withValueBackReference(ExtendedProperties.EVENT_ID, eventStart).build());
         }
 
         public void newReminder(int mins) {
@@ -1385,12 +1409,15 @@
         }
 
         public void delete(long id, String syncId) {
+            add(ContentProviderOperation.newDelete(
+                    asSyncAdapter(ContentUris.withAppendedId(Events.CONTENT_URI, id),
+                            mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE)).build());
+            // Delete the exceptions for this Event (CalendarProvider doesn't do
+            // this)
             add(ContentProviderOperation
-                    .newDelete(ContentUris.withAppendedId(EVENTS_URI, id)).build());
-            // Delete the exceptions for this Event (CalendarProvider doesn't do this)
-            add(ContentProviderOperation
-                    .newDelete(EVENTS_URI).withSelection(Events.ORIGINAL_EVENT + "=?",
-                            new String[] {syncId}).build());
+                    .newDelete(asSyncAdapter(Events.CONTENT_URI, mEmailAddress,
+                            Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE))
+                    .withSelection(Events.ORIGINAL_EVENT + "=?", new String[] {syncId}).build());
         }
 
         public void execute() {
@@ -1472,7 +1499,9 @@
                     ContentValues cv = new ContentValues();
                     cv.put(Events.STATUS, Events.STATUS_CANCELED);
                     mService.mContentResolver.update(
-                            ContentUris.withAppendedId(EVENTS_URI, eventId), cv, null, null);
+                            asSyncAdapter(ContentUris.withAppendedId(Events.CONTENT_URI, eventId),
+                                    mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), cv, null,
+                            null);
                 }
             } else {
                 s.data(Tags.CALENDAR_EXCEPTION_IS_DELETED, "0");
@@ -1676,7 +1705,9 @@
             // Get busy status from Attendees table
             long eventId = entityValues.getAsLong(Events._ID);
             int busyStatus = CalendarUtilities.BUSY_STATUS_TENTATIVE;
-            Cursor c = mService.mContentResolver.query(ATTENDEES_URI,
+            Cursor c = mService.mContentResolver.query(
+                    asSyncAdapter(Attendees.CONTENT_URI, mEmailAddress,
+                            Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE),
                     ATTENDEE_STATUS_PROJECTION, EVENT_AND_EMAIL,
                     new String[] {Long.toString(eventId), mEmailAddress}, null);
             if (c != null) {
@@ -1753,8 +1784,12 @@
                 while (c.moveToNext()) {
                     // Mark the parents of dirty exceptions
                     String serverId = c.getString(0);
-                    int cnt = cr.update(EVENTS_URI, cv, SERVER_ID_AND_CALENDAR_ID,
-                            new String[] {serverId, mCalendarIdString});
+                    int cnt = cr.update(
+                            asSyncAdapter(Events.CONTENT_URI, mEmailAddress,
+                                    Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), cv,
+                            SERVER_ID_AND_CALENDAR_ID, new String[] {
+                                    serverId, mCalendarIdString
+                            });
                     // Keep track of any orphaned exceptions
                     if (cnt == 0) {
                         orphanedExceptions.add(c.getLong(1));
@@ -1764,17 +1799,21 @@
                 c.close();
             }
 
-           // Delete any orphaned exceptions
-            for (long orphan: orphanedExceptions) {
+            // Delete any orphaned exceptions
+            for (long orphan : orphanedExceptions) {
                 userLog(TAG, "Deleted orphaned exception: " + orphan);
-                cr.delete(ContentUris.withAppendedId(EVENTS_URI, orphan), null, null);
+                cr.delete(
+                        asSyncAdapter(ContentUris.withAppendedId(Events.CONTENT_URI, orphan),
+                                mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), null, null);
             }
             orphanedExceptions.clear();
 
-            // Now we can go through dirty/marked top-level events and send them back to the server
-            EntityIterator eventIterator = EventsEntity.newEntityIterator(
-                    cr.query(EVENTS_URI, null, DIRTY_OR_MARKED_TOP_LEVEL_IN_CALENDAR,
-                            mCalendarIdArgument, null), cr);
+            // Now we can go through dirty/marked top-level events and send them
+            // back to the server
+            EntityIterator eventIterator = EventsEntity.newEntityIterator(cr.query(
+                    asSyncAdapter(Events.CONTENT_URI, mEmailAddress,
+                            Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), null,
+                    DIRTY_OR_MARKED_TOP_LEVEL_IN_CALENDAR, mCalendarIdArgument, null), cr);
             ContentValues cidValues = new ContentValues();
 
             try {
@@ -1834,8 +1873,11 @@
                         // And save it in the Event as the local id
                         cidValues.put(Events._SYNC_DATA, clientId);
                         cidValues.put(Events._SYNC_VERSION, "0");
-                        cr.update(ContentUris.withAppendedId(EVENTS_URI, eventId), cidValues,
-                                null, null);
+                        cr.update(
+                                asSyncAdapter(
+                                        ContentUris.withAppendedId(Events.CONTENT_URI, eventId),
+                                        mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE),
+                                cidValues, null, null);
                     } else {
                         if (entityValues.getAsInteger(Calendar.EventsColumns.DELETED) == 1) {
                             userLog("Deleting event with serverId: ", serverId);
@@ -1868,8 +1910,11 @@
                         cidValues.put(Events._SYNC_VERSION, version);
                         // Also save in entityValues so that we send it this time around
                         entityValues.put(Events._SYNC_VERSION, version);
-                        cr.update(ContentUris.withAppendedId(EVENTS_URI, eventId), cidValues,
-                                null, null);
+                        cr.update(
+                                asSyncAdapter(
+                                        ContentUris.withAppendedId(Events.CONTENT_URI, eventId),
+                                        mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE),
+                                cidValues, null, null);
                         s.start(Tags.SYNC_CHANGE).data(Tags.SYNC_SERVER_ID, serverId);
                     }
                     s.start(Tags.SYNC_APPLICATION_DATA);
@@ -1878,9 +1923,12 @@
 
                     // Now, the hard part; find exceptions for this event
                     if (serverId != null) {
-                        EntityIterator exIterator = EventsEntity.newEntityIterator(
-                                cr.query(EVENTS_URI, null, ORIGINAL_EVENT_AND_CALENDAR,
-                                        new String[] {serverId, mCalendarIdString}, null), cr);
+                        EntityIterator exIterator = EventsEntity.newEntityIterator(cr.query(
+                                asSyncAdapter(Events.CONTENT_URI, mEmailAddress,
+                                        Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), null,
+                                ORIGINAL_EVENT_AND_CALENDAR, new String[] {
+                                        serverId, mCalendarIdString
+                                }, null), cr);
                         boolean exFirst = true;
                         while (exIterator.hasNext()) {
                             Entity exEntity = exIterator.next();
diff --git a/src/com/android/exchange/utility/CalendarUtilities.java b/src/com/android/exchange/utility/CalendarUtilities.java
index edf3b65..3b177fa 100644
--- a/src/com/android/exchange/utility/CalendarUtilities.java
+++ b/src/com/android/exchange/utility/CalendarUtilities.java
@@ -1240,7 +1240,9 @@
         cv.put(Calendars.ACCESS_LEVEL, Calendars.OWNER_ACCESS);
         cv.put(Calendars.OWNER_ACCOUNT, account.mEmailAddress);
 
-        Uri uri = service.mContentResolver.insert(Calendars.CONTENT_URI, cv);
+        Uri uri = service.mContentResolver.insert(
+                asSyncAdapter(Calendars.CONTENT_URI, account.mEmailAddress,
+                        Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), cv);
         // We save the id of the calendar into mSyncStatus
         if (uri != null) {
             String stringId = uri.getPathSegments().get(1);
@@ -1250,6 +1252,13 @@
         return -1;
     }
 
+    static Uri asSyncAdapter(Uri uri, String account, String accountType) {
+        return uri.buildUpon()
+                .appendQueryParameter(android.provider.Calendar.CALLER_IS_SYNCADAPTER, "true")
+                .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
+                .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
+    }
+
     /**
      * Return the uid for an event based on its globalObjId
      * @param globalObjId the base64 encoded String provided by EAS
@@ -1720,32 +1729,36 @@
     }
 
     /**
-     * Create a Message for an Event that can be retrieved from CalendarProvider by its unique id
+     * Create a Message for an Event that can be retrieved from CalendarProvider
+     * by its unique id
+     *
      * @param cr a content resolver that can be used to query for the Event
      * @param eventId the unique id of the Event
-     * @param messageFlag the Message.FLAG_XXX constant indicating the type of email to be sent
-     * @param the unique id of this Event, or null if it can be retrieved from the Event
+     * @param messageFlag the Message.FLAG_XXX constant indicating the type of
+     *            email to be sent
+     * @param the unique id of this Event, or null if it can be retrieved from
+     *            the Event
      * @param the user's account
-     * @param requireAddressees if true (the default), no Message is returned if there aren't any
-     *  addressees; if false, return the Message regardless (addressees will be filled in later)
+     * @param requireAddressees if true (the default), no Message is returned if
+     *            there aren't any addressees; if false, return the Message
+     *            regardless (addressees will be filled in later)
      * @return a Message with many fields pre-filled (more later)
-     * @throws RemoteException if there is an issue retrieving the Event from CalendarProvider
+     * @throws RemoteException if there is an issue retrieving the Event from
+     *             CalendarProvider
      */
     static public EmailContent.Message createMessageForEventId(Context context, long eventId,
             int messageFlag, String uid, Account account) throws RemoteException {
         return createMessageForEventId(context, eventId, messageFlag, uid, account,
-                null /*specifiedAttendee*/);
+                null /* specifiedAttendee */);
     }
 
     static public EmailContent.Message createMessageForEventId(Context context, long eventId,
             int messageFlag, String uid, Account account, String specifiedAttendee)
             throws RemoteException {
         ContentResolver cr = context.getContentResolver();
-        EntityIterator eventIterator =
-            EventsEntity.newEntityIterator(
-                    cr.query(ContentUris.withAppendedId(Events.CONTENT_URI.buildUpon()
-                            .appendQueryParameter(android.provider.Calendar.CALLER_IS_SYNCADAPTER,
-                            "true").build(), eventId), null, null, null, null), cr);
+        EntityIterator eventIterator = EventsEntity.newEntityIterator(cr.query(
+                ContentUris.withAppendedId(Events.CONTENT_URI, eventId), null, null, null, null),
+                cr);
         try {
             while (eventIterator.hasNext()) {
                 Entity entity = eventIterator.next();