Android Custom SMS popup - Part One : The BroadcastReceiver
Join the DZone community and get the full member experience.
Join For FreeHere's a concrete and mildly useful Android application illustrating the use of some of Android fundamental concepts: Broadcast receivers, Intents, Services, Activities, and Content providers.
A word on which Android SDK version to use. While most of us would like to use the latest version with all the cool stuff, we must keep in mind that our application needs to cater to the most common Android SDK versions on the market at the time we design it. An application written for the older versions works with the newer ones, but the reverse is of course not true. The most common versions in use at the time of this writing are 2.2 (Froyo) and 2.3 (Gingerbread).
That said, let's build up on Android phone default SMS notification mechanism by having a window pop-up on SMS reception optionally with some sound attached to it, so that we can be alerted and read the message ASAP, and also respond to it right away if we choose to do so, using the SMS application(s) already available on the phone. So basically, we need to:
- Intercept incoming SMS
- Display it on the screen as a pop-up, with maybe a distinctive sound
- Call the default SMS program from that dialog in case we want to reply right away.
Intercepting SMS using a BroadcastReceiver
In general, we use a BroadcastReceiver when we want to do something on system or other applications' broadcasts, like when the phone screen is turned off, a picture is taken by the camera, a download was completed, or...an SMS has arrived. Here's how to do it:
package com.ts.pop.sms; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.telephony.SmsMessage; public class SMSReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // SMS interception code goes here }
A few brief explanations:
- A Context provides us with access to application & system resources.
- An Intent is a bundle of information that can be passed around. More on that later on.
- A Bundle is a map of key-value pairs.
- I'll let you make a wild guess on what an SmsMessage represents.
- We need to override the BroadcasdtReceiver's onReceive method if we want to handle the actual phone broadcast events.
This all fine and dandy (OK, maybe not that dandy at this point), but... how to get SMS in the midst of other broadcasts? As I said, a Bundle is a map, and SMS messages are the values in that map corresponding to key = "pdus". PDU stands for for Protocol Data Unit, information delivered through a network layer.
// get the Bundle map from the Intent parameter to onReceive() Bundle bundle = intent.getExtras(); // get the SMS received Object[] pdus = (Object[]) bundle.get("pdus"); SmsMessage[] msgs = new SmsMessage[pdus.length];
Now, we get the SMS information we need:
/** sms sender phone*/ String smsSender =""; /** body of received sms*/ String smsBody = ""; /** timerstamp */ long timestamp = 0L; for (int i=0; i<msgs.length; i++){ msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]); smsSender += msgs[i].getOriginatingAddress(); smsBody += msgs[i].getMessageBody().toString(); timestamp += msgs[i].getTimestampMillis(); }
We are nearly done with our SMS receiver. We must now inform the Android system that:
- We have a Broadcast receiver for SMS
- We need the phone user to allow our application to receive and read that SMS
That is done in an Android XML file called the Manifest. What we put in that file is our receiver and its purpose in life:
<!-- Incoming SMS messages can be intercepted by the SMSReceiver class -->< <receiver android:name="com.ts.pop.sms.SMSReceiver"> <intent-filter android:priority="999" android:exported="true"> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver>
And the permissions that the user needs to give our application in order for it to fulfill its destiny:
<!-- Permissions --> <uses-permission android:name="android.permission.RECEIVE_SMS"/> <uses-permission android:name="android.permission.READ_SMS" />
We used the following:
- An intent-filter to describe the specific broadcast we are interested in, as there are many others.
- An android:priority attribute set high to some arbitrary number, in order to take precedence over other SMS receivers, like the default one.
- An android:exported attribute set to true so we can receive messages from sources outside of our application.
We now got everything we needed, and are ready to tackle the display part. Note that all the code above is happening inside the onReceive() method. Once that method returns, the BroadcastReceiver is no longer active. We've done some background work that is for the moment, invisible to the user, and what we need to do is to hand over the processing to some other mechanism, so as to be able to carry on to the display part.
We'll do that in Part Two.
Source: Tony's Blog.
Opinions expressed by DZone contributors are their own.
Comments