Blackberry GPS/Location API

I just got finished playing with the blackberry Location API. I was pleasently suprised how it easy it was to work with. The key to it is that your phone must be a 4.2 BB OS phone (or upgraded to 4.2 like I did with my8700g) for the Location API to work with BT Pucks. The two source files for a simple application are pasted below the app is call Spot Finder.

Basically what it does is allows you to mark and save a location that you are currently in and then later find your way back to that location. It will give you the distance and direction that you need to go. Could be useful for remember your parking spot or the location of a bar you need to get back to. Unfortately in my basic testing its accurate but not that accurate. It’s not perfect but it is a interesting little application especially for learning the basics of the blackberry Location API.

You can download spot finder here.

Java Source:

/* Spot Finder.java */

package com.apsquared.spotfinder;import java.util.Enumeration;
import javax.microedition.lcdui.TextField;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.blackberry.api.invoke.*;
import javax.microedition.location.*;public class SpotFinder extends MyApp {

public static void main(String[] args)
{
SpotFinder theApp = new SpotFinder();
//To make the application enter the event thread and start processing messages, we invoke the enterEventDispatcher method
theApp.enterEventDispatcher();
}

MainScreen theMainScreen = null;
RichTextField spotLocation = null;
RichTextField currentLocation = null;
RichTextField introMsg = null;
RichTextField directions = null;

String storeName = "SPOT";

double spotLat;
double spotLong;
double curLat;
double curLong;

public SpotFinder()
{
theMainScreen = createMainScreen();
pushScreen(theMainScreen);
}

private MainScreen createMainScreen()
{

//Create a new screen for the applicatin
MainScreen screen = new MainScreen();
screen.addKeyListener(this);
screen.addTrackwheelListener(this);
introMsg = new RichTextField("Welcome to Spot Finder!");
spotLocation = new RichTextField("Current Spot: ");
currentLocation = new RichTextField("Current Location: ");
directions = new RichTextField("");

screen.add(introMsg);
screen.add(spotLocation);
screen.add(currentLocation);
screen.add(directions);
//Add a field to the title region of the screen. We use a simple LabelField here. The ELLIPSIS option truncates
// the label text with "..." if the text was too long for the space available.
screen.setTitle(new LabelField("Spot Finder", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH));
return screen;

}

public void setDirections(final String locStr)
{
UiApplication.getUiApplication().invokeLater (new Runnable() {
public void run()
{
directions.setText(locStr);
}});
}

public void setIntroMsg(final String locStr)
{
UiApplication.getUiApplication().invokeLater (new Runnable() {
public void run()
{
introMsg.setText(locStr);
}});
}

public void setCurLocation(double lat, double lng, float course, float speed)
{
curLat = lat;
curLong = lng;
String latLong = new String(curLat+" "+curLong);
setCurLocation(latLong);

//TODO: check for valid spot
Coordinates from = new Coordinates(curLat,curLong,0);
Coordinates to = new Coordinates(spotLat,spotLong,0);
float dist = from.distance(to) * (float)3.2808399 ;
//i think calculation should be azimuth - course (+360 if value is neg)
float dir = from.azimuthTo(to) - course;
if (dir<0)
dir+=360;
setDirections("Distance: "+dist+" ft.\nDirection: "+dir);
}

public void setCurLocation(final String locStr)
{
UiApplication.getUiApplication().invokeLater (new Runnable() {
public void run()
{
currentLocation.setText("Current Location:\n"+locStr);
}});
}

public void setSpot(double lat, double lng)
{
spotLat = lat;
spotLong = lng;
String latLong = new String(spotLat+" "+spotLong);
setSpot(latLong);
}

public void setSpot(final String locStr)
{
UiApplication.getUiApplication().invokeLater (new Runnable() {
public void run()
{
spotLocation.setText("Current Spot:\n"+locStr);
}});
}

public void msgBox(final String msg)
{
UiApplication.getUiApplication().invokeLater (new Runnable() {
public void run()
{
Dialog.alert(msg);
}});
}

protected void makeMenu(Menu menu, int instance)
{
Field focus = UiApplication.getUiApplication().getActiveScreen().getLeafFieldWithFocus();
if(focus != null) {
ContextMenu contextMenu = focus.getContextMenu();
if( !contextMenu.isEmpty()) {
menu.add(contextMenu);
menu.addSeparator();
}
}

MenuItem markSpot = new MenuItem("Get Current Spot",50,8) {
public void run()
{
markSpot();
}
};

MenuItem saveSpot = new MenuItem("Save Current Spot",50,8) {
public void run()
{
saveSpot();
}
};

MenuItem loadSpot = new MenuItem("Load Current Spot",50,8) {
public void run()
{
loadSpot();
}
};

MenuItem findSpot = new MenuItem("Find Current Spot",50,8) {
public void run()
{
findSpot();
}
};

menu.add(markSpot);
menu.add(saveSpot);
menu.addSeparator();
menu.add(loadSpot);
menu.add(findSpot);
}

private void saveSpot()
{
LandmarkStore lStore = LandmarkStore.getInstance(storeName);
if (lStore == null)
{
try
{
LandmarkStore.createLandmarkStore(storeName);
}
catch (Exception e)
{
msgBox("Error creating store. "+e.toString());
return;
}
}
try
{
lStore = LandmarkStore.getInstance(storeName);
Enumeration e = lStore.getLandmarks();
Landmark lMark = null;
if (e!=null && e.hasMoreElements())
{
lMark = (Landmark) e.nextElement();
lMark.setQualifiedCoordinates(new QualifiedCoordinates(spotLat,spotLong,0,Float.NaN, Float.NaN));
}
else
{
lMark = new Landmark("SPOT1","SPOT1",new QualifiedCoordinates(spotLat,spotLong,0,Float.NaN, Float.NaN),null);
}
lStore.addLandmark(lMark, null);
msgBox("Spot Saved!");
}
catch (Exception e)
{
msgBox("Error saving spot. "+e.toString());
}
}

private void loadSpot()
{
LandmarkStore lStore = LandmarkStore.getInstance(storeName);
if (lStore == null)
{
msgBox("No store to open.");
return;
}
try
{
lStore = LandmarkStore.getInstance(storeName);
Enumeration e = lStore.getLandmarks();
while (e.hasMoreElements())
{
Landmark lMark = (Landmark) e.nextElement();
setSpot(lMark.getQualifiedCoordinates().getLatitude(),lMark.getQualifiedCoordinates().getLongitude());
break;
}
}
catch (Exception e)
{
msgBox("Error saving spot. "+e.toString());
}
}

private void findSpot()
{
try
{
LocationProvider lPvd = LocationProvider.getInstance(new Criteria());
lPvd.setLocationListener(new MyLocationListener(this,false), 5, 5, 5);
}
catch (Exception e){
setIntroMsg("Error setting up location listener:\n"+e.toString());
}
}

private void markSpot()
{
try
{
LocationProvider lPvd = LocationProvider.getInstance(new Criteria());
lPvd.setLocationListener(new MyLocationListener(this,true), 1, 1, 1);
}
catch (Exception e)
{
setIntroMsg("Error getting location:\n"+e.toString());
}
}

//empty - nothing to do on exit
protected void onExit() {
}

}

/* MyLocationListener */
package com.apsquared.spotfinder;
import javax.microedition.location.*;

public class MyLocationListener implements LocationListener {

SpotFinder sf;
boolean onceOnly;

public MyLocationListener(SpotFinder sf, boolean onceOnly)
{
this.sf = sf;
this.onceOnly = onceOnly;
}

public void locationUpdated(LocationProvider provider,
Location location)
{
QualifiedCoordinates qc = location.getQualifiedCoordinates();
if (onceOnly)
{
sf.setSpot(qc.getLatitude(),qc.getLongitude());
provider.reset();
provider.setLocationListener(null, 0, 0, 0);
}
else
{
sf.setCurLocation(qc.getLatitude(),qc.getLongitude(),location.getCourse(),location.getSpeed());

}
}

public void providerStateChanged(LocationProvider provider,
int newState)
{

}
}