2

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?

fsljfke
  • 431
  • 6
  • 14
  • Try test it by another button (not by Thread sleep), and create another object PendingIntent – Style-7 Aug 16 '20 at 05:30
  • @Style-7 I tried it this way (which is similar to using another button): An FCM service that when invoked from server would set the alarm, and the button would try to cancel it. It didn't work. – fsljfke Aug 16 '20 at 06:07
  • Not sure what do you want to do. You can not set or cancel an alarm for AlarmClock. You can open standard app by Intent. – Style-7 Aug 16 '20 at 08:20

2 Answers2

2

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.

fsljfke
  • 431
  • 6
  • 14
0

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.

Keivan.k
  • 548
  • 6
  • 21
  • I tried replacing the PendingIntents' flag to `0` in the code I posted but it still doesn't work. I am running it from the same Firebase service, so I think the `context` is same as well. The first PendingIntent is able to set the alarm, but the second one is unable to cancel it from the Alarm Clock. Also, make sure you read I am talking about the Alarm Clock apps here not the usual AlarmManager. – fsljfke Aug 16 '20 at 15:19
  • Can you use the application context and see if it works or not? – Keivan.k Aug 16 '20 at 15:26
  • You are right, My answer is about the normal alarms set by alarmmanager. – Keivan.k Aug 16 '20 at 15:30
  • Why don't you just do the regular alarms like explained here? https://javapapers.com/android/android-alarm-clock-tutorial/ – Keivan.k Aug 16 '20 at 15:33
  • By "normal alarm", I meant that I suspected the fix had something to do with the [AlarmClock](https://developer.android.com/reference/android/provider/AlarmClock) rather than the setup of AlarmManager. So the "regular alarms" are I think the same thing that we are using here. I think I am doing something wrong with AlarmClock rather than AlarmManager. If you are talking about implementing the alarms interface in my own app, I wanted to let the user be able to use the alarm clock of their choice. But thanks for the tutorial link, it's helpful. – fsljfke Aug 16 '20 at 17:50
  • So it turned out as I suspected, I needed to use the `ACTION_DISMISS_ALARM` action from `AlarmClock`. I wrote an answer for that. – fsljfke Aug 16 '20 at 18:31