AS mobile phones continue to get smaller and cheaper, manufacturers are able to cram more into them. One interesting capability that is making its way into mobile phones is Global Positioning System (GPS). A GPS receiver provides the mobile phone a way to know its own location. This means that your MIDlets can now combine the awesome power of the Internet with the awesome power of GPS. From a programming perspective, it’s easy to write applications to find the nearest Starbucks or display your current location on a map at a social networking Web site.
GPS isn’t the only way to determine location, but it’s probably the most popular. Mobile phones can also use the location of the nearest cell tower to determine location, but it’s not as precise. For more information on this technique and its relationship to wireless 911 service, see Wikipedia:
http://en.wikipedia.org/wiki/Enhanced_911
The JSR 179 Location API is a standard interface to location hardware. It is required on MSA devices that have location hardware. The API is located in javax.microedition.location
.
On many of today’s devices, only signed MIDlets can use the Location API. If you intend to develop a Location API application, check your target devices and target wireless carriers to find out what you must do to make your application run.
Retrieving the device’s current location is relatively simple. You need a LocationProvider
, but first you must ask for an appropriate one. It is possible that a device supports more than one method of locating itself. For example, a device could have one LocationProvider
that uses GPS hardware and one LocationProvider
that uses cell tower positioning.
Ask for a LocationProvider
from its factory method getInstance()
by specifying the criteria it must meet. For example, you might want to retrieve only a LocationProvider
that does not incur any cost, or one that is able to return information about the orientation of the device.
If you just create a brand new Criteria
object, it has default values that will match any available LocationProvider
s. This is also equivalent to passing null
for the Criteria
argument.
If getInstance()
cannot find a matching LocationProvider
, it returns null
. If no LocationProvider
s are available currently, getInstance()
throws LocationException
.
Once you’ve got a LocationProvider
, call getLocation()
for the device’s current location. Pass a timeout value in seconds. The method blocks until the location is determined or time runs out, in which case LocationException
is thrown.
The returned Location
object can contain all sorts of useful information. The first thing to check is isValid()
, which indicates if the object contains any useful information. Next most interesting is getTimestamp()
, which tells when the location measurement was retrieved.
For the location itself, call getQualifiedCoordinates()
, which returns an object containing longitude, latitude, altitude, and the accuracy of each measurement.
LocationProvider
’s static getLastKnownLocation()
returns whatever location value was last measured by the device. Make sure you check the returned Location
’s isValid()
method. Also, check getTimestamp()
to make sure that the measurement isn’t too old to be useful.
To receive ongoing updates from a LocationProvider
, your application can register a LocationListener
by using setLocationListener()
. You need to specify how often you want updates (in seconds), how late an update is allowed to be, and how old a location measurement can be.
Here is a call that registers a listener for 4-second updates, which can be at most 1 second late, at most 1 second old.
The whole LocationListener
mechanism is really just a scheduling convenience to save you the trouble of setting up your own periodic updating mechanism.
LocationListener
has two methods you must implement. Every time a location is read, the device calls the listener’s locationUpdated()
method. Furthermore, if the provider’s state changes (becomes unavailable, for example), the providerStateChanged()
method is invoked.
A different kind of listener, ProximityListener
, is useful for applications that want to know when they are near a certain location. ProximityListener
s are registered and unregistered using static methods in LocationProvider
. All you have to do is pass in the location that interests you and a radius that describes how close to that location the device has to be before the ProximityListener
is notified.
When the device enters the area you have described, the ProximityListener
’s proximityEvent()
method is invoked.
The other major component of the JSR 179 Location API is landmark management. A landmark is a location with an associated name. Specifically, a Landmark
in the Location API has a name, a description, a QualifiedCoordinates
object, and an AddressInfo
object.
A LandmarkStore
is a simple database of landmarks. Each LandmarkStore
has a name, except for one default LandmarkStore
, which has no name. LandmarkStore
s are shared among all Java ME applications on a device but may or may not be shared with other (native) applications.
Static methods in LandmarkStore
control adding, removing, and listing LandmarkStore
s.
To open an existing LandmarkStore
, pass its name to the factory method getInstance()
.
Inside a LandmarkStore
, Landmark
s can be associated with categories, which are simply names. A Landmark
can also have a null
category, meaning it is not associated with any category.
Categories are managed using addCategory()
and deleteCategory()
. An Enumeration
of categories is returned from getCategories()
.
Use addLandmark()
to either add a new Landmark
to the LandmarkStore
or to associate a Landmark
with an additional category.
You can retrieve landmarks from the LandmarkStore
either by category or by geography. For example, the following code returns an Enumeration
of Landmark
s that match the category Sports
and any landmark name (signified by null
):
This code retrieves landmarks in the rectangle defined by the minimum and maximum latitude and longitude values, matching any (null
) category name:
Some devices know if they are horizontal, vertical, tilted left, tilted right, or some combination of angles. Like the controllers on the Nintendo Wii, devices that understand their own orientation can be used for all sorts of interesting applications.
The javax.microedition.location.Orientation
class encapsulates this information. Retrieve the current orientation by calling the static getOrientation()
method. If the device does not know its orientation, LocationException
is thrown.
When you develop Location API applications on a desktop computer, the emulator does not have access to actual GPS hardware and cannot know the location of your computer. Instead, it pretends to know. You can tell the emulator where it should pretend to be. The procedure is the same regardless of whether you use NetBeans Mobility Pack or the Sun Java Wireless Toolkit because the underlying emulator is the same.
When the emulator is running your application, choose MIDlet > External events from the emulator window’s menu. On the Location tab, you can fill in the emulator’s current simulated location and other properties related to the Location API (see Figure 27.1).
Figure 27.1. Adjusting the emulator’s location
The emulator also offers the opportunity to run a location script, which is a simple XML file that describes the movement of the emulator over time. This is great for testing applications that use ProximityListener
s or match the current location against known landmarks.
The CityGuide
sample application (part of the Sun Java Wireless Toolkit and NetBeans Mobility) is a great demonstration of using the Location API and also includes a sample location script.
StandMIDlet
is part of the example code for this book. It is easier to understand than CityGuide
and includes many of the code snippets that are presented in this chapter. See the book’s Web site to get StandMIDlet
:
http://kickbutt.jonathanknudsen.com/download.html
The JSR 179 Location API is a standard API for devices that know their own location. Use it by retrieving a LocationProvider
that meets your needs. You can get the device’s location directly from a LocationProvider
, or you can register a LocationListener
to receive periodic updates. Another type of listener, ProximityListener
, is notified when the device comes close to a certain geographic point. The Location API also includes a simple database of named landmarks, the LandmarkStore
. LandmarkStore
s have names and can store landmarks associated with one or more named categories. Finally, some devices also understand their own orientation, represented by the Orientation
class. The emulator for the Sun Java Wireless Toolkit and NetBeans Mobility Pack has a supplemental window where the simulated location can be adjusted. For more rigorous testing, a location script can be used to change the simulated location over time.
3.149.249.252