2

This is how I set a mock location in my app:

public void startMockLocation(String latitude, String longitude){

    FusedLocationProviderClient locationProvider =  new FusedLocationProviderClient(getApplicationContext());
    locationProvider.setMockMode(true);

    Location loc = new Location("gps");

    mockLocation = new Location("gps");
    mockLocation.setLatitude(Double.valueOf(latitude));
    mockLocation.setLongitude(Double.valueOf(longitude));
    mockLocation.setAltitude(loc.getAltitude());
    mockLocation.setTime(System.currentTimeMillis());

    mockLocation.setAccuracy(1f);
    mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        mockLocation.setBearingAccuracyDegrees(0.1f);
        mockLocation.setVerticalAccuracyMeters(0.1f);
        mockLocation.setSpeedAccuracyMetersPerSecond(0.01f);
    }

    locationProvider.setMockLocation(mockLocation);
}

However I wasn't able to clear the mock location and set the real location back using this code below. What should I write instead?

public void clearMockLocation() {
    locationProvider.setMockMode(false);
}
Panjeet
  • 117
  • 1
  • 18
  • the code is fine can you show your code where you are accessing current location... ? – AgentP May 30 '20 at 08:10
  • Did you get the necessary permission? – Javad Dehban May 30 '20 at 08:57
  • @PraveenSP I'm not accessing the current location anywhere. – Panjeet May 30 '20 at 11:18
  • @JavadDehban Yes, I did. – Panjeet May 30 '20 at 11:25
  • Dutch if you are not accessing location than how you know that the device is still using mock location ... even after setting mocking to false – AgentP May 30 '20 at 12:40
  • @PraveenSP I know that it is in mock location because I'm the one who set it as mock location... – Panjeet May 30 '20 at 14:44
  • We are missing something here..... again my question is how ? let me elaborate it now you set mock location using startMockLocation() so how do you know you have set it I mean there has to be someplace where you are seeing your current location which is mock ...so what is that place ... ? are you using other apps to check your current location... – AgentP May 30 '20 at 14:48
  • @PraveenSP Yes, I'm using Google Maps to see the location. – Panjeet May 30 '20 at 14:52
  • so after you are setting mock location ... you are going to google map and google map is still showing you the location you set which is mock one ... ? are you enabled GPS when you go to google map ? – AgentP May 30 '20 at 14:53
  • @PraveenSP Yes, GPS is enabled. – Panjeet May 30 '20 at 20:56

2 Answers2

0

Update:


As far, your problem is following these steps such as:

  1. Setting your mock location for Gps
  2. Going to GoogleMaps and see your mock location
  3. Turn back your app and want to stop mocking

Here I am giving you some techniques to disable mock locations.


Method.1

Spoofing or faked locations can be avoided by using the Location Manager's API.

For this you first have to import the google play services LocationServices (must visit) API:

You need to import:

import com.google.android.gms.location.LocationServices;

And in App-level build.gradle:

implementation 'com.google.android.gms:play-services-location:17.0.0'

Your Class must implement these interfaces:

public class TestMapsActivity extends FragmentActivity implements OnMapReadyCallback,
    LocationListener,
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener { ...}

Then, you need to Override these methods such as:

 @Override
    public void onConnected(Bundle bundle) {

    }


    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {

    }

    @Override
    public void onLocationChanged(Location location) {

    }

Now, We can remove the test provider before requesting the location updates from both the providers (Network or Gps):

LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

try {
    Log.d(TAG ,"Removing Test providers")
    locationManager .removeTestProvider(LocationManager.GPS_PROVIDER);
} catch (IllegalArgumentException error) {
    Log.d(TAG,"Got exception in removing test  provider");
}

locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, locationListener);

Now, If you look into the Android documentation of the LocationManager:

removeTestProvider() throws 
IllegalArgumentException    if no provider with the given name exists

You will get a better intuition from this android-issue. For that specific thread, You can try using Criteria.ACCURACY_FINE instead of LocationManager.GPS_PROVIDER such as:

LocationManager locationManager = (LocationManager)context.getSystemService( Context.LOCATION_SERVICE );

Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
String locationprovider = locationManager.getBestProvider(criteria, true);

