Alarm notification keeps firing even if it is canceled from another activity - android

I set an alarm from activity A then in activity B I can delete and update the alarm set in activity A. Updating of alarm is working but delete doesn't, I've already tried some answer from here but nothing seems to work.
I set my alarms like this.
public void Alarms() {
for(eventlist_model model:arrayList)
{
int id=model.getEvent_id();
String type=model.getEvent_type();
String date=model.getEvent_date();
String time=model.getEvent_time();
String note=model.getEvent_note();
SimpleDateFormat format= new SimpleDateFormat("yyyy-MM-dd HH:mm");
try{
String sched=date+" "+time;
Date newSched=format.parse(sched);
Calendar calendar1 = Calendar.getInstance();
calendar1.setTime(newSched);
if (calendar1.before(calendar))
calendar1.add(Calendar.DATE, 1);
Intent intent = new Intent(this, events_receiver.class).setAction("Dog_alarm");
intent.putExtra("type", type);
intent.putExtra("note", note);
intent.putExtra("id", id);
PendingIntent dog1 = PendingIntent.getBroadcast(this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
final AlarmManager alarm1 = (AlarmManager) getSystemService(ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= 19) {
alarm1.setExact(AlarmManager.RTC_WAKEUP, calendar1.getTimeInMillis(), dog1);
} else {
alarm1.set(AlarmManager.RTC_WAKEUP, calendar1.getTimeInMillis(), dog1);
}
}catch (Exception e)
{
e.printStackTrace();
}
}
}
then in activity B I use this to cancel the alarm
public void cancelTask()
{ int id=Integer.valueOf(eventid);
Intent intent = new Intent(update_task.this, events_receiver.class);
AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
PendingIntent task = PendingIntent.getBroadcast(this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarm.cancel(task);
}
But it doesn't work and Im stuck here. Can anyone help me in this?

According to documentation of cancel method of AlarmManager:
void cancel (PendingIntent operation)
Remove any alarms with a matching Intent. Any alarm, of any type,
whose Intent matches this one (as defined by filterEquals(Intent)),
will be canceled.
It means if intentA detected to be equal withintentB, using filterEqauls Method, i.e. intentA.filterEquals(intentB)==true, then intentB in alarmanger can be used to cancel intentA which already set inside alarmManager.
filterEquals documentation notices:
boolean filterEquals (Intent other)
Determine if two intents are the same for the purposes of intent
resolution (filtering). That is, if their action, data, type, class,
and categories are the same. This does not compare any extra data
included in the intents.
It means it filterEquals does not care to extras inside intents to compare them but other paramters like Action should be exactly the same.
In your case, you've missed to call setAction in cancellation intent.
So you should change your cancelTask method like this:
public void cancelTask()
{ int id=Integer.valueOf(eventid);
Intent intent = new Intent(update_task.this, events_receiver.class);
intent.setAction("Dog_alarm");//<--- this is missed
AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
PendingIntent task = PendingIntent.getBroadcast(this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarm.cancel(task);
}

Related

How to correctly cancel an AlarmClock alarm set by AlarmManager in the Clock app?

This question already has answers here, here and here. But they were not confirmed by OPs to be working, and in my case, the alarm set by the same PendingIntent doesn't get canceled. Is there a way to cancel an AlarmClock alarm?
#Override
protected void onHandleIntent(#Nullable Intent i) {
Intent i = new Intent(AlarmClock.ACTION_SET_ALARM);
i.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
i.putExtra(AlarmClock.EXTRA_HOUR, 6);
i.putExtra(AlarmClock.EXTRA_MINUTES, 0);
i.putExtra(AlarmClock.EXTRA_MESSAGE, "Good Morning");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
AlarmManager alarmMgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
PendingIntent alarmIntent = PendingIntent.getActivity(
this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
alarmIntent);
Log.d(TAG, "Alarm set");
try {
Thread.sleep(15000);
alarmMgr.cancel(alarmIntent);
Log.i(TAG, "Alarm canceled");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
This code outputs as expected:
Alarm set
Alarm canceled
But it does not cancel the alarm that was set. What am I doing wrong?
So, I found that I needed to use ACTION_DISMISS_ALARM instead of ACTION_SET_ALARM. It lets you cancel already set alarms in the alarm clock.
The answers here, here, and here suggested cancelling the PendingIntent which didn't work for me and was not confirmed to be working for the question authors either.
The explanation for why cancelling the PendingIntent from AlarmManager doesn't work, I think, could be that a PendingIntent is there to let you do something or send the intent later on. Once you've already done it (already sent the intent) you can't undo it. For example, you can cancel a notification, but can't undo opening the app from the notification (the intent or action performed) as it's already done. Moreover, in my case, it was another app that I needed to unset the alarm for so maybe I shouldn't have expected to be able to undo that action.
So in order to dismiss or cancel the alarm, you need to send a new intent with the action ACTION_DISMISS_ALARM.
Replacing the try/catch block as follows sets and cancels the alarm correctly for me:
try {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
return;
}
Thread.sleep(15000);
Intent ci = new Intent(AlarmClock.ACTION_DISMISS_ALARM);
ci.setData(i.getData());
alarmIntent = PendingIntent.getActivity(this, 0, ci, 0);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime(),
alarmIntent);
Log.i(TAG, "Alarm cancelled");
} catch (InterruptedException e) {
e.printStackTrace();
}
However, this only works for API level 23+ and doesn't let you SKIP_UI like in ACTION_SET_ALARM.
I had the same issue and I read those thread you mentioned in your question. Yes they don't work. That's how I managed to get it working:
Set Alarm:
public static void setAlarm(Context context, int requestCode, int hour, int minute){
AlarmManager alarmManager =( AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context//same context should be used when canceling the alarm
, AlarmReceiver.class);
intent.setAction("android.intent.action.NOTIFY");
//setting FLAG_CANCEL_CURRENT makes some problems. and doest allow the cancelAlarm to work properly
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1001, intent, 0);
Calendar time = getTime(hour, minute);
//set Alarm for different API levels
if (Build.VERSION.SDK_INT >= 23){
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
}
else{
alarmManager.set(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
}
Cancel Alarm:
public static void cancelAlarm(Context context, int requestCode){
AlarmManager alarmManager =( AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
//define the same intent and pending intent
Intent intent = new Intent(context//same activity should be used when canceling the alarm
, AlarmReceiver.class);
intent.setAction("android.intent.action.NOTIFY");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1001, intent, 0);
alarmManager.cancel(pendingIntent);
pendingIntent.cancel();
}
This works like a charm. The point is, for me, if I use the FLAG_CANCEL_CURRENT I couldn't cancel the alarm. When I deleted the flag and passed in 0 in my code, then I could successfully delete the alarm.
I am not sure about the other flags since I didn't try them. You can also try to change your flag or delete them.

Pending intent with different intent but same ID

I have two pending Intent to use with Alarm Manager one is:
Intent i = new Intent(context, TriggerAlarm.class);
PendingIntent pi =PendingIntent.getBroadcast(context,0,i,PendingIntent.FLAG_CANCEL_CURRENT);
and the other is:
Intent i = new Intent(context, TriggerNotification.class);
PendingIntent pi = PendingIntent.getBroadcast(context,0, i,PendingIntent.FLAG_CANCEL_CURRENT);
I use these two in different methods in my application
my question is:
Are these pendingIntents differnt from each other?? because the intents are different but the Ids are same
If I set alarm manager for each of these pending intent do both of them trigger or one replace another?
So the easy way is test it directly by yourself.
I have tested it on my computer and here is what i got:
Are these pendingIntents different from each other?? because the intents are different but the Ids are same
-Yes they are different each other although the Ids are same
If I set alarm manager for each of these pending intent do both of them trigger or one replace another?
-Both of them will be triggered
Here are my code for test, you can copy and try it by yourself
Copy this method to your activity, and call it
private void setAlarmManager() {
Log.v("AlarmManager", "Configuring AlarmManager...");
Intent startIntent1 = new Intent(context, AlarmReceiverFirst.class);
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, 0, startIntent1, PendingIntent.FLAG_CANCEL_CURRENT);
Intent startIntent2 = new Intent(context, AlarmReceiverSecond.class);
PendingIntent pendingIntent2 = PendingIntent.getBroadcast(context, 0, startIntent2, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 20);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Log.v("AlarmManager", "Starting AlarmManager for >= KITKAT version");
alarm.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent1);
alarm.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent2);
} else {
Log.v("AlarmManager", "Starting AlarmManager for < KITKAT version");
alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent1);
alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent2);
}
Log.v("AlarmManager", "AlarmManager has been started");
}
Create your first receiver class
public class AlarmReceiverFirst extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.v(this.getClass().getSimpleName(), "first alarm receiver is called");
}
}
Create your second receiver class
public class AlarmReceiverSecond extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.v(this.getClass().getSimpleName(), "second alarm receiver is called");
}
}
Register those receivers to your manifest
<receiver android:name=".AlarmReceiverFirst" />
<receiver android:name=".AlarmReceiverSecond" />
Not to be confused, what you called Id here is called request code. It is used for cancelling the pending intent.
Intents are just the action PendingIntent is bound to execute once it triggers. But this triggering criteria are entirely depending on PendingIntent itself and RequestCode is playing here a pretty good role to uniquely identify, manage and trigger PendingIntent.
Therefore, no matter what the Intent is, if the requestCode is repeated then the latter PendingIntent will trigger. If you need to trigger multiple PendingIntents, the requestCode must be different from each other.
You can have same name of intents but with different ids like following,
Intent i = new Intent(context, TriggerAlarm.class);
PendingIntent pi =PendingIntent.getBroadcast(context,System.currentTimeMillis(),i,PendingIntent.FLAG_CANCEL_CURRENT);
And
Intent i = new Intent(context, TriggerNotification.class);
PendingIntent pi = PendingIntent.getBroadcast(context,System.currentTimeMillis(), i,PendingIntent.FLAG_CANCEL_CURRENT);
This way both the intents would be distinguished differently from each other and will get triggered.You can have any unique id instead of System.currentTimeMillis()

