I’ve been working on a couple of apps recently that use the Geolocation APIs. I’ve discovered a few tips and quirks that I felt were worthy of sharing.
There are two classes that you need in order to implement location in your app – Geolocation and GeolocationEvent. When you create a Geolocation object, it turns on the GPS sensors on the device and provides you with a couple of important properties: isSupported and muted. The isSupported property is used to determine if the device has location support. If you run this on your desktop computer or on a Barnes and Noble Nook, this property will be false because no location capability exists on the device. The muted property is slightly different. This property indicates whether the user has turned off location support for the device or denied permission for the app itself.
iOS muted BUG: There is a known bug with the muted property on iOS devices with the SDK that ships with Flash Builder 4.5.1. On iOS, the Geolocation muted property is always true, so it should be ignored in the current version. This is already fixed in the next release.
There is one method to be aware of on Geolocation — setRequestedUpdateInterval() — it’s used to request a more (or less) frequent location update event. In other words, you are telling the Geolocation object to check for location changes more (or less) often. However, it’s important to note that the OS may choose a different interval to conserve battery power. The name of the method should actually be setRequestedUpdateIntervalPLEASE() because you are only requesting the interval, not commanding it.
After adding an event listener to the Geolocation object to receive location change events, you will start receiving location events in your event listener. The event contains the latitude, longitude, accuracy, speed, altitude, and heading. Here’s some important facts about location events:
- The first location event received is usually NOT the current location. It is often the “last known location” or the cached location. Your app will get this first event almost immediately, but remember, it might be an out of date location along with the associated out of date accuracy. For example, I created a simple test app that logged my location. I ran it from home and let it run for a few seconds until I was getting good accuracy of about 10 meters. I shutdown the app and drove 10 miles away and ran it again. I immediately received a location event that was the location of my house with an accuracy of 10m! If you don’t know to expect this, your app could make a bad conclusion about the location. Also, the timestamp is no help here (contrary to popular belief). I talked to the Flex engineering team to confirm this. The documentation will be updated shortly. In my opinion, it’s a bug until documented. Once documented, it’s actually a cool feature. One of the apps I’m working on has a “I am here” button that captures the current location and sends it to the server. In my code, I ignore the first event. The second location event is a real attempt to report my current location. I’ll share the full code of this in the next blog post. UPDATE: Docs will be fixed soon.
- verticalAccuracy is always wrong in my testing (Android) — There are two properties related to location accuracy – horizontalAccuracy and verticalAccuracy. The horizontalAccuracy is exactly what you think it is. However, in all of my testing across multiple devices, the verticalAccuracy is always identical to the horizontalAccuracy, which is practically impossible. I won’t go into details because it would quadruple the size of this article, but some simple web searches will confirm what I’m saying. Vertical accuracy is usually 2 to 3 times less accurate than horizontal accuracy of any GPS device (unless it uses WAAS or another augmentation system, which no Android or iOS devices supports yet). Therefore, verticalAccuracy should be ignored because it’s simply not correct. I’ve yet to figure out if this is a bug with the flash.sensors.Geolocation class or a limitation of the underlying OS. I’ve looked through the Android SDK documentation and can’t find a vertical accuracy property anywhere. If anyone can clarify, please add a comment below. If it is indeed not being reported by the underlying OS, I think it is a bug in flash.sensors.Geolocation because the expected behavior is to report either a NaN or some other obvious invalid value rather than a value that is wrong and misleading. UPDATE: On Android, the underlying OS returns “radialAccuracy” and both horizontalAccuracy and verticalAccuracy are being set to that single value. This is a bug that will be addressed. Android does not return a vertical accuracy so the value should be set to either NaN or a negative number. On iOS, the vertical accuracy is set correctly to the vertical accuracy reported by the underlying OS.
- heading is always NaN in my testing (Android) — I’ve yet to test on a device where I get a value for heading. You could write some code to calculate it based on the location history/track, but the property itself is always NaN. I highly suspect that this is a device limitation, not a bug. If anyone has seen a value for heading, let me know in the comments. UPDATE: On iOS, I get heading information.
- Two different types of determining location and a possible bug — Most modern mobile devices have two different means of determining location – WiFi/Cell-ID (coarse location) and GPS (fine location). GPS is much more accurate. I have discovered what I think is a bug with how the two types of locations are used (I’m working with engineering to confirm) — If the GPS is enabled on your device, you will not receive any WiFi/Cell-ID-based location events, so if you are out of range of GPS satellites (e.g. in the basement), you will get no location events at all (other than the initial last-known-location as mentioned above). The expected behavior (IMO) is to receive WiFi/Cell-ID-based location events until the GPS signal is acquired. You can see this behavior in the Google Maps app. When you first run Google Maps, it will show your location almost instantly but it will have a wide circle of accuracy. This is the WiFi/Cell-ID-based location. Once the GPS signal is locked in, the circle shrinks to only a few meters. However, I am unable to recreate this functionality using the flash.sensors.Geolocation class. Oddly, if you disable the GPS on your device, you will then receive WiFi-Cell-ID-based location events as expected. This feels like a bug to me and I suspect that the code uses either WiFi/Cell-ID or GPS and is not sophisticated enough to use both as I just described.
- Location permissions – On Android, there are two relevant permissions related to location – android.permission.ACCESS_FINE_LOCATION and android.permission.ACCESS_COARSE_LOCATION. I have confirmed that setting the android.permission.ACCESS_FINE_LOCATION includes the COARSE permission. In other words, you do not have to specify both permissions because FINE includes COARSE. This is confirmed at http://developer.android.com/guide/topics/location/obtaining-user-location.html.
Hopefully this clears up some confusion on Geolocation. It’s hard to test this stuff, so if you find any evidence of my conclusions being wrong, please don’t hesitate to let me know in the comments.
Writing location-based apps is incredibly fun and really creates some interesting app opportunities. In my next post, I’ll share some code for a typical “Here I am” app that handles the last-known-location event and implements a simple timeout.