GeoFence Not Triggered w/Mock Location

Bill Mote

I am trying to test GeoFences for a location aware application. I have gotten as many as 11 consecutive successes, but that is typically followed by dozens of failures. Rebooting the device does not help. Uninstalling/reinstalling does not help. Disabling location, re-enabling location does not help. Changing the devices Location Accuracy settings does not help.

I've tested on v2.3.4, v4.0.3, v4.4.2, v4.4.4 and 2 v5.0.1 physical devices. One of the Lollipop devices is a device with cellular service. The remaining devices are SIMless and used for testing only. Side note: the devices without service struggle with setting their location via MockLocation, but if they manage to set their location they almost never register a fence entry/exit.

Location is being updated via Mock Location well enough, but the GeoFence(s) are not being triggered with any reliability.

I've Googled it. I've looked at the documentation on developer.android.com site. I've searched StackOverflow. In fact, many of the suggestions made by others have been implemented in the code below.

So, how can I reliably trigger my GeoFence using MockLocation?

import android.location.Location;
import android.location.LocationManager;

public class GeoFenceTester extends ActivityInstrumentationTestCase2<GeoFenceTesterActivity> {


    public static final String TAG = GeoFenceTester.class.getSimpleName();

    private LocationManager locationManager;
    private Activity activityUnderTest;

    protected void setUp() throws Exception {
        super.setUp();
        activityUnderTest = getActivity();
        /*
            MOCK Locations are required for these tests.  If the user has not enabled MOCK Locations
            on the device or emulator these tests cannot work.
         */
        if (Settings.Secure.getInt(activityUnderTest.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 0) {
            throw new RuntimeException("Mock locations are currently disabled in Settings - These tests require mock locations");
        }

        Log.i(TAG, "Setup MOCK Location Providers");
        locationManager = (LocationManager) activityUnderTest.getSystemService(Context.LOCATION_SERVICE);

        Log.i(TAG, "GPS Provider");
        locationManager.addTestProvider(LocationManager.GPS_PROVIDER, false, true, false, false, false, false, false, Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
        locationManager.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true);

        Log.i(TAG, "Network Provider");
        locationManager.addTestProvider(LocationManager.NETWORK_PROVIDER, true, false, true, false, false, false, false, Criteria.POWER_MEDIUM, Criteria.ACCURACY_FINE);
        locationManager.setTestProviderEnabled(LocationManager.NETWORK_PROVIDER, true);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            Log.wtf(TAG, String.format("Location Accuracy: %1$d", Settings.Secure.getInt(activityUnderTest.getContentResolver(), Settings.Secure.LOCATION_MODE)));
        }

        /* Our EventBus for onEvent() callbacks */
        EventBus.getDefault().register(this);
    }

    protected void tearDown() {
        /* Our EventBus for onEvent() callbacks */
        EventBus.getDefault().unregister(this);

        locationManager.removeTestProvider(LocationManager.GPS_PROVIDER);
        locationManager.removeTestProvider(LocationManager.NETWORK_PROVIDER);
        locationManager = null;

        activityUnderTest = null;

        super.tearDown();
    }

    public void testGeoFence() {

        /*
            Using one or the other or both of these makes no difference.
        */
        Location mockGpsLocation = new Location(LocationManager.GPS_PROVIDER);
        mockGpsLocation.setLatitude(32.652411);
        mockGpsLocation.setLongitude(-79.938063);
        mockGpsLocation.setAccuracy(1.0f);
        mockGpsLocation.setTime(System.currentTimeMillis());

        Location mockNetworkLocation = new Location(LocationManager.NETWORK_PROVIDER);
        mockNetworkLocation.setLatitude(32.652411);
        mockNetworkLocation.setLongitude(-79.938063);
        mockNetworkLocation.setAccuracy(1.0f);
        mockNetworkLocation.setTime(System.currentTimeMillis());

        /*
            setElapsedRealtimeNanos() was added in API 17
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            mockGpsLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
            mockNetworkLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
        }

        try {
            Method locationJellyBeanFixMethod = Location.class.getMethod("makeComplete");
            if (locationJellyBeanFixMethod != null) {
                locationJellyBeanFixMethod.invoke(mockGpsLocation);
                locationJellyBeanFixMethod.invoke(mockNetworkLocation);
            }
        } catch (Exception e) {
            // There's no action to take here.  This is a fix for Jelly Bean and no reason to report a failure.
        }

        for (int i = 0; i < 30; i++){
            Log.i(TAG, String.format("Iterating over our location ... (%1$d)", i));
            locationManager.setTestProviderLocation(LocationManager.GPS_PROVIDER, mockGpsLocation);
            locationManager.setTestProviderLocation(LocationManager.NETWORK_PROVIDER, mockNetworkLocation);
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                Log.e(TAG, e.getMessage(), e);
            }
        }
    }

    public void onEvent(final GeoFenceUpdateEvent event) {
        // This doesn't get called about 9/10 times.
        // I have a GeoFence with a 5000m radius around 32.652411, -79.938063
    }

    public void onEvent(final LocationUpdateEvent event) {
        // This gets called without incident and event.getLatitude() & event.getLongitude() are correct.
    }

}
phoenixillusion

The Geofence manager will consider all system-wide location requests equally, not just those made by your specific application. If you have any other applications or services on the device that are currently using a Location Services, these external applications be producing Lat/Lon locations used in consideration when triggering your Geofences.

Given you are producing Mock Locations, it is possible that external applications or services are producing conflicting LocationUpdates, and that these jumps between Mock and Real locations are causing your unstable Geofence test results.

You may be able to confirm this by disabling your real Location Services in settings and purely using Mock Locations, or look for any applications that may be currently using Location Services and re-testing once those specific apps have been stopped or disabled.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Geofence Serivce triggered not fire

From Dev

mock location for testing geofence apps

From Dev

Android: Mimicking Geofence with BroadcastReceiver and Location Updates

From Dev

Can i set up a Geofence around a users current location?

From Dev

Android Geofence Automatically removed when location service is disabled / restarted

From Dev

location.href in jquery ajax success is not triggered

From Dev

Does the location manager's limit of 20 regions mean 20 total geofence AND beacon regions?

From Dev

Angularjs $location is not triggered the first time and uses old values the next time

From Dev

Geofence not triggering

From Dev

Geofence GEOFENCE_TRANSITION_DWELLING error

From Dev

Android: geofence expiration

From Dev

Geofence transition not happening

From Dev

Is there a limit to the radius of a geofence in Android?

From Dev

Android geofence transition triggers

From Dev

Creating a polygonal geofence

From Dev

Android: geofence expiration

From Dev

Continues Trigger GeoFence Event

From Dev

Add Geofence in a Service in android

From Dev

Geofence not working in Kotlin

From Dev

Geofence alert and remote feature

From Dev

GEOFENCE_NOT_AVAIBLE (code 1000) while trying to set up geofence

From Dev

Android: Build Polygonal Shape Geofence

From Dev

Geofence triggering procedure explanation needed?

From Dev

How to get residence time in a geofence?

From Java

isInterrupted() is not triggered

From Dev

$watchCollection is not triggered

From Dev

dispatchPopulateAccessibilityEvent not triggered

From Dev

Android Geofencing: Trigger only while outside geofence

From Dev

Android: What is the minimum and maximum radius for geofence

Related Related

HotTag

Archive