You are here

Some JSR 179 Location API J2ME examples

Blog Terms: 

The first 3 examples come from http://www.j2melbs.com/ .
1, The basic Location Question
Download: http://www.j2melbs.com/content/codes/lbs/CoordinateAlert.java

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.location.*;

public class CoordinateAlert extends MIDlet implements CommandListener {

private Display display;
private Form mainForm;
private Alert positionAlert;

public CoordinateAlert() {

mainForm = new Form("HelloMIDlet");
mainForm.append(new StringItem(null, "You will be alerted of your current position."));

mainForm.addCommand(new Command("Exit", Command.EXIT, 0));
mainForm.addCommand(new Command("OK", Command.OK, 1));
mainForm.setCommandListener(this);
}

public void startApp() {
display = Display.getDisplay(this);
display.setCurrent(mainForm);
}

public void pauseApp() {}

public void destroyApp(boolean unconditional) {}

public void commandAction(Command c, Displayable s) {

String label = c.getLabel();
if (label.equals("Exit")) {

notifyDestroyed();
}
else if (label.equals("OK")) {

mainForm.set(0, new StringItem(null, "Tracking location ..."));
givePositionAlert ();
mainForm.set(0, new StringItem(null, "Again get alerted of your current position?"));
}
}

private void givePositionAlert () {

try {

Criteria cr = new Criteria();
cr.setHorizontalAccuracy(500);

LocationProvider lp = LocationProvider.getInstance(cr);
Location l = lp.getLocation(60);//60 seconds, timeout

Coordinates c = l.getQualifiedCoordinates();
if (c != null) {

String lat = c.convert(c.getLatitude(),c.DD_MM);
if (c.getLatitude() > 0) {

lat = "E " + lat;
}
else {

lat = "W " + lat;
}

String lon = c.convert(c.getLongitude(),c.DD_MM);
if (c.getLatitude() > 0) {

lon = "N " + lon;
}
else {

lon = "S " + lon;
}

positionAlert = new Alert("Location Alert");
positionAlert.setString("\nYour present location is \n" + lat + "\n" + lon);
positionAlert.setTimeout(Alert.FOREVER);
}
else {

positionAlert = new Alert("Location Error");
positionAlert.setString("Null Coordinate Received");
positionAlert.setTimeout(Alert.FOREVER);
}
}
catch (Exception e) { //LocationException OR InterruptedException

positionAlert = new Alert("Location Error");
positionAlert.setString("Exception Encountered " + e);
positionAlert.setTimeout(Alert.FOREVER);
}
display.setCurrent(positionAlert);
}
}

Criteria

* Criteria class included in the location package gives the application to set constraints based on which a provider is selected. It lets you specify accuracy or refresh time limits as required by the application. An application providing precise route direction won’t work if the position accuracy is off by say 30m. With such inaccurate provider, the application might ask you to take a left turn while you are driving on a bridge over a river. The application must ascertain specific criteria before choosing a location provider.
* Remember while choosing a provider among different options, there is no preference given to any particular criteria and in case none of the available providers meet all requirements, the closest match is returned where ‘closest’ is platform-dependent.
* However there is an exception to the general case. If the application has set the cost field to indicate that the returned location provider is not allowed to incur financial cost to the end user, the implementation MUST guarantee that the returned location provider does not incur cost.
* All fields in the Criteria class are initialized to default values, you need to specifically set them if you need the values to be different like here the horizontal accuracy is set to 500 meters.

LocationProvider

* A location provider can be in three states AVAILABLE (ready to provide the location), TEMPORARILY_UNAVAILABLE (not ready due to temporary reason e.g. blocked signal while inside building), OUT_OF_SERVICE (not ready and not likely to recover in near future).
* The static method of LocationProvider class is passed the criteria and it returns the instance of a suitable location provider, a module that returns the location when asked for. LocationProvider.getInstance(Criteria cr) throws a LocationException if all providers are out of service.

