Using the Location API for Favorite Spots

By Vikram Goyal

Developing location-aware applications seems like a lot of work, especially since getting started seems to be the hardest part. In this tech tip, I will show you how to get started using the Location API (JSR 179) to get over the initial hurdle, and build a small location-aware application that you can use to tag your favorite spots.

I have tested and verified that the MIDlet works on a Nokia N95 device. When testing this on your device, make sure that it supports the Location API (JSR 179).

There are three steps in this tech tip

  1. Find and initialize a location provider
  2. Listen and act on location updates given by this provider
  3. Store and list favorite spots
The following paragraphs elaborate on these steps. It may help to have the entire source code of this MIDlet available for review while following the code snippets in these steps.

Step 1: Find and initialize a location provider

The process of discovery of a suitable location provider is broken down into two further steps. First, you need to create a set of criteria for the location provider. Second, you need to create an instance of this provider using these criteria.

The Location API provides two classes for these two steps: Criteria and LocationProvider.

To create a valid criteria, you create an instance of this class, set various parameters of the criteria. The code below, taken from the source code, creates a criteria that is suitable for our purposes.


  // create a very basic criteria for the provider
  Criteria criteria = new Criteria();
  criteria.setHorizontalAccuracy(Criteria.NO_REQUIREMENT);
  criteria.setVerticalAccuracy(Criteria.NO_REQUIREMENT);
  criteria.setPreferredResponseTime(Criteria.NO_REQUIREMENT);
  criteria.setCostAllowed(false);

As you can see, this is a very relaxed criteria. There are no specific requirements for horizontal or vertical accuracy or for response times. The only restriction is that there should not be a cost involved in using the Location API (possibly linked to the network provider).

We should be allowed to proceed only if the Location API built into your device can provide a provider based on these criteria. We do so, by asking the LocationProvider class for a provider using these criteria as the guiding set.


  // get the provider based on this criteria
  LocationProvider provider = LocationProvider.getInstance(criteria);

  // provider found
  if (provider != null) {
    provider.setLocationListener(this, -1, 0, 0);
  } else {
    display.setCurrent(
      new Alert("Error!",
      "Phone does not support Location Provider with the given criteria",
      null, AlertType.ERROR));
  }

If a provider with the given criteria cannot be found, a message is given to the user, and the MIDlet cannot proceed. But if the device can provide a valid location provider, the MIDlet sets up a location listener to listen to all the updates given by the location provider. In this case, the listener is the MIDlet itself.

Step 2: Listen and act on location updates

In the previous step, the location listener is set to the MIDlet itself. This means that the MIDlet must implement two methods provided by the LocationListener class. These two methods are locationUpdated(LocationProvider lp, Location l) and providerStateChanged(LocationProvider lp, int newState). The code below shows the implementation of the locationUpdated method.


  // if valid location is found, update the coords and status
  if(location != null && location.isValid()) {
    QualifiedCoordinates coords = location.getQualifiedCoordinates();
    coordsDisplay.setText(
      truncate(coords.getLatitude()) + ", " +
      truncate(coords.getLongitude()));
    statusDisplay.setText("Available");
    currentLocation = location;
  } else {
    coordsDisplay.setText("--, --");
    statusDisplay.setText("Unavailable");
    currentLocation = null;
  }

Each time the location of the device is updated, the location provider sends out the new location using the Location parameter in the locationUpdated method. The new location's coordinates can be picked using the getQualifiedCoordinates method.

Of course, if the device is out of range of the GPS satellites, then the provider will not be able to get the correct coordinates and, therefore, the actual location will be either null or invalid. The method checks for this before updating the status and the current location of the device.

The providerStateChanged method accepts updates when the location provider goes in and out of range of the GPS satellites. However, I found that my implementation on the Nokia N95 did not reliably send out updates for the providerStateChanged method. I therefore used the locationUpdated method to find out the status of the provider, However, I have kept the code in the providerStateChanged in case it works on other devices.

NOTE

To be on the safe side, the code in the locationUpdated method (and the corresponding providerStateChanged method) should be in its own thread to make sure that it doesn't block the normal MIDlet thread.

Step 3: Store and list favorite spots

Once the current location using the latitude and longitude have been found, it is a simple method to store this location with a tag as your favorite spot. The Location API makes it ridiculously simple by providing the Landmark store. You can either create your own Landmark store, or use the default one.

The default Landmark store is shared by all the MIDlets within the device. You create a Landmark store by using the static method provided by the LandmarkStore class. By passing in null, as shown in the following code, you are asking for the default store from this instance.

  store = LandmarkStore.getInstance(null);

The Landmark store contains the details of a location using the Landmark class. As shown in the following code, you can create a landmark by giving it a name (provide by you as a name for your favorite spot), a description (this is empty in the code below), and of course, the all important coordinates. The last parameter that is accepted by this constructor is an AddressInfo object that can be used to store actual address information, if supported by the provider. In this case, I have kept these details as simple as possible.


    // create the landmark
    Landmark landmark =
      new Landmark(name, "", currentLocation.getQualifiedCoordinates(), null);

    // and save it
    try {
      store.addLandmark(landmark, null);

      display.setCurrent(
        new Alert("Message", "Done", null, AlertType.INFO), displayForm);

      return;

    } catch(Exception ex) {
      handleError(ex);
    }

