Contents
One of the most fascinating features provided by a phone is GPS functionality (at least for me it is). I never realized that interacting with GPS functionality is so easy until I worked with it. This article is a way to help people realize the same. This article is targeted to a beginner who wants to implement GPS functionality and work with Google Maps API as well.
In this article, we will create a very simple application called GPSLocator. GPSLocator gets the Latitude and Longitude information from GPS and displays the exact (or nearest, at times) location in Google Maps.
For developing GPSLocator, we need the following applications pre-installed:
Apart from the above two things, we also require:
Explaining an application, specially developing an application is a complex task. We will try to break it down into multiple steps to make it easy to swallow. We will try to complete one step at a time and move towards our final application. So, let's get started.
The first and foremost thing is getting a Google Maps API key. Getting one is relatively easy but it requires our application to be signed with a certificate and notify Google about Hash (MD5) fingerprint of the certificate. Now, the process can be further divided into two parts:
- Creating a certificate and getting its MD5 fingerprint
We can create a new certificate by using keytool.exe, found in bin directory of JDK installation path (something like C:\Program Files\Java\jdk1.6.0_21\bin). We need to pass some information and it will generate a keystore file (Public Key Storage Certificate File). One sample output is:

For developing and testing application, we usually sign the application in Debug mode. For this, we need to sign-up for Google Maps API with the debug certificate MD5 hash. The certificate used for this purpose is debug.keystore. It is usually located in:
%userprofile%/.android/
For finding the MD5 of a certificate, we run the command:
keytool -list -alias androiddebugkey -keystore debug.keystore
-storepass android -keypass android
The output of the command looks like:

- Signing up for Google Maps API
Go to Maps API Key signup page and pass on MD5 key (highlighted above) and we get a Maps API key. The page also shows how to use API key in a MapView.

For more details about getting Google Maps API key, check Obtaining a Maps API Key.
Create a new Android Project and provide the details as below. Also, make sure to select Build Target as Google APIs.

Click Finish and the project is created. Create a Run Configuration for the project to launch an AVD targeted to Google APIs (Check Prerequisite section). Also, make sure that version of Google APIs selected for AVD and Build Target is same. Some screenshots of the configuration are:

Try running the project with the specified configuration and it should show something like:

Before we can start using MapView control from Google APIs, we need to add the Google Maps External Library (com.google.android.map) to the library. For adding a library to the project use uses-library tag. This tag needs to be added to AndroidManifest.xml. Apart from the library, we need to add relevant permissions as well. For adding permissions, we use uses-permission tag. For our application, we will add the following permissions:
android.permission.ACCESS_COARSE_LOCATION: Allows application to access coarse location (Cell ID, Wi-Fi etc.) android.permission.ACCESS_FINE_LOCATION: Allows application to access GPS location. android.permission.INTERNET: Allows application to open network sockets.
For more information about permissions, check Permissions.
The final AndroidManifest.xml should look like:
="1.0"="utf-8"
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.VertexVerveInc.GPSLocator"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<uses-library android:name="com.google.android.maps" />
<activity android:name=".GPSLocatorActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Finally, add MapView control to main.xml under res/layout. The resultant code should look like:
="1.0"="utf-8"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<com.google.android.maps.MapView
android:id="@+id/mapView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:enabled="true"
android:clickable="true"
android:apiKey="089FcDoNfk946GFlnxtjAi4zAK5ib0d3ttLUZnv"
/>
</LinearLayout>
In order to display Google Map view, we need to update our Activity class (GPSLocatorActivity). This class should extend MapActivity class in place of Activity class. We also need to import com.google.android.maps.MapActivity package to support MapActivity class. We also need to override isRouteDisplayed method of MapActivity class. This is fairly easy, just return false from the method. After all these modifications, GPSLocatorActivity.java should look like:
package com.VertexVerveInc.GPSLocator;
import com.google.android.maps.MapActivity;
import android.os.Bundle;
public class GPSLocatorActivity extends MapActivity
{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected boolean isRouteDisplayed() {
return false;
}
}
Try running the application at this stage and it should show Google Map in the Emulator.

MapView class has an in-built method setBuiltInZoomControls. Invoking this method with true/false enable/disables Zoom in/out controls. In order to invoke this method, we need to find the instance of MapView class by calling findViewById with id of MapView control. Remember id="@+id/mapView" from the main.xml. One important thing to note here is that the zoom controls will become enable once we will touch/click the map view.
We can select, if we want to show Satellite, Traffic or Street view in maps. This is simply achieved by calling setSatellite, setStreetView and setTraffic methods. Another thing to do before we move further is zoom the map a bit. Why? Because the map view shown in the above output doesn't serve any purpose. In order to set zoom level of Map, we need an instance of MapController and we can call its setZoom method. So, let's update the onCreate method of GPSLocatorActivity class to incorporate all these changes.
import com.google.android.maps.MapView;
import com.google.android.maps.MapController;
private MapView mapView;
private MapController mapController;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapView);
mapView.setStreetView(true);
mapView.setBuiltInZoomControls(true);
mapController = mapView.getController();
mapController.setZoom(16);
}
Running the application at current stage produces the following output:

