HTML5 Geolocation API: Getting the best single location

The Geolocation API is built into all modern mobile browsers and it lets you take either a quick, onetime snapshot, or you can get continuous location updates. Using the browser to get your approximate location is very, very cool, but it’s also fraught with many challenges. The vast majority of blog posts on this API talk about what it can do, this blog post focuses on how to best use it and understanding the data provided by the API.

To start things out, let’s take a quick look at a short list of some of the challenges when using the Geolocation API.

Challenge 1. You will not know where the location information is coming from. There’s no way to tell if it’s from the GPS, the cellular provider or the browser vendors location service. If you care about these things then the native Android SDK, for example, gives you a huge amount of control over what they call ‘location providers.’

Challenge 2. You cannot force the app to stay open. This means that the typical user has to keep tapping the app to keep it alive otherwise the screen will go to sleep and minimize your app.

Challenge 3. Speaking about minimizing apps, when the browser is minimized the geolocation capabilities stop working. If you have a requirement for the app to keep working in the background then you’ll need to go native.

Challenge 4. You’ll have very limited control over battery usage. Second only to the screen on your phone or tablet, the current generation of GPS chips are major energy hogs and can suck down your battery very quickly. Since the Geolocation API gives you very little control over how it works you cannot build much efficiency into your apps.

Challenge 5. Most smartphones and tablets use a consumer-grade GPS chip and antenna, and that limits the potential accuracy and precision. On average, the best possible accuracy is typically between 3 and 10 meters, or 10 – 33 feet. This is based on my own extensive experience building GPS-based mobile apps and working with many customers who are also using mobile apps. Under the most ideal scenario, the device will be kept stationary in one location until the desired accuracy number is achieved.

What’s it good for? Okay, you may be wondering what is browser-based geolocation good for? It’s perfect for very simple use cases that don’t require much accuracy. If you need to map manhole covers, or parking spaces, or any other physical things that are close together you’ll need a GPS device with professional-level capabilities.

Here are a few generic examples that I think are ideal for HTML5 Geolocation:

  • Simply getting your approximate location in latitude/longitude and converting it to a physical address.
  • Finding an approximate starting location for searching nearby places or things in a database or for getting one-time driving directions.
  • Determining which zip code, city or State you are in to enable specific features in the app.
  • Getting the approximate location of a decently sized geological feature such as a park, a building, a pond, a parking lot, a driveway, a group of trees, an intersection, etc.

What’s the best way to get a single location? The best way to get a single location is to not use getCurrentPosition() but to use watchPosition() and analyze the data for a minimum set of acceptable values.

Why? Because getCurrentPosition() simply forces the browser to barf up the best available raw, location snapshot right now. It literally forces a location out of the phone. Accuracy values can be wildly inaccurate, especially if the GPS hasn’t warmed up, or if you aren’t near a WiFi with your WiFi turned on, or if your cellular provider can’t get a good triangulation fix on your phone, or it returns a cached value from a different location altogether. There are many, many “what ifs?”

So, I recommend using watchPosition() and firing it off and letting it run until the return values meet some minimum criteria that you set. You need to know that while this is happening the location values returned may cover a fairly wide geographic area…remember our best accuracy values are 10 – 30 meters. Here’s a real-world example of Geolocation API location values that I captured over a 5 minute period while standing stationary in front of a building.

5 minute snapshot

What steps do you recommend? Here are five basic steps to help guide you towards one approach for getting the best location. This is a very simplistic approach and may not be appropriate for all use cases, but I think it’s adequate to demonstrate the basic concepts for working towards determining the best possible location.

Step 1. Immediately reject any values that have accuracy above a certain threshold that you determine. For example, let’s say we’ll reject any values with an accuracy reading greater than 50 meters.

Step 2. Create three arrays, one for accuracy, latitude and longitude. If the accuracy is below your threshold, or in this case < 50 meters, then push the values to the appropriate arrays. You will also need to set a maximize size for the array and create a simple algorithm for adding new values and removing old ones.

The array length could be 10, 20 or even 100 or more entries. Just keep in mind that the longer the array, the longer it will take to fill up and the longer the user will have to wait for the end result.

Step 3. Start calculating the average values for accuracy, latitude and longitude.

Step 4. Start calculating the standard deviation for accuracy, latitude and longitude.

