Location
Android's location stack has two APIs, three signal sources and four permission states. The history of those permissions is the clearest example of the platform learning to ask better questions.
Location is the clearest example in Android of a capability that became a negotiation. The hardware did not change much. What changed, release after release, is how precisely the user can say yes — and how hard the platform makes it to mean yes, always, everywhere.
TL;DR#
- There are two APIs: the platform's
LocationManagerand GMS's Fused Location Provider. The fused provider is usually better, but it is a Google Play services dependency, not part of AOSP. - Underneath, three sources are combined: GNSS (satellites), Wi-Fi (access-point databases) and cellular (cell-ID databases).
- The permission model evolved from install-time to runtime, then split foreground from background, then added approximate as a user choice (API 31).
- Since API 30 background location is a separate, deliberate grant; since API 34 selected-photos-style partial grants exist for media, and the location equivalents are one-time and approximate.
- The system shows an indicator when location is in use, and a global toggle can disable it.
Mental model#
Think of asking a stranger for directions.
Early Android was: you hand them a permanent badge that says "may ask anyone, anywhere, forever". It made sense in 2008, when phones were new and apps were few.
API 23 introduced: "ask me each time, and I can take the badge back."
API 30 introduced: "you may ask me while I am talking to you, but if you want to follow me home you must ask separately, and I will think about it."
API 31 introduced: "you may know roughly where I am, or exactly — I choose which."
Where the analogy breaks#
Location is not one capability. It is at least four: the current position, the history of positions, the fact that a position changed (a geofence), and the identity of the place (a saved home address). Android's permissions are a single dial, so the platform uses AppOps and API-level checks to make finer distinctions than the permission alone would suggest.
The big picture#
Text description of this diagram
A timeline of location permission changes across four lanes: how the user grants, background access, precision, and the system UI signal. At API 1 location was declared at install and could not be revoked individually. API 23 introduced the runtime permission dialog. API 26 limited background update frequency. API 29 added ACCESS_BACKGROUND_LOCATION as a separate dangerous permission. API 30 required background location to be requested separately after foreground access and added one-time grants. API 31 let the user choose approximate instead of precise. API 37 adds a system location button that grants temporary access for one request.
The shape of that timeline is the whole argument: every release narrows the default and adds a way for the user to say something more specific.
Deep dive#
The two APIs, and why both exist#
LocationManager is part of the platform. It gives you providers, request criteria and raw updates.
FusedLocationProviderClient is part of Google Play services, and it combines the same signals with
Google's models and delivers a single, smoothed stream.
The split is a deliberate consequence of the AOSP/GMS boundary. AOSP must ship a working location stack for devices without Google services; GMS can add value on top. In practice:
- The fused provider generally gives better battery behaviour, because it can use low-power geofencing and smarter scheduling.
LocationManagergives you direct access to a specific provider, which matters when you need raw GNSS or when you cannot depend on Play services.- The permission requirements are the same either way, because the fused provider ultimately calls into the platform's location service.1
The three signals#
GNSS is satellite positioning: GPS, GLONASS, Galileo, BeiDou. It is accurate outdoors and terrible indoors. The GNSS HAL receives raw measurements and, on modern devices, can do the position fix on the device rather than in a vendor library.
Wi-Fi positioning works by observing access points and looking up their known locations in a database. It works indoors and in cities, and it is fast, but it depends on a database that has to be maintained. This is why Wi-Fi scanning is treated as a location signal.
Cell positioning uses the identity of the serving tower and its neighbours. It is coarse but almost always available, including indoors, and it requires no extra radio.
The fused provider's job is to weigh these and produce one answer with an accuracy estimate. When you request high accuracy you effectively say "use GNSS even though it costs power"; when you request low power you say "prefer Wi-Fi and cell".
Precision: approximate vs precise#
Before API 31, an app asked for ACCESS_FINE_LOCATION and got the best the device could do. If the
user did not want that, the only option was to refuse, which usually meant the app did not work.
API 31 added a third answer: approximate. The user grants ACCESS_COARSE_LOCATION only, and the
platform coarsens results delivered to an app that requested fine location. The app must therefore
treat accuracy as a property of each result rather than an assumption.2
The practical consequence is a bug class: apps that assume getAccuracy() is a few metres and draw a
precise pin at a coarsened position. The correct handling is to display the accuracy radius, which is
also better UX in the precise case.
The background story#
Foreground location is easy to justify: the user is looking at your app and asked for directions. Background location is different, because the user cannot see what the app is doing.
The progression:
- API 23: runtime permission, but one grant covered both.
- API 26: background apps receive updates less frequently. The permission is the same; delivery changes.
- API 29:
ACCESS_BACKGROUND_LOCATIONbecomes a separate dangerous permission. - API 30: the app must request foreground access first, then background, in a separate request; the system may send the user to Settings. One-time grants arrive for location, camera and microphone.
The reason for the two-step request is to make the decision legible. A single dialog that says "allow this app to access location all the time" is easy to tap through. A second, separate request after the user has seen the app work is a decision rather than a reflex.3
Geofences and the background trap#
A geofence is a location request expressed as "tell me when the user crosses this boundary". It is attractive because it sounds cheap: the app is not polling. But the platform still has to know where the user is to detect the crossing, and that has the same power and privacy cost as any background location.
This is why geofences require background location and why they are subject to the same background execution limits as other work. A geofence that fires reliably is a hard engineering problem, and the platform deliberately does not promise more than it can deliver.
Indicators, toggles and AppOps#
API 31 added microphone and camera indicators, and API 30 added global toggles for both. Location has an equivalent surface: an indicator when an app is using location, and a master switch.
Underneath the permission, AppOps records the actual operation. That is how the system can
distinguish "this app has the permission" from "this app used it 200 times in the last hour", and it
is how the privacy dashboard can show what happened.
The location button#
API 37 adds USE_LOCATION_BUTTON: a system-drawn button an app can place to grant temporary location
access for a single request, without a permission dialog. The pattern is borrowed from the photo
picker — let the user perform the action rather than pre-authorise a capability.4
It is the logical endpoint of the timeline: instead of asking "may this app know where I am", the platform asks "may I share this location right now".
How it evolved#
| API | Version | What changed |
|---|---|---|
| 18 | 4.3 Jelly Bean |
|
| 23 | 6.0 Marshmallow |
|
| 28 | 9 Pie |
|
| 29 | 10 |
|
| 30 | 11 |
|
| 31 | 12 |
|
| 33 | 13 Tiramisu |
|
| 37 | 17 Cinnamon Bun |
|
Under the hood#
- the location service: provider management, permission checks, geofences
- LocationManager.javathe app-facing platform API
- the GNSS HAL contract
- AppOpsManager.javathe operation-level record behind the permission
Curiosity corner#
- GPS is American; GNSS is the general term. Android's HAL is called GNSS because the device may use several constellations at once.
- A cold fix can take 30 seconds; a warm one takes a second. The difference is whether the receiver still has the satellite ephemeris — which is why "get a fix now" and "get a fix every minute" have such different power profiles.
- Wi-Fi positioning often beats GPS indoors. The database knows where access points are, and that is more useful than a satellite signal that cannot penetrate the roof.
Try it#
adb shell dumpsys location | head -60
adb shell cmd location is-location-enabled
adb shell appops get com.example.app android:fine_location
Example output
Last Known Locations:
gps: Location[gps 51.5007,-0.1246 acc=12 ...]
network: Location[network 51.5006,-0.1248 acc=48 ...]
fused: Location[fused 51.5007,-0.1247 acc=20 ...]The appops get line is often the decisive one: it shows whether the operation was allowed and
when it was last used, which is usually more informative than the permission state alone.
Check yourself#
Check yourself
Which component decides which network an app's socket should use?
Sources#
Sources
Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.
- docsLocation services overviewdeveloper.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 12developer.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 11developer.android.comaccessed 2026-10-27↩
- docsManifest.permission | API referencedeveloper.android.comaccessed 2026-10-27↩
- docsConnectivity overviewsource.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 13 or higherdeveloper.android.comaccessed 2026-10-27↩