1328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu/*
2328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * Copyright (C) 2013 The Android Open Source Project
3328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu *
4328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * Licensed under the Apache License, Version 2.0 (the "License");
5328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * you may not use this file except in compliance with the License.
6328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * You may obtain a copy of the License at
7328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu *
8328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu *      http://www.apache.org/licenses/LICENSE-2.0
9328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu *
10328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * Unless required by applicable law or agreed to in writing, software
11328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * distributed under the License is distributed on an "AS IS" BASIS,
12328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * See the License for the specific language governing permissions and
14328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * limitations under the License.
15328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu */
16328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
17328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hupackage com.android.exchange.eas;
18328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
19f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Leeimport android.content.ContentValues;
201df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Huimport android.content.Context;
21328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
226c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Huimport com.android.emailcommon.provider.Account;
23f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Leeimport com.android.emailcommon.provider.EmailContent;
24328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.emailcommon.provider.Policy;
25328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.emailcommon.service.PolicyServiceProxy;
26328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.exchange.Eas;
27328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.exchange.EasResponse;
28328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.exchange.adapter.ProvisionParser;
29328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.exchange.adapter.Serializer;
30328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.exchange.adapter.Tags;
311df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Huimport com.android.exchange.service.EasServerConnection;
32328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.mail.utils.LogUtils;
33328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
34328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport org.apache.http.HttpEntity;
35328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
36328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport java.io.IOException;
37328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
38328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu/**
39328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * Implements the EAS Provision protocol.
40328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu *
41328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * Provisioning actually consists of two server interactions:
42328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * 1) Ask the server for the required policies.
43328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * 2) Acknowledge our disposition for enforcing those policies.
44328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu *
45328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * The structure of the requests and response are essentially the same for both, so we use the
46328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * same code and vary slightly based on which one we're doing. Also, provisioning responses can tell
47328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * us to wipe the device, so we need to handle that too.
48328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * TODO: Make it possible to ack separately, possibly by splitting into separate operations.
49328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * See http://msdn.microsoft.com/en-us/library/ee203567(v=exchg.80).aspx for more details.
50328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu */
51328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hupublic class EasProvision extends EasOperation {
52328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
53110837ebff288a75f9bda067c38e2c46797d99b5Alon Albert    private static final String LOG_TAG = Eas.LOG_TAG;
54328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
55328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** The policy type for versions of EAS prior to 2007. */
56be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu    public static final String EAS_2_POLICY_TYPE = "MS-WAP-Provisioning-XML";
57328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** The policy type for versions of EAS starting with 2007. */
58be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu    public static final String EAS_12_POLICY_TYPE = "MS-EAS-Provisioning-WBXML";
59328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
60328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** The EAS protocol Provision status for "we implement all of the policies" */
61a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    static final String PROVISION_STATUS_OK = "1";
62328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** The EAS protocol Provision status meaning "we partially implement the policies" */
63a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    static final String PROVISION_STATUS_PARTIAL = "2";
64328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
65328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Value for {@link #mPhase} indicating we're performing the initial request. */
66a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    static final int PHASE_INITIAL = 0;
67328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Value for {@link #mPhase} indicating we're performing the acknowledgement request. */
68a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    static final int PHASE_ACKNOWLEDGE = 1;
69328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Value for {@link #mPhase} indicating we're performing the acknowledgement for a wipe. */
70a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    static final int PHASE_WIPE = 2;
71328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
72328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /**
73328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * This operation doesn't use public result codes because ultimately the operation answers
74328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * a yes/no question. These result codes are used internally only to communicate from
75328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * {@link #handleResponse}.
76328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     */
77328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
78328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Result code indicating the server's policy can be fully supported. */
79328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    private static final int RESULT_POLICY_SUPPORTED = 1;
80328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Result code indicating the server's policy cannot be fully supported. */
81328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    private static final int RESULT_POLICY_UNSUPPORTED = 2;
82328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /** Result code indicating the server sent a remote wipe directive. */
83328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    private static final int RESULT_REMOTE_WIPE = 3;
84328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
85328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    private Policy mPolicy;
86328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    private String mPolicyKey;
87328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    private String mStatus;
88328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
89328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /**
90328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * Because this operation supports variants of the request and parsing, and {@link EasOperation}
91328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * has no way to communicate this into {@link #performOperation}, we use this member variable
92328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * to vary how {@link #getRequestEntity} and {@link #handleResponse} work.
93328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     */
94328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    private int mPhase;
95328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
966c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu    public EasProvision(final Context context, final Account account,
971df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Hu            final EasServerConnection connection) {
986c4254903d2f42836c5b74a934e54441ccee6dbeYu Ping Hu        super(context, account, connection);
991df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Hu        mPolicy = null;
1001df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Hu        mPolicyKey = null;
1011df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Hu        mStatus = null;
1021df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Hu        mPhase = 0;
1031df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Hu    }
1041df4a493b2efa34fce4bd8a70aca57203b4ed037Yu Ping Hu
105b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    public EasProvision(final EasOperation parentOperation) {
106b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        super(parentOperation);
107328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        mPolicy = null;
108328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        mPolicyKey = null;
109328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        mStatus = null;
110328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        mPhase = 0;
111328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
112328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
1138c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu    private int performInitialRequest() {
114328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        mPhase = PHASE_INITIAL;
1158c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        return performOperation();
116328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
117328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
1188c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu    private void performAckRequestForWipe() {
119328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        mPhase = PHASE_WIPE;
1208c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        performOperation();
121328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
122328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
1238c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu    private int performAckRequest(final boolean isPartial) {
124328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        mPhase = PHASE_ACKNOWLEDGE;
125328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        mStatus = isPartial ? PROVISION_STATUS_PARTIAL : PROVISION_STATUS_OK;
1268c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        return performOperation();
127328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
128328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
129328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /**
130328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * Make the provisioning calls to determine if we can handle the required policy.
131b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu     * @return The {@link Policy} if we support it, or null otherwise.
132328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     */
133b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu    public final Policy test() {
1348c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        int result = performInitialRequest();
135328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        if (result == RESULT_POLICY_UNSUPPORTED) {
136328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            // Check if the server will permit partial policies.
1378c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            result = performAckRequest(true);
138328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
139b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        if (result == RESULT_POLICY_SUPPORTED) {
140be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu            // The server is ok with us not supporting everything, so clear the unsupported ones.
141be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu            mPolicy.mProtocolPoliciesUnsupported = null;
142b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu        }
143be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        return (result == RESULT_POLICY_SUPPORTED || result == RESULT_POLICY_UNSUPPORTED)
144be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu                ? mPolicy : null;
145328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
146328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
147328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /**
148f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee     * Write the max attachment size that came out of the policy to the Account table in the db.
149f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee     * Once this value is written, the mapping to Account.Settings.MAX_ATTACHMENT_SIZE was
150f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee     * added to point to this column in this table.
151f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee     * @param maxAttachmentSize The max attachment size value that we want to write to the db.
152f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee     */
153f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee    private void storeMaxAttachmentSize(final int maxAttachmentSize) {
154f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee        final ContentValues values = new ContentValues(1);
155f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee        values.put(EmailContent.AccountColumns.MAX_ATTACHMENT_SIZE, maxAttachmentSize);
156f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee        Account.update(mContext, Account.CONTENT_URI, getAccountId(), values);
157f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee    }
158f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee
159f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee    /**
160328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * Get the required policy from the server and enforce it.
161328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * @return Whether we succeeded in provisioning this account.
162328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     */
1638c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu    public final boolean provision() {
1648c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        final int result = performInitialRequest();
1658c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        final long accountId = getAccountId();
166328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
167328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        if (result < 0) {
168328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            return false;
169328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
170328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
171328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        if (result == RESULT_REMOTE_WIPE) {
1728c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            performAckRequestForWipe();
173328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            LogUtils.i(LOG_TAG, "Executing remote wipe");
174328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            PolicyServiceProxy.remoteWipe(mContext);
175328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            return false;
176328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
177328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
178f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee        // Even before the policy is accepted, we can honor this setting since it has nothing
179f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee        // to do with the device policy manager and is requested by the Exchange server.
1802408dfa83cea2d31e820a3309fc8627ed065cd12Yu Ping Hu        // TODO: This was an error, this is minimum change to disable it.
1812408dfa83cea2d31e820a3309fc8627ed065cd12Yu Ping Hu        //storeMaxAttachmentSize(mPolicy.mMaxAttachmentSize);
182f4a8a08aee041db51a8baa9b64a4cffc1c83a6e6Anthony Lee
183328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // Apply the policies (that we support) with the temporary key.
184f4b85896898ab862ea2c94fc147df363a78df14cJay Shrauner        if (mPolicy != null) {
185f4b85896898ab862ea2c94fc147df363a78df14cJay Shrauner            mPolicy.mProtocolPoliciesUnsupported = null;
186f4b85896898ab862ea2c94fc147df363a78df14cJay Shrauner        }
187328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        PolicyServiceProxy.setAccountPolicy(mContext, accountId, mPolicy, null);
188328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        if (!PolicyServiceProxy.isActive(mContext, mPolicy)) {
189328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            return false;
190328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
191328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
192328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // Acknowledge to the server and make sure all's well.
1938c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu        if (performAckRequest(result == RESULT_POLICY_UNSUPPORTED) == RESULT_POLICY_UNSUPPORTED) {
194328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            return false;
195328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
196328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
197328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // Write the final policy key to the Account.
198328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        PolicyServiceProxy.setAccountPolicy(mContext, accountId, mPolicy, mPolicyKey);
199be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu
200be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        // For 12.1 and 14.0, after provisioning we need to also send the device information via
201be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        // the Settings command.
202be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        // See the comments for EasSettings for more details.
203be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        final double version = getProtocolVersion();
204be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        if (version == Eas.SUPPORTED_PROTOCOL_EX2007_SP1_DOUBLE
205be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu                || version == Eas.SUPPORTED_PROTOCOL_EX2010_DOUBLE) {
206be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu            final EasSettings settingsOperation = new EasSettings(this);
2078c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu            if (!settingsOperation.sendDeviceInformation()) {
2082e8ce13ff0b47f2b0b2f06541a0c155e0727a40dYu Ping Hu                // TODO: Do something more useful when the settings command fails.
2092e8ce13ff0b47f2b0b2f06541a0c155e0727a40dYu Ping Hu                // The consequence here is that the server will not have device info.
2102e8ce13ff0b47f2b0b2f06541a0c155e0727a40dYu Ping Hu                // However, this is NOT a provisioning failure.
211be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu            }
212be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu        }
213be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu
214328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        return true;
215328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
216328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
217328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    @Override
218328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    protected String getCommand() {
219328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        return "Provision";
220328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
221328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
222a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    /**
223a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * Add the device information to the current request.
224a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * @param context The {@link Context} for the current device.
225a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * @param userAgent The user agent string that our connection uses.
226a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * @param policyKey EAS specific tag for Provision requests.
227a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * @param policyType EAS specific tag for Provision requests.
228a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * @param status The status value that we are sending to the server in our request.
229a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * @param phase The phase of the provisioning process this requests is built for.
230a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * @param protocolVersion The version of the EAS protocol that we should speak.
231a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * @return The {@link Serializer} containing the payload for this request.
232a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     */
233a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    protected static Serializer generateRequestEntitySerializer(
234a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            final Context context, final String userAgent, final String policyKey,
235a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            final String policyType, final String status, final int phase,
236a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            final double protocolVersion) throws IOException {
237328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        final Serializer s = new Serializer();
238328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        s.start(Tags.PROVISION_PROVISION);
239328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
240328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // When requesting the policy in 14.1, we also need to send device information.
241a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee        if (phase == PHASE_INITIAL &&
242a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee                protocolVersion >= Eas.SUPPORTED_PROTOCOL_EX2010_SP1_DOUBLE) {
243a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            // The "inner" version of this function is being used because it is
244a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            // re-entrant and can be unit tested easier.  Until we are unit testing
245a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            // everything, the other version of this function still lives so that
246a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            // we are disrupting as little code as possible for now.
247a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            expandedAddDeviceInformationToSerializer(s, context, userAgent);
248328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
249a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee        if (phase == PHASE_WIPE) {
250328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            s.start(Tags.PROVISION_REMOTE_WIPE);
251328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            s.data(Tags.PROVISION_STATUS, PROVISION_STATUS_OK);
252a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            s.end(); // PROVISION_REMOTE_WIPE
253a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee        } else {
254a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            s.start(Tags.PROVISION_POLICIES);
255a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            s.start(Tags.PROVISION_POLICY);
256a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            s.data(Tags.PROVISION_POLICY_TYPE, policyType);
257a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            // When acknowledging a policy, we tell the server whether we applied the policy.
258a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            if (phase == PHASE_ACKNOWLEDGE) {
259a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee                s.data(Tags.PROVISION_POLICY_KEY, policyKey);
260a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee                s.data(Tags.PROVISION_STATUS, status);
261a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            }
262a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee            s.end().end(); // PROVISION_POLICY, PROVISION_POLICIES,
263328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
264a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee        s.end().done(); // PROVISION_PROVISION
265a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee        return s;
266a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    }
267328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
268a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    /**
269a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * Generates a request entity based on the type of request and our current context.
270a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     * @return The {@link HttpEntity} that was generated for this request.
271a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee     */
272a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    @Override
273a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee    protected HttpEntity getRequestEntity() throws IOException {
274a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee        final String policyType = getPolicyType();
275a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee        final String userAgent = getUserAgent();
276a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee        final double protocolVersion = getProtocolVersion();
277a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee        final Serializer s = generateRequestEntitySerializer(mContext, userAgent, mPolicyKey,
278a09e6cc2e8fca144de4d0b69f129b177f4a3219bAnthony Lee                policyType, mStatus, mPhase, protocolVersion);
279328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        return makeEntity(s);
280328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
281328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
282328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    @Override
2838c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu    protected int handleResponse(final EasResponse response) throws IOException {
284328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        final ProvisionParser pp = new ProvisionParser(mContext, response.getInputStream());
285328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // If this is the response for a remote wipe ack, it doesn't have anything useful in it.
286328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // Just go ahead and return now.
287328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        if (mPhase == PHASE_WIPE) {
288328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            return RESULT_REMOTE_WIPE;
289328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
290328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
291328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        if (!pp.parse()) {
292328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            throw new IOException("Error while parsing response");
293328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
294328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
295328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // What we care about in the response depends on what phase we're in.
296328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        if (mPhase == PHASE_INITIAL) {
297328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            if (pp.getRemoteWipe()) {
298328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                return RESULT_REMOTE_WIPE;
299328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            }
300328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            mPolicy = pp.getPolicy();
301328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            mPolicyKey = pp.getSecuritySyncKey();
302328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
303328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            return (pp.hasSupportablePolicySet()
304328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                    ? RESULT_POLICY_SUPPORTED : RESULT_POLICY_UNSUPPORTED);
305328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
306328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
307328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        if (mPhase == PHASE_ACKNOWLEDGE) {
308328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            mPolicyKey = pp.getSecuritySyncKey();
309328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu            return (mPolicyKey != null ? RESULT_POLICY_SUPPORTED : RESULT_POLICY_UNSUPPORTED);
310328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        }
311328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
312328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // Note: this should be unreachable, but the compiler doesn't know it.
313328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // If we somehow get here, act like we can't do anything.
314328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        return RESULT_POLICY_UNSUPPORTED;
315328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
316328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
317328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    @Override
3188c95506ad96f5990d5e4d4ca86b05ec95dd4b1d6Yu Ping Hu    protected boolean handleProvisionError() {
319328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        // If we get a provisioning error while doing provisioning, we should not recurse.
320328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        return false;
321328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
322328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu
323328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    /**
324328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     * @return The policy type for this connection.
325328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu     */
326328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    private final String getPolicyType() {
327328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu        return (getProtocolVersion() >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) ?
328328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu                EAS_12_POLICY_TYPE : EAS_2_POLICY_TYPE;
329328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu    }
330328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu}
331