Step 5. If your arrays fill up to the desired length and the average accuracy meets your best-possible criteria, and the standard deviation is acceptable then you can take the average latitude, longitude values as your approximate location.

For an example of this simple algorithm at work visit the following URL on your phone and step outside to get a clear view of the sky: https://esri.github.io/html5-geolocation-tool-js/field-location-template.html. [Updated link: Oct. 27, 2015]

OSCON 2013 – Presentation on Android SDK Geolocation

If you are headed to OSCON, swing by my session on Mastering Android Geolocation. It’s a deep dive into the Android SDKs android.location package. If you’ve ever wanted to learn about the fundamental’s of the SDKs Geolocation capabilities then this is a must attend session. It will also give you a strong foundation to understand the underlying capabilities of the new Google Play Services SDK that includes Fused Location, Activity Recognition, and Geofencing APIs.

The presentation includes digging into the capabilities of my open source GPS Testing tool that lets you easily test different aspects of the Geolocation capabilities.

Here’s the details and I hope to see you there:

 Location, Location, Location: Mastering Android Geolocation
07/25/2013  5:00pm –  5:40pm PDT (40 minutes)
Room: Portland 251 (capacity: 200)
https://www.oscon.com/oscon2013/public/schedule/detail/28713

How accurate is Android GPS? Part 2 – Consuming real-time locations

In part 1, we looked at the six types of location data available through the Android native SDK and talked about how to work with cached location data. As others have also discovered, there is a ton of information to say on this topic and way more than you could pile into a single blog post. So, this post focuses on working with real-time locations. Once you activate the location listeners they will start sending you information and knowing how to handle that data is what this post is about.

The most important take away I hope to leave you with is take time to understand your accuracy requirements and your user’s basic geographic behavior patterns. I’ve tried to liberally sprinkle example use cases to help illustrate some of the concepts.

Time and distance properties. The first thing you’ll notice when you start building location aware Android apps is you can set time and distance properties that affect how often the device will request a location update. This is accomplished using the overloaded LocationManager.requestLocationUpdates() method. These properties adjust how aggressively the device will request location updates by minimum time elapsed and minimum distance traveled. How you adjust these settings significantly affects the battery life. The equation for battery life is straightforward and simple: the shorter the minimum time interval the faster the battery will be drained.

In the code snippet below, the time and distance properties are both set to zero, which is the most aggressive setting.  You’ll get a location update if any change in location is detected at any time. This setting can result in your app accessing the GPS provider as often as 50 – 60 times or more per minute.

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,0,listener);

I’ve experimented with this setting by leaving it running, and it drained a fully charge Samsung Galaxy SIII in less than 3 hours. The phone also got very hot to the touch. It takes considerable power to run the current generation of GPS chips. Even using network location requires that the phone use its radio to make an internet request to the location processing server. So, carefully evaluate your use cases and be conservative about the time and distance properties that are needed.

Except for high performance situations, it will be rare when you need location access every second at a zero distance delta. You can also adjust these properties if your app detects a change in the usage pattern. For example, if the user slows down for a period of time then you might restart the listener using a longer time interval. The listener does not have to stay static and be set only once. Hopefully this is your “ah-hah!” moment. In fact I encourage you to make dynamic adjustments to the intervals as your usage scenarios change. The GPSTester tool allows you to easily experiment with different configurations.

Here are some use case examples:

  • Real-time tracking app for use when walking, running, biking or driving.  As expected, this app will require the most aggressive settings for time and distance.
  • Delivery vehicle tracking app. The delivery vehicle will be starting and stopping all day long. Minimal ability to plug phone into charger. This app should dynamically adjust its time and distance settings.
  • App only needs a one-time snapshot location to find nearby coffee shops. This requires that the app run until a minimum accuracy value is received and then it can turn off the location listeners. Other examples are placing a geotagging a photo, tweet or Facebook posting. You could also try your luck using the overloaded Location.requestSingleUpdate() method.

And, here’s a very basic set of technical requirements for dynamically changing requestLocationUpdates() settings:

  • Start application using minTime = 0 and minDistance = 0. Use an aggressive setting to get accurate location as quickly as possible.
  • Once accuracy is less than 50 meters and speed less than 45 mph set minTime = 5000 and minDistance = 25.
  • Speed equals 0 for greater than 1 hour. Shut off location listeners and notify user.
  • Battery gets low. Shut off location listeners and notify user.

