How to check if AlarmManager already has an alarm set?
Asked Answered
A

13

264

When my app starts, I want it to check if a particular alarm (registered via AlarmManager) is already set and running. Results from google seem to indicate that there is no way to do this. Is this still correct? I need to do this check in order to advise the user before any action is taken to create a new alarm.

Analogous answered 29/12, 2010 at 18:20 Comment(1)
Please validate the answer that solved your issue or post your own solution.Mitchmitchael
S
337

Following up on the comment ron posted, here is the detailed solution. Let's say you have registered a repeating alarm with a pending intent like this:

Intent intent = new Intent("com.my.package.MY_UNIQUE_ACTION");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, 
                                      intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MINUTE, 1);

AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60, pendingIntent);

The way you would check to see if it is active is to:

boolean alarmUp = (PendingIntent.getBroadcast(context, 0, 
        new Intent("com.my.package.MY_UNIQUE_ACTION"), 
        PendingIntent.FLAG_NO_CREATE) != null);

if (alarmUp)
{
    Log.d("myTag", "Alarm is already active");
}

The key here is the FLAG_NO_CREATE which as described in the javadoc: if the described PendingIntent **does not** already exists, then simply return null (instead of creating a new one)

Stearn answered 5/3, 2012 at 23:14 Comment(17)
Does it have to use the Intent with just an Action String? I tried specifying a class, new Intent(context, MyClass.class) but it doesn't seem to work. It always returns null even when the alarm is running.Travelled
toc777, no it needs to be a String which matches a declared action in your intent-filter in your manifest.xmlStearn
Chris, It was another issue that was causing my problem. The intent I mentioned above actually does work :)Travelled
An issue I had was not calling cancel on BOTH the alarmManager and the pendingIntent. I.E ~ alarmMgr.cancel(alarmIntent); alarmIntent.cancel();Nine
@ChrisKnight : Will this still work if I check from an app say app1 if an alarm is set and running in app2? and also,do the alarms die during an app update,and so do we need to reset it again(for app update case)?Saxecoburggotha
Always returns TRUE saying the pending intent already exist. Even after app uninstall and re-install. How long does the pending intent live?Stick
Note that you'll need to call both alarmManager.cancel(pendingIntent) and pendingIntent.cancel() in order for this solution to return false.Obstacle
for users using new Intent(context, YourService.class) , you can use .setAction("ACTIONNAME") to define an action on the intentProteus
Lifesaver. Please note that you'll need to create the intent exactly the same way you created it before, except for the flags.Dorso
It case it isn't obvious, the code in this answer does not verify that the pending intent has been registered with the alarm manager. The code simply verifies that the PendingIntent was created via getBroadcast with an equivalent target intent. You can prove this by running the alarmUp code after the getBroadcast all, but before all the calendar and alarm manager stuff. It will return true. This fact explains why you have to PendingIntent.cancel to get the value to go back to false. Strictly speaking, this doesn't answer the question.Hydrophone
Excuse me. I want to ask what is MY_UNIQUE_ACTION ? Where it is coming from ?Voiture
@LeonardFebrianto i think it was an answer long overdue but i am pretty sure you got the reason. Thats just the action name , it can be any action constant you have associated with receivers in your manifestSolothurn
does not work if alarm killed by 'force stop' etc.. It must be canceled before using this codeInterfluve
I tried Intent intent = new Intent(ctx, MyReceiver.class); instead of passing unique_action and it worked :)Maquis
tip for future readers - Make sure you are not mistaking PendingIntent.getBroadcast(...) with PendingIntent.getService(...) - save yourself some trouble! :)Tortoni
this is the first time I see so high rated WRONG answer. See comment by bigh_29.Sedberry
Just if somebody wasted a day of figuring out why this doesn't work,.... flags has to be same/match as when you created the pending intent, e.g. FLAG_IMMUTABLE.Rishi
S
131

For others who may need this, here's an answer.

