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