http://www.developer.com/ws/android/programming/Mapping-with-Google-APIs-in-Android-3753576-4.htm

Back to article

Using the Google Maps API in Android


February 15, 2012

Mapping functionality has become a must-have feature for new mobile devices. With all the new technology advances, mobile devices as well as smartphones are more than capable of handling complicated mathematical calculations on their own or keeping up with the heavy-traffic communication with the servers. GPS devices used to be the predominant gadgets for mapping capabilities, but more and more mobile devices are offering almost full-featured GPS functionalities. Android provides free, direct access to Google's popular mapping tools.

In this article, I will explore key programming APIs that power Android mapping features using a sample software project, which you can download and save.

What Google APIs Are Available for Mapping?

Before you start, all the necessary Android development tools, plug-ins, and sample codes you will need are from Google's own Android site at http://developer.android.com/. It also provides easy-to-follow instructions to get you started. I recommend you do that first if you have not done so already.

The majority of the mapping APIs are within the package com.google.android.maps. As a minimum, two of them are required to embed the mapping tools inside your software: MapActivity and MapView. MapActivity manages the activity life cycle and services behind a MapView. MapView is an Android View that displays a map. Other than these APIs, you also have MapController to perform panning and zooming of a map. ItemizedOverlay and Overlay are used to draw the user's info or objects on top of the map.

Discussing mapping without mentioning GPS is nearly impossible now because GPS has become one of the indispensable features most people would want from their mobile devices. The package android.location is included for GPS support. LocationManager is the most important API; it provides access to the system location services. The mapping and GPS APIs are the essential elements for building location-based services (LBS). You will pretty much cover all these APIs in a working example later.

Constructing a MapView by a MapActivity

First, when you create a new Android project, you need to select the option with Google APIs instead of a generic version. Then you are required to enable the following permissions and libraries in the project's AndroidManifest.xml before your software can get access to mapping and location services:

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

 

<uses-library android:name="com.google.android.maps" />

Next, you can construct a MapView only by a MapActivity because it depends on background threads that access the network and filesystem managed by MapActivity. That is to say, you should always start by extending your class from MapActivity as follows:

public class TutorialOnMaps extends MapActivity {

private static MapView mMapView;

 

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

 

requestWindowFeature(Window.FEATURE_NO_TITLE);

setContentView(R.layout.main);

 

// Get the map view from resource file

mMapView = (MapView)findViewById(R.id.mv);

 

// Add zoom controls

mMapView.setBuiltInZoomControls(true);

}

}

}

While in the default resource file main.xml, you add in some basic on-screen buttons with transparent panels. To properly "inflate" the MapView, you declare a com.google.android.maps.MapView.

One very important thing to note is android:apiKey, which authenticates your software and Google's service. This key is mandatory and needs to be signed correctly. Using the default SDK debug certificate is fine for testing purpose but when software is ready to be released to the public, an officially signed release key is required. Check out the official page, "Obtaining a Maps API Key" at code.google.com. It takes only a couple of minutes to get your own API key.

Figure 1 shows the initial screen on the emulator with your on-screen buttons.



Click here for larger image

Figure 1. Initial Map Centered On A Selected Position

<?xml version="1.0" encoding="utf-8"?>

 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent" >

 

<com.google.android.maps.MapView android:id="@+id/mv"

android:apiKey="0u1BZtyaS2K9fcA1ach_lc_Au7HvIJwXtr1Devw"

android:enabled="true"

android:clickable="true"

android:focusableInTouchMode="true"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_weight="1" />

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="horizontal"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:background="#550000ff"

android:layout_alignParentTop="true"

android:padding="2px" >

<Button android:id="@+id/sat"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginLeft="40px"

android:text="Satellite" />

(...snipped)

</LinearLayout/>

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="wrap_content"

android:layout_height="fill_parent"

android:background="#550000ff"

android:padding="2px" >

<Button android:id="@+id/zin"

android:layout_width="40dp"

android:layout_height="wrap_content"

android:layout_marginTop="50px"

android:text="+" />

(...snipped)

</LinearLayout>

 

</RelativeLayout >

 

 

Panning, Zooming, and Toggling Map Modes

As was mentioned before, MapController is used to pan and zoom a map. You need to associate each button with a click listener. One example is as follows:

// Set up the button for "Pan East"

