title: Sending and Receiving SMS and MMS in Android (pre Kit Kat Android 4.4)
body: <p>I have figured out how to send and receive SMS messages.  To send SMS messages I had to call the <code>sendTextMessage()</code> and <code>sendMultipartTextMessage()</code> methods of the <code>SmsManager</code> class.  To receive SMS messages, I had to register a receiver in the <code>AndroidMainfest.xml</code> file.  Then I had to override the <code>onReceive()</code> method of the <code>BroadcastReceiver</code>.  I have included examples below.</p>
  
  <p><strong>MainActivity.java</strong></p>
  
  <pre><code>public class MainActivity extends Activity {
      private static String SENT = "SMS_SENT";
      private static String DELIVERED = "SMS_DELIVERED";
      private static int MAX_SMS_MESSAGE_LENGTH = 160;
  
      // ---sends an SMS message to another device---
      public static void sendSMS(String phoneNumber, String message) {
  
          PendingIntent piSent = PendingIntent.getBroadcast(mContext, 0, new Intent(SENT), 0);
          PendingIntent piDelivered = PendingIntent.getBroadcast(mContext, 0,new Intent(DELIVERED), 0);
          SmsManager smsManager = SmsManager.getDefault();
  
          int length = message.length();          
          if(length &gt; MAX_SMS_MESSAGE_LENGTH) {
              ArrayList&lt;String&gt; messagelist = smsManager.divideMessage(message);          
              smsManager.sendMultipartTextMessage(phoneNumber, null, messagelist, null, null);
          }
          else
              smsManager.sendTextMessage(phoneNumber, null, message, piSent, piDelivered);
          }
      }
  
      //More methods of MainActivity ...
  }
  </code></pre>
  
  <p><strong>SMSReceiver.java</strong></p>
  
  <pre><code>public class SMSReceiver extends BroadcastReceiver {
      private final String DEBUG_TAG = getClass().getSimpleName().toString();
      private static final String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
      private Context mContext;
      private Intent mIntent;
  
      // Retrieve SMS
      public void onReceive(Context context, Intent intent) {
          mContext = context;
          mIntent = intent;
  
          String action = intent.getAction();
  
          if(action.equals(ACTION_SMS_RECEIVED)){
  
              String address, str = "";
              int contactId = -1;
  
              SmsMessage[] msgs = getMessagesFromIntent(mIntent);
              if (msgs != null) {
                  for (int i = 0; i &lt; msgs.length; i++) {
                      address = msgs[i].getOriginatingAddress();
                      contactId = ContactsUtils.getContactId(mContext, address, "address");
                      str += msgs[i].getMessageBody().toString();
                      str += "\n";
                  }
              }   
  
              if(contactId != -1){
                  showNotification(contactId, str);
              }
  
              // ---send a broadcast intent to update the SMS received in the
              // activity---
              Intent broadcastIntent = new Intent();
              broadcastIntent.setAction("SMS_RECEIVED_ACTION");
              broadcastIntent.putExtra("sms", str);
              context.sendBroadcast(broadcastIntent);
          }
  
      }
  
      public static SmsMessage[] getMessagesFromIntent(Intent intent) {
          Object[] messages = (Object[]) intent.getSerializableExtra("pdus");
          byte[][] pduObjs = new byte[messages.length][];
  
          for (int i = 0; i &lt; messages.length; i++) {
              pduObjs[i] = (byte[]) messages[i];
          }
          byte[][] pdus = new byte[pduObjs.length][];
          int pduCount = pdus.length;
          SmsMessage[] msgs = new SmsMessage[pduCount];
          for (int i = 0; i &lt; pduCount; i++) {
              pdus[i] = pduObjs[i];
              msgs[i] = SmsMessage.createFromPdu(pdus[i]);
          }
          return msgs;
      }
  
      /**
      * The notification is the icon and associated expanded entry in the status
      * bar.
      */
      protected void showNotification(int contactId, String message) {
          //Display notification...
      }
  }
  </code></pre>
  
  <p><strong>AndroidManifest.xml</strong></p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.myexample"
      android:versionCode="1"
      android:versionName="1.0" &gt;
  
      &lt;uses-sdk
          android:minSdkVersion="16"
          android:targetSdkVersion="17" /&gt;
  
      &lt;uses-permission android:name="android.permission.READ_CONTACTS" /&gt;
      &lt;uses-permission android:name="android.permission.READ_PHONE_STATE" /&gt;
      &lt;uses-permission android:name="android.permission.SEND_SMS" /&gt;
      &lt;uses-permission android:name="android.permission.RECEIVE_SMS" /&gt;
      &lt;uses-permission android:name="android.permission.READ_SMS" /&gt;
      &lt;uses-permission android:name="android.permission.WRITE_SMS" /&gt;
      &lt;uses-permission android:name="android.permission.RECEIVE_MMS" /&gt;
      &lt;uses-permission android:name="android.permission.WRITE" /&gt;
      &lt;uses-permission android:name="android.permission.VIBRATE" /&gt;
      &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
      &lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;
  
      &lt;application
          android:debuggable="true"
          android:icon="@drawable/ic_launcher_icon"
          android:label="@string/app_name" &gt;
  
          &lt;activity
              //Main activity...
              &lt;intent-filter&gt;
                  &lt;action android:name="android.intent.action.MAIN" /&gt;
  
                  &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
              &lt;/intent-filter&gt;
          &lt;/activity&gt;
          &lt;activity
              //Activity 2 ...
          &lt;/activity&gt;
          //More acitivies ...
  
          // SMS Receiver
          &lt;receiver android:name="com.myexample.receivers.SMSReceiver" &gt;
              &lt;intent-filter&gt;
                  &lt;action android:name="android.provider.Telephony.SMS_RECEIVED" /&gt;
              &lt;/intent-filter&gt;
          &lt;/receiver&gt;
  
      &lt;/application&gt;
  &lt;/manifest&gt;
  </code></pre>
  
  <p>However, I was wondering if you could send and receive MMS messages in a similar fashion.  After doing some research, many examples provided on blogs simply pass an <code>Intent</code> to the native Messaging application.  I am trying to send an MMS without leaving my application.  There doesn't seem to be a standard way of sending and receiving MMS.  Has anyone gotten this to work?</p>
  
  <p>Also, I am aware that the SMS/MMS ContentProvider is not a part of the official Android SDK, but I was thinking someone may have been able to implement this.  Any help is greatly appreciated.</p>
  
  <h1>Update</h1>
  
  <p>I have added a <code>BroadcastReceiver</code> to the <code>AndroidManifest.xml</code> file to receive MMS messages  </p>
  
  <pre><code>&lt;receiver android:name="com.sendit.receivers.MMSReceiver" &gt;
      &lt;intent-filter&gt;
          &lt;action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" /&gt;
  
          &lt;data android:mimeType="application/vnd.wap.mms-message" /&gt;
      &lt;/intent-filter&gt;
  &lt;/receiver&gt;
  </code></pre>
  
  <p>In the MMSReceiver class, the <code>onReceive()</code> method is only able to grab the phoneNumber that the message was sent from.  How do you grab other important things from an MMS such as the file path to the media attachment (image/audio/video), or the text in the MMS?</p>
  
  <p><strong>MMSReceiver.java</strong></p>
  
  <pre><code>public class MMSReceiver extends BroadcastReceiver {
      private final String DEBUG_TAG = getClass().getSimpleName().toString();
      private static final String ACTION_MMS_RECEIVED = "android.provider.Telephony.WAP_PUSH_RECEIVED";
      private static final String MMS_DATA_TYPE = "application/vnd.wap.mms-message";
  
       // Retrieve MMS
      public void onReceive(Context context, Intent intent) {
  
          String action = intent.getAction();
          String type = intent.getType();
  
          if(action.equals(ACTION_MMS_RECEIVED) &amp;&amp; type.equals(MMS_DATA_TYPE)){
  
              Bundle bundle = intent.getExtras();
  
              Log.d(DEBUG_TAG, "bundle " + bundle);
              SmsMessage[] msgs = null;
              String str = "";
              int contactId = -1;
              String address;
  
              if (bundle != null) {
  
                  byte[] buffer = bundle.getByteArray("data");
                  Log.d(DEBUG_TAG, "buffer " + buffer);
                  String incomingNumber = new String(buffer);
                  int indx = incomingNumber.indexOf("/TYPE");
                  if(indx&gt;0 &amp;&amp; (indx-15)&gt;0){
                      int newIndx = indx - 15;
                      incomingNumber = incomingNumber.substring(newIndx, indx);
                      indx = incomingNumber.indexOf("+");
                      if(indx&gt;0){
                          incomingNumber = incomingNumber.substring(indx);
                          Log.d(DEBUG_TAG, "Mobile Number: " + incomingNumber);
                      }
                  }
  
                  int transactionId = bundle.getInt("transactionId");
                  Log.d(DEBUG_TAG, "transactionId " + transactionId);
  
                  int pduType = bundle.getInt("pduType");
                  Log.d(DEBUG_TAG, "pduType " + pduType);
  
                  byte[] buffer2 = bundle.getByteArray("header");      
                  String header = new String(buffer2);
                  Log.d(DEBUG_TAG, "header " + header);
  
                  if(contactId != -1){
                      showNotification(contactId, str);
                  }
  
                  // ---send a broadcast intent to update the MMS received in the
                  // activity---
                  Intent broadcastIntent = new Intent();
                  broadcastIntent.setAction("MMS_RECEIVED_ACTION");
                  broadcastIntent.putExtra("mms", str);
                  context.sendBroadcast(broadcastIntent);
  
              }
          }
  
      }
  
      /**
      * The notification is the icon and associated expanded entry in the status
      * bar.
      */
      protected void showNotification(int contactId, String message) {
          //Display notification...
      }
  }
  </code></pre>
  
  <p>According to the <a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/provider/Telephony.java?av=f" rel="noreferrer">Documentation of android.provider.Telephony</a>:</p>
  
  <blockquote>
    <p>Broadcast Action: A new text based SMS message has been received by the device. The intent will have the following extra values:</p>
    
    <p><code>pdus</code> - An <code>Object[]</code> of <code>byte[]</code>s containing the PDUs that make up the message.</p>
    
    <p>The extra values can be extracted using <code>getMessagesFromIntent(android.content.Intent)</code>
    If a BroadcastReceiver encounters an error while processing this intent it should set the result code appropriately.</p>
  
  <pre><code> @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
   public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
  </code></pre>
    
    <hr>
    
    <p>Broadcast Action: A new data based SMS message has been received by the device. The intent will have the following extra values:</p>
    
    <p><code>pdus</code> - An <code>Object[]</code> of <code>byte[]</code>s containing the PDUs that make up the message.</p>
    
    <p>The extra values can be extracted using getMessagesFromIntent(android.content.Intent).
    If a BroadcastReceiver encounters an error while processing this intent it should set the result code appropriately.</p>
  
  <pre><code>@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  public static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED";
  </code></pre>
    
    <hr>
    
    <p>Broadcast Action: A new WAP PUSH message has been received by the device. The intent will have the following extra values:</p>
    
    <p><code>transactionId (Integer)</code> - The WAP transaction ID</p>
    
    <p><code>pduType (Integer)</code> - The WAP PDU type`</p>
    
    <p><code>header (byte[])</code> - The header of the message</p>
    
    <p><code>data (byte[])</code> - The data payload of the message</p>
    
    <p><code>contentTypeParameters (HashMap&lt;String,String&gt;)</code> - Any parameters associated with the content type (decoded from the WSP Content-Type header)</p>
    
    <p>If a BroadcastReceiver encounters an error while processing this intent it should set the result code appropriately.
    The contentTypeParameters extra value is map of content parameters keyed by their names.
    If any unassigned well-known parameters are encountered, the key of the map will be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter. If a parameter has No-Value the value in the map will be null.</p>
  
  <pre><code>@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
  public static final String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED";
  </code></pre>
  </blockquote>
  
  <h1>Update #2</h1>
  
  <p>I have figured out how to pass extras in a <code>PendingIntent</code> to be received by a <code>BroadcastReceiver</code>:
  <a href="https://stackoverflow.com/questions/14571564/android-pendingintent-extras-not-received-by-broadcastreceiver">Android PendingIntent extras, not received by BroadcastReceiver</a></p>
  
  <p>However, the extra gets passed to the <em>SendBroadcastReceiver</em> not the <em>SMSReceiver</em>.  How can I pass an extra to the <em>SMSReceiver</em>?</p>
  
  <h1>Update #3</h1>
  
  <p><strong>Receiving MMS</strong></p>
  
  <p>So after doing more research I saw some suggestions of registering a <code>ContentObserver</code>.  That way you can detect when there are any changes to the <code>content://mms-sms/conversations</code> Content Provider, consequently allowing you to detect incoming MMS.  Here is the closest example to get this to work that I have found: <a href="http://www.anddev.org/other-coding-problems-f5/where-can-i-find-information-about-sending-receiving-mms-t51284.html" rel="noreferrer">Receiving MMS</a></p>
  
  <p>However, there is a variable <code>mainActivity</code> of type <code>ServiceController</code>.  Where is the <code>ServiceController</code> class implemented?  Are there any other implementations of a registered <code>ContentObserver</code>?</p>
  
  <p><strong>Sending MMS</strong></p>
  
  <p>As for sending MMS, I have come across this example: <a href="http://www.ziddu.com/download/14286605/SendMMS3.zip.html" rel="noreferrer">Send MMS</a></p>
  
  <p>The problem is that I tried running this code on my Nexus 4, which is on Android v4.2.2, and I am receiving this error:</p>
  
  <pre><code>java.lang.SecurityException: No permission to write APN settings: Neither user 10099 nor current process has android.permission.WRITE_APN_SETTINGS.
  </code></pre>
  
  <p>The error gets thrown after querying the <code>Carriers</code> ContentProvider in the <code>getMMSApns()</code> method of the <code>APNHelper</code> class.</p>
  
  <pre><code>final Cursor apnCursor = this.context.getContentResolver().query(Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), null, null, null, null);
  </code></pre>
  
  <p>Apparently you can't <a href="https://stackoverflow.com/questions/13453640/read-apns-in-android-4-2">read APNs in Android 4.2</a>   </p>
  
  <p>What is the alternative for all those applications which use mobile data to perform operations (like sending MMS) and don't know the default APN setting present in the device?</p>
  
  <h1>Update #4</h1>
  
  <p><strong>Sending MMS</strong></p>
  
  <p>I have tried following this example: <a href="http://www.ziddu.com/download/14286605/SendMMS3.zip.html" rel="noreferrer">Send MMS</a></p>
  
  <p>As @Sam suggested in his answer: </p>
  
  <p><code>You have to add jsoup to the build path, the jar to the build path and import com.droidprism.*; To do that in android, add the jars to the libs directory first, then configure the project build path to use the jars already in the libs directory, then on the build path config click order and export and check the boxes of the jars and move jsoup and droidprism jar to the top of the build order.</code></p>
  
  <p>So now I no longer get the SecurityException errors.  I am testing now on a Nexus 5 on Android KitKat.  After running the sample code it gives me a 200 response code after the call to </p>
  
  <pre><code>MMResponse mmResponse = sender.send(out, isProxySet, MMSProxy, MMSPort);
  </code></pre>
  
  <p>However, I checked with the person I tried sending the MMS to. And they said they never received the MMS. </p>