Once you have created the landmark, you can store it in the store using the addLandmark method. The second parameter specifies a category for that landmark, but I have kept it simple by putting it in the default category.

The list of existing landmarks can be retrieved using the getLandmarks method. This returns an enumeration that can be iterated over to display to the user in a list. This is shown in the following code.


  Enumeration en = store.getLandmarks();
  while(en.hasMoreElements()) {
    Landmark landmark = (Landmark)en.nextElement();
    landmarkList.append(
      landmark.getName() +
      " - " +
      truncate(landmark.getQualifiedCoordinates().getLatitude()) + ", " +
      truncate(landmark.getQualifiedCoordinates().getLongitude()), null);

Resources

Comments:

Nice article!!

How to know whether my device supports jsr-179??

can i get list of all jsr-179 supported devices?

Posted by Nitin Sawant on April 27, 2009 at 08:51 PM PDT #

Nitin,

Most device manufacturers will tell you whether they support JSR 179 for a particular device. It is best to contact their tech support for it.

Regards,
Vikram

Posted by Vikram Goyal on April 30, 2009 at 07:17 PM PDT #

Hi Vikram,
Thanks for replying,
You are right but There are thousands of devices which support jsr-179, its not possible for me to contact each of them.

Actually, I am creating small J2ME app which will read the GPS location and send it to web server,
I want to detect if the device supports jsr-179, if it supports jsr-179 then no problem carry on, if it won't support jsr-179 then i want to show message to the user "Device not supported" and exit the app.

regards,
Nitin Sawant

Posted by Nitin Sawant on April 30, 2009 at 08:50 PM PDT #

Hi Nitin,

Of course, this is a very simple task. The code provides a solution for this. When you call the Location API provider using the method LocationProvider provider = LocationProvider.getInstance(criteria); it will be null if the provider cannot be found. You can use this to achieve what you want.

Regards,
Vikram

Posted by Vikram Goyal on April 30, 2009 at 09:31 PM PDT #

Is it possible to use this API even if there is no subscription to GPS service? e.g. I get to know the area name wherever I go based on the received signal. Is this API useful to get location from such data?

Posted by Pawan on May 05, 2009 at 03:35 AM PDT #

Hi Pawan,

Short answer is no. If there is no subscription, then the Location API will not be able to get the GPS service either. However, I am not sure if you need subscription to access the GPS service. If the device supports it, then any application should be able to access it, as it is not based on the network access provider services (unless you refer to Assisted GPS - which is and most likely a subscription based service).

HTH,
Vikram

Posted by Vikram Goyal on May 05, 2009 at 09:02 AM PDT #

Hi Vikram,
Nicely structured article. That you do not need to subscribe to GPS service once you have a GPS device built into your handset is always a surprising thing. Who pays those guys then? :)

Second and the more important question. What is the role or relevance of JME in enabling other methods of position finding? ToA, DToA, Triangulation etc. are some terms in this context that i can recall.

Third,does JME library or a webservice support conversion of the lat, lng values to meters for a different projection system?

Regards,
Nitish

Posted by nitish pandey on May 10, 2009 at 07:10 PM PDT #

The link to source code in the starting of the article is broken. FYA pse.

Posted by nitish on May 10, 2009 at 07:31 PM PDT #

Hi Nitish,

I have asked the link to the source code to be fixed. Thanks for pointing it out.

1. I think it is the device manufacturers who pay the GPS service providers for access to the GPS data, but I am not 100% sure of it.

2. AFAIK, Java ME does not yet support any other methods of position finding. It may be up to individual implementations to provide this information.

3. Not exactly sure what you mean. How would conversion happen from lat, lng to meters? By meters do you mean actual addresses? If yes, then again it depends on the Location API implementation by way of AddressInfo.

HTH,
Vikram

Posted by Vikram Goyal on May 10, 2009 at 11:20 PM PDT #

The link to the source code has been fixed. Sorry about that!

Posted by Christine Dorffi on May 11, 2009 at 08:52 AM PDT #

One comment about GPS service.

[Standalone GPS]
When you set setCostAllowed(false), as below, the device should only try to get GPS info from satellites which does not cost anything.

> criteria.setCostAllowed(false);

This might take a while to get a location fix.

[Assisted GPS]
If you want a faster and more accurate fix then you do setCostAllowed(true). With this option you also get assistance from the network to get a fix on your location. And yes it will cost you.

Now for the device actually working with the above parameters may be a different issue since different operators may have different policies.
Some might not even allow to use standalone GPS. Maybe you need to subscribe to a service. You have to check the operator policy or try to test on the device itself.

Posted by Alan Lee on June 08, 2009 at 11:10 AM PDT #

Such a useful info, thanks :)

Posted by Peter on August 23, 2009 at 01:07 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Tips for developers who use Java technologies (Java SE, Java ME, JavaFX) for mobile and embedded devices.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today