How to use GPS location services and Google Static Map API in J2ME MIDlets

8 comments - This post in romanian

Today, most mobile devices come with a GPS module or can connect to one using Bluetooth services. These devices come with support for the Location API for J2ME under JSR-179 that allow J2ME MIDlets applications to query the GPS module for geo-location coordinates. Also mobile applications integrate location based services and one increasingly used it to provide maps images using Google Maps or Google Static Maps. The later is accessible through Google Static Maps API V2, which is an open and free service (no longer requires a Maps API key) and more efficient as it minimizes network transfers.

In this article it is described and developed a fully MIDlet application that gets coordinates from the mobile device GPS module and use them to display a Google static map for that location. The application can be tested on the emulator or on a real device that has a GPS module incorporated.

You can download the full source code, including a sample test MIDlet.

If you have a mobile device that doesn’t have a GPS incorporated, this solution will not work because the J2ME Location API doesn’t have methods for connecting through Bluetooth to that external module. In this case, you need another solution (I will post it in another article) that

How to use J2ME Location API (JSR-179) and get the GPS coordinates

Midlet that displays GPS coordinates

Midlet that displays GPS coordinates

In order to communicate with the phone GPS module and get data regarding coordinates, course, altitude or speed we need classes from javax.microedition.location.* package:

  • create a javax.microedition.location.Criteria instance, used to select the location provider; although there are multiple options (described by the JSR-179 documentation), their default values are the least restrictive; in this example we choose explicitly to allow a cost for the service (it’s free) and we don’t have a power consumption requirement; this step is not so important because the device has one GPS module and these are the criteria for selecting between multiple modules;
import javax.microedition.location.*;
...
        Criteria criteria = new Criteria();
        //same as default value
        criteria.setCostAllowed(true);
        //same as default value
        criteria.setPreferredPowerConsumption(Criteria.NO_REQUIREMENT);
  • obtain the location provider reference, a LocationProvider instance, using previous defined criteria and use it to query the GPS module for the current location; the getLocation() method has a timeout parameter indication how long we are willing to wait (seconds) for the data;
  • get the coordinates and extract the latitude and longitude; Attention ! the coordinates are returned as double and only the CLDC 1.1 supports floating point data processing (set the device configuration to CLDC 1.1 for this project because CLDC 1.0 does not support double type):
LocationProvider provider = null;
double latitude;
double longitude;
try {
	//get the location provider
        provider = LocationProvider.getInstance(criteria);
	//set a timeout of 60 seconds
        Location location = provider.getLocation(60);
	//get the coordinates
        Coordinates coordinates = location.getQualifiedCoordinates();
 
        if (coordinates != null) {
            //get the latitude and longitude of the coordinates
            latitude = coordinates.getLatitude();
            longitude = coordinates.getLongitude();
        } else {
            //no coordinates
        }
    } catch (LocationException ex) {
        System.out.println("Problems with location provider ! " +
		ex.getMessage());
        ex.printStackTrace();
    } catch (InterruptedException ex) {
	System.out.println(ex.getMessage());
        ex.printStackTrace();
    }

In the final application, the previous code sample is part of the getGPSData() method. This method defines a inner class that extends Thread because we want to query the GPS module on another thread than the main one. In this way, the application will respond to commands while it is waiting for the GPS to respond.

How to get GPS data on regular intervals

If you want to develop a J2ME application that will receive GPS coordinates on regular intervals (not the case for this example) you must define a handler used by the LocationProvider to notify the application. To do this, you must implement the LocationListener interface that has 2 abstract methods:

  • locationUpdated(LocationProvider provider, Location location) – method called by the provider at regular intervals to provide the current location;
  • providerStateChanged(LocationProvider provider, int newState) – method called by the provider to announce if its new state (LocationProvider.OUT_OF_SERVICE, LocationProvider.AVAILABLE, LocationProvider.TEMPORARILY_UNAVAILABLE);
public void locationUpdated(LocationProvider arg0, Location arg1) {
        if (arg1 != null && arg1.isValid()) {
            //get the coordinates
            Coordinates coordinates = arg1.getQualifiedCoordinates();
 
            if (coordinates != null) {
                //get the latitude and longitude of the coordinates.
                latitude = coordinates.getLatitude();
                longitude = coordinates.getLongitude();
 
            } else {
                //no valid coordinates
            }
        }
    }
 
    public void providerStateChanged(LocationProvider arg0, int arg1) {
        if (arg1 == LocationProvider.OUT_OF_SERVICE ||
                arg1 == LocationProvider.TEMPORARILY_UNAVAILABLE) {
            System.out.println("GPS inactive");
        }
    }

For setting the listener and to receive updates on location, we must register the listener using setLocationListener(LocationListener listener,int interval,int timeout,int maxAge) method:

	provider.setLocationListener(this, 60, -1, -1);

For the last call, the application will receive GPS updates at each 60 seconds with default timeout and max Age.
If you want to stop the updates (this consumes battery power), this is done calling one again the setLocationListener() method:

	provider.setLocationListener(null, -1, -1, -1);

How to use Google Static Map API

Google Static Maps is a free service offered by Google to developers that want to embed maps into their applications based on URL parameters sent through a simple HTTP query string without requiring JavaScript or any dynamic page loading. The service sends an image as response.

So, in order to get an 300×300 pixels map image for the 44.435251 latitude and 26.1024 longitude, with a moderate zoom, you make a HTTP request using:

http://maps.google.com/maps/api/staticmap?center=44.435251,26.1024&zoom=14&size=300×300&sensor=false

The result is the next image:

Google Static Map Example 300x300

Google Static Map Example 300x300

For other map options, like putting markers or changing the map type, check Static Maps API V2 Developer Guide.