Android provides location based services through LocationManager (package android.Location) class. This class provides periodical updates about the location of the device. In order to user LocationManager, we need to get a reference of LocationManager class by calling getSystemService method. Later on, we need to register for location updates by calling requestLocationUpdates method.
We need to create a class implementing abstract LocationListener class. This class will be registered with Location Manager to receive updates of location. We need to override all four methods of this class, namely onLocationChanged, onProviderDisabled/Enabled, and onStatusChanged. As we are just interested in getting location updates, we will modify the code of onLocationChanged to navigate to the new location received in the map view. This is achieved by calling animateTo method of MapController.
Let's add the bits of code to our project.
import com.google.android.maps.GeoPoint;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
private LocationManager locationManager;
private LocationListener locationListener;
@Override
public void onCreate(Bundle savedInstanceState) {
...
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationListener = new GPSLocationListener();
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
0,
0,
locationListener);
...
}
private class GPSLocationListener implements LocationListener
{
@Override
public void onLocationChanged(Location location) {
if (location != null) {
GeoPoint point = new GeoPoint(
(int) (location.getLatitude() * 1E6),
(int) (location.getLongitude() * 1E6));
Toast.makeText(getBaseContext(),
"Latitude: " + location.getLatitude() +
" Longitude: " + location.getLongitude(),
Toast.LENGTH_SHORT).show();
mapController.animateTo(point);
mapController.setZoom(16);
mapView.invalidate();
}
}
...
}
On running the application, we see a message displaying information about the GPS location. We can skip to the Testing GPS functionality section to get this working. For more information about working with location, check Obtaining User Location.

We can find information about an address if we know its latitude and longitude. For this purpose, we use Geocoder class and the process is known as Geocoding. We will call getFromLocation method of the class and will pass the point as a parameter. This method returns a List of Address which contains information about address of the specified location. We can combine the information to find the complete information about the point. For this purpose, we will add a method ConvertPointToLocation to GPSLocationListener class. ConvertPointToLocation returns a string object containing address of the location.
import android.location.Geocoder;
import android.location.Address;
private class GPSLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
if (location != null) {
...
String address = ConvertPointToLocation(point);
Toast.makeText(getBaseContext(), address, Toast.LENGTH_SHORT).show();
...
}
}
public String ConvertPointToLocation(GeoPoint point) {
String address = "";
Geocoder geoCoder = new Geocoder(
getBaseContext(), Locale.getDefault());
try {
List<Address> addresses = geoCoder.getFromLocation(
point.getLatitudeE6() / 1E6,
point.getLongitudeE6() / 1E6, 1);
if (addresses.size() > 0) {
for (int index = 0;
index < addresses.get(0).getMaxAddressLineIndex(); index++)
address += addresses.get(0).getAddressLine(index) + " ";
}
}
catch (IOException e) {
e.printStackTrace();
}
return address;
}
...
Running the application shows an address on the map in place of longitude and latitude values.

A lot many times, we want to add a marker (image) to the location because the small circle (shown in maps by default) is sometimes useless. In order to add a marker, add a drawable resource to the project. We can import any image (which we want to use) to our project (simple drag and drop also works). Add the image to res/drawable folder.
In order to add a location marker to the map, we need to create a class which extends Overlay (com.google.android.maps package) class. We need to override draw method of the class and do some custom painting. The MapOverlay class looks like:
import com.google.android.maps.Overlay;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
private class GPSLocationListener implements LocationListener
{
@Override
public void onLocationChanged(Location location) {
...
mapController.animateTo(point);
mapController.setZoom(16);
MapOverlay mapOverlay = new MapOverlay();
mapOverlay.setPointToDraw(point);
List<Overlay> listOfOverlays = mapView.getOverlays();
listOfOverlays.clear();
listOfOverlays.add(mapOverlay);
String address = ConvertPointToLocation(point);
Toast.makeText(getBaseContext(), address, Toast.LENGTH_SHORT).show();
...
}
class MapOverlay extends Overlay
{
private GeoPoint pointToDraw;
public void setPointToDraw(GeoPoint point) {
pointToDraw = point;
}
public GeoPoint getPointToDraw() {
return pointToDraw;
}
@Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
super.draw(canvas, mapView, shadow);
Point screenPts = new Point();
mapView.getProjection().toPixels(pointToDraw, screenPts);
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.red);
canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 24, null);
return true;
}
}
Yes, let's run this application and as expected it should show a marker at the current GPS location.

How can we test GPS functionality when we don't have any GPS in our computer? Well, this is really tricky but Developers at Google already thought about this problem. By this I mean, Yes, we have a way to interact with GPS on the emulator. We can simulate GPS location change in emulator. We can control and query the running instance of emulator with console (telnet). On a command prompt enter "telnet localhost <port>" command to connect to the console. Port number is usually displayed in the title bar of the emulator. For example, for me it is: 5554.

We can change the GPS location by sending geo fix command. We need to pass longitude and latitude values along with it. For example, in order to change our current location to Seattle (longitude: -122.332071, latitude: 47.60621), we send 'geo fix -122.332071 47.60621' from the console. For more information about communicating with console, check Android Emulator.
Working with GPS and Google Maps API both is easy, entertaining and creative as well. GPSLocator is my first attempt to make my fellow developers aware of the same fact. Please provide your feedback and suggestions. Do I need to mention that you can rate my article as well, if you liked it.
- Initial draft: Sep 22, 2010
- Updated Google APIs link: Sep 27, 2010