MMS in Android. Part 1. Sending and receiving MMS

August 13, 2011 § 5 Comments

Judging by forums questions (and my own experience) sending mms programmatically is quite complicate issue. That is because there is no documented API for it. To start working with mms we will need to use some undocumented classes. Happily Android OS is open source project. So we can download some classes from http://android.git.kernel.org/ and use it in our code. I know that it is not the best solution (while in future version this code could be modified) but it is the only one if you want to work with mms from your code.

Before starting working with mms I would recommend get to touch with Multimedia Messaging Service Encapsulation Protocol documentation.

There are different Multimedia Message Types. Each of them has own purpose. Here is the most important ones that we will use below:

  • “m-send-req” – sending message
  • “m-notification-ind” - provide the MMS Client with information about a MM located at the recipient MMS Proxy-Relay and waiting for retrieval. Client after that should fetch MM. It doesn’t contain Message Body but only Header.
  • “m-delivery-ind” – delivery report of MM

Here are inner classes that we can use.

We will need (you can copy the whole file or “borrow part of them”):

  • android.provider.Telephony
  • com.google.android.mms.ContentType
Files from com.google.android.mms.pdu package:
  • PduHeaders – contains map of headers
  • PduBody – includes PduParts
  • PduPart – consists of part header, data uri, part data
  • GenericPdu – wraps PduHeader
  • MultimediaMessagePdu – extends GenericPdu, adds PduBody to it
  • SendReq – extends MultimediaMessagePdu, represents sending request – “m-send-req” type
  • DeliveryInd - extends GenericPdu , represents delivery report – “m-delivery-ind” type
  • NotificationInd -  extends GenericPdu , represents notification about incoming message (that is stored in MMBOX and should be retrieved from there) – “m-notification-ind” type
  • PduComposer – translate Pdu to byte[]
  • PduParser – translate byte[] to Pdu
  • PduPersister – stores MM in storage.

Ok, here are the tasks to implement comprehencive mms support for your application:

  • Sending mms
  • Receiving delivery/read report
  • Receiving incoming mms
  • Getting list of mms from storage
  • Inserting/updating/deleting mms data to/at/from storage

First of all you should understand what points from above list you are going to implement.

So, in order…

Sending mms

MMS unlike SMS is send through http connection. Actually it is just request to mmsc (Multimedia Message System Center).

First of all we have to request Connectivity Service to enable mms:

  ConnectivityManager mConnMgr = 
        (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
  int result = mConnMgr.startUsingNetworkFeature(
        ConnectivityManager.TYPE_MOBILE, "enableMMS");

If result is 0 (APN_ALREADY_ACTIVE) we can start sending MMS. But likely it is not. In that case we have to wait while it become ACTIVE. We can register broadcast receiver that listens “ConnectivityManager.CONNECTIVITY_ACTION” action. At onReceive() method of our receiver we check whether connectivity manager is ready to send mms:

    String action = intent.getAction();
    if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
        return;
    }

    NetworkInfo mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
        ConnectivityManager.EXTRA_NETWORK_INFO);

    // Check availability of the mobile network.
    if ((mNetworkInfo == null) ||
        (mNetworkInfo.getType() != ConnectivityManager.TYPE_MOBILE_MMS)) {
        return;
    }

    if (!mNetworkInfo.isConnected()) {
        return;
    } else {
	//send mms
    }

How to send mms when we are ready to do it? We can watch sources of standard messaging client that are open as almost everything in Android. To implement the same solution is not too complicated but quite intricate.

Or we can use API that was designed by Nokia that encapsulates all complexity. You can find more information and links here.

But none of the solutions works with Samsung (at list Galaxy S and Galaxy Tab). It throws exception during http request to mmsc. It seems that Samsung have changed some network properties. I have not yet figured out how to cope with it.

Receiving delivery/read report

We should implement BroadcastReceiver with follow intent filter:

    <intent-filter>
        <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
        <data android:mimeType="application/vnd.wap.mms-message" />
    </intent-filter>

In onReceive() we get pdu byte[] from intent and transform it in GenericPdu object via PduParser:

    byte[] pushData = intent.getByteArrayExtra("data");
    PduParser parser = new PduParser(pushData);
    GenericPdu pdu = parser.parse();

Than we get the pdu’s type and check whether it delivery/read report:

    int type = pdu.getMessageType();
    if(type == PduHeaders.MESSAGE_TYPE_DELIVERY_IND) {
        String messageId = new String(((DeliveryInd)pdu).getMessageId());
        //Notify app that mms with messageId was delivered
    }

Ok, here we can make a try to update data in storage. But it is not necessary. Standard messenger will do it for us. While device is not rooted it is impossible to delete or shut down standard client. And it makes our way a bit easier.

But if we want to make it anyway we get delivery status and make appropriate update of storage:

    int status = ((DeliveryInd)pdu).getStatus();
    if(status == PduHeaders.STATUS_RETRIEVED) {
        //message delivered. update storage
    }

There could be follow statuses:

  • PduHeaders.STATUS_EXPIRED
  • PduHeaders.STATUS_RETRIEVED
  • PduHeaders.STATUS_REJECTED
  • PduHeaders.STATUS_DEFERRED
  • PduHeaders.STATUS_UNRECOGNIZED
  • PduHeaders.STATUS_INDETERMINATE
  • PduHeaders.STATUS_FORWARDED
  • PduHeaders.STATUS_UNREACHABLE
The meaning is clear from it name. We can define how to act in each case. For example that’s how we can save update if the status ==  STATUS_RETRIEVED (delivered):
    ContentValues values = new ContentValues();
    values.put("msg_box", 2); //type 2 == MESSAGE_TYPE_SENT
    String where = "_id" + " = '" + messageId + "'";
    context.getContentResolver().update(
            Uri.parse("content://mms"), values, where, null);

Receiving incoming MMS

When we have new inbox MMS we receive (in our broadcast receiver that is described above) pdu that has “m-notification-ind” type. But this pdu doesn’t contain multimedia data but only location at MMBOX of our mmsc where the content is situated. And we have to download it from that location.

Actually standard message client will do it for us. I will not write how to do it by our own. It is complicated process that take a lot of code at dozen classes. You can follow the path of tasks starting from com.android.mms.transaction.PduReceiver onReceive() method. If you really need the solution you can always use the code from that package.

About these ads

§ 5 Responses to MMS in Android. Part 1. Sending and receiving MMS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

What’s this?

You are currently reading MMS in Android. Part 1. Sending and receiving MMS at maxim bogatov.

meta

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: