0

I'm setting up alarms using this code

//in onCreate()
mAlarmManager = (AlarmManager) getApplicationContext()
            .getSystemService(ALARM_SERVICE);

//called for each timer I schedule
Intent intent = new Intent (Intents.MY_INTENT_ACTION);
PendingIntent pendIntent = PendingIntent.getBroadcast(
    getApplicationContext(), alert.getID(), 
    intent, PendingIntent.FLAG_ONE_SHOT);
long delay = 1000 * alert.getDuration();
Calendar cal = Calendar.getInstance();
mAlarmManager.set(AlarmManager.RTC_WAKEUP,
    cal.getTimeInMillis() + delay, pendIntent);

But the behavior I'm seeing doesn't match what I should see in the documtation1,

public void set(int type, long triggerAtTime, PendingIntent operation)

If there is already an alarm scheduled for the same IntentSender, it will first be canceled...If there is already an alarm for this Intent scheduled (with the equality of two intents being defined by filterEquals(Intent)), then it will be removed and replaced by this one...

which suggests that calling set(int type, long triggetAtTime, PendingIntent operation) for an already alarmed intent should replace the old alarm for that intent. I'm not seeing any alarms get dropped. Instead, every alarm i set fires, despite the fact that the intents that are fired by the pending intents should all match (by filterEquals(intent)), since all I've set on each intent is an identical action.

Am I doing something wrong, or is the API not behaving as documented?

Note: changing the PendingIntent instantiation to

PendingIntent pendIntent = PendingIntent.getBroadcast(
getApplicationContext(), CONSTANT_ID,
intent, PendingIntent.FLAG_ONE_SHOT);

Behaves as expected, dropping any already set alarm, and replacing it with a new alarm.

Community
  • 1
  • 1
Chris Bye
  • 1,028
  • 7
  • 17

3 Answers3

0

Maybe it is because you are giving each alarm a different ID (Does alert.getID() give different ID's or not?). By the documentation, it shouldn't matter but yet you should still try.

If it doesn't work too, hold a reference for your last set alarm, and when you need it to be canceled, cancel it yourself then set the next one.

Jong
  • 9,045
  • 3
  • 34
  • 66
  • This is probably it. It does matter. A different ID means it's technically a different Intent. – kabuko Oct 31 '11 at 18:44
  • This is actually the funcationality I'm looking for, but it doesn't match what I expect from the docuentation, so it makes me suspect that my understanding is flawed somewhere. I added another sentence to the documentation quote indicating that the notion of reusing identical IntentSenders (PendingIntents) is addressed separately, and afaik, functioning normally. My question is whether AlarmManager looks at the intents generated by a PendingIntent, or just at the uniqueness of the PendingIntent – Chris Bye Oct 31 '11 at 18:49
  • The documentation says it mathces intents by filterEquals. filterEquals has nothing to do with PendingIntent so I'm not sure it matters. But he should test it. – Jong Oct 31 '11 at 18:50
  • Try to keep a reference to your last set alarm, so you can cancel it when needed. – Jong Oct 31 '11 at 18:58
  • Again, the current behavior, where multiple alarms use different PendingIntents to generate identical Intent for broadcast, is the desired functionality for my application. **However**, this does not match the behavior described in the documentation, and this worries me. I'm curious whether I'm wrong, or the documentation is wrong. Right now, it appears that Anrdoid compares at least the ID associated with a PendingIntent, and drops alarms for PendingIntents with matching IDs, but it does not compare whether the associated Intents are equal according to filterEquals(intent) – Chris Bye Oct 31 '11 at 19:05
  • 1
    I guess there is a problem in the documentation. I have found the documentation of the AudioManager to be "sort of" wrong, but I managed to fix it by holding a static reference to my AudioManager. Try to hold a static reference to your AlarmManager. I am holding a static reference to the AlarmManager in one of my apps, and it cancels matching intents with no problem. – Jong Oct 31 '11 at 19:11
  • Now that's just weird. I may experiment with holding a static reference, but since the observed misbehavior is actually my desired functionality (I was going to have to hack in something to make my intents NOT match), I'm mostly going to let it lie. Any thoughts on whether it's worthwhile to let someone know about this (and who to go to with it), or just let it go? There are a few acceptable workarounds to get desired behavior for any normal case i can come up with, so I don't think it's a big issue. – Chris Bye Oct 31 '11 at 19:22
  • Well, this is a serious bug IMO. In the AudioManager, if you lose your reference you can never again unmute a sound stream you have muted. This problem is serious, and if it happens in other "*Manager" objects, something has to be done. – Jong Oct 31 '11 at 19:32
  • Well, I'll see if i can make some noise on some boards, or yell at google about it. Hopefully we're just dumb and are reading the documentation wrong, but I'm not optimistic about that. This does have some implications about canceling alarms (or other managed PendingIntents), since you can't cancel on an Intent, just a PendingIntent. If there were applications that interacted more richly using pendingIntents, there could be some seriously weird behavior happening all over the place. – Chris Bye Oct 31 '11 at 20:11
0

Have you tried with PendingIntent flag : PendingIntent.FLAG_UPDATE_CURRENT intead of PendingIntent.FLAG_ONE_SHOT?

Kocus
  • 1,613
  • 17
  • 31
0

It appears the consensus is that the documentation for AlarmManager.set(), as well as other AlarmManager methods claiming that Intents (not just the wrapping PendingIntents) are compared to check whether a particular alarm is already set.

Do not rely on AlarmManager matching Intents, instead rely on the matching of PendingIntents, which appears to be working as advertised.

Chris Bye
  • 1,028
  • 7
  • 17