Home » Android

How to use Broadcast Receiver in Android – Send and Receive SMS

7 April 2012 16,539 views 25 Comments

Sending SMS is one of the basic features every phone has. In this tutorial we’ll create a SMS Sending Application for Android. You app can also Intercept any incoming SMS and perform task based on pre-defined rules, we’ll use Broadcast receiver for the listening  purpose.

Project Name: HelloSMS
Android Level: Android 2.3.3
Application Name: HelloSMS
Package Name: com.vineetdhanawat.hellosms
Create Activity: HelloSMS
Min SDK Version: 10
 

Layout

We’ll start with creating a layout for our main screen.

Components

  • 2 Text Strings
  • 2 Editable Text Box
  • Character Counter in Message
  • Send Button
Send-SMS

The Home Screen of the SendSMS App

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 >
<TextView
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="Enter the phone number of the recipient"
 />
<EditText
 android:id="@+id/phoneNo"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
/>
<TextView
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="Message"
/>
<EditText
 android:id="@+id/textMessage"
 android:layout_width="fill_parent"
 android:layout_height="160px"
 android:gravity="top"
/>
<TextView
 android:id="@+id/counter"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="160/0"
/>
<Button
 android:id="@+id/sendSMS"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="Send SMS"
/>
</LinearLayout>

HelloSMS Main Activity

In the Main HelloSMS Activity, we’ll do 2 things.

  • Bind the Send SMS button to a OnClickListener() for sending sms.
  • Bind the Message Text box to addTextChangedListener() for counter.
package com.vineetdhanawat.hellosms;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class HelloSMS extends Activity {
 // Called when the activity is first created.
  Button sendSMS;
  EditText phoneNo;
  EditText textMessage;
  TextView mCounter;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    sendSMS = (Button) findViewById(R.id.sendSMS);
    phoneNo = (EditText) findViewById(R.id.phoneNo);
    textMessage = (EditText) findViewById(R.id.textMessage);
    mCounter = (TextView) findViewById(R.id.counter);
    textMessage.addTextChangedListener(mTextEditorWatcher);
    // On Click Listener on the sendSMS Button.
    sendSMS.setOnClickListener(new View.OnClickListener() {
      public void onClick(View v) {
        String mobNo = phoneNo.getText().toString();
        String message = textMessage.getText().toString();
        if (mobNo.length()>0 && message.length()>0)
          sendSMS(mobNo, message);
        else
          Toast.makeText(getBaseContext(),
          "Please enter both phone number and message.",
          Toast.LENGTH_SHORT).show();
      }
    });
  }
}

The sendSMS() is defined as follows: We do not need to instantiate this class directly, Instead we can call getdefault() to obtain the SmsManager Object. sendTextMessage() send the sms with a PendingIntent. In this case it does nothing, but it can be used to monitor the status of sent SMS.

// Method to send SMS.
private void sendSMS(String phoneNumber, String message)
{
  PendingIntent pi = PendingIntent.getActivity(this, 0,
    new Intent(this, SMS.class), 0);
  SmsManager sms = SmsManager.getDefault();
  sms.sendTextMessage(phoneNumber, null, message, pi, null);
}

Let us modify the code to monitor the Sent / Delivered status of the SMS. We’ll need to use BroadcastReceiver object for the purpose.

// Method to send SMS.
private void sendSMS(String mobNo, String message) {
  String smsSent = "SMS_SENT";
  String smsDelivered = "SMS_DELIVERED";
  PendingIntent sentPI = PendingIntent.getBroadcast(this, 0,
     new Intent(smsSent), 0);
  PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0,
     new Intent(smsDelivered), 0);
  // Receiver for Sent SMS.
  registerReceiver(new BroadcastReceiver(){
    @Override
    public void onReceive(Context arg0, Intent arg1) {
      switch (getResultCode())
      {
        case Activity.RESULT_OK:
          Toast.makeText(getBaseContext(), "SMS sent",
            Toast.LENGTH_SHORT).show();
          break;
        case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
          Toast.makeText(getBaseContext(), "Generic failure",
            Toast.LENGTH_SHORT).show();
          break;
        case SmsManager.RESULT_ERROR_NO_SERVICE:
          Toast.makeText(getBaseContext(), "No service",
            Toast.LENGTH_SHORT).show();
          break;
        case SmsManager.RESULT_ERROR_NULL_PDU:
          Toast.makeText(getBaseContext(), "Null PDU",
            Toast.LENGTH_SHORT).show();
          break;
        case SmsManager.RESULT_ERROR_RADIO_OFF:
          Toast.makeText(getBaseContext(), "Radio off",
            Toast.LENGTH_SHORT).show();
          break;
      }
    }
  }, new IntentFilter(smsSent));
  // Receiver for Delivered SMS.
  registerReceiver(new BroadcastReceiver(){
    @Override
    public void onReceive(Context arg0, Intent arg1) {
      switch (getResultCode())
      {
        case Activity.RESULT_OK:
          Toast.makeText(getBaseContext(), "SMS delivered",
            Toast.LENGTH_SHORT).show();
          break;
        case Activity.RESULT_CANCELED:
          Toast.makeText(getBaseContext(), "SMS not delivered",
            Toast.LENGTH_SHORT).show();
          break;
        }
      }
    }, new IntentFilter(smsDelivered));
  SmsManager sms = SmsManager.getDefault();
  sms.sendTextMessage(mobNo, null, message, sentPI, deliveredPI);
}

