SMS Messaging

Intro

This lesson will walk through how to build an Android application that utilizes SMS messaging.  You'll see two versions. The first version only sends messages. The second version sends and receives messages.  

SMS Send

In order to build an app that sends SMS messages, we'll need to utilize the SmsManager class provided to us by Android in the android.telephony package.

We get an instance with the static getDefault  method. And then we use the sendTextMessage method to send the actual text messages:

SmsManager smsManager;

. . .

smsManager = SmsManager.getDefault();

. . .

smsManager.sendTextMessage("5556", null, "Hello", null, null);

 There are five arguments sent to the sendTextMessage method:

  1. (String) The destination address such as the phone number.
  2. (String) The service center address. The value of null specifies the default service center.
  3. (String) The text message sent to the destination address.
  4. (PendingIntent) The broadcast pending intent for confirming the message is successfully sent.
  5. (PendingIntent) the broadcast pending intent for confirming the message is successfully delivered (i.e., received by the destination address).

If we want to receive a broadcast when a text message is successfully sent and delivered, we do the following:

PendingIntent sentPI, deliveredPI;

. . .

sentPI = PendingIntent.getBroadcast(this, 0, new Intent("SMS SENT"), 0);

deliveredPI = PendingIntent.getBroadcast(this, 0, new Intent("SMS DELIVERED"), 0);

. . .

smsManager.sendTextMessage("5556", null, "Hello", sentPI, deliveredPI);

This will set up the broadcasts only. We need also need to establish the receiving of the broadcasts. In the earlier broadcast receiver example (the BroadcastReceiverBasic sample project), we specify the setup in the application's manifest file. In this example, we do the setup programmatically. We register the two broadcast receivers with the intent filters to catch the SMS SENT  and SMS DELIVERED  intents as:

The two broadcast receivers are defined as follows:

BroadcastReceiver confirmSentBR = new BroadcastReceiver( ) {

    @Override
    public void onReceive(Context context, Intent intent) {
        switch (getResultCode()) {
        case Activity.RESULT_OK:
            Toast.makeText(getBaseContext(),
                    "SMS sent successfully", Toast.LENGTH_SHORT).show();
            break;

        default: //all other codes are error
            Toast.makeText(getBaseContext(),
                    "Error: SMS was not sent", Toast.LENGTH_SHORT).show();
            break;
        }
    }

};

BroadcastReceiver confirmDeliveryBR = new BroadcastReceiver( ) {

    @Override
    public void onReceive(Context context, Intent intent) {
        switch (getResultCode()) {
        case Activity.RESULT_OK:
            Toast.makeText(getBaseContext(),
                "SMS delivered successfully", Toast.LENGTH_SHORT).show();
            break;

        default: //all other codes are error
            Toast.makeText(getBaseContext(),
                   "Error: SMS was not delivered",
                   Toast.LENGTH_SHORT).show();
            break;
        }

    }

};

You should replace the content of the onReceive methods with the actual code appropriate for your application.

Because the application is sending SMS text messages, we must add the following permission tag to the manifest file:

<uses-permission android:name="android.permission.SEND_SMS"></uses-permission>
IMPORTANT: The Delivery pending intent broadcast does not function in the emulator environment.

SMS Send and Receive

Now let's extend the SMS Send application by adding a feature to receive messages sent from other devices. To add this feature we need a separate broadcast receiver to recieve incoming messages. We name this receiver SMSReceiver

First we update the manifest file so the SMSReceiver will receive the intent android.provider.Telephony.SMS_RECEIVED by adding the receiver tag:

<receiver android:name=".SMSReceiver">
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
    </intent-filter>
</receiver>

and the corresponding permission tag

<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>

There are two main tasks an SMSReceiver instance performs:

  1. Extract messages from the raw PDU (protocol description unit) format and
  2. Pass the extracted messages to the Main activity via a broadcast.

Here's the SMSReceiver class:

public class SMSReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

	Bundle bundle = intent.getExtras();
	SmsMessage[] msgs;
	String text = "";

	if (bundle != null) { //we have something to pull out

   	    Object[] pdus = (Object[]) bundle.get("pdus");
	    msgs = new SmsMessage[pdus.length];

	    for (int i = 0; i < msgs.length; i++) {
		msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
		text += "From " + msgs[i].getOriginatingAddress() +
		    " : " +
		    msgs[i].getMessageBody().toString() + "\n";
	    }

	    //Now notify the Main activity about the received text so
	    //the Main can display it

	    Intent receiveIntent = new Intent();
	    receiveIntent.setAction(
		context.getString(R.string.sms_received));
	    receiveIntent.putExtra(
	    context.getString(R.string.sms_text), text);
	    context.sendBroadcast(receiveIntent);

        }

    }

}

An SMSReceiver instance is sending a broadcast to the Main activity, so now the Main activity requires the third broadcast receiver to catch the broadcast from the SMSReceiver. Here's how:

incomingSmsFilter = new IntentFilter();

incomingSmsFilter.addAction(getString(R.string.sms_received));

registerReceiver(incomingSmsBR, incomingSmsFilter);

. . .

BroadcastReceiver incomingSmsBR = new BroadcastReceiver( ) {

    @Override
    public void onReceive(Context context, Intent intent) {

	//append the incoming text at the end of display
	display.setText(display.getText().toString() + "\n" +
	intent.getExtras().getString(
	context.getString(R.string.sms_text)));

    }

};

Task: Create a new Project in Android Studio and write an app that incorporates the above code.  You'll need two AVD's to test it, so use the AVD manager to lauch them manually.  Then, when you run the app, a window will be displayed asking you which device to install the app on.  Install it on the '5554' device.  On the '5556' device, start the default messaging app.

Sometimes you need to use the code in Android Studio that was created in Eclipse.  No Problem!  All you have to do is import the Eclipse project and let Android Studio handle the conversion.  Here's an Eclipse Project for the above app: SMS_SendAndReceive.  Once you've finished the Task above, import this project into Android Studio and compare it to yours.