Iterate scheduled PendingIntents in AlarmManager - android

I have created a PendingIntent in AlarmManager with a .putExtra("id", "myuniquevaluehere");
I want to be able to fetch this scheduled intent back from AlarmManager later and cancel it. Note that when I cancel the PendingIntent, I do not know information about it other than this extra 'id' value, so I can't recreate an exact PendingIntent of it to call AlarmManager.cancel().
Is there a way to iterate scheduled PendingIntents and check the getExtra("id") of each until I find a match?

Related

Can AlarmManager schedule more than one alarm from the same code?

If I allow my user to schedule a notification using AlarmManager, and then they schedule another notification using the same code, will the first alarm be overridden? Or will both alarms be set?
When creating a pendingIntent you have to include an id:
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, ID , intent, Flags)
If the number in the ID location is always the same, then the alarm will be overridden. If it is the same then it will not be.
You can use the same code, as long as the ID is different. You can achieve this in many ways, like creating an ID based on the time you schedule the alarm for, as you may not need two alarms for the same time.

Android - How to reschedule alarms associated to app events

I found a lot of examples and questions regarding how to fire an alarm using AlarmManager (both periodical or single), but nothing similar to what I need.
My user can schedule a certain number of events (i.e. things to do), with a single-shot alarm for each of them to be fired one day before the scheduled start (showing a notification). This is easy.
My problem is that this scheduled start can be changed, thus the alarm should be moved too.
I was thinking to delete the old alarm, and to create a new one considering the new scheduled start. Knowing that I can delete an alarm using alarmMgr.cancel(alarmIntent), how can I delete the specific alarm related to the rescheduling event? Should I make each alarmIntent unique in some way?
Or there is a better way that I didn't consider (except using Google Calendar APIs to schedule and reschedule an event there, and making it managing the notification)?
While scheduling an alarm using set() API
public void set (int type, long triggerAtMillis, PendingIntent operation)
in the last argument you can mention a request code using getBroadcast
public static PendingIntent getBroadcast (Context context, int requestCode, Intent intent, int flags)
an example for this would be :
alarm.set(AlarmManager.RTC_WAKEUP, time, PendingIntent.getBroadcast(mContext, id, intentAlarm, PendingIntent.FLAG_UPDATE_CURRENT));
When you want to cancel or reschedule you can use the 'id' to specify which alarm.

Android widget change alarm interval

I have created a configure activity for my widget, where the user can choose from various update frequencies.. Until now I started the alarm in the OnEnabled() method, like this:
Intent intent = new Intent(CLOCK_WIDGET_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), 1000 * 60,
pendingIntent);
The settings are saved in shared preferences with a unique name (widgetId) and in this OnEnabled() method I can't retrieve the settings here because I can't get the widgetId yet.
There's an another problem, the user can change the frequency anytime, but this method is called just once, at the beginning. So I think I need to start the alarm in OnUpdate(), but I don't know how to do it, I don't want to make multiple instances of an alarm accidentally so I would like to ask for some advice.
To answer your second problem, calling setRepeating multiple times will not create multiple alarm as far as you provide same PendingIntent and same request code along with PendingIntent.FLAG_UPDATE_CURRENT flag. I would also suggest to use setInexactRepeating instead of setRepeating. So you can use the same code in OnUpdate() too with new frequency. Go through docs of FLAG_UPDATE_CURRENT and setInexactRepeating for more detials.

PendingIntent throughout multiple Instances

I have implemented an Alarm class wich should set a new pending Intent and always overriwrite the old one. (I would rather stop/delete all old ones but I dont know how to)
private void startAlarm(){
Intent intent = new Intent(source, Alarm_Activity.class);
// 10000 should be the ID of Intent
PendingIntent pendingIntent = PendingIntent.getActivity(source, 10000, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager)source.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),pendingIntent);
}
Unfortionatly I create this class multiple times and from different activities. I think this is the reason why it doesnt cancel the last intent (Flag_cancel_current). How can I make the Flag work throughout multiple instances of this class?
Given your code, so long as all places are using the same Intent (pointing to Alarm_Activity.class) and are using the same PendingIntent ID (10000 in your sample), your code will cancel any current PendingIntent.
This does not cancel any current alarms.
To cancel an alarm, call cancel() on AlarmManager. In particular, if you do this, get rid of PendingIntent.FLAG_CANCEL_CURRENT, so your cancelling of the old PendingIntent does not somehow interfere with your cancelling of the old alarm tied to that PendingIntent.

AlarmManager.set(...) behavior not matching documentation. Am I doing something wrong?

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.
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.
Have you tried with PendingIntent flag : PendingIntent.FLAG_UPDATE_CURRENT intead of PendingIntent.FLAG_ONE_SHOT?
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.

Categories

Resources