* When asked for the current location i.e. getLocation() is called, the location provider returns a location object with data corresponding to the current location measurement. If the provider is temporarily unavailable, it waits. However if it doesn’t get the location in the specified time limit or if the provider is out of service, it throws a LocationException. In this program the time-out is set to 60 seconds.
* The provider adheres to the set criteria used for its choice. However note that the individual location returned might not fulfill exactly the criteria used for selecting this provider. The criteria are used to select a location provider that typically is able to meet the defined criteria, but not necessarily for every individual location measurement.

Location

It contains all information of a location e.g. the co-ordinates, time stamp at which it was measured, speed etc. Methods can be invoked on the object to get the data. Sometimes the location returned by the provider might be invalid. The isValid() method can be called to check for its validity.
Coordinates and QualifiedCoordinates

* Latitudes vary from +90(North) to –90(South) and longitude from +180(East) to –180(West).
* Latitudes and longitudes are represented either as a double or in degree-minute or in degree-minute-second format.
12.52 degree (double) = 12 degree 31.2 minute (DD_MM) = 12 degree 31 minute 12.0 second (DD_MM_SS)

* Coordinates class as you have guessed contains the latitude, longitude and altitude information, which can be accessed using setter and getter methods.
* In addition it gives the functions to calculate distance between two points and also convert latitudes or longitudes from DD_MM or DD_MM_SS format to double values of vice-versa.
* QualifiedCoordinates extends Coordinates and includes the horizontal and vertical accuracies of the measurement.
* The Location object returned by the location provider contains the qualified coordinates.

Other Notes of this Program

* The sign of the latitude and longitude (+ve or -ve) is used to determine whether it is North or South and East or West.
* An alert is generated in case an Exception occurs. Never, I repeat NEVER, leave catch an exception just to compile the code, always generate an error message. A simple System.out.println message might do while developing the application. But think about actually running it on a device. In that case you must generate an Alert to detect the error.
* Note that null coordinates are generated if the location provider is available but it can’t get the location e.g. if you are inside a building. You must provide a check for that else your application throws a NullPointerException.

* It is bad practice to use string concatenation using the ‘+’ operator on strings as it takes up more resources at run time. It is better to use a StringBuffer. However for such a small program you might indulge in such luxury.

Limitations of this Program

* While getting the location you can’t interact with the UI. Try clicking the exit button and it won’t work while the application is busy getting the location info.
* Every time you want to get the coordinates, the device asks for permission. This is annoying if you want the location continuously e.g. to continuously track your position on a map.

2, Coordinate Alert using Thread
Download: http://www.j2melbs.com/content/codes/lbs/CoordinateAlertThread.java

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.location.*;

