Google Play Services: how to check if there is currently "active" pending intent callback registered to location updates/activity recognition?

Tal Kanel picture Tal Kanel · Aug 7, 2014 · Viewed 15.5k times · Source

my application perform periodic location updates and Activity recognition detection in background.

I'm doing that using the Google Play Services API's:

for example - to register to location updates, I provide pending intent to receive update:

mLocationClient.requestLocationUpdates(mLocationRequest, pendingInent);

to unregister to location update, I'm doing the following:

mLocationClient.removeLocationUpdates(pendingInent);

that's nice, and working great.

but how can I find out if there is currently a pendingIntent holding Intent to my application's component is currently registered in front of Google play services to receive location updates or not?

I notices that there is no API to check this, and the approach to check for pendingIntent existence seems not to work for API's against google play services - the pending intent stays exists even after I call the removeLocationUpdates() method.

I know I can save state (to shared preferences) indicating if now I'm registered or not, but it's not the right solution, and will be "buggy" because it can happen that google play process went down, lost the pendingIntent, but my process will still think that the location updates are "active"..

same problem exactly exists for the activity recognition updates.

Just to make it clear, all I want to do is provide to the users of my application ability to know if my app is currently collecting data in background or not, and provide them a way to toggle between that. So if there is other way to do that in reliable way - I'll except it as an answer also

reliable way = knowing if currently the pending intent really registered in from of google play services...

  • using LocationListener is not an option for me, because I must be able to receive updates event when my process is shout down - what's possible only using PendingIntent callback..

Thanks in advance.

UPDATE

this is the pendintIntent I provide to register and unregister to location updates:

Intent locationUpdatesIntent = new Intent(context, LocationUpdatesIntentService.class);
PendingIntent pendingInent = PendingIntent.getService(context, 0, locationUpdatesIntent, PendingIntent.FLAG_UPDATE_CURRENT);

and this is how I'm trying to check (unsuccessfully) if it registered or not:

Intent locationUpdatesIntent = new Intent(context, LocationUpdatesIntentService.class);
PendingIntent pendingInent = PendingIntent.getService(context, 0, locationUpdatesIntent, PendingIntent.FLAG_NO_CREATE);
boolean isLocationUpdatesEnabled = (pendingIntent != null);

isLocationUpdatesEnabled returns true event after I call removeLocationUpdates()

Answer

Manish Mulimani picture Manish Mulimani · Aug 15, 2014

Following are the scenarios when a PendingIntent is removed:

  • PendingIntent can be removed explicitly by calling PendingIntent.cancel, only by application which created it. From the docs:

Only the original application owning a PendingIntent can cancel it.

  • PendingIntent, if inactive i.e. not being used by other application, is removed by the system when the application terminates.
  • PendingIntent, if active i.e. being used by other application, is removed by the system only when the application package is uninstalled.

Hence calling removeLocationUpdates indicates the system that Google Location services no more references the PendingIntent. It does not remove it from the system. So you will have to call cancel on PendingIntent to remove it, which is absolutely fine.

mLocationClient.removeLocationUpdates(pendingInent);
pendingIntent.cancel();

//Now check whether PendingIntent exists.
Intent locationUpdatesIntent = new Intent(context, LocationUpdatesIntentService.class);
PendingIntent pendingInent = PendingIntent.getService(context, 0, locationUpdatesIntent, PendingIntent.FLAG_NO_CREATE);
boolean isLocationUpdatesEnabled = (pendingIntent != null);

Additional info from the docs:

A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it.