Google’s Android allows developers a great deal of access to the phone. Enable your applications to communicate with the outside world using SMS messages.
by Chris Haseman
ushing data to and from a third-party mobile application on demand has always been a tricky proposition. BREW allows, with the blessing of Qualcoom, SMS messages to be directed at a particular application resident on the phone. Apple's iPhone messaging platform, which, as of press time, is still in testing, allows for similar functionality through HTTP push messaging. As for Java ME, well, we're just not going to talk about Java ME. Doing data push and remote application activation with Android is somewhat similar to BREW's directed SMS process. By the time you finish this article, you should have a steady grasp of how to send and receive SMS messages from your application in Android.
You'll explore the SMS functionality in two ways. First, you'll set up a BroadcastReceiver to intercept and inspect SMS messages as they are delivered to the phone. Once you've received them you'll be able to inspect their contents, activate an application, process data, or, as we'll explore in the second part, send a return SMS message.
Author's Note: This code for this article is based on version 1.0 BETA of the Android SDK, and I'd recommend an update to the latest version of Android before trying any of the code below.
Receiving SMS Messages
Receiving and reacting to SMS events can be broken down into two tasks: registering for SMS_RECIEVED intents through the AndroidManifest.xml file, and writing code that combs through those events looking for specific text.
Registering for SMS BroadcastIntents
For you copy/paste programmers out there, you can find the entire contents of this test application here.
With absolutely nothing else, here's what the AndroidManifest.xml file looks like:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.devx.SMSExample">
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<receiver android:name=".SmsIntentReceiver" android:enabled="true">
<intent-filter>
<action android:name=
"android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
The file contains a few notable pieces of information. First, but not necessarily foremost, is the <uses-permissions> tag. This line must appear within the manifest tag but before the definition of the application. This tells Android that you'll be using the RECEIVE_SMS and SEND_SMS permissions. Currently, Android has not announced how it will deal with user notifications and permission filtering. For now, it's enough to know that the application won't work without these permission declarations.
Second, is the <receiver> tag. This block of XML tells the Android OS the name of the class to load, in this case SmsIntentReceiver, and which BroadcastIntents on which to load it. You'll tell Android which intents to send us by registering for <action> tags inside the <intent-filter> tag. In this case, you'll register for the android.provider.Telephony.SMS_RECIEVED intent. This intent is fired each time an SMS hits the phone.
Author's Note: Currently, Android does not allow one BroadcastReceiver to accept and consume an Intent. This is a major technical hurdle that must be overcome before Android is released into the world. Because you cannot consume SMS message intents, both the application and Android's native SMS application will receive the incoming SMS message. As you'll see later, this means you'll have to keep filter text for the SMS messages human readable—as they'll end up in the inbox of the person receiving the message.
Processing Incoming Messages
Okay, so your BroadcastReceiver is set up to be called each time a new SMS intent hits the phone. Now, you'll need to process these incoming messages and do something with them.
Once upon a time, Android included a function called getMessagesFromIntent() which, in their infinite wisdom, they decided to remove from the 1.0 SDK. Because I'm a nice guy, I've re-written this function for you. I won't go into too much detail on it, instead I'll just give you the source code:
private SmsMessage[]
getMessagesFromIntent(Intent intent)
{
SmsMessage retMsgs[] = null;
Bundle bdl = intent.getExtras();
try{
Object pdus[] = (Object [])bdl.get("pdus");
retMsgs = new SmsMessage[pdus.length];
for(int n=0; n < pdus.length; n++)
{
byte[] byteData = (byte[])pdus[n];
retMsgs[n] =
SmsMessage.createFromPdu(byteData);
}
}
catch(Exception e)
{
Log.e("GetMessages", "fail", e);
}
return retMsgs;
}
Again, for you copy/paste programmers, click here for the full project data. Now that you've got the Intent extras converted into SMSMessages, check out Listing 1 to see the example onReceive function.
All right, that's a fair amount of code. Let's walk through it a little bit at a time. Your first task is to be sure you've received the correct Intent. To do this, you'll need to call getAction() on the passed-in Intent class.
Next, you'll need to retrieve an array of messages that are currently in the SMS hopper. This was a tough function to track down as it's incredibly poorly documented in the Android docs (this usually means that it will change in a later release). The task involves calling getMessagesFromIntent() while again passing in the intent object, which will return an array of SmsMessage objects. You'll need to loop through these messages searching for specific trigger texts. To get the messages body out of the SmsMessage object you'll have to call getDisplayMessageBody() on each SmsMessage in the array.
Again, because Android doesn't give us a chance to pull Intents out of the broadcast stack, you'll have to make the triggers humanly readable. In this little sample application, you can see two distinct triggers. The first trigger starts an application, while the second performs a GPS lookup and fires back an SMS detailing the location of the phone. We'll get into GPS information and sending SMS messages in a minute. First things first. Let's look, really quickly, at firing up an application or Activity from a BroadcastReceiver.
Waking Up the Application
Waking up your test application on an incoming SMS simply requires you, once you've received the correct SMS, to create the appropriate Intent and send it on it's way. First, you'll need an Activity with which to start your application. For those of you who are old hands at Android development, this section is going to be a bit of a review.
The first step is to add an activity to your AndroidManifest.xml file. If you started a new project from scratch (or your cheated and downloaded the source code), chances are you already have a "hello world" activity. For reference, here's what the new activity will look like, pay careful attention to the additional action in the intent receiver tag.
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".BaseScreen" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="com.devx.SMSExample.WAKE_UP"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Insert the above listing inside the application tag alongside the receiver you defined earlier. Notice the com.devx.SMSExample.WAKE_UP action: This is the intent you'll need to send to wake up the Activity. Here’s the source code that will wake up your sample activity:
private void triggerAppLaunch(Context context)
{
Intent broadcast = new Intent("com.devx.SMSExample.WAKE_UP");
broadcast.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(new Intent(broadcast));
}
Create a new Intent with the action defined above in the AnroidManifest.xml. Because you're starting a new Activity from a BroadcastReceiver, you'll need to add the FLAG_ACTIVITY_NEW_TASK flag to the intent before calling startActivity. At this point, the incoming SMS message will launch your shiny new "hello world" activity. What you do with that activity at this point is your own business.
Sending an SMS
So far, you've learned how to listen for and respond to incoming SMS messages. To close the loop, you'll have to be able to send text messages. As an example, you'll extend the SMS listener so that it will report the GPS coordanates of the phone.
Where Did I Leave My Phone?
As a means to demonstrate sending an SMS message, you'll have to extend your SMS listener application to report, through text messaging, where it is. Because you're already listening for incoming text messages, you can just flesh out the function alluded to above. You'll just need to finish getGPSData() and sendGPSData(). Because this article isn't about position locations, you're going to be on your own for the GPS stuff. You can, however, check out one of my previous DevX articles for information on completing a GPS position lookup.
Assume, for the sake of simplicity and expediency, that you have used the phone's GPS module to obtain it's location. Further assume that you'll need to send that data back to the device requesting it. Android makes it very easy to build and send SMS messages. Listing 2 shows the code to do so.
Simple, right? Okay, maybe not so much. You'll need to build a string to send off in the text message, using the predetermined lat and lon address. You'll also need to grab the default SmsManager instance. You must, with the 0.9 version of the SDK, create a PendingIntent that can eventually be passed into the sendTextMessage call; more on that in a second. Next, you'll want to grab the return address on the incoming text message so you can address the SMS back out.
With all these pieces in place its time to call sendTextMessage.
No comments:
Post a Comment