How to Detect Fake GPS and Mock Location in Android Apps: A Developer's Security Guide

Android's developer options include a feature called "Allow mock locations," which lets any designated app feed fake GPS coordinates to the entire device. For developers, this is useful — you can simulate a delivery route, test geofenced notifications, or verify location-based logic without physically moving anywhere.
But the same mechanism can be misused. In apps that depend on real-world location data — delivery platforms, attendance systems, ride-sharing, banking — a user can install a GPS spoofing app, set a fake location, and your app will receive that fake data as if it were real. The device has no way to automatically tell the difference unless you check for it explicitly.
This article covers how to detect mock location at the app level in Android, using both modern and legacy approaches.
How Mock Location Works
On Android 6.0 and above, mock location isn't a global setting — it's granted to a specific app. The user goes to Developer Options, selects "Select mock location app," and chooses a spoofing app from the list. Once set, that app can feed arbitrary coordinates to LocationManager and FusedLocationProviderClient.
On older Android versions (5.1 and below), it was a simpler global toggle in Developer Options.
Detecting Mock Location
The most reliable approach is to check the Location object's mock flag before using the coordinates.
For Android 12 and above (API level 31+):
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
val locationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
if (location.isMock) {
// Location is from a mock provider — reject or flag it
handleMockLocation()
} else {
processRealLocation(location)
}
}
}
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
1000L,
0f,
locationListener
)
location.isMock is the modern, direct way to check this. It returns true if the location was provided by a mock provider.
For Android below API 31:
@Suppress("DEPRECATION")
fun isMockLocation(location: Location): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
location.isMock
} else {
location.isFromMockProvider
}
}
isFromMockProvider is deprecated as of API 31 but still works on older devices. Using the version check ensures correct behavior across the full Android version range.
Using Fused Location Provider
If you're using FusedLocationProviderClient (which is the recommended approach for most apps), the same check applies to the Location objects you receive in your callback:
val fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
val locationRequest = LocationRequest.Builder(
Priority.PRIORITY_HIGH_ACCURACY,
1000L
).build()
val locationCallback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
for (location in result.locations) {
if (isMockLocation(location)) {
// Handle mock location
} else {
// Use real location
}
}
}
}
fusedLocationClient.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
Checking If Mock Location Is Enabled at All
For stricter applications, you may want to reject any session where the device even has mock locations enabled — regardless of whether the current location reading is mocked. You can check this at startup:
fun isMockLocationEnabled(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) &&
Settings.Secure.getInt(
context.contentResolver,
Settings.Secure.ALLOW_MOCK_LOCATION, 0
) != 0
} else {
Settings.Secure.getInt(
context.contentResolver,
Settings.Secure.ALLOW_MOCK_LOCATION, 0
) != 0
}
}
Note: On API 23 and above, ALLOW_MOCK_LOCATION in Settings.Secure is always 0 because mock location is no longer a global toggle — it's per-app. For API 23+, the per-location isMock check is more relevant.
Detecting Whether a Mock Provider App Is Active
On API 23 and above, you can check whether any app is currently registered as the mock location provider:
fun hasMockLocationApp(context: Context): Boolean {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
return try {
locationManager.addTestProvider(
LocationManager.GPS_PROVIDER,
false, false, false, false, false, false, false,
Criteria.POWER_LOW, Criteria.ACCURACY_FINE
)
locationManager.removeTestProvider(LocationManager.GPS_PROVIDER)
false // No mock provider was active; we were able to add one
} catch (e: SecurityException) {
true // A mock provider is already registered — another app owns it
}
}
This works by trying to add a test provider. If another app has already claimed the mock provider slot, Android throws a SecurityException. That exception tells you a mock location app is active.
What to Do When Mock Location Is Detected
The right response depends on your app's use case.
For a delivery or attendance app where fake location directly enables fraud, you might block the action entirely and show an error:
if (isMockLocation(location)) {
showError("Your location appears to be mocked. Please disable any GPS spoofing apps and try again.")
return
}
For lower-stakes applications, you might log the detection server-side for review without blocking the user in the moment:
if (isMockLocation(location)) {
reportSuspiciousActivity(userId, location)
}
processLocation(location)
Avoid silently doing nothing. If you're checking for mock location, you should have a plan for what happens when you find it.
Limitations
App-level detection has limits. Rooted devices can use tools like Xposed or Magisk modules to hide mock location flags entirely, making isMock return false even for spoofed coordinates. For applications where location integrity is critical, combine app-level checks with server-side validation — look for impossible speed (jumping between distant locations in seconds), trajectory anomalies, or coordinates that don't match cell tower or Wi-Fi positioning data.
No single check is foolproof. Defense in depth — multiple signals checked at different layers — gives you the most reliable protection.
Summary
location.isMock (API 31+) and location.isFromMockProvider (pre-API 31) are the primary tools for detecting fake GPS at the app level. Check them on every location update before using the coordinates. For stricter security requirements, also check whether a mock provider app is active at startup. Pair app-level detection with server-side anomaly detection for the strongest coverage.




