Improve logic for when we start ping threads.
Also adds the ping kicker, and improves a log message.
Bug: 11081520
Change-Id: I9cc0088071a2a4e2beb03112a1f808146e576741
diff --git a/src/com/android/exchange/eas/EasPing.java b/src/com/android/exchange/eas/EasPing.java
index 07c62de..e53daeb 100644
--- a/src/com/android/exchange/eas/EasPing.java
+++ b/src/com/android/exchange/eas/EasPing.java
@@ -88,11 +88,11 @@
*/
private static final long EXTRA_POST_TIMEOUT_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
- public EasPing(final Context context, final Account account) {
+ public EasPing(final Context context, final Account account,
+ final android.accounts.Account amAccount) {
super(context, account);
mAccountId = account.mId;
- mAmAccount = new android.accounts.Account(account.mEmailAddress,
- Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE);
+ mAmAccount = amAccount;
mPingDuration = account.mPingDuration;
if (mPingDuration == 0) {
mPingDuration = DEFAULT_PING_HEARTBEAT;
diff --git a/src/com/android/exchange/eas/EasSync.java b/src/com/android/exchange/eas/EasSync.java
index 6703a0c..65c666a 100644
--- a/src/com/android/exchange/eas/EasSync.java
+++ b/src/com/android/exchange/eas/EasSync.java
@@ -137,7 +137,8 @@
// b/10797675
// TODO: figure out why and clean this up
LogUtils.d(LOG_TAG,
- "Tried to sync mailbox with invalid mailbox sync key");
+ "Tried to sync mailbox %d with invalid mailbox sync key",
+ mMailboxId);
result = -1;
} else {
result = performOperation(syncResult);
diff --git a/src/com/android/exchange/service/EmailSyncAdapterService.java b/src/com/android/exchange/service/EmailSyncAdapterService.java
index 8735e69..d76a6d6 100644
--- a/src/com/android/exchange/service/EmailSyncAdapterService.java
+++ b/src/com/android/exchange/service/EmailSyncAdapterService.java
@@ -32,7 +32,10 @@
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
+import android.provider.CalendarContract;
+import android.provider.ContactsContract;
import android.text.TextUtils;
+import android.text.format.DateUtils;
import com.android.emailcommon.Api;
import com.android.emailcommon.TempDirectory;
@@ -61,6 +64,7 @@
import com.android.mail.utils.LogUtils;
import java.util.HashMap;
+import java.util.HashSet;
/**
* Service for communicating with Exchange servers. There are three main parts of this class:
@@ -74,6 +78,12 @@
private static final String TAG = Eas.LOG_TAG;
/**
+ * The amount of time between periodic syncs intended to ensure that push hasn't died.
+ */
+ private static final long KICK_SYNC_INTERVAL =
+ DateUtils.HOUR_IN_MILLIS / DateUtils.SECOND_IN_MILLIS;
+
+ /**
* If sync extras do not include a mailbox id, then we want to perform a full sync.
*/
private static final long FULL_ACCOUNT_SYNC = Mailbox.NO_MAILBOX;
@@ -181,28 +191,81 @@
return;
}
- // If a ping is currently running, tell it to restart to pick up new params.
- final PingTask pingSyncHandler = mPingHandlers.get(account.mId);
- if (pingSyncHandler != null) {
- pingSyncHandler.restart();
+ // Don't ping for accounts that haven't performed initial sync.
+ if (EmailContent.isInitialSyncKey(account.mSyncKey)) {
return;
}
- // If we're here, then there's neither a sync nor a ping running. Start a new ping.
+ // Determine if this account needs pushes. All of the following must be true:
+ // - The account's sync interval must indicate that it wants push.
+ // - At least one content type must be sync-enabled in the account manager.
+ // - At least one mailbox of a sync-enabled type must have automatic sync enabled.
final EmailSyncAdapterService service = EmailSyncAdapterService.this;
+ final android.accounts.Account amAccount = new android.accounts.Account(
+ account.mEmailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE);
+ boolean pushNeeded = false;
if (account.mSyncInterval == Account.CHECK_INTERVAL_PUSH) {
- // TODO: Also check if we have any mailboxes that WANT push.
- // This account needs to ping.
- // Note: unlike startSync, we CANNOT allow the caller to do the actual work.
- // If we return before the ping starts, there's a race condition where another
- // ping or sync might start first. It only works for startSync because sync is
- // higher priority than ping (i.e. a ping can't start while a sync is pending)
- // and only one sync can run at a time.
- final PingTask pingHandler = new PingTask(service, account, this);
- mPingHandlers.put(account.mId, pingHandler);
- pingHandler.start();
- // Whenever we have a running ping, make sure this service stays running.
- service.startService(new Intent(service, EmailSyncAdapterService.class));
+ // Determine which content types want sync.
+ final HashSet<String> authsToSync = new HashSet();
+ if (ContentResolver.getSyncAutomatically(amAccount, EmailContent.AUTHORITY)) {
+ authsToSync.add(EmailContent.AUTHORITY);
+ }
+ if (ContentResolver.getSyncAutomatically(amAccount, CalendarContract.AUTHORITY)) {
+ authsToSync.add(CalendarContract.AUTHORITY);
+ }
+ if (ContentResolver.getSyncAutomatically(amAccount, ContactsContract.AUTHORITY)) {
+ authsToSync.add(ContactsContract.AUTHORITY);
+ }
+ // If we have at least one sync-enabled content type, check for syncing mailboxes.
+ if (!authsToSync.isEmpty()) {
+ final Cursor c = Mailbox.getMailboxesForPush(service.getContentResolver(),
+ account.mId);
+ if (c != null) {
+ try {
+ while (c.moveToNext()) {
+ final int mailboxType = c.getInt(Mailbox.CONTENT_TYPE_COLUMN);
+ if (authsToSync.contains(Mailbox.getAuthority(mailboxType))) {
+ pushNeeded = true;
+ break;
+ }
+ }
+ } finally {
+ c.close();
+ }
+ }
+ }
+ }
+
+ // 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);
+ if (pushNeeded) {
+ // First start or restart the ping as appropriate.
+ if (pingSyncHandler != null) {
+ pingSyncHandler.restart();
+ } else {
+ // Start a new ping.
+ // Note: unlike startSync, we CANNOT allow the caller to do the actual work.
+ // If we return before the ping starts, there's a race condition where another
+ // ping or sync might start first. It only works for startSync because sync is
+ // higher priority than ping (i.e. a ping can't start while a sync is pending)
+ // and only one sync can run at a time.
+ final PingTask pingHandler = new PingTask(service, account, amAccount, this);
+ mPingHandlers.put(account.mId, pingHandler);
+ pingHandler.start();
+ // Whenever we have a running ping, make sure this service stays running.
+ service.startService(new Intent(service, EmailSyncAdapterService.class));
+ }
+ // Schedule a ping kicker for this account.
+ ContentResolver.addPeriodicSync(amAccount, EmailContent.AUTHORITY, extras,
+ KICK_SYNC_INTERVAL);
+ } else {
+ if (pingSyncHandler != null) {
+ pingSyncHandler.stop();
+ }
+ // Stop the ping kicker for this account.
+ ContentResolver.removePeriodicSync(amAccount, EmailContent.AUTHORITY, extras);
}
}
diff --git a/src/com/android/exchange/service/PingTask.java b/src/com/android/exchange/service/PingTask.java
index a405e9a..b1cba07 100644
--- a/src/com/android/exchange/service/PingTask.java
+++ b/src/com/android/exchange/service/PingTask.java
@@ -35,8 +35,9 @@
private static final String TAG = Eas.LOG_TAG;
public PingTask(final Context context, final Account account,
+ final android.accounts.Account amAccount,
final EmailSyncAdapterService.SyncHandlerSynchronizer syncHandlerMap) {
- mOperation = new EasPing(context, account);
+ mOperation = new EasPing(context, account, amAccount);
mSyncHandlerMap = syncHandlerMap;
}