75

I'm setting an alarm like this:

alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, pendingEvent);

I'm interested in removing all the alarms that where previously set, clearing them.

Is there a way for me to do that or to get all the alarms that are currently set so that I can delete them manually ?

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
bluediapente
  • 3,946
  • 5
  • 32
  • 38
  • 8
    This guys shows how to list current alarms: http://stackoverflow.com/questions/6522792/get-list-of-active-pendingintents-in-alarmmanager – slott Jan 14 '12 at 15:21

5 Answers5

87

You don't have to keep reference to it. Just define a new PendingIntent like exactly the one that you defined in creating it.

For example:

if I created a PendingIntent to be fired off by the AlarmManager like this:

Intent alarmIntent = new Intent(getApplicationContext(), AlarmBroadcastReceiver.class);
alarmIntent.setData(Uri.parse("custom://" + alarm.ID));
alarmIntent.setAction(String.valueOf(alarm.ID));
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

PendingIntent displayIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, 0);

alarmManager.set(AlarmManager.RTC_WAKEUP, alarmDateTime, displayIntent);

Then somewhere in your other code (even another activity) you can do this to cancel:

Intent alarmIntent = new Intent(getApplicationContext(), AlarmBroadcastReceiver.class);
alarmIntent.setData(Uri.parse("custom://" + alarm.ID));
alarmIntent.setAction(String.valueOf(alarm.ID));
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

PendingIntent displayIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, 0);

alarmManager.cancel(displayIntent);

The important thing here is to set the PendingIntent with exactly the same data and action, and other criteria as well as stated here http://developer.android.com/reference/android/app/AlarmManager.html#cancel%28android.app.PendingIntent%29

Ziem
  • 6,579
  • 8
  • 53
  • 86
gilsaints88
  • 1,160
  • 8
  • 10
  • 7
    +1 for alarmIntent.setData(Uri.parse("custom://" + alarm.ID)); alarmIntent.setAction(String.valueOf(alarm.ID)); – dharmendra Apr 05 '13 at 14:26
  • 1
    @gilsaints88 : can you explain me, what is the function of alarm.ID and how can I declare that in both of my activity ? – mas_bejo Jan 06 '14 at 02:47
  • 2
    @mas_bejo the alarm.ID on setData(...) is for uniqueness of alarm so that we can clear any previously set alarm with same alarm.ID while the setAction(...) was used so that the intent passed from a notification is the right value when returned to an Activity via onNewIntent(). I use setData and setAction when setting up my alarm and when I'm receiving it from my Activity coming from notification I get the intent by overriding onNewIntent of Activity. the intent I get is the correct one because of setAction(...) earlier. I hope this helps. – gilsaints88 Jan 20 '14 at 18:23
  • Hi, By setData and SetAction notification get cancelled in my OPPO phone but its not get cancelled in my MOTO phone. Can you please suggest. – Nirav Patel Nov 08 '16 at 11:10
  • @NiravPatel may I ask what Android version is your OPPO and what Android version is your MOTO? Thanks – gilsaints88 Nov 12 '16 at 07:04
  • @gilsaints88 : OPPO having 5.1.1 & MOTO having 6.0 – Nirav Patel Nov 15 '16 at 06:05
  • If you wanna create multiple Alarms you should have multiple pending Intents with different ids. So you should save the ids and for next cancellations. – Mohammad H Aug 07 '17 at 13:39
68

You need to create your pending intent and then cancel it

 AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

    Intent updateServiceIntent = new Intent(context, MyPendingIntentService.class);
    PendingIntent pendingUpdateIntent = PendingIntent.getService(context, 0, updateServiceIntent, 0);

    // Cancel alarms
    try {
        alarmManager.cancel(pendingUpdateIntent);
    } catch (Exception e) {
        Log.e(TAG, "AlarmManager update was not canceled. " + e.toString());
    }
