Merge "When syncing folders, read all data first, then process" into honeycomb
diff --git a/src/com/android/exchange/EasSyncService.java b/src/com/android/exchange/EasSyncService.java
index 3b0c173..2a1560d 100644
--- a/src/com/android/exchange/EasSyncService.java
+++ b/src/com/android/exchange/EasSyncService.java
@@ -1883,6 +1883,7 @@
ArrayList<String> readyMailboxes = new ArrayList<String>();
ArrayList<String> notReadyMailboxes = new ArrayList<String>();
int pingWaitCount = 0;
+ long inboxId = -1;
while ((System.currentTimeMillis() < endTime) && !mStop) {
// Count of pushable mailboxes
@@ -1898,6 +1899,10 @@
AND_FREQUENCY_PING_PUSH_AND_NOT_ACCOUNT_MAILBOX, null, null);
notReadyMailboxes.clear();
readyMailboxes.clear();
+ // Look for an inbox, and remember its id
+ if (inboxId == -1) {
+ inboxId = Mailbox.findMailboxOfType(mContext, mAccount.mId, Mailbox.TYPE_INBOX);
+ }
try {
// Loop through our pushed boxes seeing what is available to push
while (c.moveToNext()) {
@@ -2082,6 +2087,9 @@
// we're in one of the other possible states.
userLog("pingLoop waiting for initial sync of ", uninitCount, " box(es)");
sleep(10*SECONDS, true);
+ } else if (inboxId == -1) {
+ // In this case, we're still syncing mailboxes, so sleep for only a short time
+ sleep(45*SECONDS, true);
} else {
// We've got nothing to do, so we'll check again in 20 minutes at which time
// we'll update the folder list, check for policy changes and/or remote wipe, etc.
diff --git a/src/com/android/exchange/ExchangeService.java b/src/com/android/exchange/ExchangeService.java
index 3d1466b..e9e2af7 100644
--- a/src/com/android/exchange/ExchangeService.java
+++ b/src/com/android/exchange/ExchangeService.java
@@ -2336,7 +2336,7 @@
}
// DO NOT CALL THIS IN A LOOP ON THE SERVICEMAP
- static private void stopManualSync(long mailboxId) {
+ static public void stopManualSync(long mailboxId) {
ExchangeService exchangeService = INSTANCE;
if (exchangeService == null) return;
synchronized (sSyncLock) {
diff --git a/src/com/android/exchange/adapter/FolderSyncParser.java b/src/com/android/exchange/adapter/FolderSyncParser.java
index 0d36a0e..ae20fd9 100644
--- a/src/com/android/exchange/adapter/FolderSyncParser.java
+++ b/src/com/android/exchange/adapter/FolderSyncParser.java
@@ -20,11 +20,11 @@
import com.android.email.Utility;
import com.android.email.provider.AttachmentProvider;
import com.android.email.provider.EmailContent;
-import com.android.email.provider.EmailProvider;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.AccountColumns;
import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.MailboxColumns;
+import com.android.email.provider.EmailProvider;
import com.android.exchange.Eas;
import com.android.exchange.ExchangeService;
import com.android.exchange.MockParserStream;
@@ -361,9 +361,9 @@
}
}
- private void commitMailboxes(ArrayList<Mailbox> validMailboxes,
+ private boolean commitMailboxes(ArrayList<Mailbox> validMailboxes,
ArrayList<Mailbox> userMailboxes, HashMap<String, Mailbox> mailboxMap,
- ArrayList<ContentProviderOperation> ops) throws IOException {
+ ArrayList<ContentProviderOperation> ops) {
// Go through the generic user mailboxes; we'll call them valid if any parent is valid
for (Mailbox m: userMailboxes) {
@@ -388,44 +388,26 @@
// If it IS repeatable, there's no good result, since the folder list will be invalid
try {
mContentResolver.applyBatch(EmailProvider.EMAIL_AUTHORITY, mOperations);
+ return true;
} catch (RemoteException e) {
- throw new IOException("RemoteException committing folders.");
+ userLog("RemoteException in commitMailboxes");
+ return false;
} catch (OperationApplicationException e) {
- throw new IOException("OperationApplicationException committing folders.");
+ userLog("OperationApplicationException in commitMailboxes");
+ return false;
}
}
- public void changesParser(ArrayList<ContentProviderOperation> ops, boolean initialSync)
- throws IOException {
- // Mailboxes that we known contain email
- ArrayList<Mailbox> validMailboxes = new ArrayList<Mailbox>();
- // Mailboxes that we're unsure about
- ArrayList<Mailbox> userMailboxes = new ArrayList<Mailbox>();
- // Maps folder serverId to mailbox type
- HashMap<String, Mailbox> mailboxMap = new HashMap<String, Mailbox>();
+ public void changesParser(final ArrayList<ContentProviderOperation> ops,
+ final boolean initialSync) throws IOException {
+ // Array of added mailboxes
+ final ArrayList<Mailbox> addMailboxes = new ArrayList<Mailbox>();
- int mailboxAddCount = 0;
while (nextTag(Tags.FOLDER_CHANGES) != END) {
if (tag == Tags.FOLDER_ADD) {
Mailbox mailbox = addParser();
if (mailbox != null) {
- // Save away the type of this folder
- mailboxMap.put(mailbox.mServerId, mailbox);
- // And add the mailbox to the proper list
- if (type == USER_MAILBOX_TYPE) {
- userMailboxes.add(mailbox);
- } else {
- validMailboxes.add(mailbox);
- }
- // On initial sync, we commit what we have every 20 mailboxes
- if (initialSync && (++mailboxAddCount == MAILBOX_COMMIT_SIZE)) {
- commitMailboxes(validMailboxes, userMailboxes, mailboxMap, ops);
- // Clear our arrays to prepare for more
- userMailboxes.clear();
- validMailboxes.clear();
- ops.clear();
- mailboxAddCount = 0;
- }
+ addMailboxes.add(mailbox);
}
} else if (tag == Tags.FOLDER_DELETE) {
deleteParser(ops);
@@ -437,22 +419,53 @@
skipTag();
}
- // The mock stream is used for junit tests, so that the parsing code can be tested
- // separately from the provider code.
- // TODO Change tests to not require this; remove references to the mock stream
- if (mMock != null) {
- mMock.setResult(null);
- return;
- }
-
- // Commit the sync key and mailboxes
- ContentValues cv = new ContentValues();
- cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey);
- ops.add(ContentProviderOperation.newUpdate(
- ContentUris.withAppendedId(Account.CONTENT_URI, mAccount.mId))
- .withValues(cv)
- .build());
- commitMailboxes(validMailboxes, userMailboxes, mailboxMap, ops);
+ Utility.runAsync(new Runnable() {
+ @Override
+ public void run() {
+ // Synchronize on the parser to prevent this being run multiple times concurrently
+ // (an extremely unlikely event, but nonetheless possible)
+ synchronized (FolderSyncParser.this) {
+ // Mailboxes that we known contain email
+ ArrayList<Mailbox> validMailboxes = new ArrayList<Mailbox>();
+ // Mailboxes that we're unsure about
+ ArrayList<Mailbox> userMailboxes = new ArrayList<Mailbox>();
+ // Maps folder serverId to mailbox type
+ HashMap<String, Mailbox> mailboxMap = new HashMap<String, Mailbox>();
+ int mailboxCommitCount = 0;
+ for (Mailbox mailbox : addMailboxes) {
+ // Save away the type of this folder
+ mailboxMap.put(mailbox.mServerId, mailbox);
+ // And add the mailbox to the proper list
+ if (type == USER_MAILBOX_TYPE) {
+ userMailboxes.add(mailbox);
+ } else {
+ validMailboxes.add(mailbox);
+ }
+ // On initial sync, we commit what we have every 20 mailboxes
+ if (initialSync && (++mailboxCommitCount == MAILBOX_COMMIT_SIZE)) {
+ if (!commitMailboxes(validMailboxes, userMailboxes, mailboxMap, ops)) {
+ mService.stop();
+ return;
+ }
+ // Clear our arrays to prepare for more
+ userMailboxes.clear();
+ validMailboxes.clear();
+ ops.clear();
+ mailboxCommitCount = 0;
+ }
+ }
+ // Commit the sync key and mailboxes
+ ContentValues cv = new ContentValues();
+ cv.put(AccountColumns.SYNC_KEY, mAccount.mSyncKey);
+ ops.add(ContentProviderOperation
+ .newUpdate(
+ ContentUris.withAppendedId(Account.CONTENT_URI, mAccount.mId))
+ .withValues(cv).build());
+ if (!commitMailboxes(validMailboxes, userMailboxes, mailboxMap, ops)) {
+ mService.stop();
+ }
+ }
+ }});
}
/**