Use adb shell dumpsys alarm

You can know the alarm has been set and when are they going to alarmed and interval. Also how many times this alarm has been invoked.

Slosh answered 31/7, 2014 at 3:37 Comment(4)
Not really a programmatic answer to the OP, but a cool tip. Very good to know.Kktp
append a grep to filter the usually long list of alarms: adb shell dumpsys alarm | grep <e.g. package name of your app> Also works on new Windows Systems (I use Win10)Morrell
grep is executed on the mobile device, not your PC. So if grep works depends on the Android OS. Older phones don't come with grep.Sinclare
Windows equivalent of grep is 'finstr'Trivet
A
65

Working example with receiver (the top answer was just with action).

//starting
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), MyReceiver.class);
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//my custom string action name
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_CANCEL_CURRENT);//used unique ID as 1001
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), aroundInterval, pendingIntent);//first start will start asap

//and stopping
Intent intent = new Intent(getActivity(), MyReceiver.class);//the same as up
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//the same as up
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_CANCEL_CURRENT);//the same as up
alarmManager.cancel(pendingIntent);//important
pendingIntent.cancel();//important

//checking if alarm is working with pendingIntent
Intent intent = new Intent(getActivity(), MyReceiver.class);//the same as up
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//the same as up
boolean isWorking = (PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_NO_CREATE) != null);//just changed the flag
Log.d(TAG, "alarm is " + (isWorking ? "" : "not") + " working...");

It is worth to mention:

If the creating application later (process) re-retrieves the same kind of PendingIntent (same operation, same Intent's - action, data, categories, components, flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it.

In short, your PendingIntent should have the same features (operation and intent's structure) to take control over it.

Apul answered 21/1, 2015 at 20:23 Comment(7)
I'm not sure that this is sufficient. In the case where a PendingIntent is registered with the AlarmManager and then stopped by both cancel methods, 'isWorking' above will still be true. The PendingIntent seems to have not been removed from the AlarmManager, and will keep returning an instance. How do we then effectively know when alarms have been turned on/off?Lignite
This actually worked perfectly. Things to note: the setAction() and the requestCode() need to be identical in all getBroadcast()'s and its worth uninstalling the app from your device. That caught me out. ThanksLignite
Works great. Thanks!Rosalie
Nice example but I wouldn't use 1001 as private request code there. Just 0 to make the example more obvious.Maravedi
great answer. should be moved up. ThanksShortwinded
Please refrain from using "top answer" etc.. Instead provide a link to the answer. Because answers can change positions on the page based on popularity.Fustian
This is not working solution, if you re-run the app from android studio, the pending intent get cleared, but isWorking return true, I guess same may happen when you update the appDefection
H
55

Note this quote from the docs for the set method of the Alarm Manager:

If there is already an alarm for this Intent scheduled (with the equality of two intents being defined by Intent.filterEquals), then it will be removed and replaced by this one.

If you know you want the alarm set, then you don't need to bother checking whether it already exists or not. Just create it every time your app boots. You will replace any past alarms with the same Intent.

You need a different approach if you are trying to calculate how much time is remaining on a previously created alarm, or if you really need to know whether such alarm even exists. To answer those questions, consider saving shared pref data at the time you create the alarm. You could store the clock timestamp at the moment the alarm was set, the time that you expect the alarm to go off, and the repeat period (if you setup a repeating alarm).

Hydrophone answered 21/4, 2015 at 21:31 Comment(4)
In my opinion this should be the accepted answer. Unless the OP has an special situation that justifies not restating the alarmPliable
In my case, I want to know if the alarm is already set and if so I don't want to create new one or reset the existing alarm.Uglify
Superb answer. Why didn't the OP check this at all? There's nothing you need to do.Hoodwink
There are many loop holes in this solution, this may override previously created alarm time (lets say if the time needs to be specified like t+24) so every time the app is launched alarm time keeps moving forward a state which it could never gets trigger for many, so checking the alarm if its already exists is more reliable oneRandeerandel
H
11

I have 2 alarms. I am using intent with extras instead of action to identify the events:

Intent i = new Intent(context, AppReciever.class);
i.putExtra("timer", "timer1");

the thing is that with diff extras the intent (and the alarm) wont be unique. So to able to identify which alarm is active or not, I had to define diff requestCode-s:

boolean alarmUp = (PendingIntent.getBroadcast(context, MyApp.TIMER_1, i, 
                    PendingIntent.FLAG_NO_CREATE) != null);

and here is how alarm was created:

public static final int TIMER_1 = 1;
public static final int TIMER_2 = 2;

PendingIntent pending = PendingIntent.getBroadcast(context, TIMER_1, i,
            PendingIntent.FLAG_CANCEL_CURRENT);
setInexactRepeating(AlarmManager.RTC_WAKEUP,
            cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pending);
pending = PendingIntent.getBroadcast(context, TIMER_2, i,
            PendingIntent.FLAG_CANCEL_CURRENT);
setInexactRepeating(AlarmManager.RTC_WAKEUP,
            cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pending);
Hospitaler answered 24/2, 2013 at 0:6 Comment(1)
Using the intent extras and this solution worked for me. Only one change is I am using service so I have changed it to PendingIntent.getServiceQuartz
T
10

Just found another solution, it seems to work for me

Intent myIntent = new Intent(MainActivity.this, MyReceiver.class);

boolean isWorking = (PendingIntent.getBroadcast(MainActivity.this, 0, myIntent, PendingIntent.FLAG_NO_CREATE) != null);
if (isWorking) {Log.d("alarm", "is working");} else {Log.d("alarm", "is not working");}

if(!isWorking) {
    pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, myIntent,    PendingIntent.FLAG_UPDATE_CURRENT);
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    int timeNotif = 5 * 60 * 1000;//time in ms, 7*24*60*60*1000 for 1 week
    Log.d("Notif", "Notification every (ms): " + timeNotif);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), timeNotif, pendingIntent);
    }