mPanE = (Button)findViewById(R.id.pane);

mPanE.setOnClickListener(new OnClickListener(){

// @Override

public void onClick(View arg0) {

panEast();

}

});

The panEast() function is implemented to pan a quarter of the current screen width. Other panning functionalities are done in a similar fashion. Actually, the map itself is already draggable if the device is equipped with a touch screen input. For non-touch-screen devices, you use these buttons or the arrow keys of the rocker pad to pan the map.

public void panEast() {

GeoPoint pt = new GeoPoint(

mMapView.getMapCenter().getLatitudeE6(),

mMapView.getMapCenter().getLongitudeE6()

+ mMapView.getLongitudeSpan() / 4);

mOverlayController.setCenter(pt);

mMapView.invalidate();

}

Zooming is done simply by increasing or decreasing the current zoom level through the controller.

public void zoomIn() {

mOverlayController.setZoom(mMapView.getZoomLevel() + 1);

mMapView.invalidate();

}

To toggle the map display for viewing satellite imagery or traffic, you can enable it directly from MapView.

public void toggleSatellite() {

if (mMapView.isSatellite())

mMapView.setSatellite(false);

else

mMapView.setSatellite(true);

mMapView.invalidate();

}

 

public void toggleTraffic() {

if (mMapView.isTraffic())

mMapView.setTraffic(false);

else

mMapView.setTraffic(true);

mMapView.invalidate();

}

Figures 2 and 3 show the results of toggling.



Click here for larger image

Figure 2. Satellite Imagery



Click here for larger image

Figure 3. Traffic on Satellite Imagery

 

Retrieving Info in Current MapView

When a MapView is successfully created, lots of info pertaining to the current view can be queried. Here is a list of the main functions to help you better understand the current map status.

  • getMapCenter: Returns the longitude and latitude of the map center point
  • getLatitudeSpan and getLongitudeSpan: Return the span sizes of the current view's bounding rectangle
  • getZoomLevel and getMaxZoomLevel: Return the zoom level. Each zoom level is scaled by a factor of 2.
  • isSatellite: Checks whether the map view is currently in satellite imagery mode
  • isTraffic: Checks whether the map view is displaying traffic info
  • isStreetView: Checks whether the map view is currently in street-view mode

Displaying Your Info on MapView

The base class ItemizedOverlay represents an overlay that can be used to draw and display custom graphic objects on top of a map. Your code basically overrides the draw method by drawing a marker for the default position as well as enclosing its caption within a transparent rounded rectangle. Note how the point position is converted into screen coordinates with Projection.toPixels, how the font metrics is calculated with Paint's measureText, and the anti-aliased text is drawn with Paint's setAntiAlias.

private class MyItemizedOverlay extends ItemizedOverlay {

private ArrayList<OverlayItem> mOverlayItems = new ArrayList<OverlayItem>();

private Drawable marker = null;

 

public MyItemizedOverlay(Drawable marker) {

super(marker);

this.marker = marker;

}

 

@Override

protected OverlayItem createItem(int i) {

return(mOverlayItems.get(i));

}

 

public void addOverlay(OverlayItem oi) {

mOverlayItems.add(oi);

populate();

}

 

@Override

public void draw(Canvas canvas, MapView mapView, boolean shadow) {

super.draw(canvas, mapView, shadow);

 

boundCenterBottom(marker);

 

Projection projection = mapView.getProjection();

 

// Draw point caption and its bounding rectangle

Paint p = new Paint();

p.setARGB(255, 0, 0, 255);

p.setAntiAlias(true);

p.setTextSize(12);

for (int i = 0; i < size(); i++) {

Point point = projection.toPixels(mOverlayItems.get(i).getPoint(), null);

int sw = (int)(p.measureText(mOverlayItems.get(i).getTitle()) + 0.5f);

int sh = 20;

int sx = point.x + marker.getIntrinsicWidth() / 2;

int sy = point.y - sh - 2;

RectF rec = new RectF(sx, sy, sx + sw + 10, sy + sh);

 

p.setStyle(Style.FILL);

p.setARGB(80, 0, 128, 0);

canvas.drawRoundRect(rec, 7, 7, p);

p.setStyle(Style.STROKE);

p.setARGB(255, 255, 255, 255);

canvas.drawRoundRect(rec, 7, 7, p);

canvas.drawText(mOverlayItems.get(i).getTitle(), sx + 5, sy + sh - 5, p);

}

}

 

@Override

public int size() {

return(mOverlayItems.size());

}

}

