Location Based Services on Android – Part 3/3 – CustomOverlays
This is the third part of my blog series about how to use location based services in Google Android.
The first part of this series describes the integration of the google map view and the use of the MyLocationOverlay. In the second part I demonstrate how to use an ItemizedOverlay on a google map. Third and last part of this series describes how to build a custom Overlay and show it on the map.
- Part 1 – Enable Google Maps and use a MyLocationOverlay
- Part 2 – Google Maps and ItemizedOverlay
- Part 3 – Google Maps and CustomOverlays
Part 3 – Google Maps and CustomOverlays
This part of the tutorial is pretty similar to the second article. But instead of an ItemizedOverlay we will create and use a CustomOverlay. Whenever a new location is received with the GPS sensor we will capture that location, move the map to this position and show our overlay.
You should already have integrated a google map. If you do not know how to do this – read the first part of this series. You can use the application of the first part of this series as base.
You should already have read part two of this tutorial – as it is the base for this part.
I will provide the source code first. I will not explain every single line of code, but explain the most important steps.
To use a custom overlay with a google map we need two classes – an Activity and a CustomOverlay:
- Activity: LocationBasedServicesV3
- Overlay: CustomOverlay
First the Activity. as you can see its almost the same we used when adding an ItemizedOverlay.
The Activity: LocationBasedServicesV3
package de.itemis.frey.blog.lbsv3; import java.util.Iterator; import java.util.List; import android.content.Context; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.view.View; import android.widget.LinearLayout; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapActivity; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; public class LocationBasedServicesV3 extends MapActivity { private MapView myMap; private LocationManager locManager; private LocationListener locListener; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); initMap(); initLocationManager(); } /** * Initialise the map and adds the zoomcontrols to the LinearLayout. */ private void initMap() { myMap = (MapView) findViewById(R.id.mymap); View zoomView = myMap.getZoomControls(); LinearLayout myzoom = (LinearLayout) findViewById(R.id.myzoom); myzoom.addView(zoomView); myMap.displayZoomControls(true); } private void initLocationManager() { locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); locListener = new LocationListener() { public void onLocationChanged(Location newLocation) { createAndShowCustomOverlay(newLocation); } public void onProviderDisabled(String arg0) { } public void onProviderEnabled(String arg0) { } public void onStatusChanged(String arg0, int arg1, Bundle arg2) { } }; locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locListener); } protected void createAndShowCustomOverlay(Location newLocation) { List overlays = myMap.getOverlays(); // first remove old overlay if (overlays.size() > 0) { for (Iterator iterator = overlays.iterator(); iterator .hasNext();) { iterator.next(); iterator.remove(); } } // transform the location to a geopoint GeoPoint geopoint = new GeoPoint( (int) (newLocation.getLatitude() * 1E6), (int) (newLocation .getLongitude() * 1E6)); // Create new Overlay CustomOverlay overlay = new CustomOverlay(geopoint); myMap.getOverlays().add(overlay); // move to location myMap.getController().animateTo(geopoint); // redraw map myMap.postInvalidate(); } @Override protected boolean isRouteDisplayed() { return false; } }
And our CustomOverlay
package de.itemis.frey.blog.lbsv3; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.RectF; import android.graphics.Typeface; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; import com.google.android.maps.Projection; public class CustomOverlay extends Overlay { private static final int CIRCLERADIUS = 2; private GeoPoint geopoint; public CustomOverlay(GeoPoint point) { geopoint = point; } @Override public void draw(Canvas canvas, MapView mapView, boolean shadow) { // Transfrom geoposition to Point on canvas Projection projection = mapView.getProjection(); Point point = new Point(); projection.toPixels(geopoint, point); // background Paint background = new Paint(); background.setColor(Color.WHITE); RectF rect = new RectF(); rect.set(point.x + 2 * CIRCLERADIUS, point.y - 4 * CIRCLERADIUS, point.x + 90, point.y + 12); // text "My Location" Paint text = new Paint(); text.setAntiAlias(true); text.setColor(Color.BLUE); text.setTextSize(12); text.setTypeface(Typeface.MONOSPACE); // the circle to mark the spot Paint circle = new Paint(); circle.setColor(Color.BLUE); circle.setAntiAlias(true); canvas.drawRoundRect(rect, 2, 2, background); canvas.drawCircle(point.x, point.y, CIRCLERADIUS, circle); canvas.drawText("My Location", point.x + 3 * CIRCLERADIUS, point.y + 3 * CIRCLERADIUS, text); } }
Create the CustomOverlay and add it to the map
All work is done in the method createAndShowCustomOverlay which is called when the LocationListener receives a new position. It does pretty the same like the method createAndShowMyItemizedOverlay in the second part of this tutorial.
Whenever the LocationListener receives a new position, the method createAndShowCustomOverlay is called.
It first removes all previously added overlays when necessary.
Then, transforms the received Location to a GeoPoint, and creates an instance of a CustomOverlay. It then adds the overlay to the map, centers the map to the new position and calls the map to redraw itself.
The CustomOverlay
Each overlay must extend the class com.google.android.maps.Overlay and at least overwrite its draw method. In addition we add the geopoint we receive from the gps sensor in the constructor.
The canvas obtained in the draw method is based on the visible viewport. It is not connected with the geocoordinates of the map. Therefore we use a Projection to transform the geocoordinates of the GeoPoint to a Point with pixel values of the canvas.
Based on this Point we set the position and calculate the dimensions of all drawn objects. Now we create paint-objects for the text, the marker for the position and the background of the text and draw them to the canves.
Testing
For testing use the DDMS capabilites of your eclipse – or the connect via telnet to the Android console and use the “geo fix” command as described in the first part of this series.
You are welcome to post comments or suggestions for improvement.
The complete series:

Tuesday, 21. April 2009 15:57
[...] Part 3 – Google Maps and CustomOverlays [...]
Friday, 25. December 2009 2:38
your xml is not specified here for clearity, it would be so confusing with out it.
The java code is not enogh for simplification, part 1 is good, part two and three is not for a beginner to catch up
Saturday, 26. December 2009 11:34
You should use the xml provided in the previous chapters of this tutorial. They are based on each other.