From 4427badd747b7c172934014b9f95a1be1256f35a Mon Sep 17 00:00:00 2001 From: Martin Hibdon Date: Wed, 9 Oct 2013 13:36:01 -0700 Subject: Allow multiple mailboxes to sync at one time b/11103878 Change-Id: I6a3944c9171948d3f80bbb51294841a84cf409aa --- .../exchange/ExchangeBroadcastReceiver.java | 3 +- src/com/android/exchange/eas/EasOperation.java | 36 +++++++++++++++-- src/com/android/exchange/eas/EasPing.java | 46 ++++++++++++++++++---- .../service/CalendarSyncAdapterService.java | 24 ++++++----- .../service/ContactsSyncAdapterService.java | 23 ++++++----- .../exchange/service/EasServerConnection.java | 3 +- .../exchange/service/EmailSyncAdapterService.java | 25 ++++++------ 7 files changed, 116 insertions(+), 44 deletions(-) diff --git a/src/com/android/exchange/ExchangeBroadcastReceiver.java b/src/com/android/exchange/ExchangeBroadcastReceiver.java index fbc424d1..94542e23 100644 --- a/src/com/android/exchange/ExchangeBroadcastReceiver.java +++ b/src/com/android/exchange/ExchangeBroadcastReceiver.java @@ -33,8 +33,7 @@ public class ExchangeBroadcastReceiver extends BroadcastReceiver { final Bundle bundle = new Bundle(3); bundle.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true); bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); - bundle.putLong( - Mailbox.SYNC_EXTRA_MAILBOX_ID, Mailbox.SYNC_EXTRA_MAILBOX_ID_ACCOUNT_ONLY); + bundle.putBoolean(Mailbox.SYNC_EXTRA_ACCOUNT_ONLY, true); ContentResolver.requestSync(account, EmailContent.AUTHORITY, bundle); } } diff --git a/src/com/android/exchange/eas/EasOperation.java b/src/com/android/exchange/eas/EasOperation.java index 1c695e08..87c871f0 100644 --- a/src/com/android/exchange/eas/EasOperation.java +++ b/src/com/android/exchange/eas/EasOperation.java @@ -25,6 +25,7 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.text.format.DateUtils; import com.android.emailcommon.provider.Account; @@ -44,6 +45,8 @@ import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.ByteArrayEntity; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; /** * Base class for all Exchange operations that use a POST to talk to the server. @@ -536,7 +539,7 @@ public abstract class EasOperation { msg.mAccountKey = account.mId; msg.save(mContext); requestSyncForMailbox(new android.accounts.Account(account.mEmailAddress, - Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), EmailContent.AUTHORITY, mailboxId); + Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), mailboxId); } /** @@ -546,11 +549,36 @@ public abstract class EasOperation { * @param mailboxId The id of the mailbox that needs to sync. */ protected static void requestSyncForMailbox(final android.accounts.Account amAccount, - final String authority, final long mailboxId) { + final long mailboxId) { + final Bundle extras = Mailbox.createSyncBundle(mailboxId); + ContentResolver.requestSync(amAccount, EmailContent.AUTHORITY, extras); + LogUtils.i(LOG_TAG, "requestSync EasOperation requestSyncForMailbox %s, %s", + amAccount.toString(), extras.toString()); + } + + protected static void requestSyncForMailboxes(final android.accounts.Account amAccount, + final ArrayList mailboxIds) { + final Bundle extras = Mailbox.createSyncBundle(mailboxIds); + ContentResolver.requestSync(amAccount, EmailContent.AUTHORITY, extras); + LogUtils.i(LOG_TAG, "requestSync EasOperation requestSyncForMailboxes %s, %s", + amAccount.toString(), extras.toString()); + } + + /** + * RequestNoOpSync + * This requests a sync for a particular authority purely so that that account + * in settings will recognize that it is trying to sync, and will display the + * appropriate UI. In fact, all exchange data syncing actually happens through the + * EmailSyncAdapterService. + * @param amAccount + * @param authority + */ + protected static void requestNoOpSync(final android.accounts.Account amAccount, + final String authority) { final Bundle extras = new Bundle(1); - extras.putLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, mailboxId); + extras.putBoolean(Mailbox.SYNC_EXTRA_NOOP, true); ContentResolver.requestSync(amAccount, authority, extras); - LogUtils.i(LOG_TAG, "requestSync EasOperation requestSyncForMailbox %s, %s", + LogUtils.i(LOG_TAG, "requestSync EasOperation requestNoOpSync %s, %s", amAccount.toString(), extras.toString()); } } diff --git a/src/com/android/exchange/eas/EasPing.java b/src/com/android/exchange/eas/EasPing.java index e53daeb3..24236bff 100644 --- a/src/com/android/exchange/eas/EasPing.java +++ b/src/com/android/exchange/eas/EasPing.java @@ -21,7 +21,10 @@ import android.content.ContentValues; import android.content.Context; import android.content.SyncResult; import android.database.Cursor; +import android.os.Bundle; import android.os.SystemClock; +import android.provider.CalendarContract; +import android.provider.ContactsContract; import android.text.format.DateUtils; import com.android.emailcommon.provider.Account; @@ -41,6 +44,9 @@ import org.apache.http.HttpEntity; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; /** * Performs an Exchange Ping, which is the command for receiving push notifications. @@ -323,6 +329,10 @@ public class EasPing extends EasOperation { private void requestSyncForSyncList(final ArrayList syncList) { final String[] bindArguments = new String[2]; bindArguments[0] = Long.toString(mAccountId); + + final ArrayList mailboxIds = new ArrayList(); + final HashSet contentTypes = new HashSet(); + for (final String serverId : syncList) { bindArguments[1] = serverId; // TODO: Rather than one query per ping mailbox, do it all in one? @@ -376,27 +386,49 @@ public class EasPing extends EasOperation { } */ if (c.moveToFirst()) { - requestSyncForMailbox(mAmAccount, - Mailbox.getAuthority(c.getInt(Mailbox.CONTENT_TYPE_COLUMN)), - c.getLong(Mailbox.CONTENT_ID_COLUMN)); + final long mailboxId = c.getLong(Mailbox.CONTENT_ID_COLUMN); + final int contentType = c.getInt(Mailbox.CONTENT_TYPE_COLUMN); + mailboxIds.add(mailboxId); + contentTypes.add(contentType); } } finally { c.close(); } } + + for (final int type : contentTypes) { + switch (type) { + case Mailbox.TYPE_CALENDAR: + case Mailbox.TYPE_CONTACTS: + // Ask for a no-op sync so that we'll see calendar or contacts + // syncing in settings. + requestNoOpSync(mAmAccount, Mailbox.getAuthority(type)); + default: + // Do nothing, we're already doing an Email sync. + } + } + // Ask the EmailSyncAdapter to sync all of these mailboxes, whether they're regular + // mailboxes or calendar or contacts. + requestSyncForMailboxes(mAmAccount, mailboxIds); } /** * Issue a {@link ContentResolver#requestSync} to trigger a FolderSync for an account. */ private void requestFolderSync() { - requestSyncForMailbox(mAmAccount, EmailContent.AUTHORITY, - Mailbox.SYNC_EXTRA_MAILBOX_ID_ACCOUNT_ONLY); + final Bundle extras = new Bundle(1); + extras.putBoolean(Mailbox.SYNC_EXTRA_ACCOUNT_ONLY, true); + ContentResolver.requestSync(mAmAccount, EmailContent.AUTHORITY, extras); + LogUtils.i(LOG_TAG, "requestFolderSync EasOperation %s, %s", + mAmAccount.toString(), extras.toString()); } public static void requestPing(final android.accounts.Account amAccount) { - requestSyncForMailbox(amAccount, EmailContent.AUTHORITY, - Mailbox.SYNC_EXTRA_MAILBOX_ID_PUSH_ONLY); + final Bundle extras = new Bundle(1); + extras.putBoolean(Mailbox.SYNC_EXTRA_PUSH_ONLY, true); + ContentResolver.requestSync(amAccount, EmailContent.AUTHORITY, extras); + LogUtils.i(LOG_TAG, "requestPing EasOperation %s, %s", + amAccount.toString(), extras.toString()); } } diff --git a/src/com/android/exchange/service/CalendarSyncAdapterService.java b/src/com/android/exchange/service/CalendarSyncAdapterService.java index c3683c7f..376680a4 100644 --- a/src/com/android/exchange/service/CalendarSyncAdapterService.java +++ b/src/com/android/exchange/service/CalendarSyncAdapterService.java @@ -79,6 +79,11 @@ public class CalendarSyncAdapterService extends AbstractSyncAdapterService { * be put in place at a later time. */ private static void performSync(Context context, Account account, Bundle extras) { + if (extras.getBoolean(Mailbox.SYNC_EXTRA_NOOP, false)) { + LogUtils.d(TAG, "No-op sync requested, done"); + return; + } + final ContentResolver cr = context.getContentResolver(); final boolean logging = Eas.USER_LOG; if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD)) { @@ -101,20 +106,21 @@ public class CalendarSyncAdapterService extends AbstractSyncAdapterService { } // Forward the sync request to the EmailSyncAdapterService. - final Bundle mailExtras = new Bundle(4); + final long [] mailboxIds = Mailbox.getMailboxIdsFromBundle(extras); + final Bundle mailExtras; + if (mailboxIds == null) { + // We weren't given any particular mailboxId, specify a sync for all calendars. + mailExtras = new Bundle(); + mailExtras.putInt(Mailbox.SYNC_EXTRA_MAILBOX_TYPE, Mailbox.TYPE_CALENDAR); + } else { + // Otherwise, add all of the mailboxes specified in the original sync extras. + mailExtras = Mailbox.createSyncBundle(mailboxIds); + } mailExtras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); mailExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true); if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) { mailExtras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); } - final long extrasMailboxId = extras.getLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, 0); - if (extrasMailboxId != 0) { - // If we've been given a mailbox, specify a sync for just that mailbox. - mailExtras.putLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, extrasMailboxId); - } else { - // Otherwise, specify a sync for all calendars. - mailExtras.putInt(Mailbox.SYNC_EXTRA_MAILBOX_TYPE, Mailbox.TYPE_CALENDAR); - } ContentResolver.requestSync(account, EmailContent.AUTHORITY, mailExtras); LogUtils.i(TAG, "requestSync CalendarSyncAdapter %s, %s", account.toString(), mailExtras.toString()); diff --git a/src/com/android/exchange/service/ContactsSyncAdapterService.java b/src/com/android/exchange/service/ContactsSyncAdapterService.java index 8fae508a..77eac3d0 100644 --- a/src/com/android/exchange/service/ContactsSyncAdapterService.java +++ b/src/com/android/exchange/service/ContactsSyncAdapterService.java @@ -88,6 +88,10 @@ public class ContactsSyncAdapterService extends AbstractSyncAdapterService { * be put in place at a later time. */ private static void performSync(Context context, Account account, Bundle extras) { + if (extras.getBoolean(Mailbox.SYNC_EXTRA_NOOP, false)) { + LogUtils.d(TAG, "No-op sync requested, done"); + return; + } ContentResolver cr = context.getContentResolver(); // If we've been asked to do an upload, make sure we've got work to do if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD)) { @@ -112,20 +116,21 @@ public class ContactsSyncAdapterService extends AbstractSyncAdapterService { } // Forward the sync request to the EmailSyncAdapterService. - final Bundle mailExtras = new Bundle(4); + long [] mailboxIds = Mailbox.getMailboxIdsFromBundle(extras); + final Bundle mailExtras; + if (mailboxIds == null) { + // We weren't given any particular mailboxId, specify a sync for all contacts. + mailExtras = new Bundle(); + mailExtras.putInt(Mailbox.SYNC_EXTRA_MAILBOX_TYPE, Mailbox.TYPE_CALENDAR); + } else { + // Otherwise, add all of the mailboxes specified in the original sync extras. + mailExtras = Mailbox.createSyncBundle(mailboxIds); + } mailExtras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); mailExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true); if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) { mailExtras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); } - final long extrasMailboxId = extras.getLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, 0); - if (extrasMailboxId != 0) { - // If we've been given a mailbox, specify a sync for just that mailbox. - mailExtras.putLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, extrasMailboxId); - } else { - // Otherwise, specify a sync for all calendars. - mailExtras.putInt(Mailbox.SYNC_EXTRA_MAILBOX_TYPE, Mailbox.TYPE_CONTACTS); - } ContentResolver.requestSync(account, EmailContent.AUTHORITY, mailExtras); LogUtils.i(TAG, "requestSync ContactsSyncAdapter %s, %s", account.toString(), mailExtras.toString()); diff --git a/src/com/android/exchange/service/EasServerConnection.java b/src/com/android/exchange/service/EasServerConnection.java index 8a2462f0..a14a2be1 100644 --- a/src/com/android/exchange/service/EasServerConnection.java +++ b/src/com/android/exchange/service/EasServerConnection.java @@ -523,8 +523,7 @@ public class EasServerConnection { */ protected static void requestSyncForMailbox(final android.accounts.Account amAccount, final String authority, final long mailboxId) { - final Bundle extras = new Bundle(1); - extras.putLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, mailboxId); + final Bundle extras = Mailbox.createSyncBundle(mailboxId); ContentResolver.requestSync(amAccount, authority, extras); LogUtils.i(TAG, "requestSync EasServerConnection requestSyncForMailbox %s, %s", amAccount.toString(), extras.toString()); diff --git a/src/com/android/exchange/service/EmailSyncAdapterService.java b/src/com/android/exchange/service/EmailSyncAdapterService.java index a1412db7..1de5e80f 100644 --- a/src/com/android/exchange/service/EmailSyncAdapterService.java +++ b/src/com/android/exchange/service/EmailSyncAdapterService.java @@ -232,7 +232,7 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { // Stop, start, or restart the ping as needed, as well as the ping kicker periodic sync. final PingTask pingSyncHandler = mPingHandlers.get(account.mId); final Bundle extras = new Bundle(1); - extras.putLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, Mailbox.SYNC_EXTRA_MAILBOX_ID_PUSH_ONLY); + extras.putBoolean(Mailbox.SYNC_EXTRA_PUSH_ONLY, true); if (pushNeeded) { // First start or restart the ping as appropriate. if (pingSyncHandler != null) { @@ -623,20 +623,20 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { // Figure out what we want to sync, based on the extras and our account sync status. final boolean isInitialSync = EmailContent.isInitialSyncKey(account.mSyncKey); - final long mailboxId = extras.getLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, - Mailbox.NO_MAILBOX); + final long[] mailboxIds = Mailbox.getMailboxIdsFromBundle(extras); final int mailboxType = extras.getInt(Mailbox.SYNC_EXTRA_MAILBOX_TYPE, Mailbox.TYPE_NONE); // A "full sync" means no specific mailbox or type filter was requested. - final boolean isFullSync = (mailboxId == Mailbox.NO_MAILBOX && - mailboxType == Mailbox.TYPE_NONE); + final boolean isFullSync = (mailboxIds == null && mailboxType == Mailbox.TYPE_NONE); + // A FolderSync is necessary for full sync, initial sync, and account only sync. - final boolean isFolderSync = (isFullSync || isInitialSync || - mailboxId == Mailbox.SYNC_EXTRA_MAILBOX_ID_ACCOUNT_ONLY); + final boolean accountOnly = Mailbox.isAccountOnlyExtras(extras); + final boolean pushOnly = Mailbox.isPushOnlyExtras(extras); + final boolean isFolderSync = (isFullSync || isInitialSync || accountOnly); // If we're just twiddling the push, we do the lightweight thing and bail early. - if (mailboxId == Mailbox.SYNC_EXTRA_MAILBOX_ID_PUSH_ONLY && !isFolderSync) { + if (pushOnly && !isFolderSync) { mSyncHandlerMap.modifyPing(account); LogUtils.i(TAG, "onPerformSync: mailbox push only %s, %s", acct.toString(), extras.toString()); @@ -666,10 +666,13 @@ public class EmailSyncAdapterService extends AbstractSyncAdapterService { // pings to stop. It may not matter since the things that may have been twiddled might // not affect syncing. - if (mailboxId != Mailbox.NO_MAILBOX) { + if (mailboxIds != null) { // Sync the mailbox that was explicitly requested. - syncMailbox(context, cr, acct, account, mailboxId, extras, syncResult, null, true); - } else if (mailboxId != Mailbox.SYNC_EXTRA_MAILBOX_ID_ACCOUNT_ONLY) { + for (final long mailboxId : mailboxIds) { + syncMailbox(context, cr, acct, account, mailboxId, extras, syncResult, null, + true); + } + } else if (accountOnly) { // We have to sync multiple folders. final Cursor c; if (isFullSync) { -- cgit v1.2.3