public class CoordinateAlertThread extends MIDlet implements CommandListener {

private Display display;
private Form mainForm;
private Alert positionAlert;

public CoordinateAlertThread() {

mainForm = new Form("CoordinateAlertThread");
mainForm.append(new StringItem(null, "You will be alerted of your current position."));

mainForm.addCommand(new Command("Exit", Command.EXIT, 0));
mainForm.addCommand(new Command("OK", Command.OK, 1));
mainForm.setCommandListener(this);
}

public void startApp() {
display = Display.getDisplay(this);
display.setCurrent(mainForm);
}

public void pauseApp() {}

public void destroyApp(boolean unconditional) {}

public void commandAction(Command c, Displayable s) {

String label = c.getLabel();
if (label.equals("Exit")) {

notifyDestroyed();
}
else if (label.equals("OK")) {

mainForm.set(0, new StringItem(null, "Tracking location ..."));

GPSPosition gpsPosition = new GPSPosition();
Thread positionThread = new Thread (gpsPosition);
positionThread.start();
}
}

class GPSPosition implements Runnable {

public void run() {

try {

Criteria cr = new Criteria();
cr.setHorizontalAccuracy(500);

LocationProvider lp = LocationProvider.getInstance(cr);
//60 seconds, timeout, 180 could be better based on the test on mobile phone
Location l = lp.getLocation(60);

Coordinates c = l.getQualifiedCoordinates();
if (c != null) {

String lat = c.convert(c.getLatitude(),c.DD_MM);
if (c.getLatitude() > 0) {

lat = "N "+lat;
}
else {

lat = "S "+lat;
}

String lon = c.convert(c.getLongitude(),c.DD_MM);
if (c.getLatitude() > 0) {

lon = "E " + lon;
}
else {

lon = "W " + lon;
}

positionAlert = new Alert("Location Alert");
positionAlert.setString("\nYour present location is " + lat + "\n" + lon);
positionAlert.setTimeout(Alert.FOREVER);
}
else {

positionAlert = new Alert("Location Error");
positionAlert.setString("Null Coordinate Received");
positionAlert.setTimeout(Alert.FOREVER);
}
}
catch (Exception e) { //LocationException OR InterruptedException

positionAlert = new Alert("Location Error");
positionAlert.setString("Exception Encountered " + e);
positionAlert.setTimeout(Alert.FOREVER);
}

display.setCurrent(positionAlert);
mainForm.set(0, new StringItem(null, "Again get alerted of your current position?"));
}
}

}

Coordinate Alert using Thread

Run a new project using CoordinateAlertThread.java It uses a separate thread to access the location info. So the UI remains active with the main thread taking care of it. Now you can exit even when the program is busy fetching the location info. Since threading is a general concept in Java, I am not going to elaborate on that. But remember the following points –

* Threading is important in not only location-based but J2ME application development in general. Actions like getting information from a location provider, loading an image, fetching data from a server often require a significant amount of time. Such actions should be taken care of in a separate thread so that the user can still interact with the UI. Otherwise the user might misinterpret the program to have hanged.
* While doing time-consuming jobs always give a message to the user denoting what the program is doing. In this program “Tracking location ...” is printed to notify the user of the current action.

LocationListener

Why shout every time when the other guy is ready to shout and you just need to listen? Run another project using LocationListenerTest.java Note that now the device asks for location acquiring permission only once.
How Location Listener works?

* The LocationListenerTest implements the interface LocationListener. It has to override locationUpdated() and providerStateChanged() methods.
* Here you get the location provider instance as previously but instead of invoking the getLocation() method, you register the location listener with the location provider.
* The location provider calls the locationUpdated() method in regular intervals as specified while setting the listener.

* If the state of the location provider changes, providerStateChanged() is invoked.

Points to note about Location Listener

* Check the valid values that can be passed as the ‘interval’ ‘timeout’ and ‘maxAge’ arguments to
setLocationListener(LocationListener listener, int interval, int timeout, int maxAge). ‘-1’ is passed to set default values specific to the provider. Take special care about these values, else it might not work properly. Setting default values is a safe option but should match your application requirement.
* The implementation tries to provide location info at the specified intervals but the interval might not be exact.
* If the provider becomes temporarily unavailable or out of service or if the interval specified is too short for the provider, the implementation might update with an invalid location.
* LocationUpdated() method should be short immediately passing control to a different function before it’s time for the next location update.
* Any synchronization should be taken care of by the application. Say, you should wait for the location info processing thread to complete before you go to the next step. Such synchronizing is to be ensured by the application. Thread.join() often comes handy in such situation.

Other issues

* Note that permissions (not limited to location acquiring permission but also related to file access, sending data to server etc.) for a particular application can be set manually on the device without opening the application. The procedure is device-dependent.
* Nokia 6165 model doesn’t support providerStateChanged() but 6175 will.

3, Handling Landmarks
Download: http://www.j2melbs.com/content/codes/lbs/LandmarkDistance.java

import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.location.*;
import java.util.Enumeration;

