diff options
Diffstat (limited to 'src/android/support/v7/mms/MmsHttpClient.java')
-rw-r--r-- | src/android/support/v7/mms/MmsHttpClient.java | 523 |
1 files changed, 0 insertions, 523 deletions
diff --git a/src/android/support/v7/mms/MmsHttpClient.java b/src/android/support/v7/mms/MmsHttpClient.java deleted file mode 100644 index 8ca34da..0000000 --- a/src/android/support/v7/mms/MmsHttpClient.java +++ /dev/null @@ -1,523 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v7.mms; - -import android.content.Context; -import android.os.Bundle; -import android.telephony.SmsManager; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Base64; -import android.util.Log; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Method; -import java.net.HttpURLConnection; -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.ProtocolException; -import java.net.Proxy; -import java.net.URL; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * MMS HTTP client for sending and downloading MMS messages - */ -public class MmsHttpClient { - static final String METHOD_POST = "POST"; - static final String METHOD_GET = "GET"; - - private static final String HEADER_CONTENT_TYPE = "Content-Type"; - private static final String HEADER_ACCEPT = "Accept"; - private static final String HEADER_ACCEPT_LANGUAGE = "Accept-Language"; - private static final String HEADER_USER_AGENT = "User-Agent"; - - // The "Accept" header value - private static final String HEADER_VALUE_ACCEPT = - "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic"; - // The "Content-Type" header value - private static final String HEADER_VALUE_CONTENT_TYPE_WITH_CHARSET = - "application/vnd.wap.mms-message; charset=utf-8"; - private static final String HEADER_VALUE_CONTENT_TYPE_WITHOUT_CHARSET = - "application/vnd.wap.mms-message"; - - /* - * Macro names - */ - // The raw phone number - private static final String MACRO_LINE1 = "LINE1"; - // The phone number without country code - private static final String MACRO_LINE1NOCOUNTRYCODE = "LINE1NOCOUNTRYCODE"; - // NAI (Network Access Identifier) - private static final String MACRO_NAI = "NAI"; - - // The possible NAI system property name - private static final String NAI_PROPERTY = "persist.radio.cdma.nai"; - - private final Context mContext; - private final TelephonyManager mTelephonyManager; - - /** - * Constructor - * - * @param context The Context object - */ - MmsHttpClient(Context context) { - mContext = context; - mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - } - - /** - * Execute an MMS HTTP request, either a POST (sending) or a GET (downloading) - * - * @param urlString The request URL, for sending it is usually the MMSC, and for downloading - * it is the message URL - * @param pdu For POST (sending) only, the PDU to send - * @param method HTTP method, POST for sending and GET for downloading - * @param isProxySet Is there a proxy for the MMSC - * @param proxyHost The proxy host - * @param proxyPort The proxy port - * @param mmsConfig The MMS config to use - * @param userAgent The user agent header value - * @param uaProfUrl The UA Prof URL header value - * @return The HTTP response body - * @throws MmsHttpException For any failures - */ - public byte[] execute(String urlString, byte[] pdu, String method, boolean isProxySet, - String proxyHost, int proxyPort, Bundle mmsConfig, String userAgent, String uaProfUrl) - throws MmsHttpException { - Log.d(MmsService.TAG, "HTTP: " + method + " " + Utils.redactUrlForNonVerbose(urlString) - + (isProxySet ? (", proxy=" + proxyHost + ":" + proxyPort) : "") - + ", PDU size=" + (pdu != null ? pdu.length : 0)); - checkMethod(method); - HttpURLConnection connection = null; - try { - Proxy proxy = Proxy.NO_PROXY; - if (isProxySet) { - proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)); - } - final URL url = new URL(urlString); - // Now get the connection - connection = (HttpURLConnection) url.openConnection(proxy); - connection.setDoInput(true); - connection.setConnectTimeout( - mmsConfig.getInt(CarrierConfigValuesLoader.CONFIG_HTTP_SOCKET_TIMEOUT, - CarrierConfigValuesLoader.CONFIG_HTTP_SOCKET_TIMEOUT_DEFAULT)); - // ------- COMMON HEADERS --------- - // Header: Accept - connection.setRequestProperty(HEADER_ACCEPT, HEADER_VALUE_ACCEPT); - // Header: Accept-Language - connection.setRequestProperty( - HEADER_ACCEPT_LANGUAGE, getCurrentAcceptLanguage(Locale.getDefault())); - // Header: User-Agent - Log.i(MmsService.TAG, "HTTP: User-Agent=" + userAgent); - connection.setRequestProperty(HEADER_USER_AGENT, userAgent); - // Header: x-wap-profile - final String uaProfUrlTagName = mmsConfig.getString( - CarrierConfigValuesLoader.CONFIG_UA_PROF_TAG_NAME, - CarrierConfigValuesLoader.CONFIG_UA_PROF_TAG_NAME_DEFAULT); - if (uaProfUrl != null) { - Log.i(MmsService.TAG, "HTTP: UaProfUrl=" + uaProfUrl); - connection.setRequestProperty(uaProfUrlTagName, uaProfUrl); - } - // Add extra headers specified by mms_config.xml's httpparams - addExtraHeaders(connection, mmsConfig); - // Different stuff for GET and POST - if (METHOD_POST.equals(method)) { - if (pdu == null || pdu.length < 1) { - Log.e(MmsService.TAG, "HTTP: empty pdu"); - throw new MmsHttpException(0/*statusCode*/, "Sending empty PDU"); - } - connection.setDoOutput(true); - connection.setRequestMethod(METHOD_POST); - if (mmsConfig.getBoolean( - CarrierConfigValuesLoader.CONFIG_SUPPORT_HTTP_CHARSET_HEADER, - CarrierConfigValuesLoader.CONFIG_SUPPORT_HTTP_CHARSET_HEADER_DEFAULT)) { - connection.setRequestProperty(HEADER_CONTENT_TYPE, - HEADER_VALUE_CONTENT_TYPE_WITH_CHARSET); - } else { - connection.setRequestProperty(HEADER_CONTENT_TYPE, - HEADER_VALUE_CONTENT_TYPE_WITHOUT_CHARSET); - } - if (Log.isLoggable(MmsService.TAG, Log.VERBOSE)) { - logHttpHeaders(connection.getRequestProperties()); - } - connection.setFixedLengthStreamingMode(pdu.length); - // Sending request body - final OutputStream out = - new BufferedOutputStream(connection.getOutputStream()); - out.write(pdu); - out.flush(); - out.close(); - } else if (METHOD_GET.equals(method)) { - if (Log.isLoggable(MmsService.TAG, Log.VERBOSE)) { - logHttpHeaders(connection.getRequestProperties()); - } - connection.setRequestMethod(METHOD_GET); - } - // Get response - final int responseCode = connection.getResponseCode(); - final String responseMessage = connection.getResponseMessage(); - Log.d(MmsService.TAG, "HTTP: " + responseCode + " " + responseMessage); - if (Log.isLoggable(MmsService.TAG, Log.VERBOSE)) { - logHttpHeaders(connection.getHeaderFields()); - } - if (responseCode / 100 != 2) { - throw new MmsHttpException(responseCode, responseMessage); - } - final InputStream in = new BufferedInputStream(connection.getInputStream()); - final ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); - final byte[] buf = new byte[4096]; - int count = 0; - while ((count = in.read(buf)) > 0) { - byteOut.write(buf, 0, count); - } - in.close(); - final byte[] responseBody = byteOut.toByteArray(); - Log.d(MmsService.TAG, "HTTP: response size=" - + (responseBody != null ? responseBody.length : 0)); - return responseBody; - } catch (MalformedURLException e) { - final String redactedUrl = Utils.redactUrlForNonVerbose(urlString); - Log.e(MmsService.TAG, "HTTP: invalid URL " + redactedUrl, e); - throw new MmsHttpException(0/*statusCode*/, "Invalid URL " + redactedUrl, e); - } catch (ProtocolException e) { - final String redactedUrl = Utils.redactUrlForNonVerbose(urlString); - Log.e(MmsService.TAG, "HTTP: invalid URL protocol " + redactedUrl, e); - throw new MmsHttpException(0/*statusCode*/, "Invalid URL protocol " + redactedUrl, e); - } catch (IOException e) { - Log.e(MmsService.TAG, "HTTP: IO failure", e); - throw new MmsHttpException(0/*statusCode*/, e); - } finally { - if (connection != null) { - connection.disconnect(); - } - } - } - - private static void logHttpHeaders(Map<String, List<String>> headers) { - final StringBuilder sb = new StringBuilder(); - if (headers != null) { - for (Map.Entry<String, List<String>> entry : headers.entrySet()) { - final String key = entry.getKey(); - final List<String> values = entry.getValue(); - if (values != null) { - for (String value : values) { - sb.append(key).append('=').append(value).append('\n'); - } - } - } - Log.v(MmsService.TAG, "HTTP: headers\n" + sb.toString()); - } - } - - private static void checkMethod(String method) throws MmsHttpException { - if (!METHOD_GET.equals(method) && !METHOD_POST.equals(method)) { - throw new MmsHttpException(0/*statusCode*/, "Invalid method " + method); - } - } - - private static final String ACCEPT_LANG_FOR_US_LOCALE = "en-US"; - - /** - * Return the Accept-Language header. Use the current locale plus - * US if we are in a different locale than US. - * This code copied from the browser's WebSettings.java - * - * @return Current AcceptLanguage String. - */ - public static String getCurrentAcceptLanguage(Locale locale) { - final StringBuilder buffer = new StringBuilder(); - addLocaleToHttpAcceptLanguage(buffer, locale); - - if (!Locale.US.equals(locale)) { - if (buffer.length() > 0) { - buffer.append(", "); - } - buffer.append(ACCEPT_LANG_FOR_US_LOCALE); - } - - return buffer.toString(); - } - - /** - * Convert obsolete language codes, including Hebrew/Indonesian/Yiddish, - * to new standard. - */ - private static String convertObsoleteLanguageCodeToNew(String langCode) { - if (langCode == null) { - return null; - } - if ("iw".equals(langCode)) { - // Hebrew - return "he"; - } else if ("in".equals(langCode)) { - // Indonesian - return "id"; - } else if ("ji".equals(langCode)) { - // Yiddish - return "yi"; - } - return langCode; - } - - private static void addLocaleToHttpAcceptLanguage(StringBuilder builder, Locale locale) { - final String language = convertObsoleteLanguageCodeToNew(locale.getLanguage()); - if (language != null) { - builder.append(language); - final String country = locale.getCountry(); - if (country != null) { - builder.append("-"); - builder.append(country); - } - } - } - - private static final Pattern MACRO_P = Pattern.compile("##(\\S+)##"); - /** - * Resolve the macro in HTTP param value text - * For example, "something##LINE1##something" is resolved to "something9139531419something" - * - * @param value The HTTP param value possibly containing macros - * @return The HTTP param with macro resolved to real value - */ - private String resolveMacro(String value, Bundle mmsConfig) { - if (TextUtils.isEmpty(value)) { - return value; - } - final Matcher matcher = MACRO_P.matcher(value); - int nextStart = 0; - StringBuilder replaced = null; - while (matcher.find()) { - if (replaced == null) { - replaced = new StringBuilder(); - } - final int matchedStart = matcher.start(); - if (matchedStart > nextStart) { - replaced.append(value.substring(nextStart, matchedStart)); - } - final String macro = matcher.group(1); - final String macroValue = getHttpParamMacro(macro, mmsConfig); - if (macroValue != null) { - replaced.append(macroValue); - } - nextStart = matcher.end(); - } - if (replaced != null && nextStart < value.length()) { - replaced.append(value.substring(nextStart)); - } - return replaced == null ? value : replaced.toString(); - } - - /** - * Add extra HTTP headers from mms_config.xml's httpParams, which is a list of key/value - * pairs separated by "|". Each key/value pair is separated by ":". Value may contain - * macros like "##LINE1##" or "##NAI##" which is resolved with methods in this class - * - * @param connection The HttpURLConnection that we add headers to - * @param mmsConfig The MmsConfig object - */ - private void addExtraHeaders(HttpURLConnection connection, Bundle mmsConfig) { - final String extraHttpParams = mmsConfig.getString( - CarrierConfigValuesLoader.CONFIG_HTTP_PARAMS); - if (!TextUtils.isEmpty(extraHttpParams)) { - // Parse the parameter list - String paramList[] = extraHttpParams.split("\\|"); - for (String paramPair : paramList) { - String splitPair[] = paramPair.split(":", 2); - if (splitPair.length == 2) { - final String name = splitPair[0].trim(); - final String value = resolveMacro(splitPair[1].trim(), mmsConfig); - if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(value)) { - // Add the header if the param is valid - connection.setRequestProperty(name, value); - } - } - } - } - } - - /** - * Return the HTTP param macro value. - * Example: LINE1 returns the phone number, etc. - * - * @param macro The macro name - * @param mmsConfig The carrier configuration values - * @return The value of the defined macro - */ - private String getHttpParamMacro(final String macro, final Bundle mmsConfig) { - if (MACRO_LINE1.equals(macro)) { - return getSelfNumber(); - } else if (MACRO_LINE1NOCOUNTRYCODE.equals(macro)) { - return PhoneNumberHelper.getNumberNoCountryCode( - getSelfNumber(), getSimOrLocaleCountry()); - } else if (MACRO_NAI.equals(macro)) { - return getEncodedNai(mmsConfig.getString( - CarrierConfigValuesLoader.CONFIG_NAI_SUFFIX, - CarrierConfigValuesLoader.CONFIG_NAI_SUFFIX_DEFAULT)); - } - return null; - } - - /** - * Get the device phone number - * - * @return the phone number text - */ - private String getSelfNumber() { - if (Utils.supportMSim()) { - final SubscriptionManager subscriptionManager = SubscriptionManager.from(mContext); - final SubscriptionInfo info = subscriptionManager.getActiveSubscriptionInfo( - SmsManager.getDefaultSmsSubscriptionId()); - if (info != null) { - return info.getNumber(); - } else { - return null; - } - } else { - return mTelephonyManager.getLine1Number(); - } - } - - /** - * Get the country ISO code from SIM or system locale - * - * @return the country ISO code - */ - private String getSimOrLocaleCountry() { - String country = null; - if (Utils.supportMSim()) { - final SubscriptionManager subscriptionManager = SubscriptionManager.from(mContext); - final SubscriptionInfo info = subscriptionManager.getActiveSubscriptionInfo( - SmsManager.getDefaultSmsSubscriptionId()); - if (info != null) { - country = info.getCountryIso(); - } - } else { - country = mTelephonyManager.getSimCountryIso(); - } - if (!TextUtils.isEmpty(country)) { - return country.toUpperCase(); - } else { - return Locale.getDefault().getCountry(); - } - } - - /** - * Get encoded NAI string to use as the HTTP header for some carriers. - * On L-MR1+, we call the hidden system API to get this - * On L-MR1-, we try to find it via system property. - * - * @param naiSuffix the suffix to append to NAI before encoding - * @return the Base64 encoded NAI string to use as HTTP header - */ - private String getEncodedNai(final String naiSuffix) { - String nai; - if (Utils.supportMSim()) { - nai = getNaiBySystemApi( - getSlotId(Utils.getEffectiveSubscriptionId(MmsManager.DEFAULT_SUB_ID))); - } else { - nai = getNaiBySystemProperty(); - } - if (!TextUtils.isEmpty(nai)) { - Log.i(MmsService.TAG, "NAI is not empty"); - if (!TextUtils.isEmpty(naiSuffix)) { - nai = nai + naiSuffix; - } - byte[] encoded = null; - try { - encoded = Base64.encode(nai.getBytes("UTF-8"), Base64.NO_WRAP); - } catch (UnsupportedEncodingException e) { - encoded = Base64.encode(nai.getBytes(), Base64.NO_WRAP); - } - try { - return new String(encoded, "UTF-8"); - } catch (UnsupportedEncodingException e) { - return new String(encoded); - } - } - return null; - } - - /** - * Invoke hidden SubscriptionManager.getSlotId(int) - * - * @param subId the subId - * @return the SIM slot ID - */ - private static int getSlotId(final int subId) { - try { - final Method method = SubscriptionManager.class.getMethod("getSlotId", Integer.TYPE); - if (method != null) { - return (Integer) method.invoke(null, subId); - } - } catch (Exception e) { - Log.w(MmsService.TAG, "SubscriptionManager.getSlotId failed " + e); - } - return -1; - } - - /** - * Get NAI using hidden TelephonyManager.getNai(int) - * - * @param slotId the SIM slot ID - * @return the NAI string - */ - private String getNaiBySystemApi(final int slotId) { - try { - final Method method = mTelephonyManager.getClass().getMethod("getNai", Integer.TYPE); - if (method != null) { - return (String) method.invoke(mTelephonyManager, slotId); - } - } catch (Exception e) { - Log.w(MmsService.TAG, "TelephonyManager.getNai failed " + e); - } - return null; - } - - /** - * Get NAI using hidden SystemProperties.get(String) - * - * @return the NAI string as system property - */ - private static String getNaiBySystemProperty() { - try { - final Class systemPropertiesClass = Class.forName("android.os.SystemProperties"); - if (systemPropertiesClass != null) { - final Method method = systemPropertiesClass.getMethod("get", String.class); - if (method != null) { - return (String) method.invoke(null, NAI_PROPERTY); - } - } - } catch (Exception e) { - Log.w(MmsService.TAG, "SystemProperties.get failed " + e); - } - return null; - } -} |