How to download and display the Google Static Map image on the mobile device

MIDlet that displays a Google Static map

MIDlet that displays a Google Static map

The MIDlet gets the coordinates from the GPS module and use them to construct the HTTP query. The image is downloaded and displayed on a Canvas form:

  • the form used to display the image is extending Canvas class (in J2ME, Canvas and GameCanvas are the only forms that allow access to the Graphics reference needed to draw);
  • the HTTP query string if generated using the 2 coordinates (latitude, longitude) and the zoom level, which are defined at form level as instance variables;
public class GoogleMaps extends Canvas implements CommandListener {
 
    Command cmdBack = new Command("Back", Command.EXIT, 1);
    Command cmdRefresh = new Command("Refresh", Command.SCREEN, 10);
 
    //reference to the parent MIDlet
    MidletGPS midGPS;
    int zoom = 14;		//default value for zoom
    String latitude = "";
    String longitude = "";
 
    public GoogleMaps(MidletGPS mGPS, String Lat, String Longit) {
        latitude = Lat;
        longitude = Longit;
        midGPS = mGPS;
 
        this.addCommand(cmdBack);
        this.addCommand(cmdRefresh);
 
        this.setCommandListener(this);
    }
 
...
}
  • the image is downloaded using a HttpConnection, that manages the connection, and an InputStream for getting the serialized form of the map;
  • once the stream is obtained, the image is created directly using the Image.createImage(InputStream) method or based on a byte array;
private Image getGoogleMap() {
    HttpConnection connection = null;
    InputStream inputStream = null;
 
    //get the width and the height of the screen
    int width = this.getWidth();
    int height = this.getHeight();
 
    //the query string for the Google service
    String url = "http://maps.google.com/maps/api/staticmap?center=";
    url += this.latitude + "," + this.longitude;
    url += "&zoom=" + String.valueOf(zoom);
    url += "&size=" + width + "x" + height + "&sensor=true";
 
    try {
        connection = (HttpConnection) Connector.open(url);
        connection.setRequestMethod(HttpConnection.GET);
        inputStream = connection.openInputStream();
 
        Image map = Image.createImage(inputStream);
 
//	      //the alternative way
//            ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
//            //get the image byte by byte
//            int c;
//            while ((c = inputStream.read()) != -1) {
//                byteArray.write(c);
//            }
//            byte[] buffer = byteArray.toByteArray();
//            byteArray.close();
//
//            //create an Image object
//            logo = Image.createImage(buffer, 0, buffer.length);
 
        return map;
 
    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        try {
            if (inputStream != null) {
                inputStream.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    return null;
}
  • the image will be displayed on the entire form by overriding the Canvas paint method;
    protected void paint(Graphics g) {
        //get the image
        Image map = getGoogleMap();
        if(map!=null){
            //draw the image on the canvas
            g.drawImage(map, 0, 0, Graphics.LEFT | Graphics.TOP);
        }
        else{
            g.setColor(255,0,0);
            g.drawString("No map available", 20, 20, 0);
        }
    }
  • if you want to modify the zoom level (+ or –) we can define a handler for key pressed event; this is possible by overriding the void keyPressed(int keyCode) method; in this example, we will use 1 key to make a zoom out and 3 key to make a zoom in:
    protected void keyPressed(int keyCode) {
        if (((char) keyCode) == '1') {
            zoom--;
        }
        if (((char) keyCode) == '3') {
            zoom++;
        }
	//call the paint event
        this.repaint();
    }
  • in the keyPressed you can also modify the latitude and longitude with 0.02 and request a new map allowing users to move in all directions with the other keys (the code is available in the example full source code)

How to test the application in Netbeans using a GPS emulator

GPS emulator in the External Events Generator

GPS emulator in the External Events Generator

If you want to test the GPS MIDlet in the NetBeans mobile emulator (Java Platform Micro Edition SDK 3.0) you need something that will emulate the GPS module. The emulator has what you need and this is the External Event Generator.

1. open the External Event Generator using mobile emulator View sub-option;

2. set your GPS data; if you want to generate multiple GPS values, create a xml script file an load it using  the Browse button; a possible script file can look like this:

<waypoints>
  <waypoint time="0" latitude="44.435251" longitude="26.1024" altitude="100" />
  <waypoint time="10000" latitude="46.435251" longitude="24.1024" altitude="0" />
</waypoints>

3. send the data in order to be received by the mobile platform emulator

You can download the full source code, including a sample test MIDlet. The example also allow the user to move in all directions on the map.

For another solution that implements mobile GPS data and Google Maps web services, you can check Developing Location Based Services: Introducing the Location API for J2ME

, , ,


  1. #1 by Jeevana on July 28th, 2011

    Excellent Post. Two Thumbs UP…!!

  2. #2 by Rotelando on August 31st, 2011

    This article was really helpful. Thank you very much and God Bless!

    I want to ask, is it possible to show directions(From on location to another) on the static map.

  3. #4 by Rotelando on September 1st, 2011

    Thanks. will go check it out.

  4. #5 by Riyad on October 13th, 2011

    Thanks.It is really helpful for beginners.

  5. #6 by karan on October 14th, 2011

    please anyone help me i can’t connect to internet..
    when i click Display map
    an alert mag display can
    when i press yes then emulator not work
    its always ask me can connect with airtime?
    how can i handle this prob.

    thank you & please help me….

  6. #7 by Coder on November 17th, 2011

    You post is AWESOME! It cleared my thoughts after days of unsuccessful j2me googleing!
    Keep up the good work

  7. #8 by Anggita on February 21st, 2012

    Hey!!! this post is really AWESOME!!! 2 THUMBS FOR U!!!
    thank u very much for u’r help.. I just working on it.. :-)

(will not be published)

  1. No trackbacks yet.