3

I am a newbie to android and java. I am trying to make an application to perform following task.

  • receive incoming sms (which will have latitude and longitude information)
  • show them on map with markers So every time an sms comes map should get a new marker.

currently I have a map where I can show a point and I have implemented a broadcast receiver to get lattitude and longitude form SMS.

But I am unsure how to update the map from broadcast receiver on receiving a new sms.

Any help or tips will be useful.

Thank you

Alok
  • 163
  • 1
  • 14

2 Answers2

5

There are 3 items you need to address:

A. Receive an SMS via a BroadcastReceiver

B. Annotating a MapView using an ItemizedOverlay

C. Communicate the updates from the BroadcastReceiver to the activity showing the map

Item A: Receive SMS

  1. Implement your BroadcastReceiver class:

    public class SMSBroadcastReceiver extends BroadcastReceiver
    {
        private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
    
        @Override 
        public void onReceive(Context context, Intent intent) 
        {
            if (intent.getAction().equals (SMS_RECEIVED)) 
            {
                Bundle bundle = intent.getExtras();
                if (bundle != null) 
                {
                    Object[] pdusData = (Object[])bundle.get("pdus");
                    for (int i = 0; i < pdus.length; i++) 
                    {
                        SmsMessage message = SmsMessage.createFromPdu((byte[])pdus[i]);
    
                        /* ... extract lat/long from SMS here */
                    }
                }
            }
        }
    }
    
  2. Specify your broadcast receiver in the app manifest:

    <manifest ... > 
            <application ... >
                    <receiver 
                            android:name=".SMSBroadcastReceiver"
                            android:enabled="true"
                            android:exported="true">
                            <intent-filter>
                                    <action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
                            </intent-filter>
                    </receiver>
            </application>
    </manifest>
    

(Credits go to the posters in this thread: Android - SMS Broadcast receiver)

Item B: Annotate the Map

  1. Create a class derived from ItemizedOverlay, which is used to inform a MapView of any markers which need to be displayed:

    class LocationOverlay extends ItemizedOverlay<OverlayItem>
    {
            public LocationOverlay(Drawable marker) 
            {         
                    /* Initialize this class with a suitable `Drawable` to use as a marker image */
    
                    super( boundCenterBottom(marker));
            }
    
            @Override     
            protected OverlayItem createItem(int itemNumber) 
            {         
                    /* This method is called to query each overlay item. Change this method if
                       you have more than one marker */
    
                    GeoPoint point = /* ... the long/lat from the sms */
                    return new OverlayItem(point, null, null);     
            }
    
       @Override 
       public int size() 
       {
                    /* Return the number of markers here */
                    return 1; // You only have one point to display
       } 
    }
    
  2. Now, incorporate the overlay into an activity that displays the actual map:

    public class CustomMapActivity extends MapActivity 
    {     
        MapView map;
        @Override
    
            public void onCreate(Bundle savedInstanceState) 
            {     
                super.onCreate(savedInstanceState);         
                setContentView(R.layout.main);      
    
                /* We're assuming you've set up your map as a resource */
                map = (MapView)findViewById(R.id.map);
    
                /* We'll create the custom ItemizedOverlay and add it to the map */
                LocationOverlay overlay = new LocationOverlay(getResources().getDrawable(R.drawable.icon));
                map.getOverlays().add(overlay);
            }
    }
    

Item C: Communicate the updates

This is the trickiest part (see also Updating an Activity from a BroadcastReceiver). If the app's MapActivity is currently visible, it needs to be notified of the newly received markers. If the MapActivity isn't active, any received points need to be stored somewhere until the user chooses to view the map.

  1. Define the private intent (in CustomMapActivity):

    private final String UPDATE_MAP = "com.myco.myapp.UPDATE_MAP"
    
  2. Create the private BroadcastReceiver (in CustomMapActivity):

    private  BroadcastReceiver updateReceiver =  new BroadcastReceiver()
    {
        @Override
        public void onReceive(Context context, Intent intent) 
        {
            // custom fields where the marker location is stored
            int longitude = intent.getIntExtra("long");
            int latitude = intent.getIntExtra("lat");
    
            // ... add the point to the `LocationOverlay` ...
            // (You will need to modify `LocationOverlay` if you wish to track more
            // than one location)
    
            // Refresh the map
    
            map.invalidate();
        }
    }
    
  3. Register your private BroadcastReceiver when the activity is started (add this to CustomMapActivity.onCreate):

    IntentFilter filter = new IntentFilter();
    filter.addAction(UPDATE_MAP);
    registerReceiver(updateReceiver /* from step 2 */, filter);
    
  4. Invoke your private intent from the public BroadcastReceiver (add this to SMSBroadcastReceiver.onReceive):

    Intent updateIntent = new Intent();
    updateIntent.setAction(UPDATE_MAP);
    updateIntent.putExtra("long", longitude);
    updateIntent.putExtra("lat", latitude);
    context.sendBroadcast(updateIntent);
    
