1ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu/* 2ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * Copyright (C) 2013 The Android Open Source Project 3ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * 4ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * Licensed under the Apache License, Version 2.0 (the "License"); 5ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * you may not use this file except in compliance with the License. 6ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * You may obtain a copy of the License at 7ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * 8ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * http://www.apache.org/licenses/LICENSE-2.0 9ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * 10ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * Unless required by applicable law or agreed to in writing, software 11ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * distributed under the License is distributed on an "AS IS" BASIS, 12ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * See the License for the specific language governing permissions and 14ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * limitations under the License. 15ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu */ 16ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 17ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hupackage com.android.exchange.eas; 18ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 19ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport android.content.ContentResolver; 2026b41fab64a805f3f938e135addbb9603f1637afMartin Hibdonimport android.content.ContentValues; 21ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport android.content.Context; 22ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport android.database.Cursor; 234427badd747b7c172934014b9f95a1be1256f35aMartin Hibdonimport android.os.Bundle; 2426b41fab64a805f3f938e135addbb9603f1637afMartin Hibdonimport android.os.SystemClock; 25f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdonimport android.provider.CalendarContract; 26f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdonimport android.provider.ContactsContract; 27ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport android.text.format.DateUtils; 28ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 29ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.emailcommon.provider.Account; 30ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.emailcommon.provider.EmailContent; 3126b41fab64a805f3f938e135addbb9603f1637afMartin Hibdonimport com.android.emailcommon.provider.EmailContent.AccountColumns; 32ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.emailcommon.provider.EmailContent.MailboxColumns; 33ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.emailcommon.provider.Mailbox; 3455f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdonimport com.android.exchange.CommandStatusException.CommandStatus; 35ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.Eas; 36ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.EasResponse; 37ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.adapter.PingParser; 38ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.adapter.Serializer; 39ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.adapter.Tags; 40ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.mail.utils.LogUtils; 41ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 42ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport org.apache.http.HttpEntity; 43ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 44ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport java.io.IOException; 45ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport java.util.ArrayList; 464427badd747b7c172934014b9f95a1be1256f35aMartin Hibdonimport java.util.HashSet; 47ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 48ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu/** 49ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * Performs an Exchange Ping, which is the command for receiving push notifications. 50328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * See http://msdn.microsoft.com/en-us/library/ee200913(v=exchg.80).aspx for more details. 51ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu */ 52ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hupublic class EasPing extends EasOperation { 53110837ebff288a75f9bda067c38e2c46797d99b5Alon Albert private static final String TAG = Eas.LOG_TAG; 54ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 55ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu private static final String WHERE_ACCOUNT_KEY_AND_SERVER_ID = 56ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu MailboxColumns.ACCOUNT_KEY + "=? and " + MailboxColumns.SERVER_ID + "=?"; 57ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 58ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu private final android.accounts.Account mAmAccount; 5926b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon private long mPingDuration; 60ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 61ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu /** 6226b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon * The default heartbeat interval specified to the Exchange server. This is the maximum amount 6326b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon * of time (in seconds) that the server should wait before responding to the ping request. 64ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu */ 6526b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon private static final long DEFAULT_PING_HEARTBEAT = 66ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 8 * (DateUtils.MINUTE_IN_MILLIS / DateUtils.SECOND_IN_MILLIS); 67ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 6826b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon /** 6926b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon * The minimum heartbeat interval we should ever use, in seconds. 7026b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon */ 7126b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon private static final long MINIMUM_PING_HEARTBEAT = 7226b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon 8 * (DateUtils.MINUTE_IN_MILLIS / DateUtils.SECOND_IN_MILLIS); 7326b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon 7426b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon /** 7526b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon * The maximum heartbeat interval we should ever use, in seconds. 7626b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon */ 7726b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon private static final long MAXIMUM_PING_HEARTBEAT = 7826b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon 28 * (DateUtils.MINUTE_IN_MILLIS / DateUtils.SECOND_IN_MILLIS); 7926b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon 8026b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon /** 8126b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon * The maximum amount that we can change with each adjustment, in seconds. 8226b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon */ 8326b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon private static final long MAXIMUM_HEARTBEAT_INCREMENT = 8426b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon 5 * (DateUtils.MINUTE_IN_MILLIS / DateUtils.SECOND_IN_MILLIS); 85ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 86ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu /** 8726b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon * The extra time for the timeout used for the HTTP POST (in milliseconds). Notionally this 8826b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon * should be the same as ping heartbeat but in practice is a few seconds longer to allow for 8926b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon * latency in the server's response. 90ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu */ 9126b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon private static final long EXTRA_POST_TIMEOUT_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS; 92ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 936285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu public EasPing(final Context context, final Account account, 946285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu final android.accounts.Account amAccount) { 95ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu super(context, account); 966285ee2ecc9136238accd4ce7927b59cd95792aeYu Ping Hu mAmAccount = amAccount; 9726b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon mPingDuration = account.mPingDuration; 9826b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon if (mPingDuration == 0) { 9926b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon mPingDuration = DEFAULT_PING_HEARTBEAT; 10026b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon } 1016c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu LogUtils.d(TAG, "initial ping duration " + mPingDuration + " account " + getAccountId()); 102ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 103ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 104ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public final int doPing() { 10526b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon final long startTime = SystemClock.elapsedRealtime(); 1068c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu final int result = performOperation(); 107ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (result == RESULT_RESTART) { 108ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return PingParser.STATUS_EXPIRED; 10961ebb38e67421fd122c81f046bf11778b61a2113Martin Hibdon } else if (result == RESULT_NETWORK_PROBLEM) { 11026b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon final long timeoutDuration = SystemClock.elapsedRealtime() - startTime; 111dc15b97b8975b994992d14d2cf3e6c8a80645b5dYu Ping Hu LogUtils.d(TAG, "doPing request failure, timed out after %d millis", timeoutDuration); 11226b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon decreasePingDuration(); 113ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 114ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return result; 115ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 116ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 11726b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon private void decreasePingDuration() { 11826b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon mPingDuration = Math.max(MINIMUM_PING_HEARTBEAT, 11926b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon mPingDuration - MAXIMUM_HEARTBEAT_INCREMENT); 12026b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon LogUtils.d(TAG, "decreasePingDuration adjusting by " + MAXIMUM_HEARTBEAT_INCREMENT + 1216c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu " new duration " + mPingDuration + " account " + getAccountId()); 12226b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon storePingDuration(); 12326b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon } 12426b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon 12526b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon private void increasePingDuration() { 12626b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon mPingDuration = Math.min(MAXIMUM_PING_HEARTBEAT, 12726b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon mPingDuration + MAXIMUM_HEARTBEAT_INCREMENT); 12826b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon LogUtils.d(TAG, "increasePingDuration adjusting by " + MAXIMUM_HEARTBEAT_INCREMENT + 1296c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu " new duration " + mPingDuration + " account " + getAccountId()); 13026b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon storePingDuration(); 13126b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon } 13226b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon 13326b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon private void storePingDuration() { 13426b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon final ContentValues values = new ContentValues(1); 13526b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon values.put(AccountColumns.PING_DURATION, mPingDuration); 1366c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu Account.update(mContext, Account.CONTENT_URI, getAccountId(), values); 137ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 138ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 139ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public final android.accounts.Account getAmAccount() { 140ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return mAmAccount; 141ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 142ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 143ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu @Override 144ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu protected String getCommand() { 145ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return "Ping"; 146ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 147ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 148ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu @Override 149ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu protected HttpEntity getRequestEntity() throws IOException { 150ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // Get the mailboxes that need push notifications. 151ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final Cursor c = Mailbox.getMailboxesForPush(mContext.getContentResolver(), 1526c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu getAccountId()); 153ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (c == null) { 154ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu throw new IllegalStateException("Could not read mailboxes"); 155ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 156ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 157ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // TODO: Ideally we never even get here unless we already know we want a push. 158ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu Serializer s = null; 159ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu try { 160ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu while (c.moveToNext()) { 161ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final Mailbox mailbox = new Mailbox(); 162ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu mailbox.restore(c); 163ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu s = handleOneMailbox(s, mailbox); 164ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 165ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } finally { 166ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu c.close(); 167ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 168ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 169ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (s == null) { 170ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu abort(); 171ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu throw new IOException("No mailboxes want push"); 172ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 173ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // This sequence of end()s corresponds to the start()s that occur in handleOneMailbox when 174ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // the Serializer is first created. If either side changes, the other must be kept in sync. 175ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu s.end().end().done(); 176ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return makeEntity(s); 177ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 178ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 179ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu @Override 1808c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu protected int handleResponse(final EasResponse response) throws IOException { 181ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (response.isEmpty()) { 18226b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon // TODO this should probably not be an IOException, maybe something more descriptive? 183ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu throw new IOException("Empty ping response"); 184ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 185ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 186f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.d(TAG, "EasPing.handleResponse"); 187f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon 188ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // Handle a valid response. 189ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final PingParser pp = new PingParser(response.getInputStream()); 190ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu pp.parse(); 191ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final int pingStatus = pp.getPingStatus(); 192ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 193ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // Take the appropriate action for this response. 194ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // Many of the responses require no explicit action here, they just influence 195ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // our re-ping behavior, which is handled by the caller. 1966c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu final long accountId = getAccountId(); 197ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu switch (pingStatus) { 198ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu case PingParser.STATUS_EXPIRED: 1996c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu LogUtils.i(TAG, "Ping expired for account %d", accountId); 20026b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon // On successful expiration, we can increase our ping duration 20126b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon increasePingDuration(); 202ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu break; 203ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu case PingParser.STATUS_CHANGES_FOUND: 2046c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu LogUtils.i(TAG, "Ping found changed folders for account %d", accountId); 205ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu requestSyncForSyncList(pp.getSyncList()); 206ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu break; 207ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu case PingParser.STATUS_REQUEST_INCOMPLETE: 208ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu case PingParser.STATUS_REQUEST_MALFORMED: 209ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // These two cases indicate that the ping request was somehow bad. 210ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // TODO: It's insanity to re-ping with the same data and expect a different 211ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // result. Improve this if possible. 2126c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu LogUtils.e(TAG, "Bad ping request for account %d", accountId); 213ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu break; 214ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu case PingParser.STATUS_REQUEST_HEARTBEAT_OUT_OF_BOUNDS: 21526b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon long newDuration = pp.getHeartbeatInterval(); 21626b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon LogUtils.i(TAG, "Heartbeat out of bounds for account %d, " + 2176c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu "old duration %d new duration %d", accountId, mPingDuration, newDuration); 21826b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon mPingDuration = newDuration; 21926b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon storePingDuration(); 220ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu break; 221ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu case PingParser.STATUS_REQUEST_TOO_MANY_FOLDERS: 2226c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu LogUtils.i(TAG, "Too many folders for account %d", accountId); 223ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu break; 224ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu case PingParser.STATUS_FOLDER_REFRESH_NEEDED: 2256c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu LogUtils.i(TAG, "FolderSync needed for account %d", accountId); 226ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu requestFolderSync(); 227ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu break; 228ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu case PingParser.STATUS_SERVER_ERROR: 2296c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu LogUtils.i(TAG, "Server error for account %d", accountId); 230ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu break; 23155f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.SERVER_ERROR_RETRY: 23255f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon // Try again later. 2336c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu LogUtils.i(TAG, "Retryable server error for account %d", accountId); 23455f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon return RESULT_RESTART; 23555f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon 23655f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon // These errors should not happen. 23755f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.USER_DISABLED_FOR_SYNC: 23855f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.USERS_DISABLED_FOR_SYNC: 23955f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.USER_ON_LEGACY_SERVER_CANT_SYNC: 24055f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.DEVICE_QUARANTINED: 24155f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.ACCESS_DENIED: 24255f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.USER_ACCOUNT_DISABLED: 24355f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.NOT_PROVISIONABLE_PARTIAL: 24455f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.NOT_PROVISIONABLE_LEGACY_DEVICE: 24555f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.TOO_MANY_PARTNERSHIPS: 24655f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon LogUtils.e(TAG, "Unexpected error %d on ping", pingStatus); 24755f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon return RESULT_AUTHENTICATION_ERROR; 24855f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon 24955f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon // These errors should not happen. 25055f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.SYNC_STATE_NOT_FOUND: 25155f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.SYNC_STATE_LOCKED: 25255f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.SYNC_STATE_CORRUPT: 25355f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.SYNC_STATE_EXISTS: 25455f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.SYNC_STATE_INVALID: 25555f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.NEEDS_PROVISIONING_WIPE: 25655f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.NEEDS_PROVISIONING: 25755f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.NEEDS_PROVISIONING_REFRESH: 25855f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.NEEDS_PROVISIONING_INVALID: 25955f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.WTF_INVALID_COMMAND: 26055f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.WTF_INVALID_PROTOCOL: 26155f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.WTF_DEVICE_CLAIMS_EXTERNAL_MANAGEMENT: 26255f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.WTF_UNKNOWN_ITEM_TYPE: 26355f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.WTF_REQUIRES_PROXY_WITHOUT_SSL: 26455f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon case CommandStatus.ITEM_NOT_FOUND: 26555f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon LogUtils.e(TAG, "Unexpected error %d on ping", pingStatus); 26655f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon return RESULT_OTHER_FAILURE; 26755f26fbb0146cd64a244510bfcb7dbb14569466eMartin Hibdon 268ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu default: 269ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu break; 270ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 271ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 272ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return pingStatus; 273ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 274ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 275ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 276ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu @Override 277ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu protected boolean addPolicyKeyHeaderToRequest() { 278ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return false; 279ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 280ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 281ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu @Override 282ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu protected long getTimeout() { 28326b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon return mPingDuration * DateUtils.SECOND_IN_MILLIS + EXTRA_POST_TIMEOUT_MILLIS; 284ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 285ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 286ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu /** 287ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * If mailbox is eligible for push, add it to the ping request, creating the {@link Serializer} 288ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * for the request if necessary. 289ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * @param mailbox The mailbox to check. 290ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * @param s The {@link Serializer} for this request, or null if it hasn't been created yet. 291ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * @return The {@link Serializer} for this request, or null if it hasn't been created yet. 292ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * @throws IOException 293ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu */ 294ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu private Serializer handleOneMailbox(Serializer s, final Mailbox mailbox) throws IOException { 295ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // We can't push until the initial sync is done 296ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (mailbox.mSyncKey != null && !mailbox.mSyncKey.equals("0")) { 297ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (ContentResolver.getSyncAutomatically(mAmAccount, 298ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu Mailbox.getAuthority(mailbox.mType))) { 299ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (s == null) { 300ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // No serializer yet, so create and initialize it. 301ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // Note that these start()s correspond to the end()s in doInBackground. 302ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // If either side changes, the other must be kept in sync. 303ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu s = new Serializer(); 304ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu s.start(Tags.PING_PING); 30526b41fab64a805f3f938e135addbb9603f1637afMartin Hibdon s.data(Tags.PING_HEARTBEAT_INTERVAL, Long.toString(mPingDuration)); 306ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu s.start(Tags.PING_FOLDERS); 307ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 308ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu s.start(Tags.PING_FOLDER); 309ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu s.data(Tags.PING_ID, mailbox.mServerId); 310ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu s.data(Tags.PING_CLASS, Eas.getFolderClass(mailbox.mType)); 311ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu s.end(); 312ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 313ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 314ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return s; 315ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 316ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 317ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu /** 318ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * Make the appropriate calls to {@link ContentResolver#requestSync} indicated by the 319ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * current ping response. 320ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * @param syncList The list of folders that need to be synced. 321ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu */ 322ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu private void requestSyncForSyncList(final ArrayList<String> syncList) { 323ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final String[] bindArguments = new String[2]; 3246c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu bindArguments[0] = Long.toString(getAccountId()); 3254427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon 326f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon final ArrayList<Long> emailMailboxIds = new ArrayList<Long>(); 327f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon final ArrayList<Long> calendarMailboxIds = new ArrayList<Long>(); 328f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon final ArrayList<Long> contactsMailboxIds = new ArrayList<Long>(); 3294427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon 330ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu for (final String serverId : syncList) { 331ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu bindArguments[1] = serverId; 332ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // TODO: Rather than one query per ping mailbox, do it all in one? 333ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final Cursor c = mContext.getContentResolver().query(Mailbox.CONTENT_URI, 334ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu Mailbox.CONTENT_PROJECTION, WHERE_ACCOUNT_KEY_AND_SERVER_ID, 335ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu bindArguments, null); 336ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (c == null) { 337ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // TODO: proper error handling. 338ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu break; 339ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 340ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu try { 341ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu /** 342ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * Check the boxes reporting changes to see if there really were any... 343ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * We do this because bugs in various Exchange servers can put us into a 344ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * looping behavior by continually reporting changes in a mailbox, even 345ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * when there aren't any. 346ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * 347ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * This behavior is seemingly random, and therefore we must code 348ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * defensively by backing off of push behavior when it is detected. 349ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * 350ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * One known cause, on certain Exchange 2003 servers, is acknowledged by 351ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * Microsoft, and the server hotfix for this case can be found at 352ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * http://support.microsoft.com/kb/923282 353ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu */ 354bb0141b49e7eff978fa445249dc888461ea581e3Martin Hibdon // TODO: Implement the above 355ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (c.moveToFirst()) { 3564427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon final long mailboxId = c.getLong(Mailbox.CONTENT_ID_COLUMN); 3574427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon final int contentType = c.getInt(Mailbox.CONTENT_TYPE_COLUMN); 358f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon switch (contentType) { 359f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon case Mailbox.TYPE_MAIL: 360f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon case Mailbox.TYPE_INBOX: 361f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon case Mailbox.TYPE_DRAFTS: 362f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon case Mailbox.TYPE_SENT: 363f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon case Mailbox.TYPE_TRASH: 364f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon case Mailbox.TYPE_JUNK: 365f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon emailMailboxIds.add(mailboxId); 366f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon case Mailbox.TYPE_CALENDAR: 367f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon calendarMailboxIds.add(mailboxId); 368f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon case Mailbox.TYPE_CONTACTS: 369f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon contactsMailboxIds.add(mailboxId); 370f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon default: 371f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.e(LOG_TAG, "unexpected collectiontype %d in EasPing", contentType); 372f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon } 373ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 374ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } finally { 375ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu c.close(); 376ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 377ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 378f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon requestSyncForMailboxes(mAmAccount, EmailContent.AUTHORITY, emailMailboxIds); 379f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon requestSyncForMailboxes(mAmAccount, CalendarContract.AUTHORITY, calendarMailboxIds); 380f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon requestSyncForMailboxes(mAmAccount, ContactsContract.AUTHORITY, contactsMailboxIds); 381ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 382ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 383ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu /** 384ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * Issue a {@link ContentResolver#requestSync} to trigger a FolderSync for an account. 385ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu */ 386ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu private void requestFolderSync() { 3874427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon final Bundle extras = new Bundle(1); 3884427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon extras.putBoolean(Mailbox.SYNC_EXTRA_ACCOUNT_ONLY, true); 3894427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon ContentResolver.requestSync(mAmAccount, EmailContent.AUTHORITY, extras); 390f8cccaecc8148d12d58ffcba5ce7366191316ac0Martin Hibdon LogUtils.i(LOG_TAG, "requestFolderSync EasPing %s, %s", 3914427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon mAmAccount.toString(), extras.toString()); 392ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 393ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 3942cc96b73358378d57c53a45d6da63a77b618a45dYu Ping Hu /** 3952cc96b73358378d57c53a45d6da63a77b618a45dYu Ping Hu * Request a ping-only sync via the SyncManager. This is used in error paths, which is also why 3962cc96b73358378d57c53a45d6da63a77b618a45dYu Ping Hu * we don't just create and start a new ping task immediately: in the case where we have loss 3972cc96b73358378d57c53a45d6da63a77b618a45dYu Ping Hu * of network, we want to take advantage of the SyncManager to schedule this when we expect it 3982cc96b73358378d57c53a45d6da63a77b618a45dYu Ping Hu * to be able to work. 3992cc96b73358378d57c53a45d6da63a77b618a45dYu Ping Hu * @param amAccount Account that needs to ping. 4002cc96b73358378d57c53a45d6da63a77b618a45dYu Ping Hu */ 401ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public static void requestPing(final android.accounts.Account amAccount) { 4022cc96b73358378d57c53a45d6da63a77b618a45dYu Ping Hu final Bundle extras = new Bundle(2); 4034427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon extras.putBoolean(Mailbox.SYNC_EXTRA_PUSH_ONLY, true); 4042cc96b73358378d57c53a45d6da63a77b618a45dYu Ping Hu extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 4054427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon ContentResolver.requestSync(amAccount, EmailContent.AUTHORITY, extras); 4064427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon LogUtils.i(LOG_TAG, "requestPing EasOperation %s, %s", 4074427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon amAccount.toString(), extras.toString()); 408ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 409ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu 410ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu} 411