Geofences not triggering (pendingintents and broadcastreceiver)
Asked Answered
K

2

7

I've used the Android tutorial with Geofences which, obviously, doesn't work when app is closed. So, after searching around, I've noticed user b-ryce on SO used BroadcastReceiver so geofences get triggered even if app is not active (link for his SO question).

I just cannot force geofences to trigger when I move outside/inside registered location. Here's my procedure:

    /**
     * GeoLocation library
     */
    mGeoLocation = new GeoLocation(sInstance);


    /**
     * mReceiver init
     */
    mReceiver = new Receiver();
    sInstance.registerReceiver(mReceiver, mReceiver.createIntentFilter());

And inside GeoLocation class:

/*
 * Create a PendingIntent that triggers an IntentService in your
 * app when a geofence transition occurs.
 */
protected PendingIntent getTransitionPendingIntent() {
    if (mGeoPendingIntent != null) {
        return mGeoPendingIntent;
    }

    else {

        // Create an explicit Intent
        //  Intent intent = new Intent(mContext,
        //          ReceiveTransitionsIntentService.class);

        Intent intent = new Intent(getClass().getPackage().getName() + ".GEOFENCE_RECEIVE");

        /**
         * Return the PendingIntent
         */
        return PendingIntent.getBroadcast(
                mContext,
                0,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT);

    }
}

Here's how I create new geofence:

                        Geofence fence = new Geofence.Builder()
                                .setRequestId(hashCode)
                                        // when entering this geofence
                                .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
                                .setCircularRegion(
                                        Double.parseDouble(single.getSetting("latitude")),
                                        Double.parseDouble(single.getSetting("longitude")),
                                        Float.parseFloat(single.getSetting("radius")) // radius in meters
                                )
                                .setExpirationDuration(Geofence.NEVER_EXPIRE)
                                .build();

                        mGeofences.add(fence);

Array gets populated and we call AddGeofences method inside Geofence class

mGeoLocation.AddGeofences(mGeofences);

AndroidManifest.xml for reciever class:

    <!-- RECEIVER -->
    <receiver android:name=".Receiver" >
    </receiver>

And the Receiver class should just log when geofence triggers

public void onReceive(Context context, Intent intent) {
    String action = intent.getAction();

    Log.d("sfen", "Broadcast recieved "+ action +" but not needed.");
}

The problem is, that Geofence are triggering ONLY when I open map inside my app where I pick the locations. Closing the app (running it in background) doesn't trigger anything and geofence transitions don't trigger anything.

Can someone tell me what am I doing wrong?

Kit answered 9/9, 2014 at 19:32 Comment(8)
Does the geofence trigger when you open another app that uses geolocation? For example, if you set your geofence, close your app, then open Google Maps and move into, or out of, the geo fenced area. Does this trigger the geo fence?Irisation
@RussWilde - yes, when i moved my app in background and opened Google Maps, both of my actions get triggered.Kit
That's unfortunate to hear; I've had very mixed results with geo fences, including in other apps like IFTTT and Field Trip, every time I was wondering why some geo fences just weren't triggered reliably and I had guessed that Android's underlying location service just wasn't updating frequently enough to catch every location. Sadly I don't have a useful solution, if this is the case, but I am also interested in any answers others can offer.Irisation
@Kit - hi do u mind sharing as to how you made this work eventually ?Pyx
@Rat-a-tat-a-tatRatatouille Until today, I wasn't able to find the proper solution. Contacting google location services developers didn't worked either (since noone replied).Kit
@Kit - thats sad how did u go abt doing it then ??Pyx
I'll create a new github project with only one activity, one background service and one reciever. Putting in static geolocations and lets see if that will work. Also, github.com/chenjishi/android_location_demo this project doesn't work at all.Kit
I too have the same result. Geofence is only triggered when I open a map in my app. Will add this question to favorites.Fluke
A
0

you should use IntentService to receive geofencing event(not receiver).I wrote a demo at https://github.com/chenjishi/android_location_demo.

1.first define LocationClient

    private LocationClient locationClient;