Tuscarora answered 25/7, 2016 at 23:18 Comment(2)
Sometimes, on Marshmallow, after you force-stop an app, getBroadcast() will return non-null, but the alarm is not set.Pinon
@Pinon did you solve the problem?3d
C
10

While almost everyone over here has given the correct answer, no body explained on what basis are the Alarms work

You can actually learn more about AlarmManager and its working here . But here is the quick answer

You see AlarmManager basically schedules a PendingIntent at some time in future. So in order to cancel the scheduled Alarm you need to cancel the PendingIntent.

Always keep note of two things while creating the PendingIntent

PendingIntent.getBroadcast(context,REQUEST_CODE,intent, PendingIntent.FLAG_UPDATE_CURRENT);
  • Request Code - Acts as the unique identifier
  • Flag - Defines the behavior of PendingIntent

Now to check if the Alarm is already scheduled or to cancel the Alarm you just need to get access to the same PendingIntent. This can be done if you use same request code and use FLAG_NO_CREATE like shown below

PendingIntent pendingIntent=PendingIntent.getBroadcast(this,REQUEST_CODE,intent,PendingIntent.FLAG_NO_CREATE);

if (pendingIntent!=null)
   alarmManager.cancel(pendingIntent);

With FLAG_NO_CREATE it will return null if the PendingIntent doesn't already exist. If it already exists it returns reference to the existing PendingIntent

Cata answered 6/5, 2018 at 5:31 Comment(2)
If Request Code is an identifier, is it important to pass the Intent with the matching Action?Consubstantiate
Is there a way to get the time the alarm was scheduled for with the alarmanager if you have the pending intent?Duleba
A
7

If you target Android 12 (i.e) Target SDK 31, then, for AlarmManager, PendingIntent cannot be created without a Mutable or an Immutable flag. Without this Mutability flag, the application will throw a runtime error. See this documentation for more details about this. The following code snippet is working for me and will help fellow people who target their application for Android 12.