Community
  • 1
  • 1
Tony the Pony
  • 40,327
  • 71
  • 187
  • 281
  • Thanks for the reply.I have a doubt. How will the map change based on different sms location? – Alok Apr 18 '12 at 19:55
  • This depends on how you are conveying the location data in the SMS. You will need to parse the SMS when it is received, store the location data, which is then used in the ItemizedOverlay. – Tony the Pony Apr 18 '12 at 19:58
  • @TonythePony : I think the question here is with the overlay how often will it refresh the map? lets say if sms comes in every 5 seconds.. will it refresh the map automatically? – rinku Apr 18 '12 at 20:11
  • 1
    The easiest way to refresh the `MapView` is to call its `invalidate` method. As far as I know, `ItemizedOverlay` does not have any kind of automatic change notification. – Tony the Pony Apr 18 '12 at 20:18
  • @TonythePony so the question is how to perform MapView invalidate from a broadcast receiver which will be running in background ? btw I am working with alok on the same project. – rinku Apr 18 '12 at 20:22
  • Ok, got it. What Femi suggested in his answer could work. What happens if the map activity is not active? You would need a mechanism to store any received messages until the next time the user displays the map. What is the exact use case? – Tony the Pony Apr 18 '12 at 20:27
  • so the usecase is fairly simple. when we have the application active it should intercept all the sms with and fetchs lat and long info (this part is done including parsing etc). now what we need is we need to show these points on the map as and when we get sms. so lets say if the app was active for 1 min and there were 5 sms came it should plot 5 marker points on the map(based on received Lat and Long info) – rinku Apr 18 '12 at 20:31
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/10246/discussion-between-rohit-bhatnagar-and-tony-the-pony) – rinku Apr 18 '12 at 20:35
  • 04-19 11:18:50.605: E/AndroidRuntime(717): at com.google.android.maps.ItemizedOverlay.getIndexToDraw(ItemizedOverlay.java:211) I get this error any idea how to resolve it? or can you share the portion of code if you have tried it? – rinku Apr 19 '12 at 11:42
  • Actually, if you post the issue as a new question, I'll try to answer it. Working with map overlays is useful to a lot of developers. – Tony the Pony Apr 19 '12 at 11:56
  • @TonythePony : I am actually implementing a remote tracking device for my project. The last bit of my project requires me to make an android application to show the location based on the messages received. I am an embedded electrical engineer and am very very new with android. I need to complete this part to complete my project. Based on your suggestions and tips and Rohit's help, we have developed something, but its still somehow missing the BroadcastReceiver functionality. I will really appreciate if you can tell me how I am implementing it wrong. I can send you my project. Thank you. – Alok Apr 19 '12 at 16:44
  • Was the added *Item C* in my answer helpful? Also, I found this short ebook useful regarding intents, broadcast receivers, etc.: http://www.amazon.com/gp/product/B0068F897C – Tony the Pony Apr 23 '12 at 06:26
4

It sounds like you are looking for detail on how to communicate between your Activity and the BroadcastReceiver? One approach (there are many different approaches) is to have your map Activity register a temporary BroadcastReceiver that is setup to only listen to private broadcasts from your app, and then have your SMS broadcast receiver generate a new broadcast with the latitude/longitude from the SMS. In your map Activity your receiver will add a new point to the map every time it receives a new private broadcast.

Femi
  • 64,273
  • 8
  • 118
  • 148