diff options
author | Yu Ping Hu <yph@google.com> | 2014-03-07 19:17:02 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-03-07 19:17:02 +0000 |
commit | f382d4ffbde7e16eea4cc3aebca220e6cad81735 (patch) | |
tree | b3e7ac8fa80fe99c43f1491c74ccc83ba4f7e768 | |
parent | 2909f4d00bf188f0d0c76ff8e61a306f862193fd (diff) | |
parent | 52c9dfbbed3860d9b7dfc60fae466f620464151c (diff) | |
download | Exchange-f382d4ffbde7e16eea4cc3aebca220e6cad81735.tar.gz |
Merge "Switch contacts sync to an EasSyncBase." into ub-mail-klp-mr2
-rw-r--r-- | src/com/android/exchange/adapter/ContactsSyncParser.java | 4 | ||||
-rw-r--r-- | src/com/android/exchange/adapter/FolderSyncParser.java | 4 | ||||
-rw-r--r-- | src/com/android/exchange/eas/EasSyncBase.java | 18 | ||||
-rw-r--r-- | src/com/android/exchange/eas/EasSyncCollectionTypeBase.java | 49 | ||||
-rw-r--r-- | src/com/android/exchange/eas/EasSyncContacts.java (renamed from src/com/android/exchange/service/EasContactsSyncHandler.java) | 127 | ||||
-rw-r--r-- | src/com/android/exchange/eas/EasSyncMail.java | 7 | ||||
-rw-r--r-- | src/com/android/exchange/service/EasMailboxSyncHandler.java | 196 | ||||
-rw-r--r-- | src/com/android/exchange/service/EasSyncHandler.java | 10 | ||||
-rw-r--r-- | src/com/android/exchange/service/EmailSyncAdapterService.java | 26 |
9 files changed, 147 insertions, 294 deletions
diff --git a/src/com/android/exchange/adapter/ContactsSyncParser.java b/src/com/android/exchange/adapter/ContactsSyncParser.java index c5b6068e..3504bd94 100644 --- a/src/com/android/exchange/adapter/ContactsSyncParser.java +++ b/src/com/android/exchange/adapter/ContactsSyncParser.java @@ -40,7 +40,7 @@ import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.Utility; import com.android.exchange.Eas; -import com.android.exchange.service.EasContactsSyncHandler; +import com.android.exchange.eas.EasSyncContacts; import com.android.exchange.service.EasSyncHandler; import com.android.exchange.utility.CalendarUtilities; import com.android.mail.utils.LogUtils; @@ -1308,7 +1308,7 @@ public class ContactsSyncParser extends AbstractSyncParser { @Override protected void wipe() { LogUtils.w(TAG, "Wiping contacts for account %d", mAccount.mId); - EasContactsSyncHandler.wipeAccountFromContentProvider(mContext, + EasSyncContacts.wipeAccountFromContentProvider(mContext, mAccount.mEmailAddress); } } diff --git a/src/com/android/exchange/adapter/FolderSyncParser.java b/src/com/android/exchange/adapter/FolderSyncParser.java index 4805cdc3..de06658c 100644 --- a/src/com/android/exchange/adapter/FolderSyncParser.java +++ b/src/com/android/exchange/adapter/FolderSyncParser.java @@ -40,8 +40,8 @@ import com.android.emailcommon.utility.AttachmentUtilities; 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.service.EasContactsSyncHandler; import com.android.mail.utils.LogUtils; import com.google.common.annotations.VisibleForTesting; @@ -761,7 +761,7 @@ public class FolderSyncParser extends AbstractSyncParser { protected void wipe() { EasCalendarSyncHandler.wipeAccountFromContentProvider(mContext, mAccount.mEmailAddress); - EasContactsSyncHandler.wipeAccountFromContentProvider(mContext, + EasSyncContacts.wipeAccountFromContentProvider(mContext, mAccount.mEmailAddress); // Save away any mailbox sync information that is NOT default diff --git a/src/com/android/exchange/eas/EasSyncBase.java b/src/com/android/exchange/eas/EasSyncBase.java index ede73b5f..871000ed 100644 --- a/src/com/android/exchange/eas/EasSyncBase.java +++ b/src/com/android/exchange/eas/EasSyncBase.java @@ -1,8 +1,10 @@ package com.android.exchange.eas; import android.content.Context; +import android.net.TrafficStats; import android.text.format.DateUtils; +import com.android.emailcommon.TrafficFlags; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.Mailbox; @@ -70,6 +72,9 @@ public class EasSyncBase extends EasOperation { if (mCollectionTypeHandler == null) { return false; } + // Set up traffic stats bookkeeping. + final int trafficFlags = TrafficFlags.getSyncFlags(mContext, mAccount); + TrafficStats.setThreadStatsTag(trafficFlags | mCollectionTypeHandler.getTrafficFlag()); } return result; } @@ -121,6 +126,9 @@ public class EasSyncBase extends EasOperation { final String key = getSyncKey(); while (result == RESULT_MORE_AVAILABLE) { result = super.performOperation(); + if (result == RESULT_MORE_AVAILABLE || result == RESULT_DONE) { + mCollectionTypeHandler.cleanup(mContext, mAccount); + } // TODO: Clear pending request queue. final String newKey = getSyncKey(); if (result == RESULT_MORE_AVAILABLE && key.equals(newKey)) { @@ -155,16 +163,14 @@ public class EasSyncBase extends EasOperation { case Mailbox.TYPE_INBOX: case Mailbox.TYPE_DRAFTS: case Mailbox.TYPE_SENT: -// case Mailbox.TYPE_TRASH: - case Mailbox.TYPE_JUNK: { + case Mailbox.TYPE_TRASH: + //case Mailbox.TYPE_JUNK: return new EasSyncMail(); - } case Mailbox.TYPE_CALENDAR: - // TODO: fill this in when we have EasSyncContacts; + // TODO: fill this in when we have EasSyncCalendar; return null; case Mailbox.TYPE_CONTACTS: - // TODO: fill this in when we have EasSyncContacts; - return null; + return new EasSyncContacts(mAccount.mEmailAddress); default: LogUtils.e(LOG_TAG, "unexpected collectiontype %d", type); return null; diff --git a/src/com/android/exchange/eas/EasSyncCollectionTypeBase.java b/src/com/android/exchange/eas/EasSyncCollectionTypeBase.java index d8e578c0..555e5353 100644 --- a/src/com/android/exchange/eas/EasSyncCollectionTypeBase.java +++ b/src/com/android/exchange/eas/EasSyncCollectionTypeBase.java @@ -4,8 +4,10 @@ import android.content.Context; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.Mailbox; +import com.android.exchange.Eas; import com.android.exchange.adapter.AbstractSyncParser; import com.android.exchange.adapter.Serializer; +import com.android.exchange.adapter.Tags; import java.io.IOException; import java.io.InputStream; @@ -21,6 +23,13 @@ public abstract class EasSyncCollectionTypeBase { public static final int MAX_WINDOW_SIZE = 512; /** + * Get the flag for traffic bookkeeping for this sync type. + * @return The appropriate value from {@link com.android.emailcommon.TrafficFlags} for this + * sync. + */ + public abstract int getTrafficFlag(); + + /** * Write the contents of a Collection node in an EAS sync request appropriate for our mailbox. * See http://msdn.microsoft.com/en-us/library/gg650891(v=exchg.80).aspx for documentation on * the contents of this sync request element. @@ -49,4 +58,44 @@ public abstract class EasSyncCollectionTypeBase { */ public abstract AbstractSyncParser getParser(final Context context, final Account account, final Mailbox mailbox, final InputStream is) throws IOException; + + /** + * After every successful sync iteration, this function gets called to cleanup any state to + * match the sync result (e.g., to clean up an external ContentProvider for PIM data). + * @param context + * @param account + */ + public void cleanup(final Context context, final Account account) {} + + /** + * Shared non-initial sync options for PIM (contacts & calendar) objects. + * + * @param s The {@link com.android.exchange.adapter.Serializer} for this sync request. + * @param filter The lookback to use, or null if no lookback is desired. + * @param protocolVersion The EAS protocol version for this request, as a double. + * @param windowSize + * @throws IOException + */ + protected static void setPimSyncOptions(final Serializer s, final String filter, + final double protocolVersion, int windowSize) throws IOException { + s.tag(Tags.SYNC_DELETES_AS_MOVES); + s.tag(Tags.SYNC_GET_CHANGES); + s.data(Tags.SYNC_WINDOW_SIZE, String.valueOf(windowSize)); + s.start(Tags.SYNC_OPTIONS); + // Set the filter (lookback), if provided + if (filter != null) { + s.data(Tags.SYNC_FILTER_TYPE, filter); + } + // Set the truncation amount and body type + if (protocolVersion >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { + s.start(Tags.BASE_BODY_PREFERENCE); + // Plain text + s.data(Tags.BASE_TYPE, Eas.BODY_PREFERENCE_TEXT); + s.data(Tags.BASE_TRUNCATION_SIZE, Eas.EAS12_TRUNCATION_SIZE); + s.end(); + } else { + s.data(Tags.SYNC_TRUNCATION, Eas.EAS2_5_TRUNCATION_SIZE); + } + s.end(); + } } diff --git a/src/com/android/exchange/service/EasContactsSyncHandler.java b/src/com/android/exchange/eas/EasSyncContacts.java index 8757b927..3a6ffc05 100644 --- a/src/com/android/exchange/service/EasContactsSyncHandler.java +++ b/src/com/android/exchange/eas/EasSyncContacts.java @@ -1,4 +1,4 @@ -package com.android.exchange.service; +package com.android.exchange.eas; import android.content.ContentProviderOperation; import android.content.ContentResolver; @@ -7,10 +7,8 @@ import android.content.ContentValues; import android.content.Context; import android.content.Entity; import android.content.EntityIterator; -import android.content.SyncResult; import android.database.Cursor; import android.net.Uri; -import android.os.Bundle; import android.provider.ContactsContract; import android.provider.ContactsContract.CommonDataKinds.Email; import android.provider.ContactsContract.CommonDataKinds.Event; @@ -54,9 +52,11 @@ import java.util.TimeZone; * Contact state is in the contacts provider, not in our DB (and therefore not in e.g. mMailbox). * The Mailbox in the Email DB is only useful for serverId and syncInterval. */ -public class EasContactsSyncHandler extends EasSyncHandler { +public class EasSyncContacts extends EasSyncCollectionTypeBase { private static final String TAG = Eas.LOG_TAG; + public static final int PIM_WINDOW_SIZE_CONTACTS = 10; + private static final String MIMETYPE_GROUP_MEMBERSHIP_AND_ID_EQUALS = ContactsContract.Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE + "' AND " + GroupMembership.GROUP_ROW_ID + "=?"; @@ -152,34 +152,44 @@ public class EasContactsSyncHandler extends EasSyncHandler { public static final String ACCOUNT_NAME = "data8"; } - public EasContactsSyncHandler(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; + public EasSyncContacts(final String emailAddress) { + mAccountManagerAccount = new android.accounts.Account(emailAddress, + Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE); } @Override - protected int getTrafficFlag() { + public int getTrafficFlag() { return TrafficFlags.DATA_CONTACTS; } @Override - protected String getFolderClassName() { - return "Contacts"; + 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); + return; + } + + final int windowSize = numWindows * PIM_WINDOW_SIZE_CONTACTS; + if (windowSize > MAX_WINDOW_SIZE + PIM_WINDOW_SIZE_CONTACTS) { + throw new IOException("Max window size reached and still no data"); + } + setPimSyncOptions(s, null, protocolVersion, + windowSize < MAX_WINDOW_SIZE ? windowSize : MAX_WINDOW_SIZE); + + setUpsyncCommands(s, context.getContentResolver(), account, mailbox, protocolVersion); } @Override - protected AbstractSyncParser getParser(final InputStream is) throws IOException { - // Store the parser because we'll want to ask it about whether groups are used later. - // TODO: It'd be nice to find a cleaner way to get this result back from the parser. - mParser = new ContactsSyncParser(mContext, mContentResolver, is, - mMailbox, mAccount, mAccountManagerAccount); + public AbstractSyncParser getParser(final Context context, final Account account, + final Mailbox mailbox, final InputStream is) throws IOException { + mParser = new ContactsSyncParser(context, context.getContentResolver(), is, mailbox, + account, mAccountManagerAccount); return mParser; } - @Override - protected void setInitialSyncOptions(final Serializer s) throws IOException { + private void setInitialSyncOptions(final Serializer s) throws IOException { // These are the tags we support for upload; whenever we add/remove support // (in addData), we need to update this list s.start(Tags.SYNC_SUPPORTED); @@ -243,15 +253,6 @@ public class EasContactsSyncHandler extends EasSyncHandler { s.end(); // SYNC_SUPPORTED } - @Override - protected void setNonInitialSyncOptions(final Serializer s, int numWindows) throws IOException { - final int windowSize = numWindows * PIM_WINDOW_SIZE_CONTACTS; - if (windowSize > MAX_WINDOW_SIZE + PIM_WINDOW_SIZE_CONTACTS) { - throw new IOException("Max window size reached and still no data"); - } - setPimSyncOptions(s, null, windowSize < MAX_WINDOW_SIZE ? windowSize : MAX_WINDOW_SIZE); - } - /** * Add account info and the "caller is syncadapter" param to a URI. * @param uri The {@link Uri} to add to. @@ -281,10 +282,9 @@ public class EasContactsSyncHandler extends EasSyncHandler { /** * Mark contacts in dirty groups as dirty. */ - private void dirtyContactsWithinDirtyGroups() { - final String emailAddress = mAccount.mEmailAddress; - final Cursor c = mContentResolver.query( - uriWithAccountAndIsSyncAdapter(Groups.CONTENT_URI, emailAddress), + private void dirtyContactsWithinDirtyGroups(final ContentResolver cr, final Account account) { + final String emailAddress = account.mEmailAddress; + final Cursor c = cr.query( uriWithAccountAndIsSyncAdapter(Groups.CONTENT_URI, emailAddress), GROUPS_ID_PROJECTION, Groups.DIRTY + "=1", null, null); if (c == null) { return; @@ -300,19 +300,17 @@ public class EasContactsSyncHandler extends EasSyncHandler { final long id = c.getLong(0); updateValues.put(GroupMembership.GROUP_ROW_ID, id); updateArgs[0] = Long.toString(id); - mContentResolver.update(ContactsContract.Data.CONTENT_URI, updateValues, + cr.update(ContactsContract.Data.CONTENT_URI, updateValues, MIMETYPE_GROUP_MEMBERSHIP_AND_ID_EQUALS, updateArgs); } // Really delete groups that are marked deleted - mContentResolver.delete(uriWithAccountAndIsSyncAdapter( - Groups.CONTENT_URI, emailAddress), + cr.delete(uriWithAccountAndIsSyncAdapter(Groups.CONTENT_URI, emailAddress), Groups.DELETED + "=1", null); // Clear the dirty flag for all of our groups updateValues.clear(); updateValues.put(Groups.DIRTY, 0); - mContentResolver.update(uriWithAccountAndIsSyncAdapter( - Groups.CONTENT_URI, emailAddress), updateValues, null, - null); + cr.update(uriWithAccountAndIsSyncAdapter(Groups.CONTENT_URI, emailAddress), + updateValues, null, null); } } finally { c.close(); @@ -638,9 +636,11 @@ public class EasContactsSyncHandler extends EasSyncHandler { * Add a note to the upsync. * @param s The {@link Serializer} for this sync request. * @param cv The {@link ContentValues} with the data for this note. + * @param protocolVersion * @throws IOException */ - private void sendNote(final Serializer s, final ContentValues cv) throws IOException { + private void sendNote(final Serializer s, final ContentValues cv, final double protocolVersion) + throws IOException { // Even when there is no local note, we must explicitly upsync an empty note, // which is the only way to force the server to delete any pre-existing note. String note = ""; @@ -649,7 +649,7 @@ public class EasContactsSyncHandler extends EasSyncHandler { note = cv.getAsString(Note.NOTE).replaceAll("\n", "\r\n"); } // Format of upsync data depends on protocol version - if (getProtocolVersion() >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { + if (protocolVersion >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { s.start(Tags.BASE_BODY); s.data(Tags.BASE_TYPE, Eas.BODY_PREFERENCE_TEXT).data(Tags.BASE_DATA, note); s.end(); @@ -681,10 +681,11 @@ public class EasContactsSyncHandler extends EasSyncHandler { * @param cv The {@link ContentValues} with the data for this email address. * @param count The number of email addresses that have already been added. * @param displayName The display name for this contact. + * @param protocolVersion * @throws IOException */ private void sendEmail(final Serializer s, final ContentValues cv, final int count, - final String displayName) throws IOException { + final String displayName, final double protocolVersion) throws IOException { // Get both parts of the email address (a newly created one in the UI won't have a name) final String addr = cv.getAsString(Email.DATA); String name = cv.getAsString(Email.DISPLAY_NAME); @@ -700,7 +701,7 @@ public class EasContactsSyncHandler extends EasSyncHandler { final String value; // Only send the raw email address for EAS 2.5 (Hotmail, in particular, chokes on // an RFC822 address) - if (getProtocolVersion() < Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { + if (protocolVersion < Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { value = addr; } else { value = '\"' + name + "\" <" + addr + '>'; @@ -711,19 +712,19 @@ public class EasContactsSyncHandler extends EasSyncHandler { } } - @Override - protected void setUpsyncCommands(final Serializer s) throws IOException { + private void setUpsyncCommands(final Serializer s, final ContentResolver cr, + final Account account, final Mailbox mailbox, final double protocolVersion) + throws IOException { // Find any groups of ours that are dirty and dirty those groups' members - dirtyContactsWithinDirtyGroups(); + dirtyContactsWithinDirtyGroups(cr, account); // First, let's find Contacts that have changed. final Uri uri = uriWithAccountAndIsSyncAdapter( - ContactsContract.RawContactsEntity.CONTENT_URI, mAccount.mEmailAddress); + ContactsContract.RawContactsEntity.CONTENT_URI, account.mEmailAddress); // Get them all atomically final EntityIterator ei = ContactsContract.RawContacts.newEntityIterator( - mContentResolver.query(uri, null, ContactsContract.RawContacts.DIRTY + "=1", null, - null)); + cr.query(uri, null, ContactsContract.RawContacts.DIRTY + "=1", null, null)); final ContentValues cidValues = new ContentValues(); try { boolean first = true; @@ -744,12 +745,12 @@ public class EasContactsSyncHandler extends EasSyncHandler { if (serverId == null) { // This is a new contact; create a clientId final String clientId = - "new_" + mMailbox.mId + '_' + System.currentTimeMillis(); + "new_" + mailbox.mId + '_' + System.currentTimeMillis(); LogUtils.d(TAG, "Creating new contact with clientId: %s", clientId); s.start(Tags.SYNC_ADD).data(Tags.SYNC_CLIENT_ID, clientId); // And save it in the raw contact cidValues.put(ContactsContract.RawContacts.SYNC1, clientId); - mContentResolver.update(ContentUris.withAppendedId(rawContactUri, + cr.update(ContentUris.withAppendedId(rawContactUri, entityValues.getAsLong(ContactsContract.RawContacts._ID)), cidValues, null, null); } else { @@ -811,7 +812,7 @@ public class EasContactsSyncHandler extends EasSyncHandler { // We must gather these, and send them together (below) groupIds.add(cv.getAsInteger(GroupMembership.GROUP_ROW_ID)); } else if (mimeType.equals(Note.CONTENT_ITEM_TYPE)) { - sendNote(s, cv); + sendNote(s, cv, protocolVersion); } else if (mimeType.equals(Photo.CONTENT_ITEM_TYPE)) { sendPhoto(s, cv); } else { @@ -822,7 +823,7 @@ public class EasContactsSyncHandler extends EasSyncHandler { // We do the email rows last, because we need to make sure we've found the // displayName (if one exists); this would be in a StructuredName rnow for (final ContentValues cv: emailValues) { - sendEmail(s, cv, emailCount++, displayName); + sendEmail(s, cv, emailCount++, displayName, protocolVersion); } // Now, we'll send up groups, if any @@ -830,9 +831,8 @@ public class EasContactsSyncHandler extends EasSyncHandler { boolean groupFirst = true; for (final int id: groupIds) { // Since we get id's from the provider, we need to find their names - final Cursor c = mContentResolver.query(ContentUris.withAppendedId( - Groups.CONTENT_URI, id), - GROUP_TITLE_PROJECTION, null, null, null); + final Cursor c = cr.query(ContentUris.withAppendedId(Groups.CONTENT_URI, + id), GROUP_TITLE_PROJECTION, null, null, null); try { // Presumably, this should always succeed, but ... if (c.moveToFirst()) { @@ -863,10 +863,8 @@ public class EasContactsSyncHandler extends EasSyncHandler { } @Override - protected void cleanup(final int syncResult) { - if (syncResult == SYNC_RESULT_FAILED) { - return; - } + public void cleanup(final Context context, final Account account) { + final ContentResolver cr = context.getContentResolver(); // Mark the changed contacts dirty = 0 // Permanently delete the user deletions @@ -885,16 +883,15 @@ public class EasContactsSyncHandler extends EasSyncHandler { .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build()) .build()); } - ops.execute(mContext); + ops.execute(context); if (mParser != null && mParser.isGroupsUsed()) { // Make sure the title column is set for all of our groups // And that all of our groups are visible // TODO Perhaps the visible part should only happen when the group is created, but // this is fine for now. final Uri groupsUri = uriWithAccountAndIsSyncAdapter(Groups.CONTENT_URI, - mAccount.mEmailAddress); - final Cursor c = mContentResolver.query(groupsUri, - new String[] {Groups.SOURCE_ID, Groups.TITLE}, + account.mEmailAddress); + final Cursor c = cr.query(groupsUri, new String[] {Groups.SOURCE_ID, Groups.TITLE}, Groups.TITLE + " IS NULL", null, null); final ContentValues values = new ContentValues(); values.put(Groups.GROUP_VISIBLE, 1); @@ -902,8 +899,8 @@ public class EasContactsSyncHandler extends EasSyncHandler { while (c.moveToNext()) { final String sourceId = c.getString(0); values.put(Groups.TITLE, sourceId); - mContentResolver.update(uriWithAccountAndIsSyncAdapter(groupsUri, - mAccount.mEmailAddress), values, Groups.SOURCE_ID + "=?", + cr.update(uriWithAccountAndIsSyncAdapter(groupsUri, + account.mEmailAddress), values, Groups.SOURCE_ID + "=?", new String[] {sourceId}); } } finally { diff --git a/src/com/android/exchange/eas/EasSyncMail.java b/src/com/android/exchange/eas/EasSyncMail.java index eec5bdf3..f5e0e153 100644 --- a/src/com/android/exchange/eas/EasSyncMail.java +++ b/src/com/android/exchange/eas/EasSyncMail.java @@ -3,6 +3,7 @@ package com.android.exchange.eas; import android.content.Context; import android.database.Cursor; +import com.android.emailcommon.TrafficFlags; import com.android.emailcommon.provider.Account; import com.android.emailcommon.provider.EmailContent.Message; import com.android.emailcommon.provider.EmailContent.MessageColumns; @@ -32,6 +33,12 @@ public class EasSyncMail extends EasSyncCollectionTypeBase { private static final int EMAIL_WINDOW_SIZE = 10; + + @Override + public int getTrafficFlag() { + return TrafficFlags.DATA_EMAIL; + } + @Override public void setSyncOptions(final Context context, final Serializer s, final double protocolVersion, final Account account, final Mailbox mailbox, diff --git a/src/com/android/exchange/service/EasMailboxSyncHandler.java b/src/com/android/exchange/service/EasMailboxSyncHandler.java deleted file mode 100644 index 03846741..00000000 --- a/src/com/android/exchange/service/EasMailboxSyncHandler.java +++ /dev/null @@ -1,196 +0,0 @@ -package com.android.exchange.service; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.SyncResult; -import android.database.Cursor; -import android.os.Bundle; - -import com.android.emailcommon.TrafficFlags; -import com.android.emailcommon.provider.Account; -import com.android.emailcommon.provider.EmailContent.Message; -import com.android.emailcommon.provider.EmailContent.MessageColumns; -import com.android.emailcommon.provider.EmailContent.SyncColumns; -import com.android.emailcommon.provider.Mailbox; -import com.android.emailcommon.service.SyncWindow; -import com.android.exchange.Eas; -import com.android.exchange.adapter.AbstractSyncParser; -import com.android.exchange.adapter.EmailSyncParser; -import com.android.exchange.adapter.Serializer; -import com.android.exchange.adapter.Tags; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; - -/** - * Performs an Exchange mailbox sync for "normal" mailboxes. - */ -public class EasMailboxSyncHandler extends EasSyncHandler { - /** - * The projection used for building the fetch request list. - */ - private static final String[] FETCH_REQUEST_PROJECTION = { SyncColumns.SERVER_ID }; - private static final int FETCH_REQUEST_SERVER_ID = 0; - - private static final int EMAIL_WINDOW_SIZE = 10; - - /** - * List of server ids for messages to fetch from the server. - */ - private final ArrayList<String> mMessagesToFetch = new ArrayList<String>(); - - public EasMailboxSyncHandler(final Context context, final ContentResolver contentResolver, - final Account account, final Mailbox mailbox, final Bundle syncExtras, - final SyncResult syncResult) { - super(context, contentResolver, account, mailbox, syncExtras, syncResult); - } - - private String getEmailFilter() { - final int syncLookback = mMailbox.mSyncLookback == SyncWindow.SYNC_WINDOW_ACCOUNT - ? mAccount.mSyncLookback : mMailbox.mSyncLookback; - switch (syncLookback) { - case SyncWindow.SYNC_WINDOW_1_DAY: - return Eas.FILTER_1_DAY; - case SyncWindow.SYNC_WINDOW_3_DAYS: - return Eas.FILTER_3_DAYS; - case SyncWindow.SYNC_WINDOW_1_WEEK: - return Eas.FILTER_1_WEEK; - case SyncWindow.SYNC_WINDOW_2_WEEKS: - return Eas.FILTER_2_WEEKS; - case SyncWindow.SYNC_WINDOW_1_MONTH: - return Eas.FILTER_1_MONTH; - case SyncWindow.SYNC_WINDOW_ALL: - return Eas.FILTER_ALL; - default: - // Auto window is deprecated and will also use the default. - return Eas.FILTER_1_WEEK; - } - } - - /** - * Find partially loaded messages and add their server ids to {@link #mMessagesToFetch}. - */ - private void addToFetchRequestList() { - final Cursor c = mContentResolver.query(Message.CONTENT_URI, FETCH_REQUEST_PROJECTION, - MessageColumns.FLAG_LOADED + "=" + Message.FLAG_LOADED_PARTIAL + " AND " + - MessageColumns.MAILBOX_KEY + "=?", new String[] {Long.toString(mMailbox.mId)}, - null); - if (c != null) { - try { - while (c.moveToNext()) { - mMessagesToFetch.add(c.getString(FETCH_REQUEST_SERVER_ID)); - } - } finally { - c.close(); - } - } - } - - @Override - protected int getTrafficFlag() { - return TrafficFlags.DATA_EMAIL; - } - - @Override - protected String getFolderClassName() { - return "Email"; - } - - @Override - protected AbstractSyncParser getParser(final InputStream is) throws IOException { - return new EmailSyncParser(mContext, mContentResolver, is, mMailbox, mAccount); - } - - @Override - protected void setInitialSyncOptions(final Serializer s) { - // No-op. - } - - @Override - protected void setNonInitialSyncOptions(final Serializer s, int numWindows) throws IOException { - // Check for messages that aren't fully loaded. - addToFetchRequestList(); - // The "empty" case is typical; we send a request for changes, and also specify a sync - // window, body preference type (HTML for EAS 12.0 and later; MIME for EAS 2.5), and - // truncation - // If there are fetch requests, we only want the fetches (i.e. no changes from the server) - // so we turn MIME support off. Note that we are always using EAS 2.5 if there are fetch - // requests - if (mMessagesToFetch.isEmpty()) { - // Permanently delete if in trash mailbox - // In Exchange 2003, deletes-as-moves tag = true; no tag = false - // In Exchange 2007 and up, deletes-as-moves tag is "0" (false) or "1" (true) - final boolean isTrashMailbox = mMailbox.mType == Mailbox.TYPE_TRASH; - if (getProtocolVersion() < Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { - if (!isTrashMailbox) { - s.tag(Tags.SYNC_DELETES_AS_MOVES); - } - } else { - s.data(Tags.SYNC_DELETES_AS_MOVES, isTrashMailbox ? "0" : "1"); - } - s.tag(Tags.SYNC_GET_CHANGES); - - final int windowSize = numWindows * EMAIL_WINDOW_SIZE; - if (windowSize > MAX_WINDOW_SIZE + EMAIL_WINDOW_SIZE) { - throw new IOException("Max window size reached and still no data"); - } - s.data(Tags.SYNC_WINDOW_SIZE, - String.valueOf(windowSize < MAX_WINDOW_SIZE ? windowSize : MAX_WINDOW_SIZE)); - s.start(Tags.SYNC_OPTIONS); - // Set the lookback appropriately (EAS calls this a "filter") - s.data(Tags.SYNC_FILTER_TYPE, getEmailFilter()); - // Set the truncation amount for all classes - if (getProtocolVersion() >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) { - s.start(Tags.BASE_BODY_PREFERENCE); - // HTML for email - s.data(Tags.BASE_TYPE, Eas.BODY_PREFERENCE_HTML); - s.data(Tags.BASE_TRUNCATION_SIZE, Eas.EAS12_TRUNCATION_SIZE); - s.end(); - } else { - // Use MIME data for EAS 2.5 - s.data(Tags.SYNC_MIME_SUPPORT, Eas.MIME_BODY_PREFERENCE_MIME); - s.data(Tags.SYNC_MIME_TRUNCATION, Eas.EAS2_5_TRUNCATION_SIZE); - } - s.end(); - } else { - // If we have any messages that are not fully loaded, ask for plain text rather than - // MIME, to guarantee we'll get usable text body. This also means we should NOT ask for - // new messages -- we only want data for the message explicitly fetched. - s.start(Tags.SYNC_OPTIONS); - s.data(Tags.SYNC_MIME_SUPPORT, Eas.MIME_BODY_PREFERENCE_TEXT); - s.data(Tags.SYNC_TRUNCATION, Eas.EAS2_5_TRUNCATION_SIZE); - s.end(); - } - } - - /** - * Add FETCH commands for messages that need a body (i.e. we didn't find it during our earlier - * sync; this happens only in EAS 2.5 where the body couldn't be found after parsing the - * message's MIME data). - * @param s The {@link Serializer} for this sync request. - * @throws IOException - */ - private void addFetchCommands(final Serializer s) throws IOException { - if (!mMessagesToFetch.isEmpty()) { - s.start(Tags.SYNC_COMMANDS); - for (final String serverId : mMessagesToFetch) { - s.start(Tags.SYNC_FETCH).data(Tags.SYNC_SERVER_ID, serverId).end(); - } - s.end(); - } - } - - @Override - protected void setUpsyncCommands(final Serializer s) throws IOException { - addFetchCommands(s); - } - - @Override - protected void cleanup(final int syncResult) { - if (syncResult == SYNC_RESULT_MORE_AVAILABLE) { - // Prepare our member variables for another sync request. - mMessagesToFetch.clear(); - } - } -} diff --git a/src/com/android/exchange/service/EasSyncHandler.java b/src/com/android/exchange/service/EasSyncHandler.java index 6614399c..148da49a 100644 --- a/src/com/android/exchange/service/EasSyncHandler.java +++ b/src/com/android/exchange/service/EasSyncHandler.java @@ -126,19 +126,9 @@ public abstract class EasSyncHandler extends EasServerConnection { final Bundle syncExtras, final SyncResult syncResult) { if (account != null && mailbox != null) { switch (mailbox.mType) { - case Mailbox.TYPE_INBOX: - case Mailbox.TYPE_MAIL: - case Mailbox.TYPE_DRAFTS: - case Mailbox.TYPE_SENT: - case Mailbox.TYPE_TRASH: - return new EasMailboxSyncHandler(context, contentResolver, account, mailbox, - syncExtras, syncResult); case Mailbox.TYPE_CALENDAR: return new EasCalendarSyncHandler(context, contentResolver, accountManagerAccount, account, mailbox, syncExtras, syncResult); - case Mailbox.TYPE_CONTACTS: - return new EasContactsSyncHandler(context, contentResolver, - accountManagerAccount, account, mailbox, syncExtras, syncResult); } } // Unknown mailbox type. diff --git a/src/com/android/exchange/service/EmailSyncAdapterService.java b/src/com/android/exchange/service/EmailSyncAdapterService.java index 05e7a01e..6a2ed421 100644 --- a/src/com/android/exchange/service/EmailSyncAdapterService.java +++ b/src/com/android/exchange/service/EmailSyncAdapterService.java @@ -63,6 +63,7 @@ import com.android.exchange.Eas; 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.EasFolderSync; import com.android.exchange.eas.EasLoadAttachment; import com.android.exchange.eas.EasMoveItems; @@ -461,7 +462,7 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { LogUtils.d(TAG, "IEmailService.deleteAccountPIMData"); if (emailAddress != null) { final Context context = EmailSyncAdapterService.this; - EasContactsSyncHandler.wipeAccountFromContentProvider(context, emailAddress); + EasSyncContacts.wipeAccountFromContentProvider(context, emailAddress); EasCalendarSyncHandler.wipeAccountFromContentProvider(context, emailAddress); } // TODO: Run account reconciler? @@ -875,18 +876,17 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { // Non-mailbox syncs are whole account syncs initiated by the AccountManager and are // treated as background syncs. // TODO: Push will be treated as "user" syncs, and probably should be background. - final ContentValues cv = new ContentValues(2); - updateMailbox(context, mailbox, cv, isMailboxSync ? - EmailContent.SYNC_STATUS_USER : EmailContent.SYNC_STATUS_BACKGROUND); - try { - if (mailbox.mType == Mailbox.TYPE_OUTBOX) { - return syncOutbox(context, cr, account, mailbox); - } + if (mailbox.mType == Mailbox.TYPE_OUTBOX || mailbox.isSyncable()) { + final ContentValues cv = new ContentValues(2); + updateMailbox(context, mailbox, cv, isMailboxSync ? + EmailContent.SYNC_STATUS_USER : EmailContent.SYNC_STATUS_BACKGROUND); + try { + if (mailbox.mType == Mailbox.TYPE_OUTBOX) { + return syncOutbox(context, cr, account, mailbox); + } - if(mailbox.isSyncable()) { // TODO: This conditional logic is temporary until EasSyncHandler is obsolete. - if (mailbox.mType == Mailbox.TYPE_INBOX || mailbox.mType == Mailbox.TYPE_MAIL || - mailbox.mType == Mailbox.TYPE_SENT) { + if (mailbox.mType != Mailbox.TYPE_CALENDAR) { final EasSyncBase operation = new EasSyncBase(context, account, mailbox); return operation.performOperation(); } else { @@ -908,9 +908,9 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { } } } + } finally { + updateMailbox(context, mailbox, cv, EmailContent.SYNC_STATUS_NONE); } - } finally { - updateMailbox(context, mailbox, cv, EmailContent.SYNC_STATUS_NONE); } return EasSyncBase.RESULT_DONE; |