Let us now implement the addTextChangedListener() as Counter.

SMS-Counter

Counter Display = No of Chars Left / Required SMS Count

private final TextWatcher mTextEditorWatcher = new TextWatcher() {
  public void beforeTextChanged(CharSequence s, int start,
   int count, int after) {
  }
  public void onTextChanged(CharSequence s, int start,
   int before, int count) {
    //This sets a textview to the current length
    String smsNo;
    if(s.length() == 0)
      smsNo = "0";
    else
    smsNo = String.valueOf(s.length()/160 + 1);
    String smsLength = String.valueOf(160-(s.length()%160));
    mCounter.setText(smsLength+"/"+smsNo);
  }
  @Override
  public void afterTextChanged(Editable arg0) {
    // TODO Auto-generated method stub
  }
};

Permissions

In the AndroidManifest.xml file, we need to add the two permissions SEND_SMS and RECEIVE_SMS

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.vineetdhanawat.hellosms"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="10" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".HelloSMS"
            android:label="@string/app_name" >
            <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <uses-permission android:name="android.permission.SEND_SMS">
	</uses-permission>
	<uses-permission android:name="android.permission.RECEIVE_SMS">
	</uses-permission>
</manifest>

Broadcast Receiver (Intercepting SMS)

Applications can intercept Incoming SMS as well. To do so, you need to add <receiver> element inside AndroidManifest.xml . Make sure it is included inside element.

<receiver android:name="com.vineetdhanawat.hellosms.SMSReceiver"
  android:enabled="true">
  <intent-filter>
  <action android:name="android.provider.Telephony.SMS_RECEIVED" />
  </intent-filter>
</receiver>

Add a new Class file SMSReceiver.java. Here we’ll be parsing the intercepted sms and displaying as Toast. But this will Toast all the incoming sms. In case you want to Toast particular senders, use getOriginatingAddress();

package com.vineetdhanawat.hellosms;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;
public class SMSReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
	    // Parse the SMS.
		Bundle bundle = intent.getExtras();
		SmsMessage[] msgs = null;
		String str = "";
		if (bundle != null)
		{
			// Retrieve the SMS.
			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]);
				// In case of a particular App / Service.
                //if(msgs[i].getOriginatingAddress().equals("+91XXX"))
                //{
				str += "SMS from " + msgs[i].getOriginatingAddress();
				str += " :";
				str += msgs[i].getMessageBody().toString();
				str += "\n";
                //}
            }
			// Display the SMS as Toast.
            Toast.makeText(context, str, Toast.LENGTH_SHORT).show();
        }
	}
}

That’s it. You can also use two emulators, By default they will have device names as emulator-5554 and emulator-5556. You can test it by sending sms from one of them to another giving emulator-5556 or just 5556 as the number.

App Ideas?

Using the Location Sensing (GPS) post which i posted a while before, and Broadcast Receiver above, It opens up a whole lot possibility of Apps.

Apps like JustDial. Where you have a lot of options like Theatres, Restaurant etc. All you need to do is choose an option. The app detects your location and sends your location to a pre-defined no. The server responds with list of available results (Say nearest Restaurants).

Want to learn more about Android Service and Broadcast Receiver? Check out Vogel’s Blog

Do you have any other Interesting App Ideas? Do share with us in the comments!