Alex Volovoy
  • 67,778
  • 13
  • 73
  • 54
  • 1
    Correct. It is not possible to query the AlarmManager for existing PendingIntents. You have to keep a reference on them. – Emmanuel Nov 30 '10 at 17:27
  • 44
    No reference needed. alarmManager.cancel cancels all of them docs: 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. – Alex Volovoy Nov 30 '10 at 17:32
  • 5
    How do keep the reference to them I store everything in database So how do i keep reference to it ? – Arjit Sep 14 '11 at 08:41
  • 8
    What if my intent has some extra value or bundle ... do i need to create the same intent with the same extra value to be able to cancel the intent? – FinalDark Dec 07 '13 at 19:46
  • 2
    also need to perform pendingUpdateIntent.cancelt() to make it work completely – Soham Feb 20 '14 at 23:41
  • 13
    @FinalDark extras are not considered when matching `Intent`s, so it makes no difference what extras were in the `Intent` when you created it. You can cancel the alarm by using an `Intent` without extras. – David Wasser Mar 03 '14 at 11:15
  • What if I lost the references to the pending intents? They are going to be enabled forever until user restarts her device? – Jesus Almaral - Hackaprende Nov 01 '17 at 21:42
  • @JesusAlmaral you would build the pending intent using the same Id, note you don't create pending intents, you "get" them. You only need to keep references to the ID, let Android handle the pending intent bit. – RobVoisey Jun 06 '18 at 13:26
26

To cancel an alarm you need to re-create the same PendingIntent and pass the same request code.

So, I have created an AlarmUtils to help me saving all the request codes in the preferences to cancel it in the future if it is needing. All you need is to use the following class and call the following methods:

  • addAlarm to add a new alarm and pass a request code.
  • cancelAlarm to remove an alarm, you need to re-create the same
    Intent and pass the same request code.
  • hasAlarm to verify if that alarm as added, you need to re-create the same Intent and pass the same request code.
  • cancelAllAlarms to remove ALL alarms setted.

My AlarmUtils

public class AlarmUtils {

    private static final String sTagAlarms = ":alarms";

    public static void addAlarm(Context context, Intent intent, int notificationId, Calendar calendar) {

        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        } else {
            alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
        }

