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
- Find and initialize a location provider
- Listen and act on location updates given by this provider
- 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