I am have a method that sets an alarm using information froma SQLite database i created.
public void scheduleItem(Long textId, Calendar when){
Intent i = new Intent(mContext, onAlarmReceiver.class);
i.putExtra(DbAdapter.KEY_ROWID, textId);
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, PendingIntent.FLAG_ONE_SHOT);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, when.getTimeInMillis(), pi);
Log.e("SchedulerManager", "Task scheduled");
Now as you see this responds to a database. Now if the an item in the database is deleted by a user. I dont want the alarm to still be set for a item that has been deleted.
How can i pull back the alarm using the Long textId that is taken as a parameter in my scheduleItem() method?
EDIT: I just created this method to cancel a currently pending intent.
Maybe this will do it.
public void cancelAlarm(Long textId){
Intent g = new Intent(mContext, onAlarmReceiver.class);
g.putExtra(SmsDbAdapter.KEY_ROWID, textId);
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, g, 0);
mAlarmManager.cancel(pi);
}
You have to invoke the cancel method: http://developer.android.com/reference/android/app/AlarmManager.html#cancel(android.app.PendingIntent)
with the same PendingIntent that you have setted before with alarm manager. (or better, an Intent that match what you have setted before)
Related
I'm trying to create a test of a method that clear some data in the database, cancel one existing AlarmManager (clearing the same PendingIntent) and deleting a file in the storage etc.
The test consist basically in three steps:
- Launch a method that create the alarms managers and put data into the database
- Launch the method that clear everything
- All the check
The test is failing when Robolectric try to create the pending intent with a NullPointerException.
#Test
public void testClearExpiredVideoDownloadedContent() {
mDatabase.post_action().addVideo(mVideoSample, StaticDbConfig.TableNames.DOWNLOADED_CONTENT);
//Run the method to create the timer for downloaded content into the database
int numberAlarmCreated = SuperBase.setUpContextExpireAlarm(mContext);
assertEquals("Alarm has not been created", 1, numberAlarmCreated);
//Run method to clear the expired content
mDatabase.delete_action().clearExpiredVideoContent(mContext, mVideoSample);
//ALL THE CHECKS
}
Method setUpContextExpireAlarm is crashing when i use the pending intent:
Intent intent = new Intent(context, ExpiredContentReceiver.class);
intent.putExtra(ExpiredContentReceiver.EXTRA_VIDEO_INFO, video);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, video.getId(), intent, PendingIntent.FLAG_NO_CREATE);
SimpleDateFormat format = new SimpleDateFormat(StaticAppConfig.MatDateFormat);
Date d = format.parse(video.getExpiryDate());
alarmMgr.setRepeating( //CRASHING HERE BECAUSE alarmIntent is null
AlarmManager.RTC_WAKEUP,
d.getTime(),
AlarmManager.INTERVAL_DAY,
alarmIntent);
EDIT
This is the method that create the alarm manager and pending intent:
public static int setUpContextExpireAlarm(Context context){
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
ArrayList<VideosV0> videosV0s = new DatabaseHandler(context, null).get_action().getNotExpiredDownloadedContent();
for(VideosV0 video : videosV0s){
try {
Intent intent = new Intent(context, ExpiredContentReceiver.class);
intent.putExtra(ExpiredContentReceiver.EXTRA_VIDEO_INFO, video);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, video.getId(), intent, PendingIntent.FLAG_NO_CREATE);
SimpleDateFormat format = new SimpleDateFormat(StaticAppConfig.MatDateFormat);
Date d = format.parse(video.getExpiryDate());
alarmMgr.setRepeating(
AlarmManager.RTC_WAKEUP,
d.getTime(),
AlarmManager.INTERVAL_DAY,
alarmIntent);
Logging.i("Setting up the alarm for content ["+video.getTitle()+" ("+video.getId()+")], the alarm will be triggered on ["+video.getExpiryDate()+"("+d.getTime()+")] ");
} catch (ParseException e) {
e.printStackTrace();
}
}
return videosV0s.size();
}
This call:
PendingIntent alarmIntent = PendingIntent.getBroadcast(context,
video.getId(), intent, PendingIntent.FLAG_NO_CREATE);
does not create a PendingIntent. If you specify PendingIntent.FLAG_NO_CREATE then no PendingIntent is created, it will only return one if there is already one there.
If you want to have multiple alarms, you need to make sure that the PendingIntent is unique. Remove the flag PendingIntent.FLAG_NO_CREATE and make sure to use either a unique ACTION on each Intent OR a unique requestCode in the call to PendingIntent.getBroadcast(). This will ensure that it creates a new one every time.
I am making an application that uses AlarmManager.setInexactRepeating() method, that takes a PendingIntent as a paramater.
I start this by calling my setAlarm() method
public void setRepeatingAlarm() {
Intent intent = new Intent(this, AlarmReceiver.class);
String url = getAssembledUrl();
intent.putExtra("url", url);
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
}
and stop it by stopAlarm()
private void stopRepeatingAlarm() {
alarmManager.cancel(pendingIntent);
pendingIntent.cancel();
}
Works just fine. However when activity gets destroyed, and user decides to stop the alarm, obviously the pending intent is null, as it gets created in the setRepeatingAlarm() method that wasnt called during current activities life.
Whats the correct way to get around this?
I could be creating the pending intent in Activity.onCreate() and that would solve this problem, however I will not be able to start the alarm again as the pending intent got canceled and needs to be recreated again (i think, unless there is a way to check the intent was canceled that i dont know about)
Actually, as it turns out
PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
returns the same pending intent, if the intent is the same so, all i needed was
private void stopRepeatingAlarm() {
if(pendingIntent == null) {
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
alarmManager.cancel(pendingIntent);
}
I am creating a repeating alarm. This works fine using the following code:
Intent intent = new Intent(this.ctx, AlarmReceiver.class);
intent.setAction("" + notificationId);
intent.putExtra(AlarmReceiver.TITLE, alarmTitle);
intent.putExtra(AlarmReceiver.SUBTITLE, alarmSubTitle);
intent.putExtra(AlarmReceiver.TICKER_TEXT, alarmTicker);
intent.putExtra(AlarmReceiver.NOTIFICATION_ID, notificationId);
PendingIntent sender = PendingIntent.getBroadcast(this.ctx, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = getAlarmManager();
am.setRepeating(AlarmManager.RTC_WAKEUP, triggerTime, 60000, sender);
Now I want to cancel an existing notification message (which pops up every minute for testing purposes), I invoke the following code, passing it an identical notificationId:
Intent intent = new Intent(this.ctx, AlarmReceiver.class);
intent.setAction("" + notificationId);
PendingIntent pi = PendingIntent.getService(this.ctx, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = getAlarmManager();
try {
am.cancel(pi);
} catch (Exception e) {
Log.e(PLUGIN_NAME, "AlarmManager update was not canceled. " + e.toString());
}
I see that pi != null, however the notification keeps coming and is not being cancelled. Both code snippets reside in the same class.
Basically I have two questions:
- How can I cancel a single alarm using its unique ID?
- How can I cancel all alarms, regardless of the ID?
UPDATE: I found that posting my issue here helps to get my mind straight. Changing the cancel code from:
PendingIntent sender = PendingIntent.getService( ... )
To:
PendingIntent sender = PendingIntent.getBroadcast( ... )
Helps to solve question 1. However the code to cancel all events, still does not work:
Intent intent = new Intent(this.ctx, AlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this.ctx, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = getAlarmManager();
am.cancel(pi);
I'm a noob here. But I think if you want to cancel the alarm, you have to use the exact same instance of PendingIntent. That means "their action, data, type, class, and categories are the same" as defined by filterEquals(Intent) . Therefore, you need to use the same requestCode here, not 0. Maybe you could use a list to store the Notification Ids, and iterate them to cancel all alarms.
I think , you should use same AlarmManager object to cancel the alram and also try to use same PendingIntent.
This is what sets the alarm
public void setSilent(Long taskId, Calendar when){
Intent i = new Intent(mContext, SilentReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(mContext, 1 , i, PendingIntent.FLAG_ONE_SHOT);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, when.getTimeInMillis(), pi);
It takes in an id and date to use with the intent.
I am canceling it in another file when the user clicks delete. using
Intent i = new Intent(null, SilentReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(null, 1 , i, PendingIntent.FLAG_ONE_SHOT);
should this work because it has the same request code as the first one or am I doing something wrong?
You have to save a reference to your first PendingIntent. This way you can use:
mAlarmManager.cancel(pi);
And the alarm should be cancelled.
This answer has been repeated many times. Please search before asking.
Be careful to send a PendingIntent to stop the alarm with the same data than the Intent to create the alarm: problem with cancel the alarm manager pending intent
I am trying to get a reminder/alarm Service` working in my note/todo app. I am able to set a reminder for a particular item and the alarm triggers and displays a notification successfully.
My problem is how can my Service know which note/todo item set that particular reminder. I'd like for the user to be able to click on the notificaiton in the status bar and have the item which trigger it come up. But I have no way of passing that information to the Service as they don't accept Bundles from the PendingIntent.
I currently set the alarm with the following:
private void createAlarm() {
Intent i = new Intent(this, AlarmService.class);
PendingIntent sender = PendingIntent.getService(this, 0, i, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, mReminderCal.getTimeInMillis(), sender);
}
I just need a way to send along the _id of the item in my database so my Service can launch the item with that same _id when the notification is clicked.
I hope my question isn't too confusing.
Thanks!
Why don't you put all your need into Intent data? Something like this:
final Intent intent = new Intent(context, UpdatesActivity.class);
intent.putExtra(ID, "foo");
final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
Then on receiving end you do
String id = getIntent().getStringExtra(ID);