Smartphones

Mobile developer tips on location requests and Android Proximity Alerts

Kyle Miller provides sample code for fetching location on mobile web, and highlights potential issues you might face when setting up Proximity Alerts in Android.

In my previous post, I offered an overview of the security model differences between iOS and Android when using Location services and shared the basics of using the LocationManager in an Android application. In this post, I discuss using location in a mobile web application and ProximityAlerts in Android.

Location in mobile web

In mobile web, obtaining the user's location is very straightforward. The main method we are concerned about is "navigator.geolocation.getCurrentPosition()." This is a code snippet to demonstrate a thoughtful design pattern when requesting the user's location:

<SCRIPT type="text/javascript">

var gLat = -1;

var gLong = -1;
$(document).ready( function() {
try {

if( navigator.geolocation ) {

navigator.geolocation.getCurrentPosition(successCallback, errorCallback, {maximumAge:600000, timeout:0});

}

}

catch( error ) {

alert( "document.ready: " + error.description );

}

} );
// Request a position. We only accept cached positions whose age is not
// greater than 10 minutes. If the user agent does not have a fresh
// enough cached position object, it will immediately invoke the error
// callback.
function successCallback(position) {
try {
var timestamp = position.timestamp;
gLat = coords.latitude;
gLong = coords.longitude;
}
catch( error ) {
alert( "successCallback: " + error.description );

}

}
function errorCallback(error) {

try {

switch(error.code) {

case error.TIMEOUT:

// Quick fallback when no suitable cached position exists.

doFallback();

// Acquire a new position object.

navigator.geolocation.getCurrentPosition(successCallback, errorCallback);

break;

default:

//alert('default');

break;

//case ... // treat the other error cases.

}

}

catch( error ) {

alert( "errorCallback: " + error.description );

}

}
function doFallback() {

// No fresh enough cached position available.

}

</SCRIPT>

The code uses jQuery's "ready" function to begin requesting the user's location from the mobile device as soon as the page is finished loading. By passing the "maximumAge" parameter, we are telling the browser that any location less than 10 minutes old is suitable (mainly for speed).

If a cached location less than 10 minutes old exists, the "successCallback" method will be invoked; if not, then the "errorCallback" method will fire. In the errorCallback method, we can first check the error code and then invoke "doFallback" to possibly load a default location or provide feedback to the user while we call "navigator.geolocation.getCurrentPosition" again -- this time without the "maximumAge" parameter to fetch a new location.

Android Proximity Alerts

The Android API has a neat feature when it comes to location called Proximity Alerts. These alerts allow you to set up specific areas of interest (or GeoFences), and then let the OS alert your application when the user is exiting or entering one. The specific API call is:

LocationManager - public void addProximityAlert (double latitude, double longitude, float radius, long expiration, PendingIntent intent)

The documentation on Proximity Alerts is sparse and vague at best. When I tried to implement Proximity Alerts, I encountered a number of issues, each of which I briefly describe below.

Expiration

According to the documentation:

"After the number of milliseconds given by the expiration parameter, the location manager will delete this proximity alert and no longer monitor it. A value of -1 indicates that there should be no expiration time."

This may have more to do with the way PendingIntents work, but I found that once the Context is killed from which the PendingItent was created, the Proximity Alert won't fire (even when I passed -1 for expiration time). If you wish to continuously track specific GeoFences, you'll need a persistent service running in the background, which you can use as the Context when creating a PendingIntent (rather than creating it from an Activity). Every time the OS shuts down and restarts your service, you'll need to recreate the Proximity Alerts.

Multiple PendingIntents firing

When I started implementing Proximity Alerts, I was using the same intent action string to generate the PendingIntent for each one. I found that the PendingIntents started firing multiple times when I would enter or exit one of the GeoFences. Also, I confirmed that each time the service I was using restarted (and thus recreated the Proximity Alerts), the PendingIntent would fire once more than the last time, as if they were building.

This was frustrating because even though I was careful to call removeProximityAlert and even created the new PendingIntent with FLAG.CANCEL_CURRENT, this continued to happen. I never figured out how to suppress this, so my solution was to create a unique intent action string for each PendingIntent using a timestamp concatenated on the end. I then had to store all of these strings so I could remove the Proximity Alerts later. However, it solved my problem, and I was happy to find a "solution."

When do they fire?

It wasn't until I plotted the GeoFences being tracked and my current location on a map and drove around that I finally figured out what was going on.

Imagine two circles. One circle is the GeoFence being tracked (lat/lng and radius). The other circle is your location, which is comprised of a lat/lng and an accuracy as the radius (with GPS accuracy will be a very small value of around 5-10 meters, and can be upwards of 1,500 meters with Network Location). When the two circles first intersect, an "entering" Proximity Alert will fire; when the circles fully separate, an "exiting" proximity alert will fire.

So let's say your GeoFence is set for 100 meters, and the user's phone is using Network Location with an accuracy of 1500 meters. This means that the Proximity Alert will actually fire from 1,600 meters away rather than the 100 you set.

About

Kyle is a senior software engineer specializing in web/Android development living in Austin TX. He's a self-professed "gadget freak" whose passion for mobile devices drove him to jump into the mobile industry in 2010. He enjoys the fast-paced nature ...

0 comments

Editor's Picks