Time to 1st real-time location. It can take up to several minutes to get the first GPS or Network location result. Use effective notifications to let your users know there will be a delay in getting this information. For example, many Android mapping apps use an accuracy circle around the current location indicator to give a sense of accuracy level. 

As you can see in the GPS Provider screenshot taken from the GPS Tester app, using a warm GPS it took ~9 secs to get the first GPS result from the device and then 1450ms to get the next update for an accuracy of 3.0 meters.  By warm I’m referring to a device where the GPS and Network location have been accessed recently.

How long it takes to start getting accurate results depends on many different factors of which you, as the developer, will have very little control over but you’ll need to plan for accordingly. As discussed in Part 1, many developers lean heavily on the cached locations to try and work around these types of delays. Yet, depending on your use cases and the end user personas these results can either be very useful or fantastically inaccurate.

According to Google user interface responsiveness guidelines 100 to 200 milliseconds is where users will start to perceive slowness and we are talking about 9 whole seconds here that the user had to wait. Of course 9 seconds is “fast” for a GPS acquisition. And, you can typically expect much longer time frames, especially on a cold device, and until the accuracy drops down to within a few hundred meters or less.

I’ve seen differences in acquisition times between two phones of the same exact model and same settings even though they were placed right next to each other. Other factors that affect acquisition times can be as simple as where you placed the phone in the car such as down by the gear shift between the seats or up on the dashboard. Or the user could be standing just inside a restaurant under a metal awning because it’s raining outside.  The list goes on and on. Cement, bricks, metal, car bodies, heavy foliage and buildings are some other examples of things that can interfere with GPS signal accuracy and the time to first acquisition. Like the Boy Scouts say, “Be Prepared” and be kind to your users by using user interface notifications to let them know of location acquisition delays.

Streaming real-time locations. Once the device starts providing real-time locations, my suggestion is to check the accuracy of each result and consider rejecting those greater than a certain amount that are based on your requirements. The longer the location provider runs, and if the device has an unobstructed views of the sky and good cellular connection, then typically the accuracy will improve up to a certain point and then level off, and then it will fluctuate.  Here’s a pseudo-code snippet showing how to check the accuracy of each GPS location result:

public void onLocationChanged(Location location) {
     if(location.getAccuracy() < 100.0 && location.getSpeed() < 6.95){
          //Do something
     }
     else{
          //Continue listening for a more accurate location
     }
}

Here are some rough examples of accuracy thresholds I used for a project last year. Your requirements may vary as to how these different thresholds will affect the behavior of your application; these were examples that required geocoding that converted the current location to an approximate address. Depending on the result the application gave different feedback to the user:

  • Rooftop  <= 10 meters (desired result)
  • Street >10 meters and <= 100 meters (let user know it’s close but not perfect. Good enough?)
  • Neighborhood > 100 meters and  <= 500 meters (give visual feedback that accuracy is low)
  • City > 500 meters and <= 2000 meters (ask user to verify city name from a list)
  • County > 2000 meters (prompt for manual location input)

Take into account your own unique use cases. You might completely reject any accuracy value greater than 100 meters (328 ft) if your app simply helps people find open parking lots at NFL games. You could have an app that returns a list of Dentist offices within a 5 mile (8000m) radius. Or a weather app could only need to know approximately what city you are in. These are just ideas to help get you thinking.

Not all real-time location data is alike.  Continuing on the theme of consuming real-time location, let’s dig into a few more examples of why it should be looked at closely. Here’s one thing that I keep forgetting even though I’ve blogged about it: you can get null location values and if not properly handled they will crash the app. That’s an easy one to forget until your users start to report random application crashes.

You can also look for what I’ll call spurious results. These are results that are way outside what you might consider a running average. Check the distance between the last location result and the current location result using the Location.distanceBetween() method. If the distance and speed required to cover that distance is significantly greater than the running average, then you can reject that result.

I also want to mention that simply holding the device in one location while standing outdoors can result in the latitude/longitude wandering over a reasonable distance. Even if you set the phone on a rock the results can wander. Just keep this in mind if you have accuracy requirements. Just because the user is standing still outdoors doesn’t mean that the indicated location will stay exactly the same. It could wander over a 10 to 50 meter radius or more.