public class LandmarkDistance extends MIDlet implements CommandListener {

private Display display;
private Form mainForm;
private Alert positionAlert;
private LandmarkStore landmarkStore;
private ChoiceGroup landmarkList;

public LandmarkDistance() {

buildMainForm();
}

private void buildMainForm() {

mainForm = new Form("LandmarkDistance");
StringItem welcomeMsg = new StringItem("welcome", "Press OK to see list of Landmarks");
mainForm.append(welcomeMsg);

mainForm.addCommand(new Command("Exit", Command.EXIT, 0));
mainForm.addCommand(new Command("OK", Command.OK, 1));
mainForm.setCommandListener(this);
}

public void startApp() {

display = Display.getDisplay(this);
display.setCurrent(mainForm);

buildLandmarkDirectory();
}

public void pauseApp() {}

public void destroyApp(boolean unconditional) {}

private void buildLandmarkDirectory() {

try {

LandmarkStore.createLandmarkStore("landmarks");
landmarkStore = LandmarkStore.getInstance("landmarks");
landmarkStore.addCategory("NY");
Landmark landmark = new Landmark("liberty",null,new QualifiedCoordinates(40.689, 74.045, 0, Float.NaN, Float.NaN) ,null);
landmarkStore.addLandmark(landmark, "NY");
}
catch (Exception e) {

Alert alert = new Alert ("Error in landmark creation section");
alert.setString(e.toString());
alert.setTimeout(alert.FOREVER);
display.setCurrent(alert);

}
}

public void commandAction(Command c, Displayable s) {

String label = c.getLabel();
if (label.equals("Exit")) {

try {

LandmarkStore.deleteLandmarkStore("landmarks");
}
catch (Exception e) {

Alert alert = new Alert ("Error");
alert.setString(e.toString());
alert.setTimeout(alert.FOREVER);
display.setCurrent(alert);
}
notifyDestroyed();
}
else if (label.equals("OK")) {

String level = mainForm.get(0).getLabel();
if (level.equals("welcome")) {

listLandmarks("_top");
}
else if (level.equals("main")) {

listLandmarks(landmarkList.getString(landmarkList.getSelectedIndex()));
}
else {

LocationInfo locationInfo = new LocationInfo(level, landmarkList.getString(landmarkList.getSelectedIndex()));
Thread locationInfoThread = new Thread(locationInfo);
for (int i=0; i< mainForm.size(); i++) {

mainForm.delete(i);
}
mainForm.append("Getting location Provider ...");
locationInfoThread.start();
}
}
}

private void listLandmarks(String category) {

Enumeration landmarkEnumeration = null;
landmarkList = new ChoiceGroup (null,ChoiceGroup.EXCLUSIVE);
String msgLabel = null;

if (category == "_top") {

landmarkEnumeration = landmarkStore.getCategories();
while (landmarkEnumeration.hasMoreElements()) {

landmarkList.append((String)(landmarkEnumeration.nextElement()), null);
}
msgLabel = "main";
}
else {

try {

landmarkEnumeration = landmarkStore.getLandmarks(category, null);
}
catch (Exception e) {

Alert alert = new Alert ("Error in getLandmarks " + e);
display.setCurrent(alert);
}
while (landmarkEnumeration.hasMoreElements()) {

Landmark landmark = (Landmark)(landmarkEnumeration.nextElement());
landmarkList.append(landmark.getName(), null);
}
msgLabel = category;
}

mainForm.set(0,new StringItem(msgLabel,null));
if (mainForm.size() == 1) {

mainForm.append(landmarkList);
}
else {

mainForm.set(1,landmarkList);
}
}

class LocationInfo implements Runnable {

String category, landmarkName;
boolean quit;

LocationInfo(String category, String landmarkName) {

this.category = category;
this.landmarkName = landmarkName;
}

public void run() {

try {
Enumeration landmarkEnum = landmarkStore.getLandmarks(category, landmarkName);
Landmark landmark = (Landmark)landmarkEnum.nextElement();

Coordinates target = landmark.getQualifiedCoordinates();

Criteria cr = new Criteria();
cr.setHorizontalAccuracy(500);

LocationProvider lp = LocationProvider.getInstance(cr);

//mainForm.delete(0);

while(!quit) {

mainForm.append("\nrefreshing distance ...");
Location l = lp.getLocation(60);
Coordinates present = l.getQualifiedCoordinates();
if (present != null && target!= null) {

float distance = target.distance(present);
for (int i=0; i < mainForm.size(); i++) {

mainForm.delete(i);
}
mainForm.set(0,new StringItem(null,"\n" + landmarkName + " distance : " + distance + "m"));
}
else {

positionAlert = new Alert("Error");
positionAlert.setString("Null Coordinate Received");
positionAlert.setTimeout(Alert.FOREVER);
}
Thread.sleep(15000);
}
}
catch (Exception e) {

positionAlert = new Alert("Error");
positionAlert.setString(e.toString());
positionAlert.setTimeout(Alert.FOREVER);
}

}

void quit() {

this.quit = true;
}
}
}

