Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android Mock location not working with locationservices.fusedlocationapi

Tags:

After downloading and using 'Fake Gps' from google store, I thought of creating one for educational purposes.

I am using GoogleApiClient FusedLocationAPI for getting my current location and for creating a mock location. I am able to get my current location, but am unable to mock location.

public class GoogleApiClientGeoLocation implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
    private GoogleApiClient googleApiClient;

    public GoogleApiClientGeoLocation(Context activity) {
        googleApiClient = new GoogleApiClient.Builder(activity, this, this).addApi(LocationServices.API).build();
        ....
    }

    public void connect() {
        if (googleApiClient != null) {
           googleApiClient.connect();
        }
    }

    public void disconnect() {
        googleApiClient.disconnect();
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.e("TAG","Location changed"+location.getLatitude() + ", "+ location.getLongitude());
    }

    private static final String PROVIDER = LocationManager.NETWORK_PROVIDER;//"flp";
    private static final double LAT = 37.377166;
    private static final double LNG = -122.086966;
    private static final float ACCURACY = 3.0f;

    public Location createLocation(double lat, double lng, float accuracy) { //<-for testing purposes using a static lat,long
        // Create a new Location
        Location newLocation = new Location(PROVIDER);
        newLocation.setLatitude(LAT);
        newLocation.setLongitude(LNG);
        newLocation.setAltitude(1000);
        newLocation.setElapsedRealtimeNanos(System.nanoTime());
        newLocation.setTime(System.currentTimeMillis());
        newLocation.setAccuracy(500);
        return newLocation;
    }

    public void startMock() {
        LocationServices.FusedLocationApi.setMockMode(googleApiClient, true);
    }
    public void stopMock() {
        LocationServices.FusedLocationApi.setMockMode(googleApiClient, false);
    }
    public void domock() {
        Location testLocation = createLocation(LAT, LNG, ACCURACY);
        if (ContextCompat.checkSelfPermission(_context, android.Manifest.permission.ACCESS_FINE_LOCATION)
            == PackageManager.PERMISSION_GRANTED) {

            LocationServices.FusedLocationApi.setMockLocation(googleApiClient, testLocation);
            Log.e("TAG","Location Mocked");
        }else{
            Log.e("TAG","Can not Mock location");
        }
    }
}

I have a class GoogleApiClientGeoLocation which handles all the functions. Flow is initialization->connect->startmock->mock->stopmock->disconnect

If I do a connect(), locationchange() gives me current location, however when I startmock() and domock() locationchange() pauses and returns nothing, and when I stopmock() locationchange() starts giving me current location again.

I do get a log message saying 'location mocked'.

Is my 'PROVIDER' wrong?

I want to be able to create a mock location and be able to go to google map and see it pointing to mock location.

like image 995
j4rey Avatar asked Jul 30 '16 11:07

j4rey


People also ask

What is a fused location app?

The fused location provider is a location API in Google Play services that intelligently combines different signals to provide the location information that your app needs.

What is mock location with FLP?

"Allow Mock locations" are built-in phone settings which let users hide their GPS location while using their device.


1 Answers

It appears FusedLocationProvider is on a different clock then the System clock. I.e. elapsedRealTimeNanos is different then System.nanoTime. So the times you set by using the System clock will be off and I’m assuming the new Locations are considered stale and invalid.

To get a valid elapsedRealTimeNanos I add an offset to the System.nanoTime() each time I create a mock Location. I calculate that offset when I first connect to the googleApiClient:

Location current = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
nanoOffset = current.getElapsedRealtimeNanos() - System.nanoTime();

Then, the complete mock Location I create is as follows:

Location location = new Location("flp");  // indicates mock 
locationlocation.setLatitude(latLon.getLat());
location.setLongitude(latLon.getLon());
location.setTime(System.currentTimeMillis());
location.setAccuracy(6f);
location.setElapsedRealtimeNanos(System.nanoTime() + nanoOffset);
like image 158
TonyC Avatar answered Sep 28 '22 04:09

TonyC