Friday, September 16, 2011

Location based app triggered by an SMS


Location based services has been the favorites for many application developers right from the day when poor man’s GPS evolved. Following this the handsets matured further in supporting GPS. We are in the world of smart phones which have definitely been the talk of the town and have been penetrating into various market segments at a very high pace. There still seems to be a window of handsets out in the market which are not “smart” enough. Challenge here is to find applications where both these segments can interact and benefit. Is it possible? Well, yes to some extent and the main weapon being the SMS.

While exploring this I came across many articles and examples that talk about SMS and location information processing. I take this opportunity in combining these two behaviors and come up with this application which finds the location or rather the street address whenever an SMS is received. Here the originator sends an SMS to a handset on which this android application is running. The app processes this request and finds the street address. The street detail is now communicated back to the originator using SMS. This way I have the street address of my friend by just using my legacy phone. Technically speaking, the application runs on the android phones. Originator need not have this android client installed.

Now, let’s dive deep to understand how this application can be written.
Listening to SMS:
SMS is the trigger or an event on which the app will begin the processing. This calls for an event handling mechanism. This is achieved in the android framework with the help of intent receivers. In the android manifest file the receivers and the intent filters will be defined as below.
<receiver android:enabled="true" android:name=".phonetracer">
<intent-filter> <action  android:name="android.provider.Telephony.SMS_RECEIVED">  
</intent-filter>
</receiver>
Application will need the permission from the android platform to receive SMS. This is done by defining the permissions in the manifest file.
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
Heart of this app is a broadcast receiver (here phonetracer) which will receive the broadcast messages that are delivered as intents. This class can be outlined as follows.
public class phonetracer extends BroadcastReceiver {
    //Callback will be called whenever SMS is received.
    @Override
    public void onReceive(Context context, Intent intent) {
            //Take action here.
    }
}
Broadcast receiver's "onReceive" method needs to be overridden with the implementation specific to the application. Once the intent is received SMS message is parsed to extract the payload and the originating address. The originating address is the address on which the application will respond back once the processing is completed.
Private static final String SMS_RECIEVED=”android.provider.Telephoney.SMS_RECEIVED”;/
/---get the SMS message passed in---
Bundle bundle = intent.getExtras();       
SmsMessage[] msgs = null;

String payload = null;
if (intent.getAction().equals(SMS_RECEIVED)) {
    if (bundle != null){
     //---retrieve the SMS message received---
     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]);
        OrigAddress = msgs[i].getOriginatingAddress();
        payload = msgs[i].getMessageBody().toString().trim();
                        
     }
    }
}
Registering Location:
Following permissions are required to be defined in the manifest file for operating the location services.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
As discussed earlier, the location is derived when an SMS is received. But you don’t want this application to process on any SMS payload that is received. A keyword can be agreed upon and defined in the app. The keyword can be a simple text that a user can type in, for eg. “FindMe”. Application will filter the SMS processing based on this keyword.
Registration of the location services is done with the help of a Location Manager handle that is obtained from the ‘getSystemService’ method call. A location listener is registered with the location manager which gets notified about the location. This listener will also get notified if the location changes.

//Define a specific SMS code
String code =“FindMe”                                                
if(payload.equals(code)){
  LocationManager mlocManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if(mlocManager != null )
   mlocManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, 5000, 0, mlocListener);
}            
MyLocationListener implements the interface LocationListener. On detection of location first time or any time there is a change in the location the onLocationChanged will be called with Location object. The latitude and longitude is now available in the Location object.

public class MyLocationListener implements LocationListener {
            public void onLocationChanged(Location loc)
            {
                  if( loc != null ){
                        String result  = decodeLatLong(loc)   
                        sendSMS(OrigAddress,result);
                       }
                                                     
               }
            public void onProviderDisabled(String provider){}          
            public void onProviderEnabled(String provider){}
            public void onStatusChanged(String provider, int status, Bundle extras){}
      }
Decoding Location and Sending SMS
The Lat and long information that is present in the Location data object should be reverse decoded to get the proper street address. This is done using android’s Geocoder.

    private String decodeLatLong(Location loc){
      String result = null;        
            Geocoder geocoder = new Geocoder(context, Locale.getDefault());
        
            try {
                   List<Address> list = geocoder.getFromLocation(
                                  loc.getLatitude(), loc.getLongitude(), 1);
            if (list != null && list.size() > 0) {
                Address address = list.get(0);
                // sending back first address line and locality
                result = address.getAddressLine(0) + ", " + address.getLocality();
             }
        } catch (IOException e) {
            //exception
          }
        return result;
   } 
The decoded address will be sent out to the originating address by SMS. SMSManager provides a ‘sendTextMessage’ method to facilitate this.

private void sendSMS(String phoneNumber, String message)
    {       
        SmsManager sms = SmsManager.getDefault();
        sms.sendTextMessage(phoneNumber, null, message, null, null);
 }  
The android manifest file will need to have two more permission to perform the geo-decoding and the sending SMS out of the application.

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SEND_SMS"/> 
Before concluding this let me put a note on the list of imports required for this project.

import android.content.BroadcastReceiver;
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.widget.Toast;
The last import in the above list i.e the android.widget.Toast can be used for debugging the flow in the form of alerts. A sample eg. of using “Toast” is as follows.

Toast.makeText(context, “Your message”, Toast.LENGTH_SHORT).show();
If you are no longer interested in location updates you may deregister using the Location Manager's "removeUpdates" call.

As a concluding remark, this application can be extended further to make more interesting location based services. Please feel free to try this out and in case you face any problems do post in your queries.

Happy coding…


No comments:

Post a Comment