Geolocation tips, quirks, and possible bugs (flash.sensors.Geolocation)
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.
Geolocation object
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.
GeolocationEvent object
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.





Hi there, we have been using iPad 2′s, and some android devices in our experiments, and we have found heading to work correctly. These devices do have compasses listed in their device specs, so I think your correct in assuming that it’s limited to device.
Cheers
You are correct. I received an email from engineering this morning with clarification and I just verified that heading is correct on iOS and simply not reported by my Android devices.
Thanks!
Greg
Thanks Greg.
If you could keep us updated on the coarse location data not being accessible when the GPS is enabled but not receiving issue that would be great. There are so many times during the day when your average user can’t get a GPS lock and for it to seamlessly switch to WiFi location data and maybe also dispatch an event when this happens would be perfect.
Cheers, Mike.
Great and thorough writeup.
IMO you skipped setRequestedUpdateInterval() a little too lightly though. I would really like some kind of discussion of what interval is optimal for different use cases. I’ve had a hard time finding anything on that subject.
Hi Greg,
I was trying to run a small app to test the GeoLoaction and the GeoLocationEvent classes from a HTC Android phone but the app just seems to hang after some time. When it is made to run on a device it displays the
‘Access to GPS Allowed.. and
‘Finding Location texts’
but after that nothing happens. Below is the code that I am using. I have also set the android permissions.
———————————–
protected var g:Geolocation = new Geolocation();
protected function view1_viewActivateHandler(event:ViewNavigatorEvent):void
{
if (Geolocation.isSupported)
{
// Note: un-comment the muted check for android OS, however there is currently a bug on iOS where it will always return
// muted and not update the location if left uncommented.
if (g.muted)
{
log.text = “Access to GPS has been muted”;
return;
}else{
log.text = “Access to GPS allowed…”;
}
log.appendText(“Finding Location…”);
g.addEventListener(StatusEvent.STATUS, onStatus);
g.addEventListener(GeolocationEvent.UPDATE, onUpdate);
}
else
{
currentState = “unsupported”;
lblSupport.text = “Geolocation is not supported on this device.”;
}
}
private function onStatus(event:StatusEvent):void{
log.appendText(“current status: ” + event.level);
}
protected function onUpdate(event:GeolocationEvent):void
{
trace(“Update event called”);
g.removeEventListener(GeolocationEvent.UPDATE, onUpdate);
log.text = “latitude = ” + event.latitude +
“\nlongitude = ” + event.longitude +
“\naltitude = ” + event.altitude +
“\nverticalAccuracy = ” + event.verticalAccuracy +
“\nhorizontalAccuracy = ” + event.horizontalAccuracy +
“\nspeed = ” + event.speed +
“\nheading = ” + event.heading +
“\ntimestamp = ” + event.timestamp;
// auto-scroll the text area to the latest text
StyleableTextField(log.textDisplay).scrollV = StyleableTextField(log.textDisplay).scrollV+1;
}
———————————————–
But just clueless as where I may be going wrong. Any heads up on this would be of great help. Only 1 thing, is that I was trying to run this from India, is there a location issue?
Thanks and Regards,
Paromita
Am having a hard time implementing “zoom to my location” functionality on iOS with Flash Builder 4.5. I tried a combination of keys in the app.xml file, I have an iPhone 4, and the gps is functioning and tested with google maps and camera.
If I set GPS and location-services keys as required devices, the app wont even install on my iPhone. If I dont, it does install but the gps doesnt zoom the map to the devices location. This is working on android.
<![CDATA[
UIDeviceFamily
1
2
telephony
YES
location-services
YES
gps
YES
]]>
high
private function init():void
{
geolocation_creationCompleteHandler(‘onStart’);
}
public var geolocationType:String;
protected function geolocation_creationCompleteHandler(type:String):void
{
if(type == ‘onStart’)
{
geolocationType = type;
}
else
{
geolocationType = ‘fButton’;
}
if( Geolocation.isSupported )
{
g = new Geolocation();
locateMeBut.enabled = true;
g.setRequestedUpdateInterval(1000);
if( g.muted )
{
locateMeBut.enabled = false;
myMap.addEventListener(MapEvent.LOAD, goToInitialExtent);
return;
}
g.addEventListener(GeolocationEvent.UPDATE,geoLocation_UpdateHandler, false,0,true);
}
else
{
//don’t do anything, gps is not supported or not on
}
}
Have you had any luck with getting geolocation updates to be received while the screen is off on iOS? I am having a hard time gettin my app to run ANY code once the screen goes to sleep.
Me too.
iOS suspends the app completely. Nothing can execute. You’ll have to write some native code to handle this I believe (see http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html). It might be possible to do something with a native extension (new in AIR 3.0), but I’m not sure yet.
If iOS suspends the app even after declaring background services I don’t see how writing a native extension would help, but I’m willing to attempt testing it out.
I’m having troubles getting an accurate event.speed value on my ios device. Is this a known bug? It’s off by approximately 15km/h while the horizontal accuracy is around 10m.