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

15,928

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.

Share:
15,928
Tal Kanel
Author by

Tal Kanel

Programmer with a deep knowledge and understanding when it comes to object oriented programming and object oriented design. got most of the experience from developing .NET framework and Java applications, by using the right architectures and design patterns per each. plans for now to continue make my way as a young developer who becomes every day more and more professional and experienced in the field. Specialties: Android applications development and design for smart-phones and tablets, supporting OS versions: 2.1 (Eclair), 2.2 (Froyo), 2.3.X (Gingerbread), 3.X.X (Honeycomb), 4.0 (Ice cream sandwich) Programming Languages: Java, C#, C++, C IDEs: Eclipse, IntelliJ, Visual Studio.

Updated on June 29, 2022

Comments

  • Tal Kanel
    Tal Kanel almost 2 years

    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()

  • Tal Kanel
    Tal Kanel over 9 years
    as I mentioned, my problem is not to display to the user, but to know if it really registered right now to updates. I don't want to use foreground service with LocationListener , because then if my process went down - google won't be able to wake my application. that's why I must user pendingIntent as a callback, and not a LocationListener callback.
  • danny117
    danny117 over 9 years
    I thought I had everything covered ability to know if app is collecting data (notification) with a way provided to toggle (notification intent). Not collecting data no notification.
  • Tal Kanel
    Tal Kanel over 9 years
    Thank you very much for your answer. Besides the fact that I don't want to show to the user this undissmisable notification, this approach will not work for registration to location updates with pendingIntent callback, because pendingIntent can be still registred if my Service, and even my entire process is stopped
  • danny117
    danny117 over 9 years
    Sorry I couldn't help. Your going for pending intent so your process can be awakened by the location. That's a good reason. I'm just brain storming. You could putextra a sequential number in your pending intent. Store lastnumberreceived and lastnumbersent in static sequential variables and use the difference between the two to determine if intents have been lost.
  • Tal Kanel
    Tal Kanel over 9 years
    Thanks for sharing this ideas! I Appreciate it .. I'm hoping that there is more trivial and reliable/official straight forward solution without workaround tricks, and hope this bounty will bring this solution out
  • Tal Kanel
    Tal Kanel over 9 years
    your solution sounds good and promising, I'll try it as soon as I can, and came back to reward you if really adding pendingIntent.cancel() works as you desribed :->
  • Tal Kanel
    Tal Kanel over 9 years
    just checked it. looking great! as you said, calling cancel() seems to do the job! thank you very much for your answer!! I was already a bit skeptic there is really solution to that.. great to learn something new!