I have occasionally seen wild location fluctuations that were enough to make a mapping application nauseatingly jump back and forth between different center points. Unfortunately, when it happened I didn’t have the device on a debugger, but I suspect it had to do with the phone detecting various WiFi end points when I stopped at stoplights along my route. It’s possible the phone tried to resolve those WiFi locations using the Google Network Location service and that there was some lag time in processing those results.

Are Android, off-the-shelf, retail smartphones as accurate as something like a Trimble Pro Series Receiver? No way, not all, definitely not! If you have high accuracy, field-usage requirements calling for sub-meter results you should not be using a typical retail Android device. For example, if you are standing in an intersection with four manhole covers that are two feet apart and form a circle, you could not accurately map which manhole cover is the right one that you need to be working in if you are using an off-the-shelf Android. Using my own phone as an example, on a good day my Samsung Galaxy SIII occasionally has down to 3 meters GPS accuracy for short periods of time and then it can start wandering.

Comparing Network and GPS locations and using Criteria. Yes, you should definitely compare the results between these two. The more data you have the better. There’s not a whole lot to say about this other than look at timestamps, accuracy and distance traveled factors. In my experience, just something to keep in mind is the network locations happen much slower than the GPS. I expected this because of the lag time involved with the phone sending information to the remote location service and then waiting for a result to come back. You can read more about how location services work in this article.

The use of android.location.Criteria can also be used to control which listener(s) are used. You can experiment with Criteria using the GPSTester tool. The only minor caveat is it doesn’t include all possible criteria in the current version (v1.2.1.1). My general recommendation is to skip Criteria and hard code in the validation rules. I don’t currently subscribe to the idea that the Criteria will know what’s best for my end users. Please comment below if you feel otherwise, but in my own experience I haven’t come across a use case where Criteria gave what I thought was the right answer. In one use case, the Criteria was set to not incur costs, yet the value returned was to use the network provider even though GPS was available. Using the network location service would have incurred bandwidth costs.

What to do when app is minimized? A common workflow is for a user to minimize the app and then either forget about it or come back to it later. I’ve included this because it’s common for the user to get a phone call or a text message that results in the app being minimized. In most of the use cases I work with, the requirements call for both the GPS and Network Location services to be shut off when the app is minimized. It’s just way too easy for the user to forget about the app and then it could kill the battery in a very short time.

There is the option of using a passive listener. I rarely use these because it assumes some other unknown application will spin up the GPS or Network Location providers.  Your use cases will help you decide whether or not implementing a passive listener is a good idea. If your target audience is a 20-something student who is constantly using location based social media such as Facebook every hour and eighteen hours a day then there’s a good chance the passive listener will return recent and mostly accurate results. However, if you are building a commercial-grade application on a work-related phone then a passive listener is significantly less likely, or even highly unlikely, to speed up the applications ability to get a fast fix on startup.

Use Intents when implementing a passive listener, this involves adding directives in the AndroidManifest.xml as well as writing some code. A great example of how to do this can be found here, so I’m not going to reinvent the wheel. Just don’t forget to add the receiver tag to your manifest:

 <receiver android:name=".receivers.PassiveLocationChangeReceiver"/>

When the app restarts you can use information from the passive listener and consider whether or not it meets your accuracy criteria. You can also use the passive listener to run background processes within your app while it is minimized. You’ll use the Location timestamp once the app is opened again. If the timestamp is very recent, such as less than one hour old, then you could consider using the passive location immediately. Otherwise, you’ll be back to waiting for a real-time location result. For this approach consider comparing Location.getRealtimeNanos() to SystemClock.elapsedRealtimeNanos(). If your target audience are business travelers, then for example you might want to reject cached results that are greater than 8 hours old because chances are the user has hopped on a plane.

Privacy, data storage and data consumption. Yeh, it’s a bummer I even had to bring this up. I’m not a lawyer, but every lawyer I’ve worked with on these types of production applications strongly reminds me to have a Privacy Policy and to be transparent about how the data is stored and how the data is used. Don’t try to do this on your own, hire a lawyer or the equivalent of a lawyer in your country, as the case law is constantly changing and can vary from State-to-State and Country-to-Country.

And, that’s the wrap-up for Part 2. Stay tuned for additional posts on this series that cover using the GPSTester tool and how to interpret the results.

References

Google Developer docs – Location Strategies

Android blog – Deep dive into location

GPS Testing Tool (open source)

HTML5 Geolocation API – How accurate is it, really?