Related Posts Plugin for WordPress, Blogger...

  • Deepak Jaiswal888

    really awasome 
      thank u ………………

    • http://twitter.com/vineetdhanawat Vineet Dhanawat

      Glad you liked it! :)

  • giox

    Thanks a lot! I’ve a question: Does it work if the message is longer than 160 chars? Shouldn’t you use sendmultiparttextmessage instead?

    • http://twitter.com/vineetdhanawat Vineet Dhanawat

      Thanks for pointing out the mistake. I did not try sending sms > 160 characters. Will update the code soon!

  • Rajeshk

    this sending sms is good. how should i make this one to work between devices ???
    please help me ……..

    • http://twitter.com/vineetdhanawat Vineet Dhanawat

      You can make it work between two emulators by using the device names (emulator-5554 and 
      emulator-5556). For cellphones, use the 10-digit long no to send sms.

  • lucasbuckmcg

    How would you unregister your receiver? I’m using your code, thx btw :) sending one sms is fine, upon sending the second it creates another instance of broadcast receiver, so i receive 2 x sms sent notifications, 3 on the 3rd, 4 on the 4th etc.

    • http://twitter.com/vineetdhanawat Vineet Dhanawat

      Somehow I am not facing any such issues. Any updates?

    • http://www.facebook.com/richard.warner.986 Richard Warner

      Am new to Eclipse, but it seems really flakey. For instance, closing an emulator window sometimes messes it up where I have to close Eclipse and start it again.

      Sometimes the launcher will fail, but after a few times it will work…sometimes again takes a restart/reboot for launcher to work.

      Have not seen this issue before, but now am seeing it. Every SMS Send increments the number of times it is seen on the sending emulator. (As lucas mentions, it is as if there are multiple instances of the receiver responding, though the previous instance should go to garbage collection and only one should ever be active.) Did not have this issue before.

      • http://www.facebook.com/richard.warner.986 Richard Warner

        Have researched this a bit, and finding that the SMS sent and delivered intents are “sticky”. They hang around, and every time a new one is sent, all the sticky ones are received by the receiver plus the new one.

        Not sure why was *not* a problem before? Also not sure how to resolve it. Suppose if could get the sent and delivered intents to be unsticky, that would fix it.

  • Pingback: Counter display code in SMS « NIKSHITS

  • http://www.facebook.com/richard.warner.986 Richard Warner

    Is there an Eclipse project one can import? I am new to Eclipse and can never get these examples to work.

    In this case, and in general, there are name issues.
    setContentView(R.layout.main); #Multiple markers for main
    sendSMS = (Button) findViewById(R.id.sendSMS); #sendSMS cannot be resolved
    phoneNo = (EditText) findViewById(R.id.phoneNo); #phoneNo cannot be resolved
    textMessage = (EditText) findViewById(R.id.textMessage); #textMessage cannot be resolved
    mCounter = (TextView) findViewById(R.id.counter); #counter cannot be resolved
    textMessage.addTextChangedListener(mTextEditorWatcher); #mTextEditorWatcher cannot be resolved.

    How to make it work?

  • http://www.facebook.com/richard.warner.986 Richard Warner

    Hmmm. Saved files, cleaned, and renamed .xml activity file: main.xml. That got rid of all the errors and it compiles and runs. But, when I do a test and click the send button on the emulator, I get, “Generic Failure” message. Everything works, but I do not get a success message on the send. Will test it on a live phone and see if that works.

  • http://www.facebook.com/richard.warner.986 Richard Warner

    The test on a live phone failed. It said it produced an error with the packet analyzer.

    • http://www.facebook.com/richard.warner.986 Richard Warner

      Would not load onto the phone.

  • http://www.facebook.com/richard.warner.986 Richard Warner

    Maybe added in wrong place in manifest file… Will experiment with different places.

  • http://www.facebook.com/richard.warner.986 Richard Warner

    No luck, cannot get it to go.

  • http://www.facebook.com/richard.warner.986 Richard Warner

    Does block go inside block? Seems like it should be a direct child of application. Also, my Eclipse complained until I moved the blocks to before the block.

  • http://www.facebook.com/richard.warner.986 Richard Warner

    Making progress!! It entirely works between emulators now. with the previous mods done, then restarting Eclipse, it all works and life is good… Except it will not install on the phone. Have installed other apps by just emailing them. With this one there is a “Problem parsing the package” error.

    Yay! It looks like by changing MinSDK from 10 to 8 it is a go. Testing that all functions work on Frodo 2.2.2 now.

  • http://www.facebook.com/richard.warner.986 Richard Warner

    One issue I see is that the sending emulator displays an “SMS Sent” message, but not an “SMS Delivered” message. Not getting the verification message from the receiving emulator or phone (have tried it on live phones too).

    • http://www.facebook.com/richard.warner.986 Richard Warner

      Oh, maybe “delivered” is only sent after the receiving person READS the message? Am getting “Msg Delivered” on live phones, not on emulator.

      • http://www.vineetdhanawat.com/ vineetdhanawat

        True! Delivery Notification works only on real devices.

  • Craig W

    can i use this to receive an sms feed? i receive sms alerts from a local news station for weather and traffic and i was hoping this would intercept the alerts and output the info into the app…? Really would appreciate any ideas you may have.. thanks!

    • http://www.vineetdhanawat.com/ vineetdhanawat

      Yes, you can. Class file SMSReceiver.java is for that purpose. Please go through the code.