Android testing Robolectric NullPointerException creating PendingIntent

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.

Creating Multiple Alarm?

Trying to create multiple Alarms using unique PendingIntent . However I am having trouble with this,
From MainActivity I press a button to set an Alarm, and the code for that is:
public void alarmSet(View view)
{
int idTime = (int) System.currentTimeMillis();
Intent intent = new Intent(MainActivity.this, AddAlarm.class);
intent.putExtra("pendInt",idTime);
startActivity(new Intent(MainActivity.this, AddAlarm.class));
}
Taking System time as unique id I am passing the value to the other activity from which I call the Broadcast to initiate alarm. Code for this Activity is:
Intent receive = getIntent();
pen = receive.getIntExtra("pendInt",0);
And here is the method in which I set the alarm.
private void setAlarm(Calendar targetCal)
{
Intent alarmintent = new Intent(AddAlarm.this, AlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(AddAlarm.this, pen, alarmintent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, targetCal.getTimeInMillis(), sender);
}
This works for single alarms , however it doesn't generate multiple alarms. What might be the possible reason? Any help will be appreciated. Do I need to post the Broadcast class as well ?
you are making Intent and putting extra but passing another Intent to startActivity()
just replace this
startActivity(new Intent(MainActivity.this, AddAlarm.class));
to this
startActivity(intent );

Cancel an AlarmManager pendingIntent in another pendingintent

I want cancel AlarmManager which define a service,in this service might start a new AlarmManger or cancel alarm that defined before.And I know the params pendingintent in alarmManager.cancel(PendingIntent),must be the same.compare with filterEquals(Intent other)
but It still not work.cancel failed.
here is my code
public class GetRoundStroe {
private Store[] stores;
private Context mContext;
public GetRoundStroe(Context mContext) {
this.mContext = mContext;
}
public Store[] getStores() {
if (ComCommand.haveInternet(mContext)) {
start_am_normal();
} else {
start_am_silence();
}
return stores;
}
public Store[] start_am_silence() {
long firstTime = SystemClock.elapsedRealtime();
AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
if (AlarmHolder.mAlarmNormal != null) {
am.cancel(AlarmHolder.mAlarmNormal);
}
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
firstTime, TestSwitch.getInstance().getSilence_time(), AlarmHolder.mAlarmSilence);
return null;
}
public Store[] start_am_normal() {
long firstTime = SystemClock.elapsedRealtime();
AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
if (AlarmHolder.mAlarmSilence != null) {
MyLog.e(GetRoundStroe.class,"AlarmHolder.mAlarmSilence"+AlarmHolder.mAlarmSilence+"");
am.cancel(AlarmHolder.mAlarmSilence);
}
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
firstTime, TestSwitch.getInstance().getNormal_time(), AlarmHolder.mAlarmNormal);
return null;
}
private static final class AlarmHolder {
static final PendingIntent mAlarmSilence = PendingIntent.getService(ApplicationContext.getInstance(),
0,
new Intent(ApplicationContext.getInstance(), GetRoundSilenceService.class),
0);
static final PendingIntent mAlarmNormal = PendingIntent.getService(ApplicationContext.getInstance(),
0, new
Intent(ApplicationContext.getInstance(), GetRoundNormalService.class),
0);
}
}
GetRoundSilenceService and GerRoundNormalService invoke start_am_normal() or start_am_silence; Anyone could help me? thanks
myIntent = new Intent(SetActivity.this, AlarmActivity.class);
pendingIntent = PendingIntent.getActivity(CellManageAddShowActivity.this,
id, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
pendingIntent.cancel();
alarmManager.cancel(pendingIntent);
These lines of code surely can help you remove/cancel the pending intent and alarm.
The main thing that you will need is:
Create pending intent with the same id and appropriate intent FLAG.
Cancel that pending intent.
Cancel the alarm using alarm manager.
#MKJParekh answer is correct, however I would like to add more information so that we all know what will work and what will not.
Lets say on activityA you create and set the AlarmManager to open activityC in 30 seconds, then on some other activity which can be any, we want to cancel that AlarmManager. Thus, we would do the following;
in activityA we create and set the AlarmManager;
//activityA
Intent myIntentA = new Intent(actvityA.this, activityB.class)
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent myPendingIntent = PendingIntent.getActivity(activityA.this, 0, myIntentA, PendingIntent.FLAG_ONE_SHOT);
//Calendar with the time we want to fire the Alarm
Calendar calendar = Calendar.getInstance(); // Get Current Time
calendar.add(Calendar.SECOND,30); //Fire Alarm in 30 seconds from Now.
((AlarmManager)getSystemService(ALARM_SERVICE)).setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), myPendingIntent);
in Another Activity some time later we want to cancel such AlarmManager created in activityA which we have no access to. Lets call this current activity activityZ;
//activityZ
Intent myIntentZ = new Intent(activityZ.this, activityB.class);
PendingIntent pendingIntentZ = PendingIntent.getActivity(activityZ.this, 0, myIntentZ, PendingIntent.FLAG_ONE_SHOT);
((AlarmManager)getSystemService(ALARM_SERVICE)).cancel(pendingIntentZ);
Some important points,
The context we provide in activityA in new Intent(context) and getActivity(context) are the same, however they do not have to match the activity from where we are canceling the AlarmManager, in this case activityZ has another context.
The class we want to open with the AlarmManager has to be the same in both activities new Intent (context, activityB.class), the requestCode which is an int must be the same, I used 0 for this example. Finally the flag has to be the same in both activities PendingIntent.FLAG_ONE_SHOT.
myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); was used because PendingIntent.getActivity requires it if we are starting an activity outside of a context of an existing activity.

Categories

Resources