diff options
author | Martin Hibdon <mhibdon@google.com> | 2014-03-06 16:31:35 -0800 |
---|---|---|
committer | Martin Hibdon <mhibdon@google.com> | 2014-03-07 13:24:09 -0800 |
commit | 8ee92f0cda3737b8a5ff2159a88d98b43194e98e (patch) | |
tree | f42c79b255d2e5a72c06f6fdccbf7e40d34f514f | |
parent | 60f38260dd0800bc7fa343740ba12dea55795b74 (diff) | |
download | Exchange-8ee92f0cda3737b8a5ff2159a88d98b43194e98e.tar.gz |
Add EasCalendarSync
Change-Id: I24ce12c72b9269dd98842db974e88cb44392eff0
-rw-r--r-- | src/com/android/exchange/adapter/CalendarSyncParser.java | 4 | ||||
-rw-r--r-- | src/com/android/exchange/adapter/FolderSyncParser.java | 4 | ||||
-rw-r--r-- | src/com/android/exchange/eas/EasSyncBase.java | 8 | ||||
-rw-r--r-- | src/com/android/exchange/eas/EasSyncCalendar.java (renamed from src/com/android/exchange/service/EasCalendarSyncHandler.java) | 306 | ||||
-rw-r--r-- | src/com/android/exchange/service/EasSyncHandler.java | 9 | ||||
-rw-r--r-- | src/com/android/exchange/service/EmailSyncAdapterService.java | 3 |
6 files changed, 196 insertions, 138 deletions
diff --git a/src/com/android/exchange/adapter/CalendarSyncParser.java b/src/com/android/exchange/adapter/CalendarSyncParser.java index f059c097..111b510d 100644 --- a/src/com/android/exchange/adapter/CalendarSyncParser.java +++ b/src/com/android/exchange/adapter/CalendarSyncParser.java @@ -26,7 +26,7 @@ import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.Utility; import com.android.exchange.Eas; import com.android.exchange.adapter.AbstractSyncAdapter.Operation; -import com.android.exchange.service.EasCalendarSyncHandler; +import com.android.exchange.eas.EasSyncCalendar; import com.android.exchange.utility.CalendarUtilities; import com.android.mail.utils.LogUtils; import com.google.common.annotations.VisibleForTesting; @@ -1357,7 +1357,7 @@ public class CalendarSyncParser extends AbstractSyncParser { @Override protected void wipe() { LogUtils.w(TAG, "Wiping calendar for account %d", mAccount.mId); - EasCalendarSyncHandler.wipeAccountFromContentProvider(mContext, + EasSyncCalendar.wipeAccountFromContentProvider(mContext, mAccount.mEmailAddress); } } diff --git a/src/com/android/exchange/adapter/FolderSyncParser.java b/src/com/android/exchange/adapter/FolderSyncParser.java index de06658c..f6334c7a 100644 --- a/src/com/android/exchange/adapter/FolderSyncParser.java +++ b/src/com/android/exchange/adapter/FolderSyncParser.java @@ -41,7 +41,7 @@ import com.android.exchange.CommandStatusException; import com.android.exchange.CommandStatusException.CommandStatus; import com.android.exchange.Eas; import com.android.exchange.eas.EasSyncContacts; -import com.android.exchange.service.EasCalendarSyncHandler; +import com.android.exchange.eas.EasSyncCalendar; import com.android.mail.utils.LogUtils; import com.google.common.annotations.VisibleForTesting; @@ -759,7 +759,7 @@ public class FolderSyncParser extends AbstractSyncParser { @Override protected void wipe() { - EasCalendarSyncHandler.wipeAccountFromContentProvider(mContext, + EasSyncCalendar.wipeAccountFromContentProvider(mContext, mAccount.mEmailAddress); EasSyncContacts.wipeAccountFromContentProvider(mContext, mAccount.mEmailAddress); diff --git a/src/com/android/exchange/eas/EasSyncBase.java b/src/com/android/exchange/eas/EasSyncBase.java index 871000ed..98763c5e 100644 --- a/src/com/android/exchange/eas/EasSyncBase.java +++ b/src/com/android/exchange/eas/EasSyncBase.java @@ -127,7 +127,7 @@ public class EasSyncBase extends EasOperation { while (result == RESULT_MORE_AVAILABLE) { result = super.performOperation(); if (result == RESULT_MORE_AVAILABLE || result == RESULT_DONE) { - mCollectionTypeHandler.cleanup(mContext, mAccount); + mCollectionTypeHandler.cleanup(mContext, mAccount, result); } // TODO: Clear pending request queue. final String newKey = getSyncKey(); @@ -166,9 +166,9 @@ public class EasSyncBase extends EasOperation { case Mailbox.TYPE_TRASH: //case Mailbox.TYPE_JUNK: return new EasSyncMail(); - case Mailbox.TYPE_CALENDAR: - // TODO: fill this in when we have EasSyncCalendar; - return null; + case Mailbox.TYPE_CALENDAR: { + return new EasSyncCalendar(mContext, mAccount, mMailbox); + } case Mailbox.TYPE_CONTACTS: return new EasSyncContacts(mAccount.mEmailAddress); default: diff --git a/src/com/android/exchange/service/EasCalendarSyncHandler.java b/src/com/android/exchange/eas/EasSyncCalendar.java index 38526b9f..14aa7367 100644 --- a/src/com/android/exchange/service/EasCalendarSyncHandler.java +++ b/src/com/android/exchange/eas/EasSyncCalendar.java @@ -1,4 +1,4 @@ -package com.android.exchange.service; +package com.android.exchange.eas; import android.content.ContentResolver; import android.content.ContentUris; @@ -25,6 +25,7 @@ import com.android.calendarcommon2.DateException; import com.android.calendarcommon2.Duration; import com.android.emailcommon.TrafficFlags; import com.android.emailcommon.provider.Account; +import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.Utility; @@ -34,6 +35,7 @@ import com.android.exchange.adapter.AbstractSyncParser; import com.android.exchange.adapter.CalendarSyncParser; import com.android.exchange.adapter.Serializer; import com.android.exchange.adapter.Tags; +import com.android.exchange.service.EasSyncHandler; import com.android.exchange.utility.CalendarUtilities; import com.android.mail.utils.LogUtils; import com.google.common.collect.Sets; @@ -49,12 +51,14 @@ import java.util.UUID; /** * Performs an Exchange Sync for a Calendar collection. */ -public class EasCalendarSyncHandler extends EasSyncHandler { +public class EasSyncCalendar extends EasSyncCollectionTypeBase { private static final String TAG = Eas.LOG_TAG; // TODO: Some constants are copied from CalendarSyncAdapter and are still used by the parser. // These values need to stay in sync; when the parser is cleaned up, be sure to unify them. + private static final int PIM_WINDOW_SIZE_CALENDAR = 10; + /** Projection for getting a calendar id. */ private static final String[] CALENDAR_ID_PROJECTION = { Calendars._ID }; private static final int CALENDAR_ID_COLUMN = 0; @@ -112,7 +116,7 @@ public class EasCalendarSyncHandler extends EasSyncHandler { private static final String EXTENDED_PROPERTY_ATTENDEES = "attendees"; private static final String EXTENDED_PROPERTY_CATEGORIES = "categories"; - private final android.accounts.Account mAccountManagerAccount; + private final android.accounts.Account mAndroidAccount; private final long mCalendarId; // The following lists are populated as part of upsync, and handled during cleanup. @@ -123,15 +127,16 @@ public class EasCalendarSyncHandler extends EasSyncHandler { /** Emails that need to be sent due to this upsync. */ private final ArrayList<Message> mOutgoingMailList = new ArrayList<Message>(); - public EasCalendarSyncHandler(final Context context, final ContentResolver contentResolver, - final android.accounts.Account accountManagerAccount, final Account account, - final Mailbox mailbox, final Bundle syncExtras, final SyncResult syncResult) { - super(context, contentResolver, account, mailbox, syncExtras, syncResult); - mAccountManagerAccount = accountManagerAccount; - final Cursor c = mContentResolver.query(Calendars.CONTENT_URI, CALENDAR_ID_PROJECTION, + public EasSyncCalendar(final Context context, final Account account, + final Mailbox mailbox) { + super(); + mAndroidAccount = new android.accounts.Account(account.mEmailAddress, + Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE); + final ContentResolver cr = context.getContentResolver(); + final Cursor c = cr.query(Calendars.CONTENT_URI, CALENDAR_ID_PROJECTION, CALENDAR_SELECTION_ACCOUNT_AND_SYNC_ID, new String[] { - mAccount.mEmailAddress, + account.mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE, mailbox.mServerId, }, null); @@ -146,11 +151,11 @@ public class EasCalendarSyncHandler extends EasSyncHandler { // Check if we have a calendar for this account with no server Id. If so, it was // synced with an older version of the sync adapter before serverId's were // supported. - final Cursor c1 = mContentResolver.query(Calendars.CONTENT_URI, + final Cursor c1 = cr.query(Calendars.CONTENT_URI, CALENDAR_ID_PROJECTION, CALENDAR_SELECTION_ACCOUNT_AND_NO_SYNC, new String[] { - mAccount.mEmailAddress, + account.mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE, }, null); if (c1 != null) { @@ -158,10 +163,10 @@ public class EasCalendarSyncHandler extends EasSyncHandler { if (c1.moveToFirst()) { id = c1.getLong(CALENDAR_ID_COLUMN); final ContentValues values = new ContentValues(); - values.put(Calendars._SYNC_ID, mMailbox.mServerId); - mContentResolver.update( + values.put(Calendars._SYNC_ID, mailbox.mServerId); + cr.update( ContentUris.withAppendedId( - asSyncAdapter(Calendars.CONTENT_URI), id), + asSyncAdapter(Calendars.CONTENT_URI, account), id), values, null, /* where */ null /* selectionArgs */); @@ -174,8 +179,8 @@ public class EasCalendarSyncHandler extends EasSyncHandler { if (id >= 0) { mCalendarId = id; } else { - mCalendarId = CalendarUtilities.createCalendar(mContext, mContentResolver, - mAccount, mMailbox); + mCalendarId = CalendarUtilities.createCalendar(context, cr, account, + mailbox); } } } finally { @@ -185,7 +190,27 @@ public class EasCalendarSyncHandler extends EasSyncHandler { } @Override - protected int getTrafficFlag() { + public void setSyncOptions(final Context context, final Serializer s, + final double protocolVersion, final Account account, final Mailbox mailbox, + final boolean isInitialSync, final int numWindows) throws IOException { + if (isInitialSync) { + setInitialSyncOptions(s); + } else { + setNonInitialSyncOptions(s, numWindows, protocolVersion); + setUpsyncCommands(context, account, protocolVersion, s); + } + } + + + @Override + public AbstractSyncParser getParser(final Context context, final Account account, + final Mailbox mailbox, final InputStream is) throws IOException { + return new CalendarSyncParser(context, context.getContentResolver(), is, mailbox, account, + mAndroidAccount, mCalendarId); + } + + @Override + public int getTrafficFlag() { return TrafficFlags.DATA_CALENDAR; } @@ -205,34 +230,25 @@ public class EasCalendarSyncHandler extends EasSyncHandler { /** * Convenience wrapper to {@link #asSyncAdapter(android.net.Uri, String)}. */ - private Uri asSyncAdapter(final Uri uri) { - return asSyncAdapter(uri, mAccount.mEmailAddress); + private Uri asSyncAdapter(final Uri uri, final Account account) { + return asSyncAdapter(uri, account.mEmailAddress); } - @Override protected String getFolderClassName() { return "Calendar"; } - - @Override - protected AbstractSyncParser getParser(final InputStream is) throws IOException { - return new CalendarSyncParser(mContext, mContentResolver, is, - mMailbox, mAccount, mAccountManagerAccount, mCalendarId); - } - - @Override protected void setInitialSyncOptions(final Serializer s) throws IOException { // Nothing to do for Calendar. } - @Override - protected void setNonInitialSyncOptions(final Serializer s, int numWindows) throws IOException { + protected void setNonInitialSyncOptions(final Serializer s, final int numWindows, + final double protocolVersion) throws IOException { final int windowSize = numWindows * PIM_WINDOW_SIZE_CALENDAR; if (windowSize > MAX_WINDOW_SIZE + PIM_WINDOW_SIZE_CALENDAR) { throw new IOException("Max window size reached and still no data"); } - setPimSyncOptions(s, Eas.FILTER_2_WEEKS, + setPimSyncOptions(s, Eas.FILTER_2_WEEKS, protocolVersion, windowSize < MAX_WINDOW_SIZE ? windowSize : MAX_WINDOW_SIZE); } @@ -242,12 +258,13 @@ public class EasCalendarSyncHandler extends EasSyncHandler { * @param calendarIdString {@link #mCalendarId}, as a String. * @param calendarIdArgument calendarIdString, in a String array. */ - private void markParentsOfDirtyEvents(final String calendarIdString, - final String[] calendarIdArgument) { + private void markParentsOfDirtyEvents(final Context context, final Account account, + final String calendarIdString, final String[] calendarIdArgument) { + final ContentResolver cr = context.getContentResolver(); // We've got to handle exceptions as part of the parent when changes occur, so we need // to find new/changed exceptions and mark the parent dirty final ArrayList<Long> orphanedExceptions = new ArrayList<Long>(); - final Cursor c = mContentResolver.query(Events.CONTENT_URI, + final Cursor c = cr.query(Events.CONTENT_URI, ORIGINAL_EVENT_PROJECTION, DIRTY_EXCEPTION_IN_CALENDAR, calendarIdArgument, null); if (c != null) { try { @@ -258,7 +275,7 @@ public class EasCalendarSyncHandler extends EasSyncHandler { while (c.moveToNext()) { // Mark the parents of dirty exceptions final long parentId = c.getLong(ORIGINAL_EVENT_ORIGINAL_ID_COLUMN); - final int cnt = mContentResolver.update(asSyncAdapter(Events.CONTENT_URI), cv, + final int cnt = cr.update(asSyncAdapter(Events.CONTENT_URI, account), cv, EVENT_ID_AND_CALENDAR_ID, new String[] { Long.toString(parentId), calendarIdString }); // Keep track of any orphaned exceptions @@ -274,8 +291,8 @@ public class EasCalendarSyncHandler extends EasSyncHandler { // Delete any orphaned exceptions for (final long orphan : orphanedExceptions) { LogUtils.d(TAG, "Deleted orphaned exception: %d", orphan); - mContentResolver.delete(asSyncAdapter( - ContentUris.withAppendedId(Events.CONTENT_URI, orphan)), null, null); + cr.delete(asSyncAdapter( + ContentUris.withAppendedId(Events.CONTENT_URI, orphan), account), null, null); } } @@ -306,10 +323,11 @@ public class EasCalendarSyncHandler extends EasSyncHandler { * @param entity The {@link Entity} for this event. * @param clientId The client id for this event. */ - private void sendDeclinedEmail(final Entity entity, final String clientId) { + private void sendDeclinedEmail(final Context context, final Account account, + final Entity entity, final String clientId) { final Message msg = - CalendarUtilities.createMessageForEntity(mContext, entity, - Message.FLAG_OUTGOING_MEETING_DECLINE, clientId, mAccount); + CalendarUtilities.createMessageForEntity(context, entity, + Message.FLAG_OUTGOING_MEETING_DECLINE, clientId, account); if (msg != null) { LogUtils.d(TAG, "Queueing declined response to %s", msg.mTo); mOutgoingMailList.add(msg); @@ -363,13 +381,15 @@ public class EasCalendarSyncHandler extends EasSyncHandler { * @throws IOException * TODO: This can probably be refactored/cleaned up more. */ - private void sendEvent(final Entity entity, final String clientId, final Serializer s) + private void sendEvent(final Context context, final Account account, final Entity entity, + final String clientId, final double protocolVersion, final Serializer s) throws IOException { // Serialize for EAS here // Set uid with the client id we created // 1) Serialize the top-level event // 2) Serialize attendees and reminders from subvalues // 3) Look for exceptions and serialize with the top-level event + final ContentResolver cr = context.getContentResolver(); final ContentValues entityValues = entity.getEntityValues(); final boolean isException = (clientId == null); boolean hasAttendees = false; @@ -396,8 +416,8 @@ public class EasCalendarSyncHandler extends EasSyncHandler { final long eventId = entityValues.getAsLong(Events._ID); final ContentValues cv = new ContentValues(1); cv.put(Events.STATUS, Events.STATUS_CANCELED); - mContentResolver.update( - asSyncAdapter(ContentUris.withAppendedId(Events.CONTENT_URI, eventId)), + cr.update(asSyncAdapter( + ContentUris.withAppendedId(Events.CONTENT_URI, eventId), account), cv, null, null); } } else { @@ -468,7 +488,7 @@ public class EasCalendarSyncHandler extends EasSyncHandler { String loc = entityValues.getAsString(Events.EVENT_LOCATION); if (!TextUtils.isEmpty(loc)) { - if (getProtocolVersion() < Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { + if (protocolVersion < Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { // EAS 2.5 doesn't like bare line feeds loc = Utility.replaceBareLfWithCrlf(loc); } @@ -476,7 +496,7 @@ public class EasCalendarSyncHandler extends EasSyncHandler { } s.writeStringValue(entityValues, Events.TITLE, Tags.CALENDAR_SUBJECT); - if (getProtocolVersion() >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { + if (protocolVersion >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { s.start(Tags.BASE_BODY); s.data(Tags.BASE_TYPE, "1"); s.writeStringValue(entityValues, Events.DESCRIPTION, Tags.BASE_DATA); @@ -488,7 +508,7 @@ public class EasCalendarSyncHandler extends EasSyncHandler { if (!isException) { // For Exchange 2003, only upsync if the event is new - if ((getProtocolVersion() >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) || !isChange) { + if ((protocolVersion >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) || !isChange) { s.writeStringValue(entityValues, Events.ORGANIZER, Tags.CALENDAR_ORGANIZER_EMAIL); } @@ -580,7 +600,7 @@ public class EasCalendarSyncHandler extends EasSyncHandler { } s.data(Tags.CALENDAR_ATTENDEE_NAME, attendeeName); s.data(Tags.CALENDAR_ATTENDEE_EMAIL, attendeeEmail); - if (getProtocolVersion() >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { + if (protocolVersion >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { s.data(Tags.CALENDAR_ATTENDEE_TYPE, "1"); // Required } s.end(); // Attendee @@ -601,14 +621,14 @@ public class EasCalendarSyncHandler extends EasSyncHandler { if (organizerEmail == null && entityValues.containsKey(Events.ORGANIZER)) { organizerEmail = entityValues.getAsString(Events.ORGANIZER); } - if (mAccount.mEmailAddress.equalsIgnoreCase(organizerEmail)) { + if (account.mEmailAddress.equalsIgnoreCase(organizerEmail)) { s.data(Tags.CALENDAR_MEETING_STATUS, hasAttendees ? "1" : "0"); } else { s.data(Tags.CALENDAR_MEETING_STATUS, "3"); } // For Exchange 2003, only upsync if the event is new - if (((getProtocolVersion() >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) || !isChange) && + if (((protocolVersion >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) || !isChange) && organizerName != null) { s.data(Tags.CALENDAR_ORGANIZER_NAME, organizerName); } @@ -635,12 +655,14 @@ public class EasCalendarSyncHandler extends EasSyncHandler { * @param selfOrganizer Whether the user is the organizer of this event. * @throws IOException */ - private void handleExceptionsToRecurrenceRules(final Serializer s, final Entity entity, - final ContentValues entityValues, final String serverId, final String clientId, - final String calendarIdString, final boolean selfOrganizer) throws IOException { - final EntityIterator exIterator = EventsEntity.newEntityIterator(mContentResolver.query( - asSyncAdapter(Events.CONTENT_URI), null, ORIGINAL_EVENT_AND_CALENDAR, - new String[] { serverId, calendarIdString }, null), mContentResolver); + private void handleExceptionsToRecurrenceRules(final Serializer s, final Context context, + final Account account,final Entity entity, final ContentValues entityValues, + final String serverId, final String clientId, final String calendarIdString, + final boolean selfOrganizer, final double protocolVersion) throws IOException { + final ContentResolver cr = context.getContentResolver(); + final EntityIterator exIterator = EventsEntity.newEntityIterator(cr.query( + asSyncAdapter(Events.CONTENT_URI, account), null, ORIGINAL_EVENT_AND_CALENDAR, + new String[] { serverId, calendarIdString }, null), cr); boolean exFirst = true; while (exIterator.hasNext()) { final Entity exEntity = exIterator.next(); @@ -649,7 +671,7 @@ public class EasCalendarSyncHandler extends EasSyncHandler { exFirst = false; } s.start(Tags.CALENDAR_EXCEPTION); - sendEvent(exEntity, null, s); + sendEvent(context, account, exEntity, null, protocolVersion, s); final ContentValues exValues = exEntity.getEntityValues(); if (getInt(exValues, Events.DIRTY) == 1) { // This is a new/updated exception, so we've got to notify our @@ -666,7 +688,7 @@ public class EasCalendarSyncHandler extends EasSyncHandler { // to the user, we have to reset it first to the original // organizer exValues.put(Events.ORGANIZER, entityValues.getAsString(Events.ORGANIZER)); - sendDeclinedEmail(exEntity, clientId); + sendDeclinedEmail(context, account, exEntity, clientId); } } else { flag = Message.FLAG_OUTGOING_MEETING_INVITE; @@ -685,8 +707,8 @@ public class EasCalendarSyncHandler extends EasSyncHandler { } if (selfOrganizer) { - final Message msg = CalendarUtilities.createMessageForEntity(mContext, exEntity, - flag, clientId, mAccount); + final Message msg = CalendarUtilities.createMessageForEntity(context, exEntity, + flag, clientId, account); if (msg != null) { LogUtils.d(TAG, "Queueing exception update to %s", msg.mTo); mOutgoingMailList.add(msg); @@ -714,8 +736,8 @@ public class EasCalendarSyncHandler extends EasSyncHandler { // Now send a cancellation email final Message removedMessage = - CalendarUtilities.createMessageForEntity(mContext, removedEntity, - Message.FLAG_OUTGOING_MEETING_CANCEL, clientId, mAccount); + CalendarUtilities.createMessageForEntity(context, removedEntity, + Message.FLAG_OUTGOING_MEETING_CANCEL, clientId, account); if (removedMessage != null) { LogUtils.d(TAG, "Queueing cancellation for removed attendees"); mOutgoingMailList.add(removedMessage); @@ -737,10 +759,12 @@ public class EasCalendarSyncHandler extends EasSyncHandler { * @param eventId The id for this event. * @param clientId The client side id for this event. */ - private void updateAttendeesAndSendMail(final Entity entity, final ContentValues entityValues, - final boolean selfOrganizer, final long eventId, final String clientId) { + private void updateAttendeesAndSendMail(final Context context, final Account account, + final Entity entity, final ContentValues entityValues, final boolean selfOrganizer, + final long eventId, final String clientId) { // Go through the extended properties of this Event and pull out our tokenized // attendees list and the user attendee status; we will need them later + final ContentResolver cr = context.getContentResolver(); String attendeeString = null; long attendeeStringId = -1; String userAttendeeStatus = null; @@ -764,8 +788,8 @@ public class EasCalendarSyncHandler extends EasSyncHandler { // is dirty, in which case we DON'T send email about the Event) if (selfOrganizer && (getInt(entityValues, Events.DIRTY) == 1)) { final Message msg = - CalendarUtilities.createMessageForEventId(mContext, eventId, - Message.FLAG_OUTGOING_MEETING_INVITE, clientId, mAccount); + CalendarUtilities.createMessageForEventId(context, eventId, + Message.FLAG_OUTGOING_MEETING_INVITE, clientId, account); if (msg != null) { LogUtils.d(TAG, "Queueing invitation to %s", msg.mTo); mOutgoingMailList.add(msg); @@ -797,20 +821,21 @@ public class EasCalendarSyncHandler extends EasSyncHandler { final ContentValues cv = new ContentValues(); cv.put(ExtendedProperties.VALUE, newTokenizedAttendees.toString()); if (attendeeString != null) { - mContentResolver.update(asSyncAdapter(ContentUris.withAppendedId( - ExtendedProperties.CONTENT_URI, attendeeStringId)), cv, null, null); + cr.update(asSyncAdapter(ContentUris.withAppendedId( + ExtendedProperties.CONTENT_URI, attendeeStringId), account), + cv, null, null); } else { // If there wasn't an "attendees" property, insert one cv.put(ExtendedProperties.NAME, EXTENDED_PROPERTY_ATTENDEES); cv.put(ExtendedProperties.EVENT_ID, eventId); - mContentResolver.insert(asSyncAdapter(ExtendedProperties.CONTENT_URI), cv); + cr.insert(asSyncAdapter(ExtendedProperties.CONTENT_URI, account), cv); } // Whoever is left has been removed from the attendee list; send them // a cancellation for (final String removedAttendee: originalAttendeeList) { // Send a cancellation message to each of them - final Message cancelMsg = CalendarUtilities.createMessageForEventId(mContext, - eventId, Message.FLAG_OUTGOING_MEETING_CANCEL, clientId, mAccount, + final Message cancelMsg = CalendarUtilities.createMessageForEventId(context, + eventId, Message.FLAG_OUTGOING_MEETING_CANCEL, clientId, account, removedAttendee); if (cancelMsg != null) { // Just send it to the removed attendee @@ -854,12 +879,12 @@ public class EasCalendarSyncHandler extends EasSyncHandler { // Save away the new status final ContentValues cv = new ContentValues(1); cv.put(ExtendedProperties.VALUE, Integer.toString(currentStatus)); - mContentResolver.update(asSyncAdapter(ContentUris.withAppendedId( - ExtendedProperties.CONTENT_URI, userAttendeeStatusId)), + cr.update(asSyncAdapter(ContentUris.withAppendedId( + ExtendedProperties.CONTENT_URI, userAttendeeStatusId), account), cv, null, null); // Send mail to the organizer advising of the new status - final Message msg = CalendarUtilities.createMessageForEventId(mContext, eventId, - messageFlag, clientId, mAccount); + final Message msg = CalendarUtilities.createMessageForEventId(context, eventId, + messageFlag, clientId, account); if (msg != null) { LogUtils.d(TAG, "Queueing invitation reply to %s", msg.mTo); mOutgoingMailList.add(msg); @@ -878,9 +903,11 @@ public class EasCalendarSyncHandler extends EasSyncHandler { * @return Whether this function added anything to s. * @throws IOException */ - private boolean handleEntity(final Serializer s, final Entity entity, - final String calendarIdString, final boolean first) throws IOException { + private boolean handleEntity(final Serializer s, final Context context, final Account account, + final Entity entity, final String calendarIdString, final boolean first, + final double protocolVersion) throws IOException { // For each of these entities, create the change commands + final ContentResolver cr = context.getContentResolver(); final ContentValues entityValues = entity.getEntityValues(); // We first need to check whether we can upsync this event; our test for this // is currently the value of EXTENDED_PROPERTY_ATTENDEES_REDACTED @@ -913,7 +940,7 @@ public class EasCalendarSyncHandler extends EasSyncHandler { LogUtils.d(TAG, "Sending Calendar changes to the server"); } - final boolean selfOrganizer = organizerEmail.equalsIgnoreCase(mAccount.mEmailAddress); + final boolean selfOrganizer = organizerEmail.equalsIgnoreCase(account.mEmailAddress); // Find our uid in the entity; otherwise create one String clientId = entityValues.getAsString(Events.SYNC_DATA2); if (clientId == null) { @@ -929,22 +956,22 @@ public class EasCalendarSyncHandler extends EasSyncHandler { final ContentValues cv = new ContentValues(2); cv.put(Events.SYNC_DATA2, clientId); cv.put(EVENT_SYNC_VERSION, "0"); - mContentResolver.update( - asSyncAdapter(ContentUris.withAppendedId(Events.CONTENT_URI, eventId)), + cr.update( + asSyncAdapter(ContentUris.withAppendedId(Events.CONTENT_URI, eventId), account), cv, null, null); } else if (entityValues.getAsInteger(Events.DELETED) == 1) { LogUtils.d(TAG, "Deleting event with serverId: %s", serverId); s.start(Tags.SYNC_DELETE).data(Tags.SYNC_SERVER_ID, serverId).end(); mDeletedIdList.add(eventId); if (selfOrganizer) { - final Message msg = CalendarUtilities.createMessageForEventId(mContext, - eventId, Message.FLAG_OUTGOING_MEETING_CANCEL, null, mAccount); + final Message msg = CalendarUtilities.createMessageForEventId(context, + eventId, Message.FLAG_OUTGOING_MEETING_CANCEL, null, account); if (msg != null) { LogUtils.d(TAG, "Queueing cancellation to %s", msg.mTo); mOutgoingMailList.add(msg); } } else { - sendDeclinedEmail(entity, clientId); + sendDeclinedEmail(context, account, entity, clientId); } // For deletions, we don't need to add application data, so just bail here. return true; @@ -955,44 +982,46 @@ public class EasCalendarSyncHandler extends EasSyncHandler { final String version = getEntityVersion(entityValues); final ContentValues cv = new ContentValues(1); cv.put(EVENT_SYNC_VERSION, version); - mContentResolver.update( - asSyncAdapter( ContentUris.withAppendedId(Events.CONTENT_URI, eventId)), - cv, null, null); + cr.update( asSyncAdapter(ContentUris.withAppendedId(Events.CONTENT_URI, eventId), + account), cv, null, null); // Also save in entityValues so that we send it this time around entityValues.put(EVENT_SYNC_VERSION, version); } s.start(Tags.SYNC_APPLICATION_DATA); - sendEvent(entity, clientId, s); + sendEvent(context, account, entity, clientId, protocolVersion, s); // Now, the hard part; find exceptions for this event if (serverId != null) { - handleExceptionsToRecurrenceRules(s, entity, entityValues, serverId, clientId, - calendarIdString, selfOrganizer); + handleExceptionsToRecurrenceRules(s, context, account, entity, entityValues, serverId, + clientId, calendarIdString, selfOrganizer, protocolVersion); } s.end().end(); // ApplicationData & Add/Change mUploadedIdList.add(eventId); - updateAttendeesAndSendMail(entity, entityValues, selfOrganizer, eventId, clientId); + updateAttendeesAndSendMail(context, account, entity, entityValues, selfOrganizer, eventId, + clientId); return true; } - @Override - protected void setUpsyncCommands(final Serializer s) throws IOException { + protected void setUpsyncCommands(Context context, final Account account, + final double protocolVersion, final Serializer s) throws IOException { + final ContentResolver cr = context.getContentResolver(); final String calendarIdString = Long.toString(mCalendarId); final String[] calendarIdArgument = { calendarIdString }; - markParentsOfDirtyEvents(calendarIdString, calendarIdArgument); + markParentsOfDirtyEvents(context, account, calendarIdString, calendarIdArgument); // Now go through dirty/marked top-level events and send them back to the server final EntityIterator eventIterator = EventsEntity.newEntityIterator( - mContentResolver.query(asSyncAdapter(Events.CONTENT_URI), null, - DIRTY_OR_MARKED_TOP_LEVEL_IN_CALENDAR, calendarIdArgument, null), mContentResolver); + cr.query(asSyncAdapter(Events.CONTENT_URI, account), null, + DIRTY_OR_MARKED_TOP_LEVEL_IN_CALENDAR, calendarIdArgument, null), cr); try { boolean first = true; while (eventIterator.hasNext()) { final boolean addedCommand = - handleEntity(s, eventIterator.next(), calendarIdString, first); + handleEntity(s, context, account, eventIterator.next(), calendarIdString, + first, protocolVersion); if (addedCommand) { first = false; } @@ -1006,39 +1035,72 @@ public class EasCalendarSyncHandler extends EasSyncHandler { } @Override - protected void cleanup(final int syncResult) { - if (syncResult != SYNC_RESULT_FAILED) { - // Clear dirty and mark flags for updates sent to server - if (!mUploadedIdList.isEmpty()) { - final ContentValues cv = new ContentValues(2); - cv.put(Events.DIRTY, 0); - cv.put(EVENT_SYNC_MARK, "0"); - for (final long eventId : mUploadedIdList) { - mContentResolver.update(asSyncAdapter(ContentUris.withAppendedId( - Events.CONTENT_URI, eventId)), cv, null, null); - } - } - // Delete events marked for deletion - if (!mDeletedIdList.isEmpty()) { - for (final long eventId : mDeletedIdList) { - mContentResolver.delete(asSyncAdapter(ContentUris.withAppendedId( - Events.CONTENT_URI, eventId)), null, null); - } + public void cleanup(final Context context, final Account account) { + final ContentResolver cr = context.getContentResolver(); + // Clear dirty and mark flags for updates sent to server + if (!mUploadedIdList.isEmpty()) { + final ContentValues cv = new ContentValues(2); + cv.put(Events.DIRTY, 0); + cv.put(EVENT_SYNC_MARK, "0"); + for (final long eventId : mUploadedIdList) { + cr.update(asSyncAdapter(ContentUris.withAppendedId( + Events.CONTENT_URI, eventId), account), cv, null, null); } - // Send all messages that were created during this sync. - for (final Message msg : mOutgoingMailList) { - sendMessage(mAccount, msg); + } + // Delete events marked for deletion + if (!mDeletedIdList.isEmpty()) { + for (final long eventId : mDeletedIdList) { + cr.delete(asSyncAdapter(ContentUris.withAppendedId( + Events.CONTENT_URI, eventId), account), null, null); } } - // Clear our lists for the next Sync request, if necessary. - if (syncResult != SYNC_RESULT_MORE_AVAILABLE) { - mDeletedIdList.clear(); - mUploadedIdList.clear(); - mOutgoingMailList.clear(); + // Send all messages that were created during this sync. + for (final Message msg : mOutgoingMailList) { + sendMessage(context, account, msg); } + + mDeletedIdList.clear(); + mUploadedIdList.clear(); + mOutgoingMailList.clear(); } /** + * Convenience method for adding a Message to an account's outbox + * @param account The {@link Account} from which to send the message. + * @param msg The message to send + */ + protected void sendMessage(final Context context, final Account account, + final EmailContent.Message msg) { + long mailboxId = Mailbox.findMailboxOfType(context, account.mId, Mailbox.TYPE_OUTBOX); + // TODO: Improve system mailbox handling. + if (mailboxId == Mailbox.NO_MAILBOX) { + LogUtils.d(TAG, "No outbox for account %d, creating it", account.mId); + final Mailbox outbox = + Mailbox.newSystemMailbox(context, account.mId, Mailbox.TYPE_OUTBOX); + outbox.save(context); + mailboxId = outbox.mId; + } + msg.mMailboxKey = mailboxId; + msg.mAccountKey = account.mId; + msg.save(context); + requestSyncForMailbox(EmailContent.AUTHORITY, mailboxId); + } + + /** + * Issue a {@link android.content.ContentResolver#requestSync} for a specific mailbox. + * @param amAccount The {@link android.accounts.Account} for the account we're pinging. + * @param authority The authority for the mailbox that needs to sync. + * @param mailboxId The id of the mailbox that needs to sync. + */ + protected void requestSyncForMailbox(final String authority, final long mailboxId) { + final Bundle extras = Mailbox.createSyncBundle(mailboxId); + ContentResolver.requestSync(mAndroidAccount, authority, extras); + LogUtils.d(TAG, "requestSync EasServerConnection requestSyncForMailbox %s, %s", + mAndroidAccount.toString(), extras.toString()); + } + + + /** * Delete an account from the Calendar provider. * @param context Our {@link Context} * @param emailAddress The email address of the account we wish to delete diff --git a/src/com/android/exchange/service/EasSyncHandler.java b/src/com/android/exchange/service/EasSyncHandler.java index 148da49a..1eeecdd6 100644 --- a/src/com/android/exchange/service/EasSyncHandler.java +++ b/src/com/android/exchange/service/EasSyncHandler.java @@ -33,6 +33,7 @@ import com.android.exchange.adapter.AbstractSyncParser; import com.android.exchange.adapter.Parser; import com.android.exchange.adapter.Serializer; import com.android.exchange.adapter.Tags; +import com.android.exchange.eas.EasSyncCalendar; import com.android.exchange.eas.EasProvision; import com.android.mail.utils.LogUtils; @@ -124,13 +125,7 @@ public abstract class EasSyncHandler extends EasServerConnection { final android.accounts.Account accountManagerAccount, final Account account, final Mailbox mailbox, final Bundle syncExtras, final SyncResult syncResult) { - if (account != null && mailbox != null) { - switch (mailbox.mType) { - case Mailbox.TYPE_CALENDAR: - return new EasCalendarSyncHandler(context, contentResolver, - accountManagerAccount, account, mailbox, syncExtras, syncResult); - } - } + // FLAG: Obsolete function // Unknown mailbox type. LogUtils.e(TAG, "Invalid mailbox type %d", mailbox.mType); return null; diff --git a/src/com/android/exchange/service/EmailSyncAdapterService.java b/src/com/android/exchange/service/EmailSyncAdapterService.java index 6a2ed421..4c119385 100644 --- a/src/com/android/exchange/service/EmailSyncAdapterService.java +++ b/src/com/android/exchange/service/EmailSyncAdapterService.java @@ -64,6 +64,7 @@ import com.android.exchange.R.drawable; import com.android.exchange.R.string; import com.android.exchange.adapter.PingParser; import com.android.exchange.eas.EasSyncContacts; +import com.android.exchange.eas.EasSyncCalendar; import com.android.exchange.eas.EasFolderSync; import com.android.exchange.eas.EasLoadAttachment; import com.android.exchange.eas.EasMoveItems; @@ -463,7 +464,7 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { if (emailAddress != null) { final Context context = EmailSyncAdapterService.this; EasSyncContacts.wipeAccountFromContentProvider(context, emailAddress); - EasCalendarSyncHandler.wipeAccountFromContentProvider(context, emailAddress); + EasSyncCalendar.wipeAccountFromContentProvider(context, emailAddress); } // TODO: Run account reconciler? } |