Search code examples
androidalarmmanagerandroid-pendingintentandroid-alarms

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?


Solution

  • 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.