2.init it

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    if (resp == ConnectionResult.SUCCESS) {
        locationClient = new LocationClient(this, this, this);
        locationClient.connect();
    }
}

3.when connect success, register geofences

@Override
public void onConnected(Bundle bundle) {
    ArrayList<Store> storeList = getStoreList();
    if (null != storeList && storeList.size() > 0) {
        ArrayList<Geofence> geofenceList = new ArrayList<Geofence>();
        for (Store store : storeList) {
            float radius = (float) store.radius;
            Geofence geofence = new Geofence.Builder()
                    .setRequestId(store.id)
                    .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
                    .setCircularRegion(store.latitude, store.longitude, radius)
                    .setExpirationDuration(Geofence.NEVER_EXPIRE)
                    .build();

            geofenceList.add(geofence);
        }

        PendingIntent geoFencePendingIntent = PendingIntent.getService(this, 0,
                new Intent(this, GeofenceIntentService.class), PendingIntent.FLAG_UPDATE_CURRENT);
        locationClient.addGeofences(geofenceList, geoFencePendingIntent, this);
    }
}

4.finally define the IntentService to receive geofencing event

public class GeofenceIntentService extends IntentService {
public static final String TRANSITION_INTENT_SERVICE = "ReceiveTransitionsIntentService";

public GeofenceIntentService() {
    super(TRANSITION_INTENT_SERVICE);
}

@Override
protected void onHandleIntent(Intent intent) {
    if (LocationClient.hasError(intent)) {
        //todo error process
    } else {
        int transitionType = LocationClient.getGeofenceTransition(intent);
        if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER ||
                transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
            List<Geofence> triggerList = LocationClient.getTriggeringGeofences(intent);

            for (Geofence geofence : triggerList) {
                generateNotification(geofence.getRequestId(), "address you defined");
            }
        }
    }
}

private void generateNotification(String locationId, String address) {
    long when = System.currentTimeMillis();
    Intent notifyIntent = new Intent(this, MainActivity.class);
    notifyIntent.putExtra("id", locationId);
    notifyIntent.putExtra("address", address);
    notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationCompat.Builder builder =
            new NotificationCompat.Builder(this)
                    .setSmallIcon(R.drawable.dac_logo)
                    .setContentTitle(locationId)
                    .setContentText(address)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true)
                    .setDefaults(Notification.DEFAULT_SOUND)
                    .setWhen(when);

    NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify((int) when, builder.build());
}

}

Application answered 12/9, 2014 at 8:4 Comment(4)
Hi. As stated and I will also quote b-ryce's reply: So after playing around with this a bit, it looks like the ReceiveTransitionsIntentService as defined in the sample code will stop getting the notifications when the app is not around. I think this is a big problem with the example code. So it looks like there are VERY mixed results using Geofences. Still not sure why this sometimes is working for some and always working for others...Kit
@Kit did you ensured that your phone's location service checkbox is checked??? Geofencing need location service enabled, you should give user a guide to enable it.Application
I did. I did noticed, however on one of the phones, since I've upgraded it from 4.4.2 to 4.4.4 to work better. Will test more and post results (if any)Kit
@JishiChen Can you take a look on this question please?Receiver
A
0

I see 2 problems. The first is that you aren't creating the PendingIntent properly. Looks like you are doing this:

    // Create an explicit Intent
    //  Intent intent = new Intent(mContext,
    //          ReceiveTransitionsIntentService.class);

    Intent intent = new Intent(getClass().getPackage().getName() + ".GEOFENCE_RECEIVE");

First of all, the comment is incorrect. This is NOT an "explicit Intent". This generates an Intent that only contains an ACTION. You need an "explicit Intent" that launches your BroadcastReceiver.

You need to do this instead:

    Intent intent = new Intent(mContext, Receiver.class);

Second problem is that you need to allow your BroadcastReceiver to be launched by other apps. For that, you need to declare it "exported" in the manifest. Change your manifest entry to this:

<!-- RECEIVER -->
    <receiver android:name=".Receiver"
              android:exported="true"/>
Aberration answered 11/6, 2023 at 18:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.