EasOperation.java revision 70755e7a47c2199e6f047d5736ad7b63111aae82
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;
20b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Huimport android.content.ContentUris;
21b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Huimport android.content.ContentValues;
22ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport android.content.Context;
23ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport android.content.SyncResult;
24b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Huimport android.net.Uri;
25be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Huimport android.os.Build;
26ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport android.os.Bundle;
272e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdonimport android.telephony.TelephonyManager;
28a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Huimport android.text.TextUtils;
29ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport android.text.format.DateUtils;
30ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
31ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.emailcommon.provider.Account;
32ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.emailcommon.provider.EmailContent;
33ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.emailcommon.provider.HostAuth;
34ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.emailcommon.provider.Mailbox;
35b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Huimport com.android.emailcommon.utility.Utility;
36ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.Eas;
37ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.EasResponse;
38ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.adapter.Serializer;
39be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Huimport com.android.exchange.adapter.Tags;
40ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.exchange.service.EasServerConnection;
41ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport com.android.mail.utils.LogUtils;
42ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
43ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport org.apache.http.HttpEntity;
44b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Huimport org.apache.http.client.methods.HttpUriRequest;
45ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport org.apache.http.entity.ByteArrayEntity;
46ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
47ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Huimport java.io.IOException;
484427badd747b7c172934014b9f95a1be1256f35aMartin Hibdonimport java.util.ArrayList;
49ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
50ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu/**
51ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * Base class for all Exchange operations that use a POST to talk to the server.
52ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu *
53ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * The core of this class is {@link #performOperation}, which provides the skeleton of making
54ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * a request, handling common errors, and setting fields on the {@link SyncResult} if there is one.
55ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * This class abstracts the connection handling from its subclasses and callers.
56ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu *
57ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * A subclass must implement the abstract functions below that create the request and parse the
58ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * response. There are also a set of functions that a subclass may override if it's substantially
59ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * different from the "normal" operation (e.g. most requests use the same request URI, but auto
60ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * discover deviates since it's not account-specific), but the default implementation should suffice
61ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * for most. The subclass must also define a public function which calls {@link #performOperation},
62ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * possibly doing nothing other than that. (I chose to force subclasses to do this, rather than
63ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * provide that function in the base class, in order to force subclasses to consider, for example,
64ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * whether it needs a {@link SyncResult} parameter, and what the proper name for the "doWork"
65ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * function ought to be for the subclass.)
66ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu */
67ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hupublic abstract class EasOperation {
68ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    public static final String LOG_TAG = Eas.LOG_TAG;
69ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
70ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /** The maximum number of server redirects we allow before returning failure. */
71ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    private static final int MAX_REDIRECTS = 3;
72ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
73ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /** Message MIME type for EAS version 14 and later. */
74ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    private static final String EAS_14_MIME_TYPE = "application/vnd.ms-sync.wbxml";
75ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
76328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Error code indicating the operation was cancelled via {@link #abort}. */
77328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    public static final int RESULT_ABORT = -1;
78328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Error code indicating the operation was cancelled via {@link #restart}. */
79328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    public static final int RESULT_RESTART = -2;
80328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Error code indicating the Exchange servers redirected too many times. */
81328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    public static final int RESULT_TOO_MANY_REDIRECTS = -3;
82328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Error code indicating the request failed due to a network problem. */
83328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    public static final int RESULT_REQUEST_FAILURE = -4;
84328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Error code indicating a 403 (forbidden) error. */
85328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    public static final int RESULT_FORBIDDEN = -5;
86328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Error code indicating an unresolved provisioning error. */
87328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    public static final int RESULT_PROVISIONING_ERROR = -6;
88328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Error code indicating an authentication problem. */
89328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    public static final int RESULT_AUTHENTICATION_ERROR = -7;
90b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    /** Error code indicating the client is missing a certificate. */
91b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    public static final int RESULT_CLIENT_CERTIFICATE_REQUIRED = -8;
92b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    /** Error code indicating we don't have a protocol version in common with the server. */
93b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    public static final int RESULT_PROTOCOL_VERSION_UNSUPPORTED = -9;
94328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Error code indicating some other failure. */
95b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    public static final int RESULT_OTHER_FAILURE = -10;
96328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
97ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected final Context mContext;
98328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
99328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /**
100328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * The account id for this operation.
1016f0cf29be849d3a95a9168cb6fa09de12635e818Yu Ping Hu     * NOTE: You will be tempted to add a reference to the {@link Account} here. Resist.
1026f0cf29be849d3a95a9168cb6fa09de12635e818Yu Ping Hu     * It's too easy for that to lead to creep and stale data.
103328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     */
1046f0cf29be849d3a95a9168cb6fa09de12635e818Yu Ping Hu    protected final long mAccountId;
105ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    private final EasServerConnection mConnection;
106ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
1071df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Hu    // TODO: Make this private again when EasSyncHandler is converted to be a subclass.
1081df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Hu    protected EasOperation(final Context context, final long accountId,
109b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu            final EasServerConnection connection) {
110b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        mContext = context;
111b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        mAccountId = accountId;
112b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        mConnection = connection;
113b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    }
114b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu
115ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected EasOperation(final Context context, final Account account, final HostAuth hostAuth) {
116328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        this(context, account.mId, new EasServerConnection(context, account, hostAuth));
117ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
118ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
119ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected EasOperation(final Context context, final Account account) {
120ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        this(context, account, HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv));
121ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
122ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
123b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    /**
124b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * This constructor is for use by operations that are created by other operations, e.g.
125b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * {@link EasProvision}.
126b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * @param parentOperation The {@link EasOperation} that is creating us.
127b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     */
128b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    protected EasOperation(final EasOperation parentOperation) {
129b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        this(parentOperation.mContext, parentOperation.mAccountId, parentOperation.mConnection);
130328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
131ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
132ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
133ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * Request that this operation terminate. Intended for use by the sync service to interrupt
134ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * running operations, primarily Ping.
135ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
136ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    public final void abort() {
137ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        mConnection.stop(EasServerConnection.STOPPED_REASON_ABORT);
138ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
139ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
140ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
141ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * Request that this operation restart. Intended for use by the sync service to interrupt
142ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * running operations, primarily Ping.
143ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
144ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    public final void restart() {
145ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        mConnection.stop(EasServerConnection.STOPPED_REASON_RESTART);
146ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
147ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
148ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
149ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * The skeleton of performing an operation. This function handles all the common code and
150ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * error handling, calling into virtual functions that are implemented or overridden by the
151ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * subclass to do the operation-specific logic.
152328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     *
153328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * The result codes work as follows:
154328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * - Negative values indicate common error codes and are defined above (the various RESULT_*
155328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     *   constants).
156328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * - Non-negative values indicate the result of {@link #handleResponse}. These are obviously
157328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     *   specific to the subclass, and may indicate success or error conditions.
158328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     *
159328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * The common error codes primarily indicate conditions that occur when performing the POST
160328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * itself, such as network errors and handling of the HTTP response. However, some errors that
161328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * can be indicated in the HTTP response code can also be indicated in the payload of the
162328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * response as well, so {@link #handleResponse} should in those cases return the appropriate
163328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * negative result code, which will be handled the same as if it had been indicated in the HTTP
164328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * response code.
165328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     *
166ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @param syncResult If this operation is a sync, the {@link SyncResult} object that should
167ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     *                   be written to for this sync; otherwise null.
168328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * @return A result code for the outcome of this operation, as described above.
169ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
170ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected final int performOperation(final SyncResult syncResult) {
171ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        // We handle server redirects by looping, but we need to protect against too much looping.
172ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        int redirectCount = 0;
173ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
174ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        do {
175b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu            // Perform the HTTP request and handle exceptions.
176ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            final EasResponse response;
177ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            try {
1780f9116d3dfc7bc4210f551858006d4bd956d0cd3Martin Hibdon                if (registerClientCert()) {
1790f9116d3dfc7bc4210f551858006d4bd956d0cd3Martin Hibdon                    response = mConnection.executeHttpUriRequest(makeRequest(), getTimeout());
1800f9116d3dfc7bc4210f551858006d4bd956d0cd3Martin Hibdon                } else {
18139f4a323bc9dd497850e57971aabff97fb035111Paul Sliwowski                    LogUtils.e(LOG_TAG, "Problem registering client cert");
1820f9116d3dfc7bc4210f551858006d4bd956d0cd3Martin Hibdon                    // TODO: Is this the best stat to increment?
1830f9116d3dfc7bc4210f551858006d4bd956d0cd3Martin Hibdon                    if (syncResult != null) {
1840f9116d3dfc7bc4210f551858006d4bd956d0cd3Martin Hibdon                        ++syncResult.stats.numAuthExceptions;
1850f9116d3dfc7bc4210f551858006d4bd956d0cd3Martin Hibdon                    }
1860f9116d3dfc7bc4210f551858006d4bd956d0cd3Martin Hibdon                    return RESULT_CLIENT_CERTIFICATE_REQUIRED;
1870f9116d3dfc7bc4210f551858006d4bd956d0cd3Martin Hibdon                }
188ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            } catch (final IOException e) {
189ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                // If we were stopped, return the appropriate result code.
190ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                switch (mConnection.getStoppedReason()) {
191ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    case EasServerConnection.STOPPED_REASON_ABORT:
192ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                        return RESULT_ABORT;
193ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    case EasServerConnection.STOPPED_REASON_RESTART:
194ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                        return RESULT_RESTART;
195ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    default:
196ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                        break;
197ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                }
198ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                // If we're here, then we had a IOException that's not from a stop request.
199dc15b97b8975b994992d14d2cf3e6c8a80645b5dYu Ping Hu                String message = e.getMessage();
200dc15b97b8975b994992d14d2cf3e6c8a80645b5dYu Ping Hu                if (message == null) {
201dc15b97b8975b994992d14d2cf3e6c8a80645b5dYu Ping Hu                    message = "(no message)";
202dc15b97b8975b994992d14d2cf3e6c8a80645b5dYu Ping Hu                }
203dc15b97b8975b994992d14d2cf3e6c8a80645b5dYu Ping Hu                LogUtils.i(LOG_TAG, "IOException while sending request: %s", message);
204ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                if (syncResult != null) {
205ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    ++syncResult.stats.numIoExceptions;
206ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                }
207ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                return RESULT_REQUEST_FAILURE;
208ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            } catch (final IllegalStateException e) {
209ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                // Subclasses use ISE to signal a hard error when building the request.
2106f0cf29be849d3a95a9168cb6fa09de12635e818Yu Ping Hu                // TODO: Switch away from ISEs.
211ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                LogUtils.e(LOG_TAG, e, "Exception while sending request");
212ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                if (syncResult != null) {
213ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    syncResult.databaseError = true;
214ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                }
215ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                return RESULT_OTHER_FAILURE;
216ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            }
217ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
218ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            // The POST completed, so process the response.
219ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            try {
220328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                final int result;
221ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                // First off, the success case.
222ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                if (response.isSuccess()) {
223ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    try {
224328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        result = handleResponse(response, syncResult);
225328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        if (result >= 0) {
226328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                            return result;
227328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        }
228ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    } catch (final IOException e) {
229ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                        LogUtils.e(LOG_TAG, e, "Exception while handling response");
230ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                        if (syncResult != null) {
2312629e0f0eac5bb6c4d5982bdf65a989b03d46d3dAlon Albert                            ++syncResult.stats.numIoExceptions;
232ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                        }
2332629e0f0eac5bb6c4d5982bdf65a989b03d46d3dAlon Albert                        return RESULT_REQUEST_FAILURE;
234ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    }
235328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                } else {
236328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    result = RESULT_OTHER_FAILURE;
237ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                }
238ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
239328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                // If this operation has distinct handling for 403 errors, do that.
240328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                if (result == RESULT_FORBIDDEN || (response.isForbidden() && handleForbidden())) {
241ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    LogUtils.e(LOG_TAG, "Forbidden response");
242328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    if (syncResult != null) {
243328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        // TODO: Is this the best stat to increment?
244328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        ++syncResult.stats.numAuthExceptions;
245328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    }
246328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    return RESULT_FORBIDDEN;
247328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                }
248328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
249328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                // Handle provisioning errors.
250328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                if (result == RESULT_PROVISIONING_ERROR || response.isProvisionError()) {
251328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    if (handleProvisionError(syncResult, mAccountId)) {
252328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        // The provisioning error has been taken care of, so we should re-do this
253328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        // request.
254328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        continue;
255328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    }
256328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    if (syncResult != null) {
25739f4a323bc9dd497850e57971aabff97fb035111Paul Sliwowski                        LogUtils.e(LOG_TAG, "Issue with provisioning");
258328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        // TODO: Is this the best stat to increment?
259328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        ++syncResult.stats.numAuthExceptions;
260328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    }
261328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    return RESULT_PROVISIONING_ERROR;
262328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                }
263328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
264328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                // Handle authentication errors.
265328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                if (response.isAuthError()) {
266ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    LogUtils.e(LOG_TAG, "Authentication error");
267328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    if (syncResult != null) {
268328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        ++syncResult.stats.numAuthExceptions;
269328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    }
270b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                    if (response.isMissingCertificate()) {
271b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                        return RESULT_CLIENT_CERTIFICATE_REQUIRED;
272b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                    }
273328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    return RESULT_AUTHENTICATION_ERROR;
274ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                }
275ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
276328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                // Handle redirects.
277328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                if (response.isRedirectError()) {
278328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    ++redirectCount;
279328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    mConnection.redirectHostAuth(response.getRedirectAddress());
280328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    // Note that unlike other errors, we do NOT return here; we just keep looping.
281328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                } else {
282328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    // All other errors.
2830c899a81b9b6000a4dc2766415d6ead33641f679Yu Ping Hu                    LogUtils.e(LOG_TAG, "Generic error for operation %s: status %d, result %d",
2840c899a81b9b6000a4dc2766415d6ead33641f679Yu Ping Hu                            getCommand(), response.getStatus(), result);
285ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    if (syncResult != null) {
286328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        // TODO: Is this the best stat to increment?
287328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                        ++syncResult.stats.numIoExceptions;
288ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    }
289ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    return RESULT_OTHER_FAILURE;
290ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                }
291ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            } finally {
292ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                response.close();
293ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            }
294ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        } while (redirectCount < MAX_REDIRECTS);
295ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
296328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // Non-redirects return immediately after handling, so the only way to reach here is if we
297ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        // looped too many times.
298ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        LogUtils.e(LOG_TAG, "Too many redirects");
299ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        if (syncResult != null) {
300ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu           syncResult.tooManyRetries = true;
301ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        }
302ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        return RESULT_TOO_MANY_REDIRECTS;
303ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
304ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
305ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
306b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * Reset the protocol version to use for this connection. If it's changed, and our account is
307b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * persisted, also write back the changes to the DB.
308b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * @param protocolVersion The new protocol version to use, as a string.
309ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
310b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    protected final void setProtocolVersion(final String protocolVersion) {
311b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        if (mConnection.setProtocolVersion(protocolVersion) && mAccountId != Account.NOT_SAVED) {
312b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu            final Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, mAccountId);
313b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu            final ContentValues cv = new ContentValues(2);
314b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu            if (getProtocolVersion() >= 12.0) {
315b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                final int oldFlags = Utility.getFirstRowInt(mContext, uri,
316b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                        Account.ACCOUNT_FLAGS_PROJECTION, null, null, null,
317b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                        Account.ACCOUNT_FLAGS_COLUMN_FLAGS, 0);
318b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                final int newFlags = oldFlags
319b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                        | Account.FLAGS_SUPPORTS_GLOBAL_SEARCH + Account.FLAGS_SUPPORTS_SEARCH;
320b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                if (oldFlags != newFlags) {
321b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                    cv.put(EmailContent.AccountColumns.FLAGS, newFlags);
322b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                }
323b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu            }
324b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu            cv.put(EmailContent.AccountColumns.PROTOCOL_VERSION, protocolVersion);
325b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu            mContext.getContentResolver().update(uri, cv, null, null);
326b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        }
327b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    }
328ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
329b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    /**
330b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * Create the request object for this operation.
331b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * Most operations use a POST, but some use other request types (e.g. Options).
332b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * @return An {@link HttpUriRequest}.
333b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * @throws IOException
334b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     */
335b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    private final HttpUriRequest makeRequest() throws IOException {
336b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        final String requestUri = getRequestUri();
337b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        if (requestUri == null) {
338b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu            return mConnection.makeOptions();
339b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        }
340b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        return mConnection.makePost(requestUri, getRequestEntity(),
341b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu                getRequestContentType(), addPolicyKeyHeaderToRequest());
342ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
343ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
344ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
345ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * The following functions MUST be overridden by subclasses; these are things that are unique
346ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * to each operation.
347ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
348ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
349ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
350ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * Get the name of the operation, used as the "Cmd=XXX" query param in the request URI. Note
3510c899a81b9b6000a4dc2766415d6ead33641f679Yu Ping Hu     * that if you override {@link #getRequestUri}, then this function may be unused for normal
3520c899a81b9b6000a4dc2766415d6ead33641f679Yu Ping Hu     * operation, but all subclasses should return something non-null for use with logging.
3530c899a81b9b6000a4dc2766415d6ead33641f679Yu Ping Hu     * @return The name of the command for this operation as defined by the EAS protocol, or for
3540c899a81b9b6000a4dc2766415d6ead33641f679Yu Ping Hu     *         commands that don't need it, a suitable descriptive name for logging.
355ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
356ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected abstract String getCommand();
357ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
358ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
359b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * Build the {@link HttpEntity} which is used to construct the POST. Typically this function
360ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * will build the Exchange request using a {@link Serializer} and then call {@link #makeEntity}.
361b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * If the subclass is not using a POST, then it should override this to return null.
362ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @return The {@link HttpEntity} to pass to {@link EasServerConnection#makePost}.
363ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @throws IOException
364ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
365ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected abstract HttpEntity getRequestEntity() throws IOException;
366ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
367ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
368ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * Parse the response from the Exchange perform whatever actions are dictated by that.
369ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @param response The {@link EasResponse} to our request.
370ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @param syncResult The {@link SyncResult} object for this operation, or null if we're not
371ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     *                   handling a sync.
372328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * @return A result code. Non-negative values are returned directly to the caller; negative
373328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     *         values
374328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     *
375328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * that is returned to the caller of {@link #performOperation}.
376ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @throws IOException
377ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
378ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected abstract int handleResponse(final EasResponse response, final SyncResult syncResult)
379ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            throws IOException;
380ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
381ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
382ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * The following functions may be overriden by a subclass, but most operations will not need
383ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * to do so.
384ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
385ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
386ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
387ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * Get the URI for the Exchange server and this operation. Most (signed in) operations need
388ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * not override this; the notable operation that needs to override it is auto-discover.
389ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @return
390ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
391ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected String getRequestUri() {
392ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        return mConnection.makeUriString(getCommand());
393ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
394ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
395ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
396ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @return Whether to set the X-MS-PolicyKey header. Only Ping does not want this header.
397ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
398ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected boolean addPolicyKeyHeaderToRequest() {
399ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        return true;
400ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
401ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
402ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
403ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @return The content type of this request.
404ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
405ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected String getRequestContentType() {
406ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        return EAS_14_MIME_TYPE;
407ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
408ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
409ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
410ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @return The timeout to use for the POST.
411ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
412ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected long getTimeout() {
413ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        return 30 * DateUtils.SECOND_IN_MILLIS;
414ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
415ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
416ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
417ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * If 403 responses should be handled in a special way, this function should be overridden to
418ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * do that.
419ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @return Whether we handle 403 responses; if false, then treat 403 as a provisioning error.
420ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
421ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected boolean handleForbidden() {
422ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        return false;
423ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
424ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
425ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
426328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * Handle a provisioning error. Subclasses may override this to do something different, e.g.
427328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * to validate rather than actually do the provisioning.
428328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * @param syncResult
429328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * @param accountId
430328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * @return
431328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     */
432328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    protected boolean handleProvisionError(final SyncResult syncResult, final long accountId) {
433b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        final EasProvision provisionOperation = new EasProvision(this);
434328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        return provisionOperation.provision(syncResult, accountId);
435328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
436328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
437328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /**
438328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * Convenience methods for subclasses to use.
439328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     */
440328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
441328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /**
442ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * Convenience method to make an {@link HttpEntity} from {@link Serializer}.
443ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
444ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected final HttpEntity makeEntity(final Serializer s) {
445ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        return new ByteArrayEntity(s.toByteArray());
446ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
447ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
448328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /**
449b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * Check whether we should ask the server what protocol versions it supports and set this
450b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * account to use that version.
451b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * @return Whether we need a new protocol version from the server.
452b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     */
453b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    protected final boolean shouldGetProtocolVersion() {
454b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        // TODO: Find conditions under which we should check other than not having one yet.
455b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        return !mConnection.isProtocolVersionSet();
456b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    }
457b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu
458b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    /**
459328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * @return The protocol version to use.
460328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     */
461ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected final double getProtocolVersion() {
462ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        return mConnection.getProtocolVersion();
463ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
464ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
465ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
466328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * @return Our useragent.
467328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     */
468328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    protected final String getUserAgent() {
469328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        return mConnection.getUserAgent();
470328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
471328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
472328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /**
473b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * @return Whether we succeeeded in registering the client cert.
474b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     */
475b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    protected final boolean registerClientCert() {
476b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        return mConnection.registerClientCert();
477b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    }
478b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu
479b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    /**
480be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu     * Add the device information to the current request.
481be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu     * @param s The {@link Serializer} for our current request.
482be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu     * @throws IOException
483be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu     */
484be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu    protected final void addDeviceInformationToSerlializer(final Serializer s) throws IOException {
4852e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        final TelephonyManager tm = (TelephonyManager)mContext.getSystemService(
4862e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon                Context.TELEPHONY_SERVICE);
4872e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        final String deviceId;
4882e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        final String phoneNumber;
4892e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        final String operator;
4902e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        if (tm != null) {
4912e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon            deviceId = tm.getDeviceId();
4922e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon            phoneNumber = tm.getLine1Number();
493a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu            // TODO: This is not perfect and needs to be improved, for at least two reasons:
494a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu            // 1) SIM cards can override this name.
495a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu            // 2) We don't resend this info to the server when we change networks.
496a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu            final String operatorName = tm.getNetworkOperatorName();
497a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu            final String operatorNumber = tm.getNetworkOperator();
498a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu            if (!TextUtils.isEmpty(operatorName) && !TextUtils.isEmpty(operatorNumber)) {
499a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu                operator = operatorName + " (" + operatorNumber + ")";
500a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu            } else if (!TextUtils.isEmpty(operatorName)) {
501a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu                operator = operatorName;
502a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu            } else {
503a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu                operator = operatorNumber;
504a75ec1c369a613ef7aad62a8ffe08707e91673f5Yu Ping Hu            }
5052e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        } else {
5062e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon            deviceId = null;
5072e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon            phoneNumber = null;
5082e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon            operator = null;
5092e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        }
5102e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon
5112e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        // TODO: Right now, we won't send this information unless the device is provisioned again.
5122e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        // Potentially, this means that our phone number could be out of date if the user
5132e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        // switches sims. Is there something we can do to force a reprovision?
514be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        s.start(Tags.SETTINGS_DEVICE_INFORMATION).start(Tags.SETTINGS_SET);
515be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        s.data(Tags.SETTINGS_MODEL, Build.MODEL);
5162e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        if (deviceId != null) {
5172e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon            s.data(Tags.SETTINGS_IMEI, tm.getDeviceId());
5182e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        }
51970755e7a47c2199e6f047d5736ad7b63111aae82Yu Ping Hu        // Set the device friendly name, if we have one.
52070755e7a47c2199e6f047d5736ad7b63111aae82Yu Ping Hu        // TODO: Longer term, this should be done without a provider call.
52170755e7a47c2199e6f047d5736ad7b63111aae82Yu Ping Hu        final Bundle bundle = mContext.getContentResolver().call(
52270755e7a47c2199e6f047d5736ad7b63111aae82Yu Ping Hu                EmailContent.CONTENT_URI, EmailContent.DEVICE_FRIENDLY_NAME, null, null);
52370755e7a47c2199e6f047d5736ad7b63111aae82Yu Ping Hu        if (bundle != null) {
52470755e7a47c2199e6f047d5736ad7b63111aae82Yu Ping Hu            final String friendlyName = bundle.getString(EmailContent.DEVICE_FRIENDLY_NAME);
52570755e7a47c2199e6f047d5736ad7b63111aae82Yu Ping Hu            if (!TextUtils.isEmpty(friendlyName)) {
52670755e7a47c2199e6f047d5736ad7b63111aae82Yu Ping Hu                s.data(Tags.SETTINGS_FRIENDLY_NAME, friendlyName);
52770755e7a47c2199e6f047d5736ad7b63111aae82Yu Ping Hu            }
52870755e7a47c2199e6f047d5736ad7b63111aae82Yu Ping Hu        }
529be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        s.data(Tags.SETTINGS_OS, "Android " + Build.VERSION.RELEASE);
5302e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        if (phoneNumber != null) {
5312e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon            s.data(Tags.SETTINGS_PHONE_NUMBER, phoneNumber);
5322e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        }
5332e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        // TODO: Consider setting this, but make sure we know what it's used for.
5342e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        // If the user changes the device's locale and we don't do a reprovision, the server's
5352e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        // idea of the language will be wrong. Since we're not sure what this is used for,
5362e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        // right now we're leaving it out.
5372e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        //s.data(Tags.SETTINGS_OS_LANGUAGE, Locale.getDefault().getDisplayLanguage());
538be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        s.data(Tags.SETTINGS_USER_AGENT, getUserAgent());
5392e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        if (operator != null) {
5402e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon            s.data(Tags.SETTINGS_MOBILE_OPERATOR, operator);
5412e47c34cba847b47992420f8634ae51dddc90cd5Martin Hibdon        }
542be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        s.end().end();  // SETTINGS_SET, SETTINGS_DEVICE_INFORMATION
543be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu    }
544be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu
545be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu    /**
546ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * Convenience method for adding a Message to an account's outbox
547ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @param account The {@link Account} from which to send the message.
548ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @param msg the message to send
549ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
550328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    protected final void sendMessage(final Account account, final EmailContent.Message msg) {
551ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        long mailboxId = Mailbox.findMailboxOfType(mContext, account.mId, Mailbox.TYPE_OUTBOX);
552ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        // TODO: Improve system mailbox handling.
553ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        if (mailboxId == Mailbox.NO_MAILBOX) {
554ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            LogUtils.d(LOG_TAG, "No outbox for account %d, creating it", account.mId);
555ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            final Mailbox outbox =
556ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu                    Mailbox.newSystemMailbox(mContext, account.mId, Mailbox.TYPE_OUTBOX);
557ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            outbox.save(mContext);
558ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu            mailboxId = outbox.mId;
559ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        }
560ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        msg.mMailboxKey = mailboxId;
561ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        msg.mAccountKey = account.mId;
562ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        msg.save(mContext);
563ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        requestSyncForMailbox(new android.accounts.Account(account.mEmailAddress,
5644427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon                Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), mailboxId);
565ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
566ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu
567ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    /**
568ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * Issue a {@link android.content.ContentResolver#requestSync} for a specific mailbox.
569ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @param amAccount The {@link android.accounts.Account} for the account we're pinging.
570ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     * @param mailboxId The id of the mailbox that needs to sync.
571ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu     */
572ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    protected static void requestSyncForMailbox(final android.accounts.Account amAccount,
5734427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon            final long mailboxId) {
5744427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon        final Bundle extras = Mailbox.createSyncBundle(mailboxId);
5754427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon        ContentResolver.requestSync(amAccount, EmailContent.AUTHORITY, extras);
5764427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon        LogUtils.i(LOG_TAG, "requestSync EasOperation requestSyncForMailbox %s, %s",
5774427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon                amAccount.toString(), extras.toString());
5784427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon    }
5794427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon
5804427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon    protected static void requestSyncForMailboxes(final android.accounts.Account amAccount,
5814427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon            final ArrayList<Long> mailboxIds) {
5824427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon        final Bundle extras = Mailbox.createSyncBundle(mailboxIds);
5834427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon        ContentResolver.requestSync(amAccount, EmailContent.AUTHORITY, extras);
5844427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon        LogUtils.i(LOG_TAG, "requestSync EasOperation requestSyncForMailboxes  %s, %s",
5854427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon                amAccount.toString(), extras.toString());
5864427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon    }
5874427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon
5884427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon    /**
5894427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon     * RequestNoOpSync
5904427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon     * This requests a sync for a particular authority purely so that that account
5914427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon     * in settings will recognize that it is trying to sync, and will display the
5924427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon     * appropriate UI. In fact, all exchange data syncing actually happens through the
5934427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon     * EmailSyncAdapterService.
5944427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon     * @param amAccount
5954427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon     * @param authority
5964427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon     */
5974427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon    protected static void requestNoOpSync(final android.accounts.Account amAccount,
5984427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon            final String authority) {
599ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        final Bundle extras = new Bundle(1);
6004427badd747b7c172934014b9f95a1be1256f35aMartin Hibdon        extras.putBoolean(Mailbox.SYNC_EXTRA_NOOP, true);
601ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        ContentResolver.requestSync(amAccount, authority, extras);
6023eef378426c7c88608f53f5a268baed40259ccf6Alon Albert        LogUtils.d(LOG_TAG, "requestSync EasOperation requestNoOpSync %s, %s",
6039c7165d4c6b90101b781f90b17451efd42a17929Martin Hibdon                amAccount.toString(), extras.toString());
604ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu    }
605ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu}
606