The overlay we just created needs to be added to MapView's overlay list before it goes into effect. Here is the code segment showing how you set up the overlay controller.

mMyItemizedOverlay = new MyItemizedOverlay(marker);

mMyItemizedOverlay.addOverlay(mOverlayItem);

mMapView.getOverlays().add(mMyItemizedOverlay);

Figure 4 shows a label overlay on the map.



Click here for larger image

Figure 4. Label Overlay on the Map

Integrating with the Current GPS Location

The android.location package contains APIs allowing you to query the list of location providers as well as register for periodic updates of current positions. Each location provider maintains the files under the /data/misc/location/<provider_name> directory. Therefore, the default mock GPS provider "gps" can be found on the emulator in /data/misc/location/gps/. Different providers can generate the GPS files in different formats. More info can be found at Android's site in the references. Please note that, when you try to activate LocationManager the first time, it takes longer to initialize. Subsequent calls are more responsive. LocationListener updates mGPSPoint whenever location is changed. The following code segment gets the GPS position from the provider and then feeds it to MapView's controller.

private void centerOnGPSPosition() {

if (null == mGPSPoint) {

Toast.makeText(TutorialOnMaps.this, "No GPS info", Toast.LENGTH_LONG).show();

} else {

mDefPoint = mGPSPoint;

mOverlayController.animateTo(mDefPoint);

mOverlayController.setCenter(mDefPoint);

mMapView.invalidate();

Toast.makeText(TutorialOnMaps.this, "(" + mDefPoint.getLatitudeE6() + ", " +

mDefPoint.getLongitudeE6() + ")", Toast.LENGTH_LONG).show();

}

}

 

public class MyLocationListener implements LocationListener {

@Override

public void onLocationChanged(Location location) {

int lat = (int)(location.getLatitude() * 1E6);

int lon = (int)(location.getLongitude() * 1E6);

mGPSPoint = new GeoPoint(lat, lon);

}

 

@Override

public void onProviderDisabled(String provider) {

}

 

@Override

public void onProviderEnabled(String provider) {

}

 

@Override

public void onStatusChanged(String provider, int status, Bundle extras) {

}

}

Figure 5 shows the results.



Click here for larger image

Figure 5. GPS Info Overlay on the Map

Conclusion

After this introduction, you are probably very excited to experiment with the mapping software and perhaps add in your own features. The entire software package is available for download from the attached references and you can simply import the project into Eclipse. From Eclipse, you can create a new Android project by selecting "Creating project from existing source" and browsing to the folder to which our sample project is decompressed.

Android's mapping APIs are simple to use and yet powerful, with direct access to Google's already popular tools. As Android continues to grow with more advanced APIs, I believe more map features will be ported to this platform as well. Here are what I can think of if you would like to give it a try:

  • If you are an avid user of Google Maps, I am sure you will like its style of a draggable tool bar to control the map zooming and panning. You can go ahead and model after that user interface and functionalities. It will be an excellent addition.
  • What about adding an address search functionality, just like Google Maps can do through the Web? Parsing the search results is really the key to this feature.
  • There are other neat features you can include for your mapping software, e.g. Street View, Navigation, etc.
  • Usually, it takes a little while for a GPS receiver to initialize when it is taken to a new location, so you might get an ANR dialog (Application Not Responding) if the wait is longer than approximately five seconds. To make your software execute smoothly without any system interruption, you should create a child thread for this purpose and allow it to communicate with the main thread through a message handling scheme.

References

  1. Download and save the entire software project
  2. Google Map View
  3. Obtaining a Maps API Key
  4. Android Developers at: http://developer.android.com
  5. Androidlet at http://www.androidlet.com

About the Author

Chunyen Liu has been a software professional for many years. Some of his applications were among winners at programming contests administered by Sun, ACM, and IBM. He has co-authored software patents, written 20+ articles, reviewed books, and also created numerous hobby apps at Androidlet and The J Maker. He holds advanced degrees in Computer Science with knowledge from 20+ graduate-level courses. On the non-technical side, he is a tournament-ranked table tennis player, certified umpire, and certified coach of USA Table Tennis.

Sitemap | Contact Us