For creating an Alarm:

public static void setupReminderServiceAlarm ( Context context ) {
    Log.d ( TAG, "Trying to setup reminder service alarm" );
    if (!isReminderServiceAlarmSet ( context )) {
        AlarmManager alarmManager = (AlarmManager) context.getApplicationContext ().getSystemService ( Context.ALARM_SERVICE );
        Intent intent = new Intent ( context.getApplicationContext (), ReminderIntentReceiver.class );
        intent.setAction ( REMINDER_INTENT_ACTION );
        PendingIntent pendingIntent;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
            pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE );
        } else {
            pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, 0 );
        }
        alarmManager.setRepeating ( AlarmManager.RTC_WAKEUP, getReminderTriggerTime (), REMINDER_INTERVAL, pendingIntent );
        Log.d ( TAG, "Reminder service alarm setup completed" );
    }
}

For checking whether the alarm is already set or not:

private static boolean isReminderServiceAlarmSet ( Context context ) {
    Intent intent = new Intent ( context.getApplicationContext (), ReminderIntentReceiver.class );
    intent.setAction ( REMINDER_INTENT_ACTION );
    boolean isBackupServiceAlarmSet;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_NO_CREATE );
        isBackupServiceAlarmSet = (PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_NO_CREATE ) != null);
    } else {
        PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_NO_CREATE );
        isBackupServiceAlarmSet = (PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_NO_CREATE ) != null);
    }
    Log.d ( TAG, "Reminder service alarm is " + (isBackupServiceAlarmSet ? "" : "not ") + "set already" );
    return isBackupServiceAlarmSet;
}

For cancelling the alarm which was set earlier:

public static void cancelReminderServiceAlarm ( Context context ) {
    Log.d ( TAG, "Reminder service alarm canceled" );
    AlarmManager alarmManager = (AlarmManager) context.getApplicationContext ().getSystemService ( Context.ALARM_SERVICE );
    Intent intent = new Intent ( context.getApplicationContext (), ReminderIntentReceiver.class );
    intent.setAction ( REMINDER_INTENT_ACTION );
    PendingIntent pendingIntent;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_IMMUTABLE );
    } else {
        pendingIntent = PendingIntent.getBroadcast ( context.getApplicationContext (), REMINDER_INTENT_REQUEST_CODE, intent, 0 );
    }
    alarmManager.cancel ( pendingIntent );
    pendingIntent.cancel ();
}

Hope this answer helps people who target their application for Android 12 / SDK 31+. Also, make sure to add this permission in Manifest for scheduling alarms targeting the above.

<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
Ammonium answered 1/5, 2022 at 18:20 Comment(1)
Great and it worked for me. Thank you so much, I was wondering How you came up with following solution to pass for checking existing alarms : PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_NO_CREATE ? Earlier I was able to use only PendingIntent.FLAG_NO_CREATE, but this stopped working after targeting Android 12Bluefarb
A
5

I made a simple (stupid or not) bash script, that extracts the longs from the adb shell, converts them to timestamps and shows it in red.

echo "Please set a search filter"
read search

adb shell dumpsys alarm | grep $search | (while read i; do echo $i; _DT=$(echo $i | grep -Eo 'when\s+([0-9]{10})' | tr -d '[[:alpha:][:space:]]'); if [ $_DT ]; then echo -e "\e[31m$(date -d @$_DT)\e[0m"; fi; done;)

try it ;)

Actinomycete answered 22/6, 2015 at 14:38 Comment(0)
V
1
    Intent intent = new Intent("com.my.package.MY_UNIQUE_ACTION");
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    sqlitewraper.context, 0, intent,
                    PendingIntent.FLAG_NO_CREATE);

