summaryrefslogtreecommitdiffstats
path: root/src/android/support/v7/mms/MmsRequest.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/support/v7/mms/MmsRequest.java')
-rw-r--r--src/android/support/v7/mms/MmsRequest.java391
1 files changed, 0 insertions, 391 deletions
diff --git a/src/android/support/v7/mms/MmsRequest.java b/src/android/support/v7/mms/MmsRequest.java
deleted file mode 100644
index edf3606..0000000
--- a/src/android/support/v7/mms/MmsRequest.java
+++ /dev/null
@@ -1,391 +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.app.Activity;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.v7.mms.pdu.GenericPdu;
-import android.support.v7.mms.pdu.PduHeaders;
-import android.support.v7.mms.pdu.PduParser;
-import android.support.v7.mms.pdu.SendConf;
-import android.telephony.SmsManager;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.lang.reflect.Method;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- * MMS request base class. This handles the execution of any MMS request.
- */
-abstract class MmsRequest implements Parcelable {
- /**
- * Prepare to make the HTTP request - will download message for sending
- *
- * @param context the Context
- * @param mmsConfig carrier config values to use
- * @return true if loading request PDU from calling app succeeds, false otherwise
- */
- protected abstract boolean loadRequest(Context context, Bundle mmsConfig);
-
- /**
- * Transfer the received response to the caller
- *
- * @param context the Context
- * @param fillIn the content of pending intent to be returned
- * @param response the pdu to transfer
- * @return true if transferring response PDU to calling app succeeds, false otherwise
- */
- protected abstract boolean transferResponse(Context context, Intent fillIn, byte[] response);
-
- /**
- * Making the HTTP request to MMSC
- *
- * @param context The context
- * @param netMgr The current {@link MmsNetworkManager}
- * @param apn The APN
- * @param mmsConfig The carrier configuration values to use
- * @param userAgent The User-Agent header value
- * @param uaProfUrl The UA Prof URL header value
- * @return The HTTP response data
- * @throws MmsHttpException If any network error happens
- */
- protected abstract byte[] doHttp(Context context, MmsNetworkManager netMgr,
- ApnSettingsLoader.Apn apn, Bundle mmsConfig, String userAgent, String uaProfUrl)
- throws MmsHttpException;
-
- /**
- * Get the HTTP request URL for this MMS request
- *
- * @param apn The APN to use
- * @return The HTTP request URL in text
- */
- protected abstract String getHttpRequestUrl(ApnSettingsLoader.Apn apn);
-
- // Maximum time to spend waiting to read data from a content provider before failing with error.
- protected static final int TASK_TIMEOUT_MS = 30 * 1000;
-
- protected final String mLocationUrl;
- protected final Uri mPduUri;
- protected final PendingIntent mPendingIntent;
- // Thread pool for transferring PDU with MMS apps
- protected final ExecutorService mPduTransferExecutor = Executors.newCachedThreadPool();
-
- // Whether this request should acquire wake lock
- private boolean mUseWakeLock;
-
- protected MmsRequest(final String locationUrl, final Uri pduUri,
- final PendingIntent pendingIntent) {
- mLocationUrl = locationUrl;
- mPduUri = pduUri;
- mPendingIntent = pendingIntent;
- mUseWakeLock = true;
- }
-
- void setUseWakeLock(final boolean useWakeLock) {
- mUseWakeLock = useWakeLock;
- }
-
- boolean getUseWakeLock() {
- return mUseWakeLock;
- }
-
- /**
- * Run the MMS request.
- *
- * @param context the context to use
- * @param networkManager the MmsNetworkManager to use to setup MMS network
- * @param apnSettingsLoader the APN loader
- * @param carrierConfigValuesLoader the carrier config loader
- * @param userAgentInfoLoader the user agent info loader
- */
- void execute(final Context context, final MmsNetworkManager networkManager,
- final ApnSettingsLoader apnSettingsLoader,
- final CarrierConfigValuesLoader carrierConfigValuesLoader,
- final UserAgentInfoLoader userAgentInfoLoader) {
- Log.i(MmsService.TAG, "Execute " + this.getClass().getSimpleName());
- int result = SmsManager.MMS_ERROR_UNSPECIFIED;
- int httpStatusCode = 0;
- byte[] response = null;
- final Bundle mmsConfig = carrierConfigValuesLoader.get(MmsManager.DEFAULT_SUB_ID);
- if (mmsConfig == null) {
- Log.e(MmsService.TAG, "Failed to load carrier configuration values");
- result = SmsManager.MMS_ERROR_CONFIGURATION_ERROR;
- } else if (!loadRequest(context, mmsConfig)) {
- Log.e(MmsService.TAG, "Failed to load PDU");
- result = SmsManager.MMS_ERROR_IO_ERROR;
- } else {
- // Everything's OK. Now execute the request.
- try {
- // Acquire the MMS network
- networkManager.acquireNetwork();
- // Load the potential APNs. In most cases there should be only one APN available.
- // On some devices on which we can't obtain APN from system, we look up our own
- // APN list. Since we don't have exact information, we may get a list of potential
- // APNs to try. Whenever we found a successful APN, we signal it and return.
- final String apnName = networkManager.getApnName();
- final List<ApnSettingsLoader.Apn> apns = apnSettingsLoader.get(apnName);
- if (apns.size() < 1) {
- throw new ApnException("No valid APN");
- } else {
- Log.d(MmsService.TAG, "Trying " + apns.size() + " APNs");
- }
- final String userAgent = userAgentInfoLoader.getUserAgent();
- final String uaProfUrl = userAgentInfoLoader.getUAProfUrl();
- MmsHttpException lastException = null;
- for (ApnSettingsLoader.Apn apn : apns) {
- Log.i(MmsService.TAG, "Using APN ["
- + "MMSC=" + apn.getMmsc() + ", "
- + "PROXY=" + apn.getMmsProxy() + ", "
- + "PORT=" + apn.getMmsProxyPort() + "]");
- try {
- final String url = getHttpRequestUrl(apn);
- // Request a global route for the host to connect
- requestRoute(networkManager.getConnectivityManager(), apn, url);
- // Perform the HTTP request
- response = doHttp(
- context, networkManager, apn, mmsConfig, userAgent, uaProfUrl);
- // Additional check of whether this is a success
- if (isWrongApnResponse(response, mmsConfig)) {
- throw new MmsHttpException(0/*statusCode*/, "Invalid sending address");
- }
- // Notify APN loader this is a valid APN
- apn.setSuccess();
- result = Activity.RESULT_OK;
- break;
- } catch (MmsHttpException e) {
- Log.w(MmsService.TAG, "HTTP or network failure", e);
- lastException = e;
- }
- }
- if (lastException != null) {
- throw lastException;
- }
- } catch (ApnException e) {
- Log.e(MmsService.TAG, "MmsRequest: APN failure", e);
- result = SmsManager.MMS_ERROR_INVALID_APN;
- } catch (MmsNetworkException e) {
- Log.e(MmsService.TAG, "MmsRequest: MMS network acquiring failure", e);
- result = SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS;
- } catch (MmsHttpException e) {
- Log.e(MmsService.TAG, "MmsRequest: HTTP or network I/O failure", e);
- result = SmsManager.MMS_ERROR_HTTP_FAILURE;
- httpStatusCode = e.getStatusCode();
- } catch (Exception e) {
- Log.e(MmsService.TAG, "MmsRequest: unexpected failure", e);
- result = SmsManager.MMS_ERROR_UNSPECIFIED;
- } finally {
- // Release MMS network
- networkManager.releaseNetwork();
- }
- }
- // Process result and send back via PendingIntent
- returnResult(context, result, response, httpStatusCode);
- }
-
- /**
- * Check if the response indicates a failure when we send to wrong APN.
- * Sometimes even if you send to the wrong APN, a response in valid PDU format can still
- * be sent back but with an error status. Check one specific case here.
- *
- * TODO: maybe there are other possibilities.
- *
- * @param response the response data
- * @param mmsConfig the carrier configuration values to use
- * @return false if we find an invalid response case, otherwise true
- */
- static boolean isWrongApnResponse(final byte[] response, final Bundle mmsConfig) {
- if (response != null && response.length > 0) {
- try {
- final GenericPdu pdu = new PduParser(
- response,
- mmsConfig.getBoolean(
- CarrierConfigValuesLoader
- .CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION,
- CarrierConfigValuesLoader
- .CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION_DEFAULT))
- .parse();
- if (pdu != null && pdu instanceof SendConf) {
- final SendConf sendConf = (SendConf) pdu;
- final int responseStatus = sendConf.getResponseStatus();
- return responseStatus ==
- PduHeaders.RESPONSE_STATUS_ERROR_PERMANENT_SENDING_ADDRESS_UNRESOLVED ||
- responseStatus ==
- PduHeaders.RESPONSE_STATUS_ERROR_SENDING_ADDRESS_UNRESOLVED;
- }
- } catch (RuntimeException e) {
- Log.w(MmsService.TAG, "Parsing response failed", e);
- }
- }
- return false;
- }
-
- /**
- * Return the result back via pending intent
- *
- * @param context The context
- * @param result The result code of execution
- * @param response The response body
- * @param httpStatusCode The optional http status code in case of http failure
- */
- void returnResult(final Context context, int result, final byte[] response,
- final int httpStatusCode) {
- if (mPendingIntent == null) {
- // Result not needed
- return;
- }
- // Extra information to send back with the pending intent
- final Intent fillIn = new Intent();
- if (response != null) {
- if (!transferResponse(context, fillIn, response)) {
- // Failed to send PDU data back to caller
- result = SmsManager.MMS_ERROR_IO_ERROR;
- }
- }
- if (result == SmsManager.MMS_ERROR_HTTP_FAILURE && httpStatusCode != 0) {
- // For HTTP failure, fill in the status code for more information
- fillIn.putExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, httpStatusCode);
- }
- try {
- mPendingIntent.send(context, result, fillIn);
- } catch (PendingIntent.CanceledException e) {
- Log.e(MmsService.TAG, "Sending pending intent canceled", e);
- }
- }
-
- /**
- * Request the route to the APN (either proxy host or the MMSC host)
- *
- * @param connectivityManager the ConnectivityManager to use
- * @param apn the current APN
- * @param url the URL to connect to
- * @throws MmsHttpException for unknown host or route failure
- */
- private static void requestRoute(final ConnectivityManager connectivityManager,
- final ApnSettingsLoader.Apn apn, final String url) throws MmsHttpException {
- String host = apn.getMmsProxy();
- if (TextUtils.isEmpty(host)) {
- final Uri uri = Uri.parse(url);
- host = uri.getHost();
- }
- boolean success = false;
- // Request route to all resolved host addresses
- try {
- for (final InetAddress addr : InetAddress.getAllByName(host)) {
- final boolean requested = requestRouteToHostAddress(connectivityManager, addr);
- if (requested) {
- success = true;
- Log.i(MmsService.TAG, "Requested route to " + addr);
- } else {
- Log.i(MmsService.TAG, "Could not requested route to " + addr);
- }
- }
- if (!success) {
- throw new MmsHttpException(0/*statusCode*/, "No route requested");
- }
- } catch (UnknownHostException e) {
- Log.w(MmsService.TAG, "Unknown host " + host);
- throw new MmsHttpException(0/*statusCode*/, "Unknown host");
- }
- }
-
- private static final Integer TYPE_MOBILE_MMS =
- Integer.valueOf(ConnectivityManager.TYPE_MOBILE_MMS);
- /**
- * Wrapper for platform API requestRouteToHostAddress
- *
- * We first try the hidden but correct method on ConnectivityManager. If we can't, use
- * the old but buggy one
- *
- * @param connMgr the ConnectivityManager instance
- * @param inetAddr the InetAddress to request
- * @return true if route is successfully setup, false otherwise
- */
- private static boolean requestRouteToHostAddress(final ConnectivityManager connMgr,
- final InetAddress inetAddr) {
- // First try the good method using reflection
- try {
- final Method method = connMgr.getClass().getMethod("requestRouteToHostAddress",
- Integer.TYPE, InetAddress.class);
- if (method != null) {
- return (Boolean) method.invoke(connMgr, TYPE_MOBILE_MMS, inetAddr);
- }
- } catch (Exception e) {
- Log.w(MmsService.TAG, "ConnectivityManager.requestRouteToHostAddress failed " + e);
- }
- // If we fail, try the old but buggy one
- if (inetAddr instanceof Inet4Address) {
- try {
- final Method method = connMgr.getClass().getMethod("requestRouteToHost",
- Integer.TYPE, Integer.TYPE);
- if (method != null) {
- return (Boolean) method.invoke(connMgr, TYPE_MOBILE_MMS,
- inetAddressToInt(inetAddr));
- }
- } catch (Exception e) {
- Log.w(MmsService.TAG, "ConnectivityManager.requestRouteToHost failed " + e);
- }
- }
- return false;
- }
-
- /**
- * Convert a IPv4 address from an InetAddress to an integer
- *
- * @param inetAddr is an InetAddress corresponding to the IPv4 address
- * @return the IP address as an integer in network byte order
- */
- private static int inetAddressToInt(final InetAddress inetAddr)
- throws IllegalArgumentException {
- final byte [] addr = inetAddr.getAddress();
- return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) |
- ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeByte((byte) (mUseWakeLock ? 1 : 0));
- parcel.writeString(mLocationUrl);
- parcel.writeParcelable(mPduUri, 0);
- parcel.writeParcelable(mPendingIntent, 0);
- }
-
- protected MmsRequest(final Parcel in) {
- final ClassLoader classLoader = MmsRequest.class.getClassLoader();
- mUseWakeLock = in.readByte() != 0;
- mLocationUrl = in.readString();
- mPduUri = in.readParcelable(classLoader);
- mPendingIntent = in.readParcelable(classLoader);
- }
-}