diff options
Diffstat (limited to 'src/com/android/messaging/sms/MmsSender.java')
-rw-r--r-- | src/com/android/messaging/sms/MmsSender.java | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/src/com/android/messaging/sms/MmsSender.java b/src/com/android/messaging/sms/MmsSender.java new file mode 100644 index 0000000..6dfa81a --- /dev/null +++ b/src/com/android/messaging/sms/MmsSender.java @@ -0,0 +1,312 @@ +/* + * 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 com.android.messaging.sms; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v7.mms.MmsManager; +import android.telephony.SmsManager; + +import com.android.messaging.datamodel.MmsFileProvider; +import com.android.messaging.datamodel.action.SendMessageAction; +import com.android.messaging.datamodel.data.MessageData; +import com.android.messaging.mmslib.InvalidHeaderValueException; +import com.android.messaging.mmslib.pdu.AcknowledgeInd; +import com.android.messaging.mmslib.pdu.EncodedStringValue; +import com.android.messaging.mmslib.pdu.GenericPdu; +import com.android.messaging.mmslib.pdu.NotifyRespInd; +import com.android.messaging.mmslib.pdu.PduComposer; +import com.android.messaging.mmslib.pdu.PduHeaders; +import com.android.messaging.mmslib.pdu.PduParser; +import com.android.messaging.mmslib.pdu.RetrieveConf; +import com.android.messaging.mmslib.pdu.SendConf; +import com.android.messaging.mmslib.pdu.SendReq; +import com.android.messaging.receiver.SendStatusReceiver; +import com.android.messaging.util.Assert; +import com.android.messaging.util.LogUtil; +import com.android.messaging.util.PhoneUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * Class that sends chat message via MMS. + * + * The interface emulates a blocking send similar to making an HTTP request. + */ +public class MmsSender { + private static final String TAG = LogUtil.BUGLE_TAG; + + /** + * Send an MMS message. + * + * @param context Context + * @param messageUri The unique URI of the message for identifying it during sending + * @param sendReq The SendReq PDU of the message + * @throws MmsFailureException + */ + public static void sendMms(final Context context, final int subId, final Uri messageUri, + final SendReq sendReq, final Bundle sentIntentExras) throws MmsFailureException { + sendMms(context, + subId, + messageUri, + null /* locationUrl */, + sendReq, + true /* responseImportant */, + sentIntentExras); + } + + /** + * Send NotifyRespInd (response to mms auto download). + * + * @param context Context + * @param subId subscription to use to send the response + * @param transactionId The transaction id of the MMS message + * @param contentLocation The url of the MMS message + * @param status The status to send with the NotifyRespInd + * @throws MmsFailureException + * @throws InvalidHeaderValueException + */ + public static void sendNotifyResponseForMmsDownload(final Context context, final int subId, + final byte[] transactionId, final String contentLocation, final int status) + throws MmsFailureException, InvalidHeaderValueException { + // Create the M-NotifyResp.ind + final NotifyRespInd notifyRespInd = new NotifyRespInd( + PduHeaders.CURRENT_MMS_VERSION, transactionId, status); + final Uri messageUri = Uri.parse(contentLocation); + // Pack M-NotifyResp.ind and send it + sendMms(context, + subId, + messageUri, + MmsConfig.get(subId).getNotifyWapMMSC() ? contentLocation : null, + notifyRespInd, + false /* responseImportant */, + null /* sentIntentExtras */); + } + + /** + * Send AcknowledgeInd (response to mms manual download). Ignore failures. + * + * @param context Context + * @param subId The SIM's subId we are currently using + * @param transactionId The transaction id of the MMS message + * @param contentLocation The url of the MMS message + * @throws MmsFailureException + * @throws InvalidHeaderValueException + */ + public static void sendAcknowledgeForMmsDownload(final Context context, final int subId, + final byte[] transactionId, final String contentLocation) + throws MmsFailureException, InvalidHeaderValueException { + final String selfNumber = PhoneUtils.get(subId).getCanonicalForSelf(true/*allowOverride*/); + // Create the M-Acknowledge.ind + final AcknowledgeInd acknowledgeInd = new AcknowledgeInd(PduHeaders.CURRENT_MMS_VERSION, + transactionId); + acknowledgeInd.setFrom(new EncodedStringValue(selfNumber)); + final Uri messageUri = Uri.parse(contentLocation); + // Sending + sendMms(context, + subId, + messageUri, + MmsConfig.get(subId).getNotifyWapMMSC() ? contentLocation : null, + acknowledgeInd, + false /*responseImportant*/, + null /* sentIntentExtras */); + } + + /** + * Send a generic PDU. + * + * @param context Context + * @param messageUri The unique URI of the message for identifying it during sending + * @param locationUrl The optional URL to send to + * @param pdu The PDU to send + * @param responseImportant If the sending response is important. Responses to the + * Sending of AcknowledgeInd and NotifyRespInd are not important. + * @throws MmsFailureException + */ + private static void sendMms(final Context context, final int subId, final Uri messageUri, + final String locationUrl, final GenericPdu pdu, final boolean responseImportant, + final Bundle sentIntentExtras) throws MmsFailureException { + // Write PDU to temporary file to send to platform + final Uri contentUri = writePduToTempFile(context, pdu, subId); + + // Construct PendingIntent that will notify us when message sending is complete + final Intent sentIntent = new Intent(SendStatusReceiver.MMS_SENT_ACTION, + messageUri, + context, + SendStatusReceiver.class); + sentIntent.putExtra(SendMessageAction.EXTRA_CONTENT_URI, contentUri); + sentIntent.putExtra(SendMessageAction.EXTRA_RESPONSE_IMPORTANT, responseImportant); + if (sentIntentExtras != null) { + sentIntent.putExtras(sentIntentExtras); + } + final PendingIntent sentPendingIntent = PendingIntent.getBroadcast( + context, + 0 /*request code*/, + sentIntent, + PendingIntent.FLAG_UPDATE_CURRENT); + + // Send the message + MmsManager.sendMultimediaMessage(subId, context, contentUri, locationUrl, + sentPendingIntent); + } + + private static Uri writePduToTempFile(final Context context, final GenericPdu pdu, int subId) + throws MmsFailureException { + final Uri contentUri = MmsFileProvider.buildRawMmsUri(); + final File tempFile = MmsFileProvider.getFile(contentUri); + FileOutputStream writer = null; + try { + // Ensure rawmms directory exists + tempFile.getParentFile().mkdirs(); + writer = new FileOutputStream(tempFile); + final byte[] pduBytes = new PduComposer(context, pdu).make(); + if (pduBytes == null) { + throw new MmsFailureException( + MmsUtils.MMS_REQUEST_NO_RETRY, "Failed to compose PDU"); + } + if (pduBytes.length > MmsConfig.get(subId).getMaxMessageSize()) { + throw new MmsFailureException( + MmsUtils.MMS_REQUEST_NO_RETRY, + MessageData.RAW_TELEPHONY_STATUS_MESSAGE_TOO_BIG); + } + writer.write(pduBytes); + } catch (final IOException e) { + if (tempFile != null) { + tempFile.delete(); + } + LogUtil.e(TAG, "Cannot create temporary file " + tempFile.getAbsolutePath(), e); + throw new MmsFailureException( + MmsUtils.MMS_REQUEST_AUTO_RETRY, "Cannot create raw mms file"); + } catch (final OutOfMemoryError e) { + if (tempFile != null) { + tempFile.delete(); + } + LogUtil.e(TAG, "Out of memory in composing PDU", e); + throw new MmsFailureException( + MmsUtils.MMS_REQUEST_MANUAL_RETRY, + MessageData.RAW_TELEPHONY_STATUS_MESSAGE_TOO_BIG); + } finally { + if (writer != null) { + try { + writer.close(); + } catch (final IOException e) { + // no action we can take here + } + } + } + return contentUri; + } + + public static SendConf parseSendConf(byte[] response, int subId) { + if (response != null) { + final GenericPdu respPdu = new PduParser( + response, MmsConfig.get(subId).getSupportMmsContentDisposition()).parse(); + if (respPdu != null) { + if (respPdu instanceof SendConf) { + return (SendConf) respPdu; + } else { + LogUtil.e(TAG, "MmsSender: send response not SendConf"); + } + } else { + // Invalid PDU + LogUtil.e(TAG, "MmsSender: send invalid response"); + } + } + // Empty or invalid response + return null; + } + + /** + * Download an MMS message. + * + * @param context Context + * @param contentLocation The url of the MMS message + * @throws MmsFailureException + * @throws InvalidHeaderValueException + */ + public static void downloadMms(final Context context, final int subId, + final String contentLocation, Bundle extras) throws MmsFailureException, + InvalidHeaderValueException { + final Uri requestUri = Uri.parse(contentLocation); + final Uri contentUri = MmsFileProvider.buildRawMmsUri(); + + final Intent downloadedIntent = new Intent(SendStatusReceiver.MMS_DOWNLOADED_ACTION, + requestUri, + context, + SendStatusReceiver.class); + downloadedIntent.putExtra(SendMessageAction.EXTRA_CONTENT_URI, contentUri); + if (extras != null) { + downloadedIntent.putExtras(extras); + } + final PendingIntent downloadedPendingIntent = PendingIntent.getBroadcast( + context, + 0 /*request code*/, + downloadedIntent, + PendingIntent.FLAG_UPDATE_CURRENT); + + MmsManager.downloadMultimediaMessage(subId, context, contentLocation, contentUri, + downloadedPendingIntent); + } + + public static RetrieveConf parseRetrieveConf(byte[] data, int subId) { + if (data != null) { + final GenericPdu pdu = new PduParser( + data, MmsConfig.get(subId).getSupportMmsContentDisposition()).parse(); + if (pdu != null) { + if (pdu instanceof RetrieveConf) { + return (RetrieveConf) pdu; + } else { + LogUtil.e(TAG, "MmsSender: downloaded pdu not RetrieveConf: " + + pdu.getClass().getName()); + } + } else { + LogUtil.e(TAG, "MmsSender: downloaded pdu could not be parsed (invalid)"); + } + } + LogUtil.e(TAG, "MmsSender: downloaded pdu is empty"); + return null; + } + + // Process different result code from platform MMS service + public static int getErrorResultStatus(int resultCode, int httpStatusCode) { + Assert.isFalse(resultCode == Activity.RESULT_OK); + switch (resultCode) { + case SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS: + case SmsManager.MMS_ERROR_IO_ERROR: + return MmsUtils.MMS_REQUEST_AUTO_RETRY; + case SmsManager.MMS_ERROR_INVALID_APN: + case SmsManager.MMS_ERROR_CONFIGURATION_ERROR: + case SmsManager.MMS_ERROR_NO_DATA_NETWORK: + case SmsManager.MMS_ERROR_UNSPECIFIED: + return MmsUtils.MMS_REQUEST_MANUAL_RETRY; + case SmsManager.MMS_ERROR_HTTP_FAILURE: + if (httpStatusCode == 404) { + return MmsUtils.MMS_REQUEST_NO_RETRY; + } else { + return MmsUtils.MMS_REQUEST_AUTO_RETRY; + } + default: + return MmsUtils.MMS_REQUEST_MANUAL_RETRY; + } + } +} |