diff options
author | Yu Ping Hu <yph@google.com> | 2014-03-06 18:52:55 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-03-06 18:52:55 +0000 |
commit | 1a085db22d269721b862567c4153ebd93b2340a5 (patch) | |
tree | 68f4afae218845e7bcc3675e4bd082b090150cc8 | |
parent | 36fa2e58cd03a2f2bda55a9fcd8780f153d0c611 (diff) | |
parent | 9a2230380dc95e4b6dd66b14a43d8007dc5f784e (diff) | |
download | Exchange-1a085db22d269721b862567c4153ebd93b2340a5.tar.gz |
Merge "Switch to using EasSyncBase for mail downsync." into ub-mail-klp-mr2
4 files changed, 86 insertions, 70 deletions
diff --git a/src/com/android/exchange/eas/EasOperation.java b/src/com/android/exchange/eas/EasOperation.java index e53363ab..a03543d7 100644 --- a/src/com/android/exchange/eas/EasOperation.java +++ b/src/com/android/exchange/eas/EasOperation.java @@ -130,8 +130,8 @@ public abstract class EasOperation { public static final int RESULT_CLIENT_CERTIFICATE_REQUIRED = -8; /** Error code indicating we don't have a protocol version in common with the server. */ public static final int RESULT_PROTOCOL_VERSION_UNSUPPORTED = -9; - /** Error code indicating the account could not be loaded from the provider. */ - public static final int RESULT_ACCOUNT_ID_INVALID = -10; + /** Error code indicating a hard error when initializing the operation. */ + public static final int RESULT_INITIALIZATION_FAILURE = -10; /** Error code indicating a hard data layer error. */ public static final int RESULT_HARD_DATA_FAILURE = -11; /** Error code indicating some other failure. */ @@ -266,11 +266,9 @@ public abstract class EasOperation { public int performOperation() { // Make sure the account is loaded if it hasn't already been. if (!init(false)) { - // TODO: Fix this comment and error code, init() can now fail for reasons other than - // failing to load the account. - LogUtils.i(LOG_TAG, "Failed to load account %d before sending request for operation %s", + LogUtils.i(LOG_TAG, "Failed to initialize %d before sending request for operation %s", getAccountId(), getCommand()); - return RESULT_ACCOUNT_ID_INVALID; + return RESULT_INITIALIZATION_FAILURE; } // We handle server redirects by looping, but we need to protect against too much looping. @@ -721,31 +719,39 @@ public abstract class EasOperation { amAccount.toString(), extras.toString()); } - public static void writeResultToSyncResult(final int result, final SyncResult syncResult) { + /** + * Interpret a result code from an {@link EasOperation} and, if it's an error, write it to + * the appropriate field in {@link SyncResult}. + * @param result + * @param syncResult + * @return Whether an error code was written to syncResult. + */ + public static boolean writeResultToSyncResult(final int result, final SyncResult syncResult) { switch (result) { case RESULT_TOO_MANY_REDIRECTS: syncResult.tooManyRetries = true; - break; + return true; case RESULT_REQUEST_FAILURE: syncResult.stats.numIoExceptions = 1; - break; + return true; case RESULT_FORBIDDEN: case RESULT_PROVISIONING_ERROR: case RESULT_AUTHENTICATION_ERROR: case RESULT_CLIENT_CERTIFICATE_REQUIRED: syncResult.stats.numAuthExceptions = 1; - break; + return true; case RESULT_PROTOCOL_VERSION_UNSUPPORTED: // Only used in validate, so there's never a syncResult to write to here. break; - case RESULT_ACCOUNT_ID_INVALID: + case RESULT_INITIALIZATION_FAILURE: case RESULT_HARD_DATA_FAILURE: syncResult.databaseError = true; - break; + return true; case RESULT_OTHER_FAILURE: // TODO: Is this correct? syncResult.stats.numIoExceptions = 1; - break; + return true; } + return false; } } diff --git a/src/com/android/exchange/eas/EasSyncBase.java b/src/com/android/exchange/eas/EasSyncBase.java index dfa5e9b3..ede73b5f 100644 --- a/src/com/android/exchange/eas/EasSyncBase.java +++ b/src/com/android/exchange/eas/EasSyncBase.java @@ -30,7 +30,7 @@ public class EasSyncBase extends EasOperation { public static final int RESULT_DONE = 0; public static final int RESULT_MORE_AVAILABLE = 1; - private final boolean mInitialSync; + private boolean mInitialSync; private final Mailbox mMailbox; private EasSyncCollectionTypeBase mCollectionTypeHandler; @@ -39,8 +39,6 @@ public class EasSyncBase extends EasOperation { // TODO: Convert to accountId when ready to convert to EasService. public EasSyncBase(final Context context, final Account account, final Mailbox mailbox) { super(context, account); - // TODO: This works for email, but not necessarily for other types. - mInitialSync = EmailContent.isInitialSyncKey(getSyncKey()); mMailbox = mailbox; } @@ -82,7 +80,7 @@ public class EasSyncBase extends EasOperation { final String syncKey = getSyncKey(); LogUtils.d(TAG, "Syncing account %d mailbox %d (class %s) with syncKey %s", mAccount.mId, mMailbox.mId, className, syncKey); - + mInitialSync = EmailContent.isInitialSyncKey(syncKey); final Serializer s = new Serializer(); s.start(Tags.SYNC_SYNC); s.start(Tags.SYNC_COLLECTIONS); @@ -120,7 +118,7 @@ public class EasSyncBase extends EasOperation { public int performOperation() { int result = RESULT_MORE_AVAILABLE; mNumWindows = 1; - String key = getSyncKey(); + final String key = getSyncKey(); while (result == RESULT_MORE_AVAILABLE) { result = super.performOperation(); // TODO: Clear pending request queue. @@ -156,7 +154,7 @@ public class EasSyncBase extends EasOperation { case Mailbox.TYPE_MAIL: case Mailbox.TYPE_INBOX: case Mailbox.TYPE_DRAFTS: -// case Mailbox.TYPE_SENT: + case Mailbox.TYPE_SENT: // case Mailbox.TYPE_TRASH: case Mailbox.TYPE_JUNK: { return new EasSyncMail(); diff --git a/src/com/android/exchange/eas/EasSyncCollectionTypeBase.java b/src/com/android/exchange/eas/EasSyncCollectionTypeBase.java index 6ff15083..d8e578c0 100644 --- a/src/com/android/exchange/eas/EasSyncCollectionTypeBase.java +++ b/src/com/android/exchange/eas/EasSyncCollectionTypeBase.java @@ -15,9 +15,6 @@ import java.io.InputStream; * These details include: * - Forming the request options. Contacts, Calendar, and Mail set this up differently. * - Getting the appropriate parser for this collection type. - * These classes should be stateless, i.e. the distinct subtypes and instances are used simply - * to have polymorphic behavior for these functions. If member variables are ever added to any - * of these classes, {@link EasSyncBase} MUST change how it creates these objects. */ public abstract class EasSyncCollectionTypeBase { diff --git a/src/com/android/exchange/service/EmailSyncAdapterService.java b/src/com/android/exchange/service/EmailSyncAdapterService.java index b59822f6..05e7a01e 100644 --- a/src/com/android/exchange/service/EmailSyncAdapterService.java +++ b/src/com/android/exchange/service/EmailSyncAdapterService.java @@ -71,6 +71,7 @@ import com.android.exchange.eas.EasOutboxSync; import com.android.exchange.eas.EasPing; import com.android.exchange.eas.EasSearch; import com.android.exchange.eas.EasSync; +import com.android.exchange.eas.EasSyncBase; import com.android.mail.providers.UIProvider; import com.android.mail.utils.LogUtils; @@ -720,7 +721,6 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { // Do the bookkeeping for starting a sync, including stopping a ping if necessary. mSyncHandlerMap.startSync(account.mId); - boolean lastSyncHadError = false; try { // Perform a FolderSync if necessary. @@ -760,32 +760,29 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { } if (mailboxIds != null) { - long numIoExceptions = 0; - long numAuthExceptions = 0; // Sync the mailbox that was explicitly requested. for (final long mailboxId : mailboxIds) { - final boolean success = syncMailbox(context, cr, acct, account, mailboxId, + final int result = syncMailbox(context, cr, acct, account, mailboxId, extras, syncResult, null, true); - if (!success) { - lastSyncHadError = true; - } + EasSyncBase.writeResultToSyncResult(result, syncResult); if (hasCallbackMethod) { - final int result; + final int uiResult; if (syncResult.hasError()) { - if (syncResult.stats.numIoExceptions > numIoExceptions) { - result = UIProvider.LastSyncResult.CONNECTION_ERROR; - numIoExceptions = syncResult.stats.numIoExceptions; - } else if (syncResult.stats.numAuthExceptions> numAuthExceptions) { - result = UIProvider.LastSyncResult.AUTH_ERROR; - numAuthExceptions= syncResult.stats.numAuthExceptions; + if (syncResult.stats.numIoExceptions > 0) { + uiResult = UIProvider.LastSyncResult.CONNECTION_ERROR; + } else if (syncResult.stats.numAuthExceptions > 0) { + uiResult = UIProvider.LastSyncResult.AUTH_ERROR; } else { - result = UIProvider.LastSyncResult.INTERNAL_ERROR; + uiResult = UIProvider.LastSyncResult.INTERNAL_ERROR; } } else { - result = UIProvider.LastSyncResult.SUCCESS; + uiResult = UIProvider.LastSyncResult.SUCCESS; } EmailServiceStatus.syncMailboxStatus( - cr, extras, mailboxId,EmailServiceStatus.SUCCESS, 0, result); + cr, extras, mailboxId,EmailServiceStatus.SUCCESS, 0, uiResult); + } + if (syncResult.hasError()) { + break; } } } else if (!accountOnly && !pushOnly) { @@ -802,10 +799,11 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { try { final HashSet<String> authsToSync = getAuthsToSync(acct); while (c.moveToNext()) { - boolean success = syncMailbox(context, cr, acct, account, + final int result = syncMailbox(context, cr, acct, account, c.getLong(0), extras, syncResult, authsToSync, false); - if (!success) { - lastSyncHadError = true; + EasSyncBase.writeResultToSyncResult(result, syncResult); + if (syncResult.hasError()) { + break; } } } finally { @@ -815,11 +813,13 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { } } finally { // Clean up the bookkeeping, including restarting ping if necessary. - mSyncHandlerMap.syncComplete(lastSyncHadError, account); + mSyncHandlerMap.syncComplete(syncResult.hasError(), account); + + // If any operations had an auth error, notify the user. + if (syncResult.stats.numAuthExceptions > 0) { + showAuthNotification(account.mId, account.mEmailAddress); + } - // TODO: It may make sense to have common error handling here. Two possibilities: - // 1) performSync return value can signal some useful info. - // 2) syncResult can contain useful info. LogUtils.d(TAG, "onPerformSync: finished"); } } @@ -841,24 +841,24 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { mailbox.update(context, cv); } - private boolean syncMailbox(final Context context, final ContentResolver cr, + private int syncMailbox(final Context context, final ContentResolver cr, final android.accounts.Account acct, final Account account, final long mailboxId, final Bundle extras, final SyncResult syncResult, final HashSet<String> authsToSync, final boolean isMailboxSync) { final Mailbox mailbox = Mailbox.restoreMailboxWithId(context, mailboxId); if (mailbox == null) { - return false; + return EasSyncBase.RESULT_HARD_DATA_FAILURE; } if (mailbox.mAccountKey != account.mId) { LogUtils.e(TAG, "Mailbox does not match account: %s, %s", acct.toString(), extras.toString()); - return false; + return EasSyncBase.RESULT_HARD_DATA_FAILURE; } if (authsToSync != null && !authsToSync.contains(Mailbox.getAuthority(mailbox.mType))) { // We are asking for an account sync, but this mailbox type is not configured for // sync. Do NOT treat this as a sync error for ping backoff purposes. - return true; + return EasSyncBase.RESULT_DONE; } if (mailbox.mType == Mailbox.TYPE_DRAFTS) { @@ -869,36 +869,51 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { // that we won't sync even if the user attempts to force a sync from the UI. // Do NOT treat as a sync error for ping backoff purposes. LogUtils.d(TAG, "Skipping sync of DRAFTS folder"); - return true; + return EasSyncBase.RESULT_DONE; } - final boolean success; + // 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); - if (mailbox.mType == Mailbox.TYPE_OUTBOX) { - int result = syncOutbox(context, cr, account, mailbox); - // TODO: in some cases we might want to abort the sync completely. - success = true; - } else if(mailbox.isSyncable()) { - final EasSyncHandler syncHandler = EasSyncHandler.getEasSyncHandler(context, cr, - acct, account, mailbox, extras, syncResult); - if (syncHandler != null) { - success = syncHandler.performSync(syncResult); - } else { - success = false; + try { + if (mailbox.mType == Mailbox.TYPE_OUTBOX) { + return syncOutbox(context, cr, account, mailbox); } - } else { - success = false; - } - updateMailbox(context, mailbox, cv, EmailContent.SYNC_STATUS_NONE); - if (syncResult.stats.numAuthExceptions > 0) { - showAuthNotification(account.mId, account.mEmailAddress); + 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) { + final EasSyncBase operation = new EasSyncBase(context, account, mailbox); + return operation.performOperation(); + } else { + // TODO: This branch goes away after all conversions are done. + final EasSyncHandler syncHandler = EasSyncHandler.getEasSyncHandler(context, + cr, acct, account, mailbox, extras, syncResult); + if (syncHandler != null) { + if (!syncHandler.performSync(syncResult)) { + // This is ass-backwards, but it's a hack until this code goes away. + if (syncResult.stats.numIoExceptions > 0) { + return EasSyncBase.RESULT_REQUEST_FAILURE; + } + if (syncResult.stats.numAuthExceptions > 0) { + return EasSyncBase.RESULT_AUTHENTICATION_ERROR; + } + if (syncResult.stats.numParseExceptions > 0) { + return EasSyncBase.RESULT_OTHER_FAILURE; + } + } + } + } + } + } finally { + updateMailbox(context, mailbox, cv, EmailContent.SYNC_STATUS_NONE); } - return success; + + return EasSyncBase.RESULT_DONE; } } |