if ( locationprovider == null ) {
    Log.e(TAG, "location provider is not available.!");
    return;
}

Method.2

If the above method still doesn't work for you, you can silently enable /disable mock settings as follows:

// disable mocking. 
Settings.Secure.putString(getContentResolver(),
       Settings.Secure.ALLOW_MOCK_LOCATION, "0");

You can also get better intuition here and here.


Method.3

There is another way you can do that to get an accurate understanding whether GPS/Network providers 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);

Other Steps to follow.


You should have to follow these steps to clear/reset your mock location such as:

  • Enable mock locations in the development panel in your settings.
  • Add permissions to your Manifest.xml i.e.

    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />

  • Now again open GoogleMaps, and wait until the Gps provider to receive a new realtime-location. It could be a bit of time-consuming i.e. (1-3 minutes).

So while removing the provider, just let the Gps receive a new fresh location, then it will be resolved and fixed. If in case, it is not working again, then you can further do these steps:

Go to the app settings, Clear the App-Cache and Restart the Mobile Device.

I hope that it would work really fine. You can also visit these references to get better intuition:

Muhammad Usman Bashir
  • 1,441
  • 2
  • 14
  • 43
  • Thank you for your answer. The code doesn't always work because my app frequently crashes with this error: `java.lang.IllegalArgumentException: Provider "gps" unknown` – Panjeet Jun 03 '20 at 21:35
  • I have updated my question. If it's still not working then it's almost certain that you have no GPS provider enabled on your `device/emulator`. *It has to have this feature in order to even receive the mock locations*. – Muhammad Usman Bashir Jun 03 '20 at 22:02
  • @Dutch I have updated my answer with the most possible scenarios using different techniques. Please revisit and let me know, how can I further assist you? – Muhammad Usman Bashir Jun 04 '20 at 22:54
  • I get `error Cannot resolve symbol locationListener` after following method 1 – Panjeet Jun 05 '20 at 20:35
  • @Dutch I have improved method-1 so that you can easily include location-listener API. It will resolve your error. I have given a reference in the recent update to give you a better intuition. Please *must visit*. – Muhammad Usman Bashir Jun 05 '20 at 23:12
  • If it doesn't solve your problem, Then, share your complete code in your question. So that I can analyze. The given every possible technique is working fine for me, even I have tested on multiple devices. – Muhammad Usman Bashir Jun 06 '20 at 06:04
0

as i see your code , you are calling two methods one to set mock location and other to disable it but in other method i am not sure which object of location provider you are using , i would prefer you to declare a global object of location provider and use it anywhere

FusedLocationProviderClient locationProvider;

public void startMockLocation(String latitude, String longitude){

    locationProvider =  new FusedLocationProviderClient(getApplicationContext());
    locationProvider.setMockMode(true);

    Location loc = new Location("gps");

    mockLocation = new Location("gps");
    mockLocation.setLatitude(Double.valueOf(latitude));
    mockLocation.setLongitude(Double.valueOf(longitude));
    mockLocation.setAltitude(loc.getAltitude());
    mockLocation.setTime(System.currentTimeMillis());

    mockLocation.setAccuracy(1f);
    mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        mockLocation.setBearingAccuracyDegrees(0.1f);
        mockLocation.setVerticalAccuracyMeters(0.1f);
        mockLocation.setSpeedAccuracyMetersPerSecond(0.01f);
    }

    locationProvider.setMockLocation(mockLocation);
}

then in other method

public void clearMockLocation() {
if(locationProvider!=null){
locationProvider.setMockMode(false);
if(mockLocation!=null){
mockLocation.setLatitude(real_latitude);
    mockLocation.setLongitude(real_longitude);
    mockLocation.setAltitude(real_altitude);
    mockLocation.setTime(System.currentTimeMillis());
    mockLocation.setAccuracy(1f);
    mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        mockLocation.setBearingAccuracyDegrees(0.1f);
        mockLocation.setVerticalAccuracyMeters(0.1f);
        mockLocation.setSpeedAccuracyMetersPerSecond(0.01f);
    }

    locationProvider.setMockLocation(mockLocation);
}

}

}
Quick learner
  • 10,632
  • 4
  • 45
  • 55