FLAG_NO_CREATE is not create pending intent so that it gives boolean value false.

            boolean alarmUp = (PendingIntent.getBroadcast(sqlitewraper.context, 0,
                    new Intent("com.my.package.MY_UNIQUE_ACTION"),
                    PendingIntent.FLAG_NO_CREATE) != null);

            if (alarmUp) {
                System.out.print("k");

            }

            AlarmManager alarmManager = (AlarmManager) sqlitewraper.context
                    .getSystemService(Context.ALARM_SERVICE);
            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                    System.currentTimeMillis(), 1000 * 60, pendingIntent);

After the AlarmManager check the value of Pending Intent it gives true because AlarmManager Update The Flag of Pending Intent.

            boolean alarmUp1 = (PendingIntent.getBroadcast(sqlitewraper.context, 0,
                    new Intent("com.my.package.MY_UNIQUE_ACTION"),
                    PendingIntent.FLAG_UPDATE_CURRENT) != null);
            if (alarmUp1) {
                System.out.print("k");

            }
Viridian answered 19/8, 2015 at 13:7 Comment(0)
E
1

Based on my experience, in a more recent version of Android, I believe it only allows Broadcast messages for Alarm wake up, not starting services directly. See this link: https://developer.android.com/training/scheduling/alarms, it says:

Alarms have these characteristics:

  • They let you fire Intents at set times and/or intervals.
  • You can use them in conjunction with broadcast receivers to start services and perform other operations.

The operative word in the second sentence is "conjunction." What it explicitly states is that alarms are design for Broadcast (which implies not for starting services directly). I tried for several hours to use a PendingIntent with getService(), but could not get it to work, even though I confirmed the pending intent was working correctly simply using:

pendingIntent.send(0);

For "targetSdkVersion 29" this did not work .. [would not fire onStartCommand()]:

Intent launchIntent = new Intent(context, MyService.class);
launchIntent.putExtra(Type.KEY, SERVER_QUERY);    
PendingIntent pendingIntent =
                PendingIntent.getService(context, 0, launchIntent, 0);

I could validate the alarm was running using:

adb shell dumpsys alarm | grep com.myapp

However, this did work:

public static class AlarmReceiverWakeup extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive Alarm wakeup");
        startService(context);
    }
}


public static void scheduleAlarmWakeup(Context context) {

    Intent broadcastIntent = new Intent(context, AlarmReceiverWakeup.class);
    broadcastIntent.putExtra(Type.KEY, SERVER_QUERY);    
    PendingIntent pendingIntent =
                    PendingIntent.getBroadcast(context, 0, broadcastIntent, 0);
    AlarmManager alarmManager =
                (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

    // NOTE: using System.currentTimeMillis() fails w/ELAPSED_REALTIME_WAKEUP 
    //     use SystemClock.elapsedRealtime() instead
    alarmManager.setRepeating(
                AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime()+5000,
                AlarmManager.INTERVAL_FIFTEEN_MINUTES/4,
                getAlarmPendingIntent(context)
    );
}

BTW, this is the AndroidManifest.xml entry for the Broadcast Receiver:

<receiver android:name=".ServerQueryService$AlarmReceiverWakeup"
    android:enabled="true">
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</receiver>
Eparch answered 9/1, 2021 at 23:48 Comment(0)
T
0

Im under the impression that theres no way to do this, it would be nice though.

You can achieve a similar result by having a Alarm_last_set_time recorded somewhere, and having a On_boot_starter BroadcastReciever:BOOT_COMPLETED kinda thing.

Thatcher answered 31/1, 2011 at 1:34 Comment(0)
E
0

I made a workaround with using the android jetpack workManager.

Instead of setting an alarm straight away in alarmManager, set work in workManager where you can set the trigger time (set trigger time in workManager) and add a tag to that work. The alarm can be set and triggered when the work triggers.

And to answer your question, you simply add tag to the work by .addTag("something") and then when checking for an active work use .getWorkInfosByTag("something")

Expatriate answered 26/9, 2022 at 22:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.