I'm having an issue with mock location providers. I have an app that needs to get accurate valid locations, and I don't want the user to be able to spoof them. So I have a check for the mock locations enabled setting, which works fine.
However there is a problem with the location provider. If you enable mock locations, set a location with a gps faker app, then disable mock locations and all other location providers, the location manager still has a reference to the mock location provider. So although mock locations are disabled, the location manager tells me that gps is enabled, and serves mocked location data.
I know that you can clear test providers from the location manager, but mock locations must be enabled to do this
Anyone ever come across this, or have a work around?
Think I found a way to get an accurate reading whether GPS/Network provider are enabled or not:
ContentResolver contentResolver = context.getContentResolver();
boolean gpsEnabled = Settings.Secure.isLocationProviderEnabled(contentResolver, LocationManager.GPS_PROVIDER);
boolean networkEnabled = Settings.Secure.isLocationProviderEnabled(contentResolver, LocationManager.NETWORK_PROVIDER);
Are you sure you've called :
removeUpdates()
removeTestProvider()
setTestProviderEnabled() with false
clearTestProviderEnabled() ?
Look at how LocationManagerTest does this.
// disable mocking.
Settings.Secure.putString(getContentResolver(),
Settings.Secure.ALLOW_MOCK_LOCATION, "0");
Related
I've developed an app that receives the location from both GPS_PROVIDER and NETWORK_PROVIDER, however the NETWORK_PROVIDER returns the best values retrieved from WIFI and GPRS, without having any control over it. I need to get the value returned by the GPRS location listener even when you have WIFI active, so I can use it to dismiss the fake locations from other apps.
Is it possible to do this?
At the moment I'm testing this solution Disable / Check for Mock Location (prevent gps spoofing) , I'll let you know if it solves my issue
Unfortunately it is not possible, no.
You can do something like this:
final LocationManager locationManager = getLocationManager();
final List<String> providers = locationManager.getProviders(true);
if (providers.size() > 1) {
providers.remove(LocationManager.NETWORK_PROVIDER);
}
But you don't have the option to distinguish between a cell or a wifi network-provider!
This provider determines location based on availability of cell tower
and WiFi access points. Results are retrieved by means of a network
lookup.
Constant Value: "network"
Source: http://developer.android.com/reference/android/location/LocationManager.html#NETWORK_PROVIDER
What you can try is to use this solution. However, since this doesn't seem to be documented I'd be careful relying on it because it might break in future OS versions or might not work on every device.
I am using the Criteria object to get the best provider like so
final boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(isGpsEnabled) {
Criteria crit = new Criteria();
crit.setAccuracy(Criteria.ACCURACY_FINE);
crit.setCostAllowed(true);
crit.setPowerRequirement(Criteria.NO_REQUIREMENT);
crit.setSpeedRequirement(false);
String provider = locationManager.getBestProvider(criteria, true);
locationManager.requestLocationUpdates(provider, 600000, 0, new myLocationListener());
}
On my phone (Android 4.1) I have both "Use GPS Satellites" and "Use Wireless Networks" options enabled. Now, the above code works great when I am outdoors and it gives me the GPS location.
But, when I am indoors it does not revert to the "network" provider. It just keeps trying to get the location via GPS and never get its (I wait 1 minute or so)
When I change the code of Criteria to use Criteria.ACCURACY_COARSE then it uses "network" provider.
How do I get it to first try the GPS (because it is enabled) and because we are indoor it will not be able to connect to a satellite to then fall back to using the "network". I can't get that working easily. I state again, GPS is enabled but no access to satellites so want it to get network location instead.
Thanks.
The solution was create the location manager and attach 2 listeners to receive updates. One for GPS and another for NETWORK. You set it to receive updates fairly quickly (or depending on your own case, I just needed to get the location) You then create a method that compares the location of the GPS and Network and find which one is more accurate. You do this at most 3 times to get on average which one is returning the most accurate position and then you stop the location updates.
I'm working on an application which uses location.
My problem:
When I'm looking for the best provider, I only get the "network".
I know why but I don't know how to improve this.
In the locations settings, when I check "parameter -> location" and "security settings -> Use wireless network", the LocationManager.getBestProvider() returns only network. When it is not checked, and the GPS is active, getBestProvider returns the GPS.
What I want to do is:
When both options are checked, how to use / detect the GPS, instead of the network, as the location provider.
You have to first check whether GPS is on or not. If it is on then get the location from GPS, if not get the location from network.
To check the gps status use :
manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE );
boolean statusOfGPS = manager.isProviderEnabled(LocationManager.GPS_PROVIDER);
Given this code
if (!locator.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
//consider forcing user to turn on gps here
} else {
provider = LocationManager.GPS_PROVIDER;
}
What happens if the device does not have GPS. Right now if that provider isn't enabled then it I will jump the user to their system settings to turn it on. But what if it isn't there? How would this be handled. I dont want to necessarily lock those kind of users out of the app.
If the GPS provider is not available (or enabled), then try for whatever you can get:
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_HIGH);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
String provider = lm.getBestProvider(criteria, true);
This assumes that you prefer a rough position over no position at all.
You only need the GPS if you want precise locations. If the device simply does not have a GPS, then you can estimate with less accuracy through the NETWORK_PROVIDER. That's usually suitable if you just need the general location of a user (west side of a city, near a memorial, etc.). If you absolutely need a specific location that's within a specific accuracy for your app to work, then you're user without GPS is just out of luck.
Alternatively, if you enable GPS and the user doesn't have GPS, it simply won't get updates. In that case, you'll have to mention that the updates aren't precise because of lack of GPS, and the user will have to use a weaker version of your app.
I am using this code to get the location provider and location.
mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
Criteria criteria = new Criteria();
mBestProvider = mLocationManager.getBestProvider(criteria, false);
mLocation = mLocationManager.getLastKnownLocation(mBestProvider);
If I turn off the GPS, the location is by network, but if I reboot the phone(so I loss the last position known) and with the 3G data connections off. So I am only using WIFI, I cant get any provider thus therefore any location. However google places app can locate me. I think it might be getting the lastknownlocation.But in that case my others applications should be able to get that location. Any idea whats happening?
The way you are calling this it will return all providers enabled or not because you are passing it false which is probably your intention but have you checked the return string?
mBestProvider = mLocationManager.getBestProvider(criteria, false);
You might be getting the gps provider, or you might be getting the network provider, I have learned not to trust the criteria mechanism because it seems to work differently per carrier and device (I have had some weird bugs reported because of this)
So I always ask specifically for gps and network providers and check last known for both, then use an algo to determine the best one to use.
The network provider can use cell or wifi hotspot/routers to determine location (google keeps a database of wifi information) so it's possible to get a fix with just wifi, not saying that is whats happening but it could be.
If that bears no fruit then it's possible that they are simply caching the last location update in preferences, some applications do that. To test the thesis, failing all of the above just leave the phone in that state and move to a very different location with the same properties if possible, should only take 2000 meters or so. If your app still reports null and places reports the old location you have your answer.
If places did report the newer location with wifi, and your app cannot (assuming you actually verify you are getting the network provider) then there is a chance they are using a private API via the Google Location Server (GLS) / MASF server via partial cell / wifi info but that's at the extreme end of the tin foil curve.