Mock location are not working on Android 10, crash when addTestProvider are called:
2020-11-30 00:25:16.855 13189-13256/br.com.tupinikimtecnologia.fakegpslocation E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-2
Process: br.com.tupinikimtecnologia.fakegpslocation, PID: 13189
java.lang.IllegalArgumentException: Provider "gps" already exists
at android.os.Parcel.createException(Parcel.java:2075)
at android.os.Parcel.readException(Parcel.java:2039)
at android.os.Parcel.readException(Parcel.java:1987)
at android.location.ILocationManager$Stub$Proxy.addTestProvider(ILocationManager.java:2022)
at android.location.LocationManager.addTestProvider(LocationManager.java:1461)
at br.com.tupinikimtecnologia.fakegpslocation.feature.mock.view.MapsActivity.setMock(MapsActivity.kt:100)
at br.com.tupinikimtecnologia.fakegpslocation.feature.mock.view.MapsActivity.access$setMock(MapsActivity.kt:34)
at br.com.tupinikimtecnologia.fakegpslocation.feature.mock.view.MapsActivity$onCreate$1.invokeSuspend(MapsActivity.kt:65)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Caused by: android.os.RemoteException: Remote stack trace:
at com.android.server.LocationManagerService.addTestProvider(LocationManagerService.java:3536)
at android.location.ILocationManager$Stub.onTransact(ILocationManager.java:958)
at android.os.Binder.execTransactInternal(Binder.java:1021)
at android.os.Binder.execTransact(Binder.java:994)
2020-11-30 00:25:16.857 13189-13256/br.com.tupinikimtecnologia.fakegpslocation I/Process: Sending signal. PID: 13189 SIG: 9
Code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
ActivityCompat.requestPermissions(this, arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION), ACCESS_LOCATION_CODE)
mLocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (isMockLocationEnabled()) {
GlobalScope.launch {
while (true) {
setMock(LocationManager.GPS_PROVIDER, 39.0293211, 125.6020307);
setMock(LocationManager.NETWORK_PROVIDER, 39.0293211, 125.6020307);
}
}
} else {
AlertDialog.Builder(this)
.setTitle(R.string.dev_settings_title_dialog)
.setMessage(R.string.dev_settings_msg_dialog)
.setPositiveButton(android.R.string.ok) { dialog, which ->
Toast.makeText(this, R.string.dev_settings_msg_toast, Toast.LENGTH_LONG).show()
startActivity(Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS))
}
.show()
}
}
private fun isMockLocationEnabled(): Boolean {
val isMockLocation: Boolean
isMockLocation = try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val opsManager = getSystemService(APP_OPS_SERVICE) as AppOpsManager
Objects.requireNonNull(opsManager).checkOp(AppOpsManager.OPSTR_MOCK_LOCATION, Process.myUid(), BuildConfig.APPLICATION_ID) === AppOpsManager.MODE_ALLOWED
} else {
Settings.Secure.getString(contentResolver, "mock_location") != "0"
}
} catch (e: Exception) {
return false
}
return isMockLocation
}
private fun setMock(provider: String, latitude: Double, longitude: Double) {
mLocationManager?.addTestProvider(
provider,
false,
false,
false,
false,
false,
true,
true,
android.location.Criteria.POWER_LOW,
android.location.Criteria.ACCURACY_FINE
)
val newLocation = Location(provider)
newLocation.latitude = latitude
newLocation.longitude = longitude
newLocation.altitude = 3.0
newLocation.time = System.currentTimeMillis()
newLocation.speed = 0.01f
newLocation.bearing = 1f
newLocation.accuracy = 3f
newLocation.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
newLocation.bearingAccuracyDegrees = 0.1f
newLocation.verticalAccuracyMeters = 0.1f
newLocation.speedAccuracyMetersPerSecond = 0.01f
}
mLocationManager?.setTestProviderEnabled(provider, true)
mLocationManager?.setTestProviderLocation(provider, newLocation)
}
Crash on:
mLocationManager?.addTestProvider(
provider,
false,
false,
false,
false,
false,
true,
true,
android.location.Criteria.POWER_LOW,
android.location.Criteria.ACCURACY_FINE
)
It is crashing only on Android 10, I tried to change the provider name, but it don't work, all names are crashing. I think it is not a permission issue, because I tested with ACCESS_MOCK_LOCATION, ACCESS_FINE_LOCATION and INTERNET enabled
On Android 18 (JellyBean MR2) and above mock locations are detected using Location. isFromMockProvider() for each location. The app can detect that the location came from a mock provider when the API returns true.
You can go to its Settings > Software Information and tap on the Build Number 7 times to turn on Developer Options. Afterward, you can go to Settings > Developer Options > Mock Location App and select any fake GPS application from here. There you go! After reading this guide, you would be able to allow mock locations on Android pretty easily.
To mock location on Xiaomi Most of the Xiaomi devices have a layer of the company’s interface over Android, which is known as MIUI. Instead of the Build Number, you need to tap on the MIUI version under Settings > About Phone to unlock Developer Options.
Solution: The HyperTrack SDK filters out mock locations on the device in order to prevent them from reaching the HyperTrack API server. HyperTrack removes Mock Locations by default.
Instead of the Build Number, you need to tap on the MIUI version under Settings > About Phone to unlock Developer Options. Later, you can go to the Developer Options settings and turn on the feature for “Allow Mock Locations”.
The first thing, when you add test provider (i.e "my_provider"), it's actually interpreted real-like provider as "gps", but for test purposes. So if you ask to android, for locations sources, then it could tell you;
"gps"
, "network"
, "some_provider"
So, why you got exception ?
Actually you are already tend to get exceptions, but it's handled by the system. If you try to add already known provider like "gps"
as test provider, then the system tries to add it into location sources. So it's better to wrap mocking operations for known providers with try catch
To mock gps provider without exception, try this
public void mockGps(Location location) throws SecurityException {
location.setProvider(GPS_PROVIDER);
try{
// @throws IllegalArgumentException if a provider with the given name already exists
mLocationManager.addTestProvider(GPS_PROVIDER, false, false, false, false, false, true, true, 0, 5);
} catch (IllegalArgumentException ignored){}
try{
// @throws IllegalArgumentException if no provider with the given name exists
mLocationManager.setTestProviderEnabled(GPS_PROVIDER, true);
} catch (IllegalArgumentException ignored){
mLocationManager.addTestProvider(GPS_PROVIDER, false, false, false, false, false, true, true, 0, 5);
}
try{
// @throws IllegalArgumentException if no provider with the given name exists
mLocationManager.setTestProviderLocation(GPS_PROVIDER, location);
} catch (IllegalArgumentException ignored){
mLocationManager.addTestProvider(GPS_PROVIDER, false, false, false, false, false, true, true, 0, 5);
mLocationManager.setTestProviderEnabled(GPS_PROVIDER, true);
mLocationManager.setTestProviderLocation(GPS_PROVIDER, location);
}
}
This is not really coming from the mocking, but the LocationManager
's .addTestProvider()
. Adding the same one test-provider twice will in every case not work out, according to the source code. For later API levels, just use .setTestProviderLocation(String provider, Location loc)
instead of trying to add that mocked provider with the duplicate name; or at least remove the existing one, before trying to add another one with the same name.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With