riadrifai
riadrifai

Reputation: 1158

Stop initial triggering if device is already inside Geofence android

I am using Geofencing on android, and when creating a geo-fence the device is getting notified if the user was already inside the geo-fence, which is not the behavior I'm looking for, I only want to notify on transition ENTER and EXIT.

This is how I'm creating the geofence request:

private GeofencingRequest createGeoFenceRequest(List<Geofence> geofenceList) {
        return new GeofencingRequest.Builder()

                //The INITIAL_TRIGGER_ENTER is used to notify the user initially if he/she/other
                //is already inside the geo-fence zone
                //.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)

                .addGeofences(geofenceList)
                .build();
    }

And inside my GeofenceTransitionService.java:

@Override
protected void onHandleIntent(@Nullable Intent intent) {

    if (intent != null) {
        geofencingEvent = GeofencingEvent.fromIntent(intent);

        // Retrieve the transition type.
        geoFenceTransition = geofencingEvent.getGeofenceTransition();

    }
}

The transition type is returned as Geofence.GEOFENCE_TRANSITION_ENTER even though I am not entering, I am already inside the geofence. Anyone know how I can stop this initial trigger ?

Upvotes: 2

Views: 3249

Answers (4)

Moreno
Moreno

Reputation: 180

From the documentation

initialTrigger the notification behavior. It's a bit-wise of GeofencingRequest.INITIAL_TRIGGER_ENTER and/or GeofencingRequest.INITIAL_TRIGGER_EXIT and/or GeofencingRequest.INITIAL_TRIGGER_DWELL. When initialTrigger is set to 0 (setInitialTrigger(0)), initial trigger would be disabled.

Upvotes: 1

Nuno M. Santos
Nuno M. Santos

Reputation: 83

Why you got the initial trigger

tl;dr
It's the default behavior

I got here with a similar problem of yours:

The transition type is returned as Geofence.GEOFENCE_TRANSITION_ENTER even though I am not entering, I am already inside the geofence.

After some research, I found this behavior stated on the GeofencingRequest.Builder documentation:

Public Methods

public GeofencingRequest.Builder setInitialTrigger (int initialTrigger)
Sets the geofence notification behavior at the moment when the geofences are added. The default behavior is INITIAL_TRIGGER_ENTER and INITIAL_TRIGGER_DWELL.

To understand what those constants actually mean, we need to check the documentation for the enclosing class, GeofencingRequest:

Constant Summary

int INITIAL_TRIGGER_DWELL
A flag indicating that geofencing service should trigger GEOFENCE_TRANSITION_DWELL notification at the moment when the geofence is added and if the device is already inside that geofence for some time.

int INITIAL_TRIGGER_ENTER
A flag indicating that geofencing service should trigger GEOFENCE_TRANSITION_ENTER notification at the moment when the geofence is added and if the device is already inside that geofence.

int INITIAL_TRIGGER_EXIT
A flag indicating that geofencing service should trigger GEOFENCE_TRANSITION_EXIT notification at the moment when the geofence is added and if the device is already outside that geofence.

This explains why you were notified of a GEOFENCE_TRANSITION_ENTER even though you didn't use setInitialTrigger() - it's the default behavior.

While investigating this, I found out something interesting. If you subscribe to entrances and departures of geofences and then set the initial trigger to INITIAL_TRIGGER_ENTER | INITIAL_TRIGGER_EXIT (bitwise OR; summing both constants together would also work), you will be notified of all the geofences you're currently inside (with GEOFENCE_TRANSITION_ENTER) and also of all the geofences you're currently outside (with GEOFENCE_TRANSITION_EXIT). I haven't thought about a good use case for this, but found it interesting anyway.


How to stop the initial trigger

tl;dr
Set the initial trigger to 0, using a constant to attribute meaning to the number (e.g., private static final int NO_INITIAL_TRIGGER = 0)

Taking a closer look into the documentation of setInitialTrigger() it's possible to read:

Parameters

initialTrigger the notification behavior. It's a bit-wise of INITIAL_TRIGGER_ENTER and/or INITIAL_TRIGGER_EXIT and/or INITIAL_TRIGGER_DWELL.

The hint of using a bitwise operation, combined with the documentation found for those constants (which work as flags for each type of transition) led me to question what would happen if all of the bits were turned off.

So I tried to pass the value of 0 to setInitialTrigger(), in order to override the default behavior and turn off all of the initial triggers without having to resort to the workaround proposed by rfn123:

private GeofencingRequest createGeofencingRequest(List<Geofence> geofences) {
    return new GeofencingRequest.Builder()
            .setInitialTrigger(0)
            .addGeofences(geofences)
            .build();
}

Or - perhaps even better - giving some meaning to the magic number:

private static final int NO_INITIAL_TRIGGER = 0;

private GeofencingRequest createGeofencingRequest(List<Geofence> geofences) {
    return new GeofencingRequest.Builder()
            .setInitialTrigger(NO_INITIAL_TRIGGER)
            .addGeofences(geofences)
            .build();
}

After some hours of testing this seems to be a sensible approach even if it relies on a poorly documented behavior (as keepTrackOfYourStack has noticed, the documentation has been updated to clarify this).


Please note: From the tests I performed, it's still possible to get an almost instant trigger for a transition, depending on chosen geofences' radii and current location's precision.

For instance, you might be slightly away from the geofence and then suddenly your position is updated, putting you inside the geofence: this will trigger a geofence entrance notification. However, this entrance notification is not related to the initial trigger you've configured, but to the update in your perceived position.


On a leaving note, if you don't mind, I have a suggestion for an alternate way to implement the onHandleIntent() method.

Instead of checking for the intent object's nullity, just pass that responsibility to the GeofencingEvent#fromIntent() call. You can then check the validity of the returned event object, using a guard clause - which will increase your method's readability (at least in my opinion). This will allow you to both test for nullity and check if the event has an error.

Something like this:

@Override
protected void onHandleIntent(@Nullable Intent intent) {
    GeofencingEvent event = GeofencingEvent.fromIntent(intent);
    if (event == null || event.hasError()) {
        logInvalidEvent(event);
        return;
    }

    // Process the event...
}

Upvotes: 8

keepTrackOfYourStack
keepTrackOfYourStack

Reputation: 1255

it looks like they fixed the documentation and 0 works even though there is no constant

documentation update

Upvotes: 1

rfn123
rfn123

Reputation: 161

A workaround might be passing INITIAL_TRIGGER_DWELL to the setInitialTrigger() method. This will only trigger a notification if the device is already inside the geofence for some time. You can set this time to a very large number. However this only works if you solely use GEOFENCE_TRANSITION_DWELL in the initial triggering and are otherwise not interested in adding a dwell notification.

Check this link: https://developers.google.com/android/reference/com/google/android/gms/location/GeofencingRequest#INITIAL_TRIGGER_ENTER

Upvotes: 1

Related Questions