Android Location Providers (gps, network, passive)
Introduction #
There are 3 network providers in Android (ranging from 1.5 to 2.2). They are:
gps –> (GPS, AGPS) #
Name of the GPS location provider. This provider determines location using satellites. Depending on conditions, this provider may take a while to return a location fix. Requires the permission android.permission.ACCESS_FINE_LOCATION.
network –> (AGPS, CellID, WiFi MACID) #
Name of the network location provider. This provider determines location based on availability of cell tower and WiFi access points. Results are retrieved by means of a network lookup. Requires either of the permissions android.permission.ACCESS_COARSE_LOCATION or android.permission.ACCESS_FINE_LOCATION.
passive –> (CellID, WiFi MACID) #
A special location provider for receiving locations without actually initiating a location fix. This provider can be used to passively receive location updates when other applications or services request them without actually requesting the locations yourself. This provider will return locations generated by other providers. Requires the permission android.permission.ACCESS_FINE_LOCATION, although if the GPS is not enabled this provider might only return coarse fixes.
This is what Android calls these location providers, however, the underlying technologies to make this stuff work is mapped to the specific set of hardware and telco provided capabilities (network service).
Here is a table that maps/lists the underlying technologies in a different way:
Accuracy | Power Usage | Technology |
20ft | High |
Autonomous GPS, Provider: gps
|
200ft | Medium - Low |
Assisted GPS (AGPS), Provider: network
|
5300ft / 1mile | Low |
CellID lookup/WiFi MACID lookup, Provider: network or passive
|
Android layers these underlying techniques and technologies into the 3 network providers listed above. There is no good way know exactly what Android will use, since all phones are different. Eg, on VZW network, the LG Ally does NOT have AGPS! The Droid 2 has all providers (AGPS, GPS, CellID, etc). On ATT network, almost all phones tend to have AGPS enabled by default, etc. Varies by network, by coverage area, and by country, and by device. Also, on VZW, the passive provider ends up using Verizon Location Services, which are very inaccurate (less accurate than 1 mile).
How to think about it #
The most important thing to keep in mind is to provide some level of service, even in a situation where a user has the worst device, and the worst network service. It’s great that you can get low battery consumption and 20ft accuracy, when conditions are great. However, you can’t plan on that, and you can’t rely on that. Not in 2010 anyway :).
The following is a screenshot of RainOrShine, showing the “network” provider accuracy. Our dynamic movement algorithm takes care of switching back and forth between different providers during a single session, and also it takes care of accuracy’s changing all the time, in a single session. In fact, network providers can be switched from fine to coarse grain and back depending on the task being collected.
What it looks like on a real device #
Here is a screenshot from the Droid 2, that shows the location provider settings:
-
When only “use wireless networks” is checked, then CellID/MACID lookups are used first, and the “network” provider uses this, and gets about 200ft-1mile accuracy.
-
When only “enable assisted GPS” is checked, then AGPS is used first, and the “gps” provider uses this, and gets about 10ft-20ft accuracy.
-
When only “use GPS satellites” is checked, then, GPS is used, and the “gps’ provider uses this, and gets less than 10ft accuracy.
In all our code (for ScreamingToaster products), we first try and use the “network” provider, because it will always work on anyone’s device, and the location fix will be acquired immediately. And the accuracy is quite good – 200ft or so. You can also try “passive” first. Just keep in mind that not all providers are available on all devices, carriers, and user configurations.
If a user disables “use wireless networks” in their settings, then “network” or “passive” is not available. Then “gps” is the only option (assuming it is turned on).
Code samples #
Here is the code that you have to run in order to create a GPS enabled app, using an Android Activity or Service:
/** this criteria will settle for less accuracy, high power, and cost */
public static Criteria createCoarseCriteria() {
Criteria c = new Criteria();
c.setAccuracy(Criteria.ACCURACY_COARSE);
c.setAltitudeRequired(false);
c.setBearingRequired(false);
c.setSpeedRequired(false);
c.setCostAllowed(true);
c.setPowerRequirement(Criteria.POWER_HIGH);
return c;
}
/** this criteria needs high accuracy, high power, and cost */
public static Criteria createFineCriteria() {
Criteria c = new Criteria();
c.setAccuracy(Criteria.ACCURACY_FINE);
c.setAltitudeRequired(false);
c.setBearingRequired(false);
c.setSpeedRequired(false);
c.setCostAllowed(true);
c.setPowerRequirement(Criteria.POWER_HIGH);
return c;
}
/**
make sure to call this in the main thread, not a background thread
make sure to call locMgr.removeUpdates(...) when you are done
*/
public static void init(){
LocationManager locMgr =
LocationUtils.getLocationManager(ctx.getMyContext());
// get low accuracy provider
LocationProvider low=
locMgr.getProvider(locMgr.getBestProvider(createCoarseCriteria()));
// get high accuracy provider
LocationProvider high=
locMgr.getProvider(locMgr.getBestProvider(createFineCriteria()));
// using low accuracy provider... to listen for updates
locMgr.requestLocationUpdates(low.getName(), 0, 0f,
new LocationListener() {
public void onLocationChanged(Location location) {
// do something here to save this new location
}
public void onStatusChanged(String s, int i, Bundle bundle) {
}
public void onProviderEnabled(String s) {
// try switching to a different provider
}
public void onProviderDisabled(String s) {
// try switching to a different provider
}
});
// using high accuracy provider... to listen for updates
locMgr.requestLocationUpdates(high.getName(), 0, 0f,
new LocationListener() {
public void onLocationChanged(Location location) {
// do something here to save this new location
}
public void onStatusChanged(String s, int i, Bundle bundle) {
}
public void onProviderEnabled(String s) {
// try switching to a different provider
}
public void onProviderDisabled(String s) {
// try switching to a different provider
}
});
}
Implementation notes #
-
When attaching a location listener to a location provider (regardless of the exact kind of provider), it is important to execute this listener code in the main thread of your activity or service. If you run this in any background thread (like using an executor) then this will not work. The listener code itself has to be on the main thread. You can kick of a task in an executor in the listener, but the listener itself must run in the main thread of the app.
-
Some devices will require you to detach the listener and then reattach it periodically. This is not a bad idea, since it eliminates the possibility of the listener going stale.
-
You can switch providers at any time, and switch out a fine provider with a coarse one to save battery life, for example. There is really no limit to how often you can switch out providers. You can also do this when you discover that a provider is unavailable, via a call to the registered location listener.
-
Finally, the parameters you pass to the location provider, when you attach your location listener are totally optional. The device you are running on will decide whether to respect those parameters or not. So it’s best never to rely on them. Also, different devices behave differently with reporting location movements. Eg, the Droid X and Droid 2 are very zippy about providing location updates, they will do it every second and provide you with a very high level of accuracy. The Samsung Galaxy S is less zippy with the location updates. The HTC Incredible is better than the Galaxy S, but not as zippy with the frequent updates as the Droid X and Droid 2. Finally, the LG Ally is one of the worst with location updates, providing very infrequent updates, and very poor accuracy (even on autonomous GPS). So don’t make any assumptions about the accuracy and frequency of updates – you have to test it on real devices on real networks in real life situations.
Summary #
The best way to handle GPS is to use the “network” or “passive” provider first, and then fallback on “gps”, and depending on the task, switch between providers. This covers all cases, and provides a lowest common denominator service (in the worst case) and great service (in the best case).
👀 Watch Rust 🦀 live coding videos on our YouTube Channel.
📦 Install our useful Rust command line apps usingcargo install r3bl-cmdr
(they are from the r3bl-open-core project):
- 🐱
giti
: run interactive git commands with confidence in your terminal- 🦜
edi
: edit Markdown with style in your terminalgiti in action
edi in action