Merge "Switch over to use EasService" into ub-mail-master
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c9c3405..57e65f7 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -82,12 +82,11 @@
         <service
                 android:name="com.android.exchange.service.EasService"
                 android:exported="true">
-<!-- TODO: Switch this from EmailSyncAdapterService
             <intent-filter>
                 <action
                         android:name="com.android.email.EXCHANGE_INTENT" />
             </intent-filter>
--->
+
         </service>
 
         <!--Required stanza to register the EAS EmailSyncAdapterService with SyncManager -->
@@ -97,8 +96,6 @@
             <intent-filter>
                 <action
                     android:name="android.content.SyncAdapter" />
-                <action
-                    android:name="com.android.email.EXCHANGE_INTENT" />
             </intent-filter>
             <meta-data android:name="android.content.SyncAdapter"
                        android:resource="@xml/syncadapter_email" />
diff --git a/src/com/android/exchange/service/EmailSyncAdapterService.java b/src/com/android/exchange/service/EmailSyncAdapterService.java
index 020cae6..7fbaa66 100644
--- a/src/com/android/exchange/service/EmailSyncAdapterService.java
+++ b/src/com/android/exchange/service/EmailSyncAdapterService.java
@@ -133,434 +133,6 @@
             MessageColumns.MAILBOX_KEY + "=? and (" + SyncColumns.SERVER_ID + " is null or " +
             SyncColumns.SERVER_ID + "!=" + SEND_FAILED + ')';
 