Landmark & LandmarkStore

The program LandmarkDistance.java shows an example of using a LandmarkStore. LandmarkStore is a built-in class of the JSR-179 location API. It provides a mean to store, delete or retrieve landmarks, which can be placed under different categories (like ‘hotels’ can be a category, ‘museums’ can be another). There is a default LandmarkStore, however others can be created by an application. This application creates its own store and deletes it at the end. Note: LandmarkStores are not destroyed automatically when an application ends. The stores continue to exist and are shared by all J2ME applications.
Support Issue

The location API has a class by the name AddressInfo, an instance of which can be stored within a Landmark object to keep contact info of the location. But currently Nokia platform doesn’t support it, so in case you need to keep extra info you need to make your own class extending the default Landmark class.

==================================================================
During the testing on mobile phone, i found some phones do not support JSR179 well. Some devices for example Nokia N95 need open the GPS to warm up and some devices such as Nokia E61 always get "Timeout" Exception, and it is not easy to receive the location on phones, it takes long time and will get Timeout exception after a period of running -- I guess the phone lost the satellite signal.

Comments

Hi. I like your blog. well done!

After my test, i found it is better to use
LocationListener
than using
Location l = lp.getLocation(60);

Because lp.getLocation(timeout); could get Timeout Location Exception by the first trying and never continue the working, if the GPS signal is not good. But LocationListener will continue working until it found the satellite and detect the location(will continue doing this forever in running time).

And for Nokia N95 8GB and other phones with AGPS chips, you need make sure you have sim-card inside and not in offline mode, because those phones can not detect your location even it can find the satellites. I took one day to found this problem.

one useful link:
http://209.85.129.132/search?q=cache:RRJQfB-Krv4J:discussion.forum.nokia.com/forum/showthread.php%3Ft%3D124941+j2me+N95+gps&cd=1&hl=en&ct=clnk&gl=de&client=firefox-a

Nokia phones are famous for their user friendly functions. These gadgets come power-packed with cutting-edge technologies and thus can grab the attention of various users. Nokia, a leading manufacturer of mobile phones, puts this technological miracle even more forward. It is giving scope to every human being to stay connected throughout the day. The added advantage is the coupling of Nokia with Wi-Fi technology. It gives a different edge of utility to the customers. It also has Bluetooth, which helps in sending high-density files or videos to others. The MMS or SMS is also an important feature of Nokia Wi-Fi mobile phones. This entices the younger generation to go for a Nokia Wi-Fi mobile set. envirofone

This is very applicable since it lets you specify accuracy or refresh time limits as required by the application. Often with such inaccurate provider, the application might ask you to take a left turn while you are driving on a bridge over a river. The application must ascertain specific criteria before choosing a location provider.
_____________
idaho divorce

.

{:jawdrop:} {:)} {:)}

I love your examples. Thank you very much. They work successfully and I am happy. :-)