Apps

Take advantage of Android's GPS API

Android app developer William J. Francis walks you through the most basic of GPS usage scenarios in this tutorial.

Modern smartphones have a host of sensors on them; there are accelerometers, cameras, microphones, and the global positioning system (GPS). I'm not sure how I ever got anywhere before Google Maps.

It's not difficult to use Android's GPS API in your own applications. There are, however, a number of steps you must follow and a few guidelines to keep in mind. This tutorial will walk you through the most basic of GPS usage scenarios. You can follow along with the detailed instructions below or download and import the entire project into Eclipse.

1. Create a new Android project in Eclipse. Target Android 1.6 or higher. Be sure to rename the startup activity to Main.java and the corresponding layout to main.xml.

2. Android provides several mechanisms for getting a user's location; these mechanisms include network, passive, and GPS. You can find a description of all three in the official Android documentation. For the purposes of this tutorial, we will only be using the GPS mechanism. Therefore, in the AndroidManifest.xml file, we will need to add a single permission for ACCESS_FINE_LOCATION.

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.authorwjf.quickgpsdemo"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="4"
        android:targetSdkVersion="15" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".Main"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

3. The layout for our demonstration is defined in /res/layout/main.xml. It is a simple linear layout with two labels and a button stacked vertically.

main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:gravity="center">
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="12dip"
        android:gravity="center"
        android:textSize="14sp"
        android:textStyle="bold"
        android:textColor="#0000ff"
        android:text="Quick GPS Demo"/>
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="12dip"
        android:gravity="center"
        android:text="Fine Location = (waiting on gps...)"
        android:id="@+id/locat_label" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="12dip"
        android:layout_gravity="center"
        android:text="GPS Settings"
        android:id="@+id/settings_button"/>
</LinearLayout>

4. The /src Main.java file extends Activity while implementing both an OnClickListener and a LocationListener. We use the standard Android OnCreate override to wire up both the button and the location manager. Note the constant MIN_TIME in our class; this is how frequently the GPS is updated. You need to keep this at a reasonable value or you will drain the phone battery very quickly. For the purpose of the demo I used 60 seconds, but even that might be excessive in a live application.

Main.java

package com.authorwjf.quickgpsdemo;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
public class Main extends Activity implements OnClickListener, LocationListener {
       private LocationManager locationManager;
       private static final long MIN_TIME = 1 * 60 * 1000; //1 minute
    @Override
    public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
       locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
       locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, MIN_TIME, 0, this);
       findViewById(R.id.settings_button).setOnClickListener(this);
   }
}

5. The on click listener is responsible for invoking the system menu to allow a user to enable or disable the GPS. This is needed because for security reasons an application cannot turn on the GPS without user interaction. If that sounds like a pain it is meant to be. While as a developer the idea of being able to toggle the GPS hardware on and off at will sounds nice, I am also an Android user, and I sure don't want a rogue app running down my battery or worse uploading my location to a website for thieves alerting the world every time I leave my house.

@Override
public void onClick(View v) {
       Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
       startActivity(intent);
}

6. Next we will be responding to the location updates. To keep things simple, we are ignoring the callbacks for location services enabled/disabled; however, you must include them, and the usefulness of maintaining state should be apparent.

@Override
public void onLocationChanged(Location loc) {
int lat = (int) (loc.getLatitude());
int lng = (int) (loc.getLongitude());
       ((TextView)findViewById(R.id.locat_label)).setText
         ("Fine Location = (lat:"+Integer.toString(lat)+",
lng:"+Integer.toString(lng)+")");
}
@Override
public void onProviderDisabled(String arg0) {
       // TODO Auto-generated method stub
}
@Override
public void onProviderEnabled(String arg0) {
       // TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
       // TODO Auto-generated method stub
}

7. When dealing with hardware especially, it is always a good idea to handle the pause and resume states of the Android lifecycle.

@Override
protected void onResume() {
      super.onResume();
      locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME, 0, this);
}
@Override
protected void onPause() {
      super.onPause();
      locationManager.removeUpdates(this);
}
You can load the application to your device and give it a try (Figure A). Remember you will need to use the button to enable the GPS, and then wait at least 60 seconds for the update to occur. Figure A

If you are running the demo on an emulator, you will have to open a command prompt and telnet into the AVD to fake a location update.

First type:

telnet localhost 5554

and then:

geo fix 25 20

There, that wasn't so bad, was it? Just remember the two golden rules: only a user can enable the GPS, and keep your location access to a minimum to preserve the battery.

About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

6 comments
jwronski
jwronski

The article describes how to use Eclipse to create the app. So why not describe how to use Eclipse DDMS Emulator Control to send coordinates to emulator? Or both ways for Ant and command line developers.

aidemzo_adanac
aidemzo_adanac

GPS for finding your way around is becoming a thing of the past already (technology, faster than a speeding bullet indeed). I find most businesses these days are using on board, hardwired GPS trackers now. If an actual directional map is needed, Garmins interface with GPS trackers and connected by FMI cable for 2-way text. Its is a LOT less expensive than paying cell phone and web bills now. Companies get great benefit when setting up staff this way, many are stopping cell phone use completely (unsafe while driving anyway) and find they can reach out of office staff easier this way. The company also knows exactly where you are too, they know exactly where you've been, how long it too you to get there, when you started your day, when you finished your day, how many stops and starts you've made, WHERE you stopped or started, how long you were idling for etc, It saves a lot in administrative costs and time, reduces the company's fuel expenses, increases customer service, removes billing issues with on site time and charges, offers driver safety, lowers insurance premiums, offers theft security and simplifies recovery of stolen vehicles etc. For finding your way home from the local mall though, use your phone if you're lost.

jasonbutz
jasonbutz

You telnet command should be telnet localhost 5554 And the geo fix command should be geo fix 25 20

dimonic
dimonic

Excellent article - however, the text uses "ACCESS_FINE_PERMISSION" where it should state "ACCESS_FINE_LOCATION". The code sample has it correctly.

authorwjf
authorwjf

I appreciate you taking the time to comment. We will get this corrected right away.

authorwjf
authorwjf

I'm glad you like the article and I apologize for the type-o in the text. We will get it corrected to match the code sample ASAP.