Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting mock location in FusedLocationProviderApi

I'm trying to get mock updates from FusedLocationProviderApi, but I can't seem to make it work. This my set up method in android instrumentation test:

locationProvider = new LocationProvider(InstrumentationRegistry.getTargetContext().getApplicationContext(), settings);

// Connect first, so that we don't receive 'true' location
locationProvider.googleApiClient.blockingConnect();
// Set mock mode, to receive only mock locations
LocationServices.FusedLocationApi.setMockMode(locationProvider.googleApiClient, true);

InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
    @Override
    public void run() {
        // Start receiving locations; this call will connect api client, and if it's already connected (or after it connects) it will register for location updates
        locationProvider.start();
    }
});
// wait until we can request location updates
while (!locationProvider.isReceivingLocationUpdates) {
    Thread.sleep(10);
}

After this point I would expect any calls to LocationServices.fusedLocationApi.setMockLocation(apiClient, location) to set mock location that my listener would receive. Unfortunately this is not the case, and the listener stays silent.

My foolproof (or so I thought) method to set mock location looks like this:

private void setMockLocation(final Location location) throws Exception {
    assertTrue(locationProvider.googleApiClient.isConnected());
    assertTrue(locationProvider.isReceivingLocationUpdates);

    final CountDownLatch countDownLatch = new CountDownLatch(1);
    LocationServices.FusedLocationApi.setMockMode(locationProvider.googleApiClient, true)
            .setResultCallback(new ResultCallback<Status>() {
                @Override
                public void onResult(Status status) {
                    assertTrue(status.isSuccess());
                    LocationServices.FusedLocationApi.setMockLocation(locationProvider.googleApiClient, location)
                            .setResultCallback(new ResultCallback<Status>() {
                                @Override
                                public void onResult(Status status) {
                                    assertTrue(status.isSuccess());
                                    countDownLatch.countDown();
                                }
                            });
                }
            });
    assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS));
}

Method returns successfully, but no location is received by the listener. I'm really at a loss here. The worst part is sometimes the test would pass, but extremely randomly (to a point when the same code executed several times would pass and fail in subsequent calls). My debug manifest, for completeness, has following permissions:

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

I have allowed mock locations in settings.

like image 442
wasyl Avatar asked Aug 31 '15 17:08

wasyl


People also ask

What is fused location APK?

Simple, battery-efficient location API for Android 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.


1 Answers

this us an updated kotlin version. Be aware that you need to pick the app as a mock location provider in development options, and have permissions to do it set in a debug manifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"
    tools:ignore="ProtectedPermissions" />
</manifest>

An activity would have a val with initializer in onCreate

  private lateinit var fusedLocationClient: FusedLocationProviderClient

in oncreate()

  fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)


  fusedLocationClient.setMockMode(BuildConfig.DEBUG)

  fusedLocationClient.lastLocation
        .addOnSuccessListener { location : android.location.Location? ->
            // Got last known location. In some rare situations this can be null.
            Toast.makeText(this, location.toString(), Toast.LENGTH_SHORT).show()

        }
        .addOnFailureListener {  Toast.makeText(this, "failed", Toast.LENGTH_SHORT).show() }

and finally a way to mock a location

 private fun setMockLocation(location: android.location.Location) {
    fusedLocationClient.setMockLocation(location)
        .addOnSuccessListener { Log.d(TAG, "location mocked") }
        .addOnFailureListener { Log.d(TAG, "mock failed") }
}
like image 135
keepTrackOfYourStack Avatar answered Oct 19 '22 23:10

keepTrackOfYourStack