I'm writing an application with multiple alarms and I want to have an option to cancel them. I'm using AlarmManager and PendingIntent. My problem is that when I want to cancel an alarm, getBroadcast don't find a PendingIntent matching the criteria.
private void turnOnMorningRemider()
{
long time = System.currentTimeMillis() + 60 * 45;
Intent tmpIntent = new Intent(this, AlarmPopUpDialog.class);
tmpIntent.putExtra(getString(R.string.alarm_time_of_day), AlarmPopUpDialog.REQUEST_CODE_MORNING);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntent(tmpIntent);
// Gets a PendingIntent containing the entire back stack
morningPendingIntent = stackBuilder.getPendingIntent(AlarmPopUpDialog.REQUEST_CODE_MORNING, PendingIntent.FLAG_ONE_SHOT);
//set the alarm for particular time
alarmManager.set(AlarmManager.RTC_WAKEUP, time, morningPendingIntent);
Toast.makeText(this, "Alarm is on.", Toast.LENGTH_LONG).show();
}
To cancel alarm I use:
private void turnOffMorningReminder()
{
Intent tmpIntent = new Intent(this, AlarmPopUpDialog.class);
PendingIntent pi = PendingIntent.getBroadcast(this, AlarmPopUpDialog.REQUEST_CODE_MORNING,
tmpIntent, PendingIntent.FLAG_NO_CREATE);
if (pi != null)
{
alarmManager.cancel(pi);
Toast.makeText(this, "Alarm is off.", Toast.LENGTH_LONG).show();
}
}
The pi variable is always null, so alarm starts ringing.
The next problem is, when I try to create PendingIntent with getBroadcast (instead of stack builder) my alarm never activates.
morningPendingIntent = PendingIntent.getBroadcast(this, AlarmPopUpDialog.REQUEST_CODE_MORNING, tmpIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Is using the stack builder the reason why i can't find the intent?
I feel stupid. My problem was that my AlarmPopUpDialog extended Activity not BroadcastReceiver class. When I added a class that extened BroadcastReceiver in the middle everything started to work.
morningPendingIntent = PendingIntent.getBroadcast(this, AlarmBrodcastReceiver.REQUEST_CODE_MORNING, tmpIntent, PendingIntent.FLAG_UPDATE_CURRENT);
and
public class AlarmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Intent i = new Intent(context, AlarmPopUpDialog.class );
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtras(intent);
context.startActivity(i);
}
}
I hope that this answer will help the next poor guy.
Related
I've got a button in a list item to delete the item. When there is an alarm linked to the item I want to delete the alarm too.
To delete the item I show an alert dialog, with the delete function in the positive button:
builder.setPositiveButton("DELETE", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
DeleteList del = new DeleteList();
del.execute(listId);
}
});
But I need to delete the alarm too, and the problem is the alarm is set in another activity. I have the unique id for the PendingIntent, but I can't create the PendingIntent because I'm in a static context.
If I do:
AddListActivityFragment.deleteAlarmS(alarmId);
I get Non-static method cannot be referenced from static context.
If I do:
Intent resultIntent = new Intent(AddListActivity.this, MainActivity.class);
PendingIntent deleteIntent = PendingIntent.getBroadcast(AddListActivity.this, Integer.parseInt(alarmId), resultIntent, PendingIntent.FLAG_NO_CREATE);
if(deleteIntent != null) {
AlarmManager alarmManager = (AlarmManager) AddListActivity.this.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(deleteIntent);
deleteIntent.cancel();
}
I get "AddListActivity is not an enclosing class".
How can I solve this? How can I cancel the alarm? Do I sent some broadcast with the id that is received by AddListActivity?
Thanks
Thanks to qbix, I managed to make the method in AddListActivityFragment static. But it still doesn't cancel the alarm.
How the alarm is set in AddListActivityFragment:
private void scheduleNotification(Notification notification, long delay, int alarmId) {
Intent notificationIntent = new Intent(mContext, NotificationPublisher.class);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, alarmId);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, alarmId, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
Log.v("alarm id", "alarmid = " + alarmId);
long futureInMillis = SystemClock.elapsedRealtime() + delay;
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, futureInMillis, pendingIntent);
}
private Notification getNotification(String content, String subText, int alarmId) {
Uri uri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
long[] vib = new long[]{1000L, 1000L, 1000L, 1000L};
Intent resultIntent = new Intent(mContext, MainActivity.class);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
mContext,
alarmId,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
builder.setContentTitle("To do!");
builder.setContentText(content);
builder.setSubText(subText);
builder.setSound(uri);
builder.setVibrate(vib);
builder.setSmallIcon(R.drawable.ic_add_white_24dp);
builder.setAutoCancel(true);
builder.setContentIntent(resultPendingIntent);
return builder.build();
}
alarm set with:
scheduleNotification(getNotification(title, subText, alarmId), delay, alarmId);
How I try to cancel the alarm:
public static void deleteAlarm(String alarmId){
Toast.makeText(mContext, "delete alarm active", Toast.LENGTH_SHORT).show();
Log.v("alarm id delete", "alarmid = " + alarmId);
Intent resultIntent = new Intent(mContext, NotificationPublisher.class);
PendingIntent deleteIntent = PendingIntent.getBroadcast(mContext, Integer.parseInt(alarmId), resultIntent, PendingIntent.FLAG_NO_CREATE);
if(deleteIntent != null) {
Toast.makeText(mContext, "Alarm deleted", Toast.LENGTH_SHORT).show();
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(deleteIntent);
deleteIntent.cancel();
}
}
The "delete alarm active" Toast shows up, and the alarmId is the right one. But the Toast "alarm deleted" doesn't show and the alarm still goes off. Isn't the PendingIntent the same?
Thanks
In your AddListActivity, declare a private static member of type Context:
private static Context mContext;
In the onCreate() method of AddListActivity, initialize it:
mContext = this;
In the code block to build the PendingIntent and cancel the alarm, replace AddListActivity.this with mContext.
I solved it.
Apparently the PendingIntent needs the same flag, so when I changed it to PendingIntent.FLAG_ONE_SHOT in the deleteAlarm method it worked.
Thanks for the help.
I schedule Alarm from Activity like.
private AlarmManager mAlarmManager;
mAlarmManager = (AlarmManager) ACT_ActiveSession.getAppContext()
.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(mContext, LocalNotification.class);
intent.putExtra("alertBody", "");
intent.putExtra(K.SESSIONID, "");
intent.putExtra("TIME", "");
intent.putExtra("BATCHNO","");
intent.putExtra("REQUEST_CODE", "");
PendingIntent pendingIntent = PendingIntent.getBroadcast(
ACT_ActiveSession.getAppContext(), REQUEST_CODE, intent, 0);
mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, finishTime,
pendingIntent);
// alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, finishTime,
// (1 * 1000), pendingIntent);
intent.putExtra("",""); only used for some task on BroadcastReceiver
And Cancel Alarm From Fragment
private AlarmManager mAlarmManager;
mAlarmManager = (AlarmManager) mActivity
.getSystemService(Context.ALARM_SERVICE);
Intent updateServiceIntent = new Intent(mActivity,
ACT_Home.class);
PendingIntent pendingUpdateIntent = PendingIntent.getBroadcast(
mActivity, REQUEST_CODE,
updateServiceIntent, 0);
pendingUpdateIntent.cancel();
// Cancel alarms
if (pendingUpdateIntent != null) {
mAlarmManager.cancel(pendingUpdateIntent);
Log.e("", "alaram canceled ");
} else {
Log.e("", "pendingUpdateIntent is null");
}
But Alarm Manager is not cancelled.
Here i change mActivity = MyActivity's static getApplicationContext(); and also change different Flags and different Context.
Also I refer many answer. But doesn't work any code. Link1 Link2 Link3
please give me solution as soon as possible.
and apologize for my bad English.
You create the alarm using this Intent:
Intent intent = new Intent(mContext, LocalNotification.class);
But you try to cancel it using this Intent:
Intent updateServiceIntent = new Intent(mActivity, ACT_Home.class);
These Intents do not match, so the cancel does nothing. If you want to cancel the alarm you need to use an Intent in the cancel call that matches the Intent you used to schedule the alarm.
I am trying to stop the alarmManager in the MainActivity from the onBackPressed() method in the Map activity. I have tried the code below but the alarmManager is not being stoped and still firing. How can I fix it?
Code in the MainActivity:
Intent intent = new Intent(MainActivity.this, GetLLRD.class);
intent.putExtra("json_data", json);
PendingIntent pendingIntent = PendingIntent.getService(
getApplicationContext(), 123, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
alarm.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), 20 * 1000, pendingIntent);
startService(intent);
Code in the Map Activity:
#Override
public void onBackPressed() {
Intent intent = new Intent(Map.this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getService(
getApplicationContext(), 123, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pendingIntent);
}
u problem is u use two different classes for intent to create and stop alarm:
Intent intent = new Intent(context,
GetLLRD.class);
Intent intent = new Intent(context,
MainActivity.class);
/** as in source code - new intent constructor */
public Intent(Context packageContext, Class<?> cls) {
mComponent = new ComponentName(packageContext, cls);
}
if u want to check if u got the same pending intent as before you can try to use:
Intent.filterEquals(oherIntent);
to cancel alarm you have two options use flag or use the same intent on alarm:
PendingIntent.FLAG_CANCEL_CURRENT
& i advice to make pending intent as final - example:
/**
* create pending intent
*/
final PendingIntent pIntent(Intent alarmIntent) {
// Create a PendingIntent to be triggered when the alarm goes off
return PendingIntent.getBroadcast(getApplicationContext(), AlarmReceiver.REQUEST_CODE,
alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
* cancel alarm
*/
public void cancelAlarm(Intent alarmIntent, Context context) {
try {
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
/** use flag cancel here */
PendingIntent pIntent = PendingIntent.getService(context, AlarmReceiver.REQUEST_CODE, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
/** cancel alarm */
alarm.cancel(pIntent);
} catch (Exception e) {
// handle exception here
}
}
why to make pending intent final ?
because to cancel alarm u need:
Create pending intent with the same id and appropriate intent FLAG.
(to get reference to current pending intent)
PendingIntent.getBroadcast(context, REQUEST_CODE, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Cancel that pending intent.
PendingIntent.cancel();
Cancel the alarm using alarm manager.
AlarmManager.cancel(PendingIntent);
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.
if you are using activity, use
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
12345, intent,0);
I use AlarmManager and try to give some values in putExtra to my BroadcastReceiver. The values I send go to the BroadcastReceiver, it works fine to transmit values.
But I send my variable "counter" and I always get the old values that existed on the first start of my setRepeating(). And I know that the counter values are ways more high that I see there. So when the values change nothing happens. How can I have an event every half hour with right values?!
I've searched now for 3 hours but can't find a solution to make an interaction of my AlarmManager and some values out of a Sensor...
public void startAlarm(View view) {
try {
AlarmManager alarms = (AlarmManager) this
.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getApplicationContext(),
MyAlarmReceiver.class);
intent.putExtra("startStepCounter", startStepCounter);
intent.putExtra("lastStepCounter", lastStepCounter);
final PendingIntent pIntent = PendingIntent.getBroadcast(this,
1234567, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarms.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), timeToAlarmMilli, pIntent);
} catch (Exception e) {
}
}
public class MyAlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Alarm Receiver", "Entered");
//
Bundle bundle = intent.getExtras();
int local_start = bundle.getInt("startStepCounter");
int local_last = bundle.getInt("lastStepCounter");
Toast.makeText(context,
"ALARM " + local_start + " " + local_last,
Toast.LENGTH_SHORT).show();
}
}
look at this part of your code
final PendingIntent pIntent = PendingIntent.getBroadcast(this,
1234567, intent, PendingIntent.FLAG_CANCEL_CURRENT);
you need to provide uniuque id for secound part each time you use pending intent, so instead of 1234567, use a unique id.
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);
}