-    /**
-     * Bookkeeping for handling synchronization between pings and syncs.
-     * "Ping" refers to a hanging POST or GET that is used to receive push notifications. Ping is
-     * the term for the Exchange command, but this code should be generic enough to be easily
-     * extended to IMAP.
-     * "Sync" refers to an actual sync command to either fetch mail state, account state, or send
-     * mail (send is implemented as "sync the outbox").
-     * TODO: Outbox sync probably need not stop a ping in progress.
-     * Basic rules of how these interact (note that all rules are per account):
-     * - Only one ping or sync may run at a time.
-     * - Due to how {@link AbstractThreadedSyncAdapter} works, sync requests will not occur while
-     *   a sync is in progress.
-     * - On the other hand, ping requests may come in while handling a ping.
-     * - "Ping request" is shorthand for "a request to change our ping parameters", which includes
-     *   a request to stop receiving push notifications.
-     * - If neither a ping nor a sync is running, then a request for either will run it.
-     * - If a sync is running, new ping requests block until the sync completes.
-     * - If a ping is running, a new sync request stops the ping and creates a pending ping
-     *   (which blocks until the sync completes).
-     * - If a ping is running, a new ping request stops the ping and either starts a new one or
-     *   does nothing, as appopriate (since a ping request can be to stop pushing).
-     * - As an optimization, while a ping request is waiting to run, subsequent ping requests are
-     *   ignored (the pending ping will pick up the latest ping parameters at the time it runs).
-     */
-    public class SyncHandlerSynchronizer {
-        /**
-         * Map of account id -> ping handler.
-         * For a given account id, there are three possible states:
-         * 1) If no ping or sync is currently running, there is no entry in the map for the account.
-         * 2) If a ping is running, there is an entry with the appropriate ping handler.
-         * 3) If there is a sync running, there is an entry with null as the value.
-         * We cannot have more than one ping or sync running at a time.
-         */
-        private final HashMap<Long, PingTask> mPingHandlers = new HashMap<Long, PingTask>();
-
-        /**
-         * Wait until neither a sync nor a ping is running on this account, and then return.
-         * If there's a ping running, actively stop it. (For syncs, we have to just wait.)
-         * @param accountId The account we want to wait for.
-         */
-        private synchronized void waitUntilNoActivity(final long accountId) {
-            while (mPingHandlers.containsKey(accountId)) {
-                final PingTask pingHandler = mPingHandlers.get(accountId);
-                if (pingHandler != null) {
-                    pingHandler.stop();
-                }
-                try {
-                    wait();
-                } catch (final InterruptedException e) {
-                    // TODO: When would this happen, and how should I handle it?
-                }
-            }
-        }
-
-        /**
-         * Use this to see if we're currently syncing, as opposed to pinging or doing nothing.
-         * @param accountId The account to check.
-         * @return Whether that account is currently running a sync.
-         */
-        private synchronized boolean isRunningSync(final long accountId) {
-            return (mPingHandlers.containsKey(accountId) && mPingHandlers.get(accountId) == null);
-        }
-
-        /**
-         * If there are no running pings, stop the service.
-         */
-        private void stopServiceIfNoPings() {
-            for (final PingTask pingHandler : mPingHandlers.values()) {
-                if (pingHandler != null) {
-                    return;
-                }
-            }
-            EmailSyncAdapterService.this.stopSelf();
-        }
-
-        /**
-         * Called prior to starting a sync to update our bookkeeping. We don't actually run the sync
-         * here; the caller must do that.
-         * @param accountId The account on which we are running a sync.
-         */
-        public synchronized void startSync(final long accountId) {
-            waitUntilNoActivity(accountId);
-            mPingHandlers.put(accountId, null);
-        }
-
-        /**
-         * Starts or restarts a ping for an account, if the current account state indicates that it
-         * wants to push.
-         * @param account The account whose ping is being modified.
-         */
-        public synchronized void modifyPing(final boolean lastSyncHadError,
-                final Account account) {
-            // If a sync is currently running, it will start a ping when it's done, so there's no
-            // need to do anything right now.
-            if (isRunningSync(account.mId)) {
-                return;
-            }
-
-            // Don't ping if we're on security hold.
-            if ((account.mFlags & Account.FLAGS_SECURITY_HOLD) != 0) {
-                return;
-            }
-
-            // Don't ping for accounts that haven't performed initial sync.
-            if (EmailContent.isInitialSyncKey(account.mSyncKey)) {
-                return;
-            }
-
-            // 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) {
-                final HashSet<String> authsToSync = getAuthsToSync(amAccount);
-                // 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.putBoolean(Mailbox.SYNC_EXTRA_PUSH_ONLY, true);
-            if (pushNeeded) {
-                // First start or restart the ping as appropriate.
-                if (pingSyncHandler != null) {
-                    pingSyncHandler.restart();
-                } else {
-                    if (lastSyncHadError) {
-                        // Schedule an alarm to set up the ping in 5 minutes
-                        scheduleDelayedPing(amAccount, SYNC_ERROR_BACKOFF_MILLIS);
-                    } 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));
-                    }
-                }
-                if (SCHEDULE_KICK) {
-                    ContentResolver.addPeriodicSync(amAccount, EmailContent.AUTHORITY, extras,
-                               KICK_SYNC_INTERVAL);
-                }
-            } else {
-                if (pingSyncHandler != null) {
-                    pingSyncHandler.stop();
-                }
-                if (SCHEDULE_KICK) {
-                    ContentResolver.removePeriodicSync(amAccount, EmailContent.AUTHORITY, extras);
-                }
-            }
-        }
-
-        /**
-         * Updates the synchronization bookkeeping when a sync is done.
-         * @param account The account whose sync just finished.
-         */
-        public synchronized void syncComplete(final boolean lastSyncHadError,
-                final Account account) {
-            LogUtils.d(TAG, "syncComplete, err: " + lastSyncHadError);
-            mPingHandlers.remove(account.mId);
-            // Syncs can interrupt pings, so we should check if we need to start one now.
-            // If the last sync had a fatal error, we will not immediately recreate the ping.
-            // Instead, we'll set an alarm that will restart them in a few minutes. This prevents
-            // a battery draining spin if there is some kind of protocol error or other
-            // non-transient failure. (Actually, immediately pinging even for a transient error
-            // isn't great)
-            modifyPing(lastSyncHadError, account);
-            stopServiceIfNoPings();
-            notifyAll();
-        }
-
-        /**
-         * Updates the synchronization bookkeeping when a ping is done. Also requests a ping-only
-         * sync if necessary.
-         * @param amAccount The {@link android.accounts.Account} for this account.
-         * @param accountId The account whose ping just finished.
-         * @param pingStatus The status value from {@link PingParser} for the last ping performed.
-         *                   This cannot be one of the values that results in another ping, so this
-         *                   function only needs to handle the terminal statuses.
-         */
-        public synchronized void pingComplete(final android.accounts.Account amAccount,
-                final long accountId, final int pingStatus) {
-            mPingHandlers.remove(accountId);
-
-            // TODO: if (pingStatus == PingParser.STATUS_FAILED), notify UI.
-            // TODO: if (pingStatus == PingParser.STATUS_REQUEST_TOO_MANY_FOLDERS), notify UI.
-
-            if (pingStatus == EasOperation.RESULT_REQUEST_FAILURE ||
-                    pingStatus == EasOperation.RESULT_OTHER_FAILURE) {
-                // TODO: Sticky problem here: we necessarily aren't in a sync, so it's impossible to
-                // signal the error to the SyncManager and take advantage of backoff there. Worse,
-                // the current mechanism for how we do this will just encourage spammy requests
-                // since the actual ping-only sync request ALWAYS succeeds.
-                // So for now, let's delay a bit before asking the SyncManager to perform the sync.
-                // Longer term, this should be incorporated into some form of backoff, either
-                // by integrating with the SyncManager more fully or by implementing a Ping-specific
-                // backoff mechanism (e.g. integrate this with the logic for ping duration).
-                LogUtils.e(TAG, "Ping for account %d completed with error %d, delaying next ping",
-                        accountId, pingStatus);
-                scheduleDelayedPing(amAccount, SYNC_ERROR_BACKOFF_MILLIS);
-            } else {
-                stopServiceIfNoPings();
-            }
-
-            // TODO: It might be the case that only STATUS_CHANGES_FOUND and
-            // STATUS_FOLDER_REFRESH_NEEDED need to notifyAll(). Think this through.
-            notifyAll();
-        }
-
-    }
-    private final SyncHandlerSynchronizer mSyncHandlerMap = new SyncHandlerSynchronizer();
-
-    /**
-     * The binder for IEmailService.
-     */
-    private final IEmailService.Stub mBinder = new IEmailService.Stub() {
-
-        private String getEmailAddressForAccount(final long accountId) {
-            final String emailAddress = Utility.getFirstRowString(EmailSyncAdapterService.this,
-                    Account.CONTENT_URI, ACCOUNT_EMAIL_PROJECTION, Account.ID_SELECTION,
-                    new String[] {Long.toString(accountId)}, null, 0);
-            if (emailAddress == null) {
-                LogUtils.e(TAG, "Could not find email address for account %d", accountId);
-            }
-            return emailAddress;
-        }
-
-        @Override
-        public Bundle validate(final HostAuth hostAuth) {
-            LogUtils.d(TAG, "IEmailService.validate");
-            if (mEasService != null) {
-                try {
-                    return mEasService.validate(hostAuth);
-                } catch (final RemoteException re) {
-                    LogUtils.e(TAG, re, "While asking EasService to handle validate");
-                }
-            }
-            return new EasFolderSync(EmailSyncAdapterService.this, hostAuth).doValidate();
-        }
-
-        @Override
-        public Bundle autoDiscover(final String username, final String password) {
-            final String domain = EasAutoDiscover.getDomain(username);
-            final String uri = EasAutoDiscover.createUri(domain);
-            final Bundle result = autoDiscoverInternal(uri, username, password, true);
-            final int resultCode = result.getInt(EmailServiceProxy.AUTO_DISCOVER_BUNDLE_ERROR_CODE);
-            if (resultCode == EasAutoDiscover.RESULT_BAD_RESPONSE) {
-                // Try the alternate uri
-                final String alternateUri = EasAutoDiscover.createAlternateUri(domain);
-                return autoDiscoverInternal(alternateUri, username, password, true);
-            } else {
-                return result;
-            }
-        }
-
-        private Bundle autoDiscoverInternal(final String uri, final String username,
-                                            final String password, final boolean canRetry) {
-            EasAutoDiscover op = new EasAutoDiscover(EmailSyncAdapterService.this, uri, username, password);
-            final int result = op.performOperation();
-            if (result == EasAutoDiscover.RESULT_REDIRECT) {
-                // Try again recursively with the new uri. TODO we should limit the number of redirects.
-                String redirectUri = op.getRedirectUri();
-                return autoDiscoverInternal(redirectUri, username, password, canRetry);
-            } else if (result == EasAutoDiscover.RESULT_SC_UNAUTHORIZED) {
-                if (canRetry && username.contains("@")) {
-                    // Try again using the bare user name
-                    final int atSignIndex = username.indexOf('@');
-                    final String bareUsername = username.substring(0, atSignIndex);
-                    LogUtils.d(TAG, "%d received; trying username: %s", result, atSignIndex);
-                    // Try again recursively, but this time don't allow retries for username.
-                    return autoDiscoverInternal(uri, bareUsername, password, false);
-                } else {
-                    // Either we're already on our second try or the username didn't have an "@"
-                    // to begin with. Either way, failure.
-                    final Bundle bundle = new Bundle(1);
-                    bundle.putInt(EmailServiceProxy.AUTO_DISCOVER_BUNDLE_ERROR_CODE,
-                            EasAutoDiscover.RESULT_OTHER_FAILURE);
-                    return bundle;
-                }
-            } else if (result != EasAutoDiscover.RESULT_OK) {
-                // Return failure, we'll try again with an alternate address
-                final Bundle bundle = new Bundle(1);
-                bundle.putInt(EmailServiceProxy.AUTO_DISCOVER_BUNDLE_ERROR_CODE,
-                        EasAutoDiscover.RESULT_BAD_RESPONSE);
-                return bundle;
-
-            } else {
-                // Success.
-                return op.getResultBundle();
-            }
-        }
-        @Override
-        public void updateFolderList(final long accountId) {
-            LogUtils.d(TAG, "IEmailService.updateFolderList: %d", accountId);
-            if (mEasService != null) {
-                try {
-                    mEasService.updateFolderList(accountId);
-                    return;
-                } catch (final RemoteException re) {
-                    LogUtils.e(TAG, re, "While asking EasService to updateFolderList");
-                }
-            }
-            final String emailAddress = getEmailAddressForAccount(accountId);
-            if (emailAddress != null) {
-                final Bundle extras = new Bundle(1);
-                extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
-                ContentResolver.requestSync(new android.accounts.Account(
-                        emailAddress, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE),
-                        EmailContent.AUTHORITY, extras);
-            }
-        }
-
-        @Override
-        public void setLogging(final int flags) {
-            // TODO: fix this?
-            // Protocol logging
-            Eas.setUserDebug(flags);
-            // Sync logging
-            //setUserDebug(flags);
-        }
-
-        @Override
-        public void loadAttachment(final IEmailServiceCallback callback, final long accountId,
-                final long attachmentId, final boolean background) {
-            LogUtils.d(TAG, "IEmailService.loadAttachment: %d", attachmentId);
-            // TODO: Prevent this from happening in parallel with a sync?
-            final EasLoadAttachment operation = new EasLoadAttachment(EmailSyncAdapterService.this,
-                    accountId, attachmentId, callback);
-            operation.performOperation();
-        }
-
-        @Override
-        public void sendMeetingResponse(final long messageId, final int response) {
-            LogUtils.d(TAG, "IEmailService.sendMeetingResponse: %d, %d", messageId, response);
-            final EmailContent.Message msg = EmailContent.Message.restoreMessageWithId(
-                    EmailSyncAdapterService.this, messageId);
-            final EasOperation op = new EasSendMeetingResponse(EmailSyncAdapterService.this,
-                    msg.mAccountKey, msg, response);
-            final int result = op.performOperation();
-            if (result != EasSendMeetingResponse.RESULT_OK) {
-                LogUtils.w(TAG, "Unexpected result %d from sendMeetingResponse", result);
-            }
-        }
-
-        /**
-         * Delete PIM (calendar, contacts) data for the specified account
-         *
-         * @param emailAddress the email address for the account whose data should be deleted
-         */
-        @Override
-        public void deleteAccountPIMData(final String emailAddress) {
-            LogUtils.d(TAG, "IEmailService.deleteAccountPIMData");
-            if (emailAddress != null) {
-                final Context context = EmailSyncAdapterService.this;
-                EasSyncContacts.wipeAccountFromContentProvider(context, emailAddress);
-                EasSyncCalendar.wipeAccountFromContentProvider(context, emailAddress);
-            }
-            // TODO: Run account reconciler?
-        }
-
-        @Override
-        public int searchMessages(final long accountId, final SearchParams searchParams,
-                final long destMailboxId) {
-            LogUtils.d(TAG, "IEmailService.searchMessages");
-            final EasSearch operation = new EasSearch(EmailSyncAdapterService.this, accountId,
-                    searchParams, destMailboxId);
-            operation.performOperation();
-            return operation.getTotalResults();
-            // TODO: may need an explicit callback to replace the one to IEmailServiceCallback.
-        }
-
-        @Override
-        public void sendMail(final long accountId) {}
-
-        @Override
-        public void pushModify(final long accountId) {
-            LogUtils.d(TAG, "IEmailService.pushModify");
-            if (mEasService != null) {
-                try {
-                    mEasService.pushModify(accountId);
-                    return;
-                } catch (final RemoteException re) {
-                    LogUtils.e(TAG, re, "While asking EasService to handle pushModify");
-                }
-            }
-            final Account account = Account.restoreAccountWithId(EmailSyncAdapterService.this,
-                    accountId);
-            if (account != null) {
-                mSyncHandlerMap.modifyPing(false, account);
-            }
-        }
-
-        @Override
-        public void syncFolders(final long accountId, final boolean updateFolderList,
-                         final long[] folders) {}
-
-        @Override
-        public void syncMailboxType(final long accountId, final boolean updateFolderList,
-                         final int mailboxType) {}
-    };
-
     public EmailSyncAdapterService() {
         super();
     }