        saveAlarmId(context, notificationId);
    }

    public static void cancelAlarm(Context context, Intent intent, int notificationId) {
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        alarmManager.cancel(pendingIntent);
        pendingIntent.cancel();

        removeAlarmId(context, notificationId);
    }

    public static void cancelAllAlarms(Context context, Intent intent) {
        for (int idAlarm : getAlarmIds(context)) {
            cancelAlarm(context, intent, idAlarm);
        }
    }

    public static boolean hasAlarm(Context context, Intent intent, int notificationId) {
        return PendingIntent.getBroadcast(context, notificationId, intent, PendingIntent.FLAG_NO_CREATE) != null;
    }

    private static void saveAlarmId(Context context, int id) {
        List<Integer> idsAlarms = getAlarmIds(context);

        if (idsAlarms.contains(id)) {
            return;
        }

        idsAlarms.add(id);

        saveIdsInPreferences(context, idsAlarms);
    }

    private static void removeAlarmId(Context context, int id) {
        List<Integer> idsAlarms = getAlarmIds(context);

        for (int i = 0; i < idsAlarms.size(); i++) {
            if (idsAlarms.get(i) == id)
                idsAlarms.remove(i);
        }

        saveIdsInPreferences(context, idsAlarms);
    }

    private static List<Integer> getAlarmIds(Context context) {
        List<Integer> ids = new ArrayList<>();
        try {
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
            JSONArray jsonArray2 = new JSONArray(prefs.getString(context.getPackageName() + sTagAlarms, "[]"));

            for (int i = 0; i < jsonArray2.length(); i++) {
                ids.add(jsonArray2.getInt(i));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return ids;
    }

    private static void saveIdsInPreferences(Context context, List<Integer> lstIds) {
        JSONArray jsonArray = new JSONArray();
        for (Integer idAlarm : lstIds) {
            jsonArray.put(idAlarm);
        }

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(context.getPackageName() + sTagAlarms, jsonArray.toString());

        editor.apply();
    }
}
Ben Baron
  • 14,496
  • 12
  • 55
  • 65
extmkv
  • 1,991
  • 1
  • 18
  • 36
  • probably worth making `removeAlarmId` public so folks can remove ids when the notification has arrived. – Baggers Sep 05 '18 at 19:30
  • You can use `cancelAlarm()` for that instead because you need to create the pendingIntent to cancel the alarm – extmkv Sep 05 '18 at 19:33
  • ah interesting, so even if an alarm has passed it is still enqueued? – Baggers Sep 06 '18 at 15:58
  • `PreferenceManager` is deprecated now – Vadim Kotov Jan 09 '20 at 10:05
  • 1
    @VadimKotov you're probably using androidx already so you need to add implementation 'androidx.preference:preference:1.1.0' to your build gradle dependencies to use the androidx PrefenerceManager which is not deprecated. – Distra Mar 02 '20 at 09:00
0

If save the PendingIntent id in SharedPreference or db, you will get wrong value when Android reboot or your package force-stop

You can save all your previous PendingIntent to another new PendingIntent, then cancel all later

for example

    void createSomeAlarmAndSave() {
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, MyReceiver.class).setAction(ACTION_XXX), 0);
        getSystemService(AlarmManager.class).setInexactRepeating(AlarmManager.RTC_WAKEUP, 1000 * 60 * 15, 1000 * 60 * 15, pendingIntent);

        PendingIntent pendingIntent1 = PendingIntent.getBroadcast(this, 1, new Intent(this, MyReceiver.class).setAction(ACTION_XXX), 0);
        getSystemService(AlarmManager.class).setInexactRepeating(AlarmManager.RTC_WAKEUP, 1000 * 60 * 20, 1000 * 60 * 20, pendingIntent1);

        PendingIntent pendingIntent2 = PendingIntent.getBroadcast(this, 2, new Intent(this, MyReceiver.class).setAction(ACTION_XXX), 0);
        getSystemService(AlarmManager.class).setInexactRepeating(AlarmManager.RTC_WAKEUP, 1000 * 60 * 25, 1000 * 60 * 25, pendingIntent2);

        //save all previous PendingIntent to another new PendingIntent
        PendingIntent.getBroadcast(this, 0, new Intent(this, MyReceiver.class).putExtra("previous", new PendingIntent[]{pendingIntent, pendingIntent1, pendingIntent2}), PendingIntent.FLAG_UPDATE_CURRENT);
    }

cancel all previous PendingIntent

    void cancelAllPreviousAlarm() {
        //acquire the dedicated PendingIntent
        PendingIntent pendingIntentAllPrevious = PendingIntent.getBroadcast(this, 0, new Intent(this, MyReceiver.class), PendingIntent.FLAG_NO_CREATE);
        if (pendingIntentAllPrevious != null) {
            try {
                pendingIntentAllPrevious.send(this, 0, null, new PendingIntent.OnFinished() {
                    @Override
                    public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, String resultData, Bundle resultExtras) {
                        for (Parcelable parcelable : intent.getParcelableArrayExtra("previous")) {
                            //alarm will cancel when the corresponding PendingIntent cancel
                            ((PendingIntent) parcelable).cancel();
                        }
                    }
                }, null);
                pendingIntentAllPrevious.cancel();
            } catch (PendingIntent.CanceledException e) {
                e.printStackTrace();
            }
        }
    }
Yessy
  • 1,172
  • 1
  • 8
  • 13
0

If you re-creating the PendingIntent:

PendingIntent pendingIntent = PendingIntent.getBroadcast(
            context, 0, newIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Zain
  • 37,492
  • 7
  • 60
  • 84