1c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen/*
2c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * Copyright (C) 2014 The Android Open Source Project
3c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen *
4c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * Licensed under the Apache License, Version 2.0 (the "License");
5c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * you may not use this file except in compliance with the License.
6c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * You may obtain a copy of the License at
7c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen *
8c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen *      http://www.apache.org/licenses/LICENSE-2.0
9c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen *
10c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * Unless required by applicable law or agreed to in writing, software
11c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * distributed under the License is distributed on an "AS IS" BASIS,
12c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * See the License for the specific language governing permissions and
14c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * limitations under the License.
15c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen */
16c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen
17c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wenpackage com.android.mms.service;
18c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen
19c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wenimport android.app.Activity;
20c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wenimport android.app.PendingIntent;
21c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wenimport android.content.Context;
22c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wenimport android.content.Intent;
233a14e46a22e95062102a19c955a819bf239dbc52Ye Wenimport android.net.Uri;
24b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wenimport android.os.Bundle;
251b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastryimport android.service.carrier.CarrierMessagingService;
261b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastryimport android.service.carrier.ICarrierMessagingCallback;
274fd5a8951574cb8a74126c41ec890374eb09e8b9Ye Wenimport android.telephony.SmsManager;
284467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseriimport android.telephony.TelephonyManager;
294467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseriimport android.text.TextUtils;
30c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen
31bdb6fe1cfbc8ecb7ed56798f49de7ba62019fd72Ye Wenimport com.android.mms.service.exception.ApnException;
32bdb6fe1cfbc8ecb7ed56798f49de7ba62019fd72Ye Wenimport com.android.mms.service.exception.MmsHttpException;
33bdb6fe1cfbc8ecb7ed56798f49de7ba62019fd72Ye Wenimport com.android.mms.service.exception.MmsNetworkException;
34b07ae2f78ac69a1e7bcfb1ce62e69d7283b46295Ye Wen
35c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen/**
36c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * Base class for MMS requests. This has the common logic of sending/downloading MMS.
37c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen */
38c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wenpublic abstract class MmsRequest {
39c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen    private static final int RETRY_TIMES = 3;
40c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen
41b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen    /**
42b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     * Interface for certain functionalities from MmsService
43b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     */
44b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen    public static interface RequestManager {
45b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen        /**
463cf9a9481b8e95d0fb654d083b06ee9a23a8e4e8Ye Wen         * Enqueue an MMS request
47b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen         *
48b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen         * @param request the request to enqueue
49b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen         */
503cf9a9481b8e95d0fb654d083b06ee9a23a8e4e8Ye Wen        public void addSimRequest(MmsRequest request);
516f31811156a8aeef55011749c25d7c98d7a7a7ddShishir Agrawal
528c027a60c84d23672647a3775190ee3fa7655b34Ye Wen        /*
538c027a60c84d23672647a3775190ee3fa7655b34Ye Wen         * @return Whether to auto persist received MMS
548c027a60c84d23672647a3775190ee3fa7655b34Ye Wen         */
558c027a60c84d23672647a3775190ee3fa7655b34Ye Wen        public boolean getAutoPersistingPref();
56b83f2faa04dc275b6779644308384459ffcff63fJulian Odell
57b83f2faa04dc275b6779644308384459ffcff63fJulian Odell        /**
58b83f2faa04dc275b6779644308384459ffcff63fJulian Odell         * Read pdu (up to maxSize bytes) from supplied content uri
59b83f2faa04dc275b6779644308384459ffcff63fJulian Odell         * @param contentUri content uri from which to read
60b83f2faa04dc275b6779644308384459ffcff63fJulian Odell         * @param maxSize maximum number of bytes to read
61b83f2faa04dc275b6779644308384459ffcff63fJulian Odell         * @return read pdu (else null in case of error or too big)
62b83f2faa04dc275b6779644308384459ffcff63fJulian Odell         */
63b83f2faa04dc275b6779644308384459ffcff63fJulian Odell        public byte[] readPduFromContentUri(final Uri contentUri, final int maxSize);
64b83f2faa04dc275b6779644308384459ffcff63fJulian Odell
65b83f2faa04dc275b6779644308384459ffcff63fJulian Odell        /**
66b83f2faa04dc275b6779644308384459ffcff63fJulian Odell         * Write pdu to supplied content uri
67b83f2faa04dc275b6779644308384459ffcff63fJulian Odell         * @param contentUri content uri to which bytes should be written
68b83f2faa04dc275b6779644308384459ffcff63fJulian Odell         * @param pdu pdu bytes to write
69b83f2faa04dc275b6779644308384459ffcff63fJulian Odell         * @return true in case of success (else false)
70b83f2faa04dc275b6779644308384459ffcff63fJulian Odell         */
71b83f2faa04dc275b6779644308384459ffcff63fJulian Odell        public boolean writePduToContentUri(final Uri contentUri, final byte[] pdu);
72b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen    }
73b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen
74b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen    // The reference to the pending requests manager (i.e. the MmsService)
75b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen    protected RequestManager mRequestManager;
7618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen    // The SIM id
77a6b72c46163e5fabe74415d2bfbf877a3941150cWink Saville    protected int mSubId;
7818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen    // The creator app
7918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen    protected String mCreator;
80c984707ecf54d545a4a5809c6ce1d18bf7cee61eYe Wen    // MMS config
814467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri    protected Bundle mMmsConfig;
824467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri    // MMS config overrides that will be applied to mMmsConfig when we eventually load it.
834ed37352fed9c277f602b82998cba619c5b29363Ye Wen    protected Bundle mMmsConfigOverrides;
844467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri    // Context used to get TelephonyManager.
854467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri    protected Context mContext;
86b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen
8722519cf9f57f3cc359ccb84bcd508ae0f9750821Ye Wen    public MmsRequest(RequestManager requestManager, int subId, String creator,
884467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri            Bundle configOverrides, Context context) {
89b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen        mRequestManager = requestManager;
9018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen        mSubId = subId;
9118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen        mCreator = creator;
924ed37352fed9c277f602b82998cba619c5b29363Ye Wen        mMmsConfigOverrides = configOverrides;
934ed37352fed9c277f602b82998cba619c5b29363Ye Wen        mMmsConfig = null;
944467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri        mContext = context;
954ed37352fed9c277f602b82998cba619c5b29363Ye Wen    }
964ed37352fed9c277f602b82998cba619c5b29363Ye Wen
973cf9a9481b8e95d0fb654d083b06ee9a23a8e4e8Ye Wen    public int getSubId() {
983cf9a9481b8e95d0fb654d083b06ee9a23a8e4e8Ye Wen        return mSubId;
993cf9a9481b8e95d0fb654d083b06ee9a23a8e4e8Ye Wen    }
1003cf9a9481b8e95d0fb654d083b06ee9a23a8e4e8Ye Wen
1014ed37352fed9c277f602b82998cba619c5b29363Ye Wen    private boolean ensureMmsConfigLoaded() {
1024ed37352fed9c277f602b82998cba619c5b29363Ye Wen        if (mMmsConfig == null) {
1034ed37352fed9c277f602b82998cba619c5b29363Ye Wen            // Not yet retrieved from mms config manager. Try getting it.
1044467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri            final Bundle config = MmsConfigManager.getInstance().getMmsConfigBySubId(mSubId);
1054ed37352fed9c277f602b82998cba619c5b29363Ye Wen            if (config != null) {
1064467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                mMmsConfig = config;
1074467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                // TODO: Make MmsConfigManager authoritative for user agent and don't consult
1084467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                // TelephonyManager.
1098153aed48a84305533f26c06a07a51bd358cee41Ye Wen                final TelephonyManager telephonyManager =
1104467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                        (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
1118153aed48a84305533f26c06a07a51bd358cee41Ye Wen                final String userAgent = telephonyManager.getMmsUserAgent();
1124467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                if (!TextUtils.isEmpty(userAgent)) {
1134467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                    config.putString(SmsManager.MMS_CONFIG_USER_AGENT, userAgent);
1144467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                }
1158153aed48a84305533f26c06a07a51bd358cee41Ye Wen                final String userAgentProfileUrl = telephonyManager.getMmsUAProfUrl();
1164467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                if (!TextUtils.isEmpty(userAgentProfileUrl)) {
1174467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                    config.putString(SmsManager.MMS_CONFIG_UA_PROF_URL, userAgentProfileUrl);
1184467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                }
1194467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                // Apply overrides
1204467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                if (mMmsConfigOverrides != null) {
1214467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                    mMmsConfig.putAll(mMmsConfigOverrides);
1224467007f09a9f2319ba25aa18e04f54693e6bfa1Jonathan Basseri                }
1234ed37352fed9c277f602b82998cba619c5b29363Ye Wen            }
1244ed37352fed9c277f602b82998cba619c5b29363Ye Wen        }
1254ed37352fed9c277f602b82998cba619c5b29363Ye Wen        return mMmsConfig != null;
126b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen    }
1273a14e46a22e95062102a19c955a819bf239dbc52Ye Wen
128b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen    /**
129b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     * Execute the request
130b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     *
131b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     * @param context The context
132b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     * @param networkManager The network manager to use
133b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     */
134c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen    public void execute(Context context, MmsNetworkManager networkManager) {
1358153aed48a84305533f26c06a07a51bd358cee41Ye Wen        final String requestId = this.toString();
1368153aed48a84305533f26c06a07a51bd358cee41Ye Wen        LogUtil.i(requestId, "Executing...");
1374ed37352fed9c277f602b82998cba619c5b29363Ye Wen        int result = SmsManager.MMS_ERROR_UNSPECIFIED;
138848307f23f9b744ad538c23ef2e3b1a98e3bc635Ye Wen        int httpStatusCode = 0;
139c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen        byte[] response = null;
140e03feaba8ca6d25163ff19e433a3a3c460e834e8Ye Wen        // TODO: add mms data channel check back to fast fail if no way to send mms,
141e03feaba8ca6d25163ff19e433a3a3c460e834e8Ye Wen        // when telephony provides such API.
1424ed37352fed9c277f602b82998cba619c5b29363Ye Wen        if (!ensureMmsConfigLoaded()) { // Check mms config
1438153aed48a84305533f26c06a07a51bd358cee41Ye Wen            LogUtil.e(requestId, "mms config is not loaded yet");
1444ed37352fed9c277f602b82998cba619c5b29363Ye Wen            result = SmsManager.MMS_ERROR_CONFIGURATION_ERROR;
1454ed37352fed9c277f602b82998cba619c5b29363Ye Wen        } else if (!prepareForHttpRequest()) { // Prepare request, like reading pdu data from user
1468153aed48a84305533f26c06a07a51bd358cee41Ye Wen            LogUtil.e(requestId, "Failed to prepare for request");
1474ed37352fed9c277f602b82998cba619c5b29363Ye Wen            result = SmsManager.MMS_ERROR_IO_ERROR;
1484ed37352fed9c277f602b82998cba619c5b29363Ye Wen        } else { // Execute
1494ed37352fed9c277f602b82998cba619c5b29363Ye Wen            long retryDelaySecs = 2;
150d0c5b20403b3924cee67e0e72d745b10b0691eacAndre Furtado            // Try multiple times of MMS HTTP request, depending on the error.
151b83f2faa04dc275b6779644308384459ffcff63fJulian Odell            for (int i = 0; i < RETRY_TIMES; i++) {
152c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen                try {
1538153aed48a84305533f26c06a07a51bd358cee41Ye Wen                    networkManager.acquireNetwork(requestId);
154068f2012ef6f6e58f06bfbe7c88604a176d69657Tony Hill                    final String apnName = networkManager.getApnName();
1558153aed48a84305533f26c06a07a51bd358cee41Ye Wen                    LogUtil.d(requestId, "APN name is " + apnName);
156b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                    try {
157068f2012ef6f6e58f06bfbe7c88604a176d69657Tony Hill                        ApnSettings apn = null;
158068f2012ef6f6e58f06bfbe7c88604a176d69657Tony Hill                        try {
1598153aed48a84305533f26c06a07a51bd358cee41Ye Wen                            apn = ApnSettings.load(context, apnName, mSubId, requestId);
160068f2012ef6f6e58f06bfbe7c88604a176d69657Tony Hill                        } catch (ApnException e) {
161068f2012ef6f6e58f06bfbe7c88604a176d69657Tony Hill                            // If no APN could be found, fall back to trying without the APN name
162068f2012ef6f6e58f06bfbe7c88604a176d69657Tony Hill                            if (apnName == null) {
1639094b943daea4dcaf25eb3009158eeae55cfe799Ye Wen                                // If the APN name was already null then don't need to retry
1649094b943daea4dcaf25eb3009158eeae55cfe799Ye Wen                                throw (e);
165068f2012ef6f6e58f06bfbe7c88604a176d69657Tony Hill                            }
1668153aed48a84305533f26c06a07a51bd358cee41Ye Wen                            LogUtil.i(requestId, "No match with APN name: "
1679094b943daea4dcaf25eb3009158eeae55cfe799Ye Wen                                    + apnName + ", try with no name");
1688153aed48a84305533f26c06a07a51bd358cee41Ye Wen                            apn = ApnSettings.load(context, null, mSubId, requestId);
169068f2012ef6f6e58f06bfbe7c88604a176d69657Tony Hill                        }
1708153aed48a84305533f26c06a07a51bd358cee41Ye Wen                        LogUtil.i(requestId, "Using " + apn.toString());
171b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                        response = doHttp(context, networkManager, apn);
172b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                        result = Activity.RESULT_OK;
173b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                        // Success
174b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                        break;
175b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                    } finally {
1768153aed48a84305533f26c06a07a51bd358cee41Ye Wen                        networkManager.releaseNetwork(requestId);
177b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                    }
178b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                } catch (ApnException e) {
1798153aed48a84305533f26c06a07a51bd358cee41Ye Wen                    LogUtil.e(requestId, "APN failure", e);
180b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                    result = SmsManager.MMS_ERROR_INVALID_APN;
181b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                    break;
182b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                } catch (MmsNetworkException e) {
1838153aed48a84305533f26c06a07a51bd358cee41Ye Wen                    LogUtil.e(requestId, "MMS network acquiring failure", e);
184b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                    result = SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS;
185d0c5b20403b3924cee67e0e72d745b10b0691eacAndre Furtado                    break;
186b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                } catch (MmsHttpException e) {
1878153aed48a84305533f26c06a07a51bd358cee41Ye Wen                    LogUtil.e(requestId, "HTTP or network I/O failure", e);
188b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                    result = SmsManager.MMS_ERROR_HTTP_FAILURE;
189848307f23f9b744ad538c23ef2e3b1a98e3bc635Ye Wen                    httpStatusCode = e.getStatusCode();
190b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                    // Retry
191b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                } catch (Exception e) {
1928153aed48a84305533f26c06a07a51bd358cee41Ye Wen                    LogUtil.e(requestId, "Unexpected failure", e);
193b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                    result = SmsManager.MMS_ERROR_UNSPECIFIED;
194c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen                    break;
195c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen                }
196b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                try {
1974ed37352fed9c277f602b82998cba619c5b29363Ye Wen                    Thread.sleep(retryDelaySecs * 1000, 0/*nano*/);
198b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                } catch (InterruptedException e) {}
1994ed37352fed9c277f602b82998cba619c5b29363Ye Wen                retryDelaySecs <<= 1;
200c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen            }
201c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen        }
202848307f23f9b744ad538c23ef2e3b1a98e3bc635Ye Wen        processResult(context, result, response, httpStatusCode);
203b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen    }
204b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen
205b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen    /**
206b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     * Process the result of the completed request, including updating the message status
207b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     * in database and sending back the result via pending intents.
208848307f23f9b744ad538c23ef2e3b1a98e3bc635Ye Wen     *  @param context The context
209b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     * @param result The result code of execution
210b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     * @param response The response body
211848307f23f9b744ad538c23ef2e3b1a98e3bc635Ye Wen     * @param httpStatusCode The optional http status code in case of http failure
212b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     */
213848307f23f9b744ad538c23ef2e3b1a98e3bc635Ye Wen    public void processResult(Context context, int result, byte[] response, int httpStatusCode) {
21422519cf9f57f3cc359ccb84bcd508ae0f9750821Ye Wen        final Uri messageUri = persistIfRequired(context, result, response);
2153a14e46a22e95062102a19c955a819bf239dbc52Ye Wen
216c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen        // Return MMS HTTP request result via PendingIntent
217c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen        final PendingIntent pendingIntent = getPendingIntent();
218c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen        if (pendingIntent != null) {
219b83f2faa04dc275b6779644308384459ffcff63fJulian Odell            boolean succeeded = true;
2203a14e46a22e95062102a19c955a819bf239dbc52Ye Wen            // Extra information to send back with the pending intent
2213a14e46a22e95062102a19c955a819bf239dbc52Ye Wen            Intent fillIn = new Intent();
222c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen            if (response != null) {
223b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                succeeded = transferResponse(fillIn, response);
2243a14e46a22e95062102a19c955a819bf239dbc52Ye Wen            }
22522519cf9f57f3cc359ccb84bcd508ae0f9750821Ye Wen            if (messageUri != null) {
22622519cf9f57f3cc359ccb84bcd508ae0f9750821Ye Wen                fillIn.putExtra("uri", messageUri.toString());
227c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen            }
228848307f23f9b744ad538c23ef2e3b1a98e3bc635Ye Wen            if (result == SmsManager.MMS_ERROR_HTTP_FAILURE && httpStatusCode != 0) {
229848307f23f9b744ad538c23ef2e3b1a98e3bc635Ye Wen                fillIn.putExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, httpStatusCode);
230848307f23f9b744ad538c23ef2e3b1a98e3bc635Ye Wen            }
231c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen            try {
232b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                if (!succeeded) {
233b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                    result = SmsManager.MMS_ERROR_IO_ERROR;
234b83f2faa04dc275b6779644308384459ffcff63fJulian Odell                }
2353a14e46a22e95062102a19c955a819bf239dbc52Ye Wen                pendingIntent.send(context, result, fillIn);
236c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen            } catch (PendingIntent.CanceledException e) {
2378153aed48a84305533f26c06a07a51bd358cee41Ye Wen                LogUtil.e(this.toString(), "Sending pending intent canceled", e);
238c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen            }
239c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen        }
240b2823fa889f5c1bde4047af36b3b07672942f700Julian Odell
241b2823fa889f5c1bde4047af36b3b07672942f700Julian Odell        revokeUriPermission(context);
242c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen    }
243c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen
2443a14e46a22e95062102a19c955a819bf239dbc52Ye Wen    /**
2451b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry     * Returns true if sending / downloading using the carrier app has failed and completes the
2461b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry     * action using platform API's, otherwise false.
2471b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry     */
2481b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry    protected boolean maybeFallbackToRegularDelivery(int carrierMessagingAppResult) {
2491b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        if (carrierMessagingAppResult
2501b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry                == CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK
2511b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry                || carrierMessagingAppResult
2521b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry                        == CarrierMessagingService.DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK) {
2538153aed48a84305533f26c06a07a51bd358cee41Ye Wen            LogUtil.d(this.toString(), "Sending/downloading MMS by IP failed.");
2541b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry            mRequestManager.addSimRequest(MmsRequest.this);
2551b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry            return true;
2561b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        } else {
2571b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry            return false;
2581b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        }
2591b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry    }
2601b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry
2611b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry    /**
2621b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry     * Converts from {@code carrierMessagingAppResult} to a platform result code.
2631b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry     */
2641b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry    protected static int toSmsManagerResult(int carrierMessagingAppResult) {
2651b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        switch (carrierMessagingAppResult) {
2661b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry            case CarrierMessagingService.SEND_STATUS_OK:
2671b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry                return Activity.RESULT_OK;
2681b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry            case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK:
2691b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry                return SmsManager.MMS_ERROR_RETRY;
2701b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry            default:
2711b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry                return SmsManager.MMS_ERROR_UNSPECIFIED;
2721b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        }
2731b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry    }
2741b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry
2758153aed48a84305533f26c06a07a51bd358cee41Ye Wen    @Override
2768153aed48a84305533f26c06a07a51bd358cee41Ye Wen    public String toString() {
2778153aed48a84305533f26c06a07a51bd358cee41Ye Wen        return getClass().getSimpleName() + '@' + Integer.toHexString(hashCode());
2788153aed48a84305533f26c06a07a51bd358cee41Ye Wen    }
2798153aed48a84305533f26c06a07a51bd358cee41Ye Wen
280ab1cadebc3136446b44b4dbdcd9df51a960f289fXia Ying
281ab1cadebc3136446b44b4dbdcd9df51a960f289fXia Ying    protected String getRequestId() {
282ab1cadebc3136446b44b4dbdcd9df51a960f289fXia Ying        return this.toString();
283ab1cadebc3136446b44b4dbdcd9df51a960f289fXia Ying    }
284ab1cadebc3136446b44b4dbdcd9df51a960f289fXia Ying
2851b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry    /**
2863a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     * Making the HTTP request to MMSC
2873a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     *
2883a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     * @param context The context
289b07ae2f78ac69a1e7bcfb1ce62e69d7283b46295Ye Wen     * @param netMgr The current {@link MmsNetworkManager}
2903a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     * @param apn The APN setting
2913a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     * @return The HTTP response data
2923a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     * @throws MmsHttpException If any network error happens
2933a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     */
294b07ae2f78ac69a1e7bcfb1ce62e69d7283b46295Ye Wen    protected abstract byte[] doHttp(Context context, MmsNetworkManager netMgr, ApnSettings apn)
295b07ae2f78ac69a1e7bcfb1ce62e69d7283b46295Ye Wen            throws MmsHttpException;
296c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen
2973a14e46a22e95062102a19c955a819bf239dbc52Ye Wen    /**
2983a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     * @return The PendingIntent associate with the MMS sending invocation
2993a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     */
300c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen    protected abstract PendingIntent getPendingIntent();
3013a14e46a22e95062102a19c955a819bf239dbc52Ye Wen
3023a14e46a22e95062102a19c955a819bf239dbc52Ye Wen    /**
3033cf9a9481b8e95d0fb654d083b06ee9a23a8e4e8Ye Wen     * @return The queue should be used by this request, 0 is sending and 1 is downloading
3043a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     */
3053cf9a9481b8e95d0fb654d083b06ee9a23a8e4e8Ye Wen    protected abstract int getQueueType();
3063a14e46a22e95062102a19c955a819bf239dbc52Ye Wen
3073a14e46a22e95062102a19c955a819bf239dbc52Ye Wen    /**
30822519cf9f57f3cc359ccb84bcd508ae0f9750821Ye Wen     * Persist message into telephony if required (i.e. when auto-persisting is on or
30922519cf9f57f3cc359ccb84bcd508ae0f9750821Ye Wen     * the calling app is non-default sms app for sending)
3103a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     *
3113a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     * @param context The context
3123a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     * @param result The result code of execution
313b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen     * @param response The response body
31422519cf9f57f3cc359ccb84bcd508ae0f9750821Ye Wen     * @return The persisted URI of the message or null if we don't persist or fail
3153a14e46a22e95062102a19c955a819bf239dbc52Ye Wen     */
31622519cf9f57f3cc359ccb84bcd508ae0f9750821Ye Wen    protected abstract Uri persistIfRequired(Context context, int result, byte[] response);
317b83f2faa04dc275b6779644308384459ffcff63fJulian Odell
318b83f2faa04dc275b6779644308384459ffcff63fJulian Odell    /**
319b83f2faa04dc275b6779644308384459ffcff63fJulian Odell     * Prepare to make the HTTP request - will download message for sending
320b83f2faa04dc275b6779644308384459ffcff63fJulian Odell     * @return true if preparation succeeds (and request can proceed) else false
321b83f2faa04dc275b6779644308384459ffcff63fJulian Odell     */
322b83f2faa04dc275b6779644308384459ffcff63fJulian Odell    protected abstract boolean prepareForHttpRequest();
323b83f2faa04dc275b6779644308384459ffcff63fJulian Odell
324b83f2faa04dc275b6779644308384459ffcff63fJulian Odell    /**
325b83f2faa04dc275b6779644308384459ffcff63fJulian Odell     * Transfer the received response to the caller
326b83f2faa04dc275b6779644308384459ffcff63fJulian Odell     *
327b83f2faa04dc275b6779644308384459ffcff63fJulian Odell     * @param fillIn the intent that will be returned to the caller
328b83f2faa04dc275b6779644308384459ffcff63fJulian Odell     * @param response the pdu to transfer
329b83f2faa04dc275b6779644308384459ffcff63fJulian Odell     * @return true if response transfer succeeds else false
330b83f2faa04dc275b6779644308384459ffcff63fJulian Odell     */
331b83f2faa04dc275b6779644308384459ffcff63fJulian Odell    protected abstract boolean transferResponse(Intent fillIn, byte[] response);
332f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang
333f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang    /**
334f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang     * Revoke the content URI permission granted by the MMS app to the phone package.
335f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang     *
336f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang     * @param context The context
337f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang     */
338f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang    protected abstract void revokeUriPermission(Context context);
3391b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry
3401b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry    /**
3411b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry     * Base class for handling carrier app send / download result.
3421b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry     */
3431b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry    protected abstract class CarrierMmsActionCallback extends ICarrierMessagingCallback.Stub {
3441b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        @Override
3451b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        public void onSendSmsComplete(int result, int messageRef) {
3468153aed48a84305533f26c06a07a51bd358cee41Ye Wen            LogUtil.e("Unexpected onSendSmsComplete call with result: " + result);
3471b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        }
3481b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry
3491b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        @Override
3501b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
3518153aed48a84305533f26c06a07a51bd358cee41Ye Wen            LogUtil.e("Unexpected onSendMultipartSmsComplete call with result: " + result);
3521b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        }
3531b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry
3541b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        @Override
355cd6e4d0abc9b1aba5d8970a0b5408ecb8da5fbb6Ji Yang        public void onFilterComplete(int result) {
356cd6e4d0abc9b1aba5d8970a0b5408ecb8da5fbb6Ji Yang            LogUtil.e("Unexpected onFilterComplete call with result: " + result);
3571b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry        }
3581b2066c9c8f40e2cdabdedfe873a4c960ec7b7d6Abhijith Shastry    }
359c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen}
360