@@ -570,56 +142,12 @@
      */
     private static final String PUSH_ACCOUNTS_SELECTION =
             AccountColumns.SYNC_INTERVAL + "=" + Integer.toString(Account.CHECK_INTERVAL_PUSH);
-    private class RestartPingsTask extends AsyncTask<Void, Void, Void> {
-
-        private final ContentResolver mContentResolver;
-        private final SyncHandlerSynchronizer mSyncHandlerMap;
-        private boolean mAnyAccounts;
-
-        public RestartPingsTask(final ContentResolver contentResolver,
-                final SyncHandlerSynchronizer syncHandlerMap) {
-            mContentResolver = contentResolver;
-            mSyncHandlerMap = syncHandlerMap;
-        }
-
-        @Override
-        protected Void doInBackground(Void... params) {
-            final Cursor c = mContentResolver.query(Account.CONTENT_URI,
-                    Account.CONTENT_PROJECTION, PUSH_ACCOUNTS_SELECTION, null, null);
-            if (c != null) {
-                try {
-                    mAnyAccounts = (c.getCount() != 0);
-                    while (c.moveToNext()) {
-                        final Account account = new Account();
-                        account.restore(c);
-                        mSyncHandlerMap.modifyPing(false, account);
-                    }
-                } finally {
-                    c.close();
-                }
-            } else {
-                mAnyAccounts = false;
-            }
-            return null;
-        }
-
-        @Override
-        protected void onPostExecute(Void result) {
-            if (!mAnyAccounts) {
-                LogUtils.d(TAG, "stopping for no accounts");
-                EmailSyncAdapterService.this.stopSelf();
-            }
-        }
-    }
 
     @Override
     public void onCreate() {
         LogUtils.v(TAG, "onCreate()");
         super.onCreate();
         startService(new Intent(this, EmailSyncAdapterService.class));
-        // Restart push for all accounts that need it.
-        new RestartPingsTask(getContentResolver(), mSyncHandlerMap).executeOnExecutor(
-                AsyncTask.THREAD_POOL_EXECUTOR);
         if (DELEGATE_TO_EAS_SERVICE) {
             // TODO: This block is temporary to support the transition to EasService.
             mConnection = new ServiceConnection() {
@@ -641,11 +169,6 @@
     public void onDestroy() {
         LogUtils.v(TAG, "onDestroy()");
         super.onDestroy();
-        for (PingTask task : mSyncHandlerMap.mPingHandlers.values()) {
-            if (task != null) {
-                task.stop();
-            }
-        }
         if (DELEGATE_TO_EAS_SERVICE) {
             // TODO: This block is temporary to support the transition to EasService.
             unbindService(mConnection);
@@ -654,9 +177,6 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        if (intent.getAction().equals(Eas.EXCHANGE_SERVICE_INTENT_ACTION)) {
-            return mBinder;
-        }
         return super.onBind(intent);
     }
 
@@ -713,11 +233,14 @@
 
             // TODO: Perform any connectivity checks, bail early if we don't have proper network
             // for this sync operation.
+            // FLAG: Do we actually need to do this? I don't think the sync manager will invoke
+            // a sync if we don't have good network.
 
             final Context context = getContext();
             final ContentResolver cr = context.getContentResolver();
 
             // Get the EmailContent Account
+            // XXX shouldn't this functionality live in Account, not here?
             final Account account;
             final Cursor accountCursor = cr.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION,
                     AccountColumns.EMAIL_ADDRESS + "=?", new String[] {acct.name}, null);
@@ -766,12 +289,9 @@
                         LogUtils.e(TAG, re, "While trying to pushModify within onPerformSync");
                     }
                 }
-                mSyncHandlerMap.modifyPing(false, account);
                 return;
             }
 
-            // Do the bookkeeping for starting a sync, including stopping a ping if necessary.
-            mSyncHandlerMap.startSync(account.mId);
             int operationResult = 0;
             try {
                 // Perform a FolderSync if necessary.
@@ -799,7 +319,8 @@
                     }
 
                     // TODO: EasSync should eventually handle both up and down; for now, it's used
-                    // purely for upsync.
+                    // purely for upsync. This is not for sending, it's for upsyncing moves and
+                    // flag updates.
                     EasSync upsync = new EasSync(context, account);
                     operationResult = upsync.upsync();
                     if (operationResult < 0) {
@@ -855,9 +376,6 @@
                     }
                 }
             } finally {
-                // Clean up the bookkeeping, including restarting ping if necessary.
-                mSyncHandlerMap.syncComplete(syncResult.hasError(), account);
-
                 if (operationResult < 0) {
                     EasFolderSync.writeResultToSyncResult(operationResult, syncResult);
                     // If any operations had an auth error, notify the user.
diff --git a/src/com/android/exchange/service/PingTask.java b/src/com/android/exchange/service/PingTask.java
index cad66cf..c68ab8f 100644
--- a/src/com/android/exchange/service/PingTask.java
+++ b/src/com/android/exchange/service/PingTask.java
@@ -31,27 +31,16 @@
  */
 public class PingTask extends AsyncTask<Void, Void, Void> {
     private final EasPing mOperation;
-    // TODO: Transition away from mSyncHandlerMap -> mPingSyncSynchronizer.
-    private final EmailSyncAdapterService.SyncHandlerSynchronizer mSyncHandlerMap;
     private final PingSyncSynchronizer mPingSyncSynchronizer;
 
     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) {
-        assert syncHandlerMap != null;
-        mOperation = new EasPing(context, account, amAccount);
-        mSyncHandlerMap = syncHandlerMap;
-        mPingSyncSynchronizer = null;
-    }
 
     public PingTask(final Context context, final Account account,
             final android.accounts.Account amAccount,
             final PingSyncSynchronizer pingSyncSynchronizer) {
         assert pingSyncSynchronizer != null;
         mOperation = new EasPing(context, account, amAccount);
-        mSyncHandlerMap = null;
         mPingSyncSynchronizer = pingSyncSynchronizer;
     }
 
@@ -87,12 +76,7 @@
         }
         LogUtils.i(TAG, "Ping task ending with status: %d", pingStatus);
 
-        if (mSyncHandlerMap != null) {
-            mSyncHandlerMap.pingComplete(mOperation.getAmAccount(), mOperation.getAccountId(),
-                    pingStatus);
-        } else {
-            mPingSyncSynchronizer.pingEnd(mOperation.getAccountId(), mOperation.getAmAccount());
-        }
+        mPingSyncSynchronizer.pingEnd(mOperation.getAccountId(), mOperation.getAmAccount());
         return null;
     }
 
@@ -101,11 +85,6 @@
         // TODO: This is also hacky, should have a separate result code at minimum.
         // If the ping is cancelled, make sure it reports something to the sync adapter.
         LogUtils.w(TAG, "Ping cancelled for %d", mOperation.getAccountId());
-        if (mSyncHandlerMap != null) {
-            mSyncHandlerMap.pingComplete(mOperation.getAmAccount(), mOperation.getAccountId(),
-                    EasOperation.RESULT_REQUEST_FAILURE);
-        } else {
-            mPingSyncSynchronizer.pingEnd(mOperation.getAccountId(), mOperation.getAmAccount());
-        }
+        mPingSyncSynchronizer.pingEnd(mOperation.getAccountId(), mOperation.getAmAccount());
     }
 }