This works without any problems:
Intent mIntent = new Intent(getClass().getPackage().getName() + ".ALARM_TRIGGER");
PendingIntent pi = PendingIntent.getBroadcast(
BackgroundService.getInstance(),
mAlarmID,
mIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), interval, pi);
The code works. Everytime we run this code, it UPDATES pending intent with the ID (mAlarmID).
However, the code above doesn't trigger if phone is in deep sleep. So we have to use ELAPSED_REALTIME_WAKEUP.
mAlarmManager.setRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + startIn,
interval,
pi
);
After checking adb shell dumpsys alarm, RTC_WAKEUP always finds and updates correct pending intent. Using alarm manager with ELAPSED_REALTIME_WAKEUP however, always creates new pending intent no matter the same id. What does that mean?
in #1 everytime the code runs, you'll always find only one alarm in dumpsys alarm.
in #2 everytime the code runs, you'll find ONE MORE alarm in dumpsys alarm.
Is this bug? How then to use this code so you will always have at max 1 alarm?
Related
To quickly summarize the issue the alarm that is set disappears between when I set it and sometime the next day. My code all seems to work properly, alarms are set and go off at proper times. After the initial alarm fires and completes, it is automatically set for the next day. I can check and see it with adb shell's dumpsys alarm.
update: I have added some more log information just below here
[14/01/2017 20:57:41] Registering start alarm 1 with Alarm Manager event time: 14/01/2017 21:00:00
[14/01/2017 20:57:41] Registering stop alarm 1001 with Alarm Manager event time: 14/01/2017 21:01:00
[14/01/2017 21:00:00] Receiver has received INTENT_ACTION_ALARM_START and is launching the music player for task #1.
[14/01/2017 21:01:00] Receiver has received INTENT_ACTION_ALARM_STOP and is stopping the music player, and sending a restart request to the MusicService.
[14/01/2017 21:01:00] Restart requested on alarm 1, attempting to add new alarms for tomorrow.
[14/01/2017 21:01:00] Registering start alarm 1 with Alarm Manager event time: 15/01/2017 21:00:00
[14/01/2017 21:01:00] Registering stop alarm 1001 with Alarm Manager event time: 15/01/2017 21:01:00
Batch{43d23730 num=1 start=86684689 end=86684689}:
RTC_WAKEUP #0: Alarm{438c1740 type 0 org.hudsoft.music}
type=0 whenElapsed=86684689 when=+23h55m1s357ms window=0 repeatInterval=0 count=0
operation=PendingIntent{43af9370: PendingIntentRecord{43ddd9a8 org.hudsoft.music broadcastIntent}}
Batch{43d1e348 num=1 start=86744688 end=86744688}:
RTC_WAKEUP #0: Alarm{438c10d8 type 0 org.hudsoft.music}
type=0 whenElapsed=86744688 when=+23h56m1s357ms window=0 repeatInterval=0 count=0
operation=PendingIntent{438ea450: PendingIntentRecord{4393a970 org.hudsoft.music broadcastIntent}}
When I go to bed though and wake up and check the next day the Alarm is curiously missing from the adb shell dumpsys output, it also never executes.
My question is where does the alarm go to without any user interaction? How can I set an alarm that will persist? The documentation claims that "The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running"
My current design is that when the app opens or when BOOT event is received by receiver I run an IntentService that sets all my alarms and goes away, assuming Alarm Manager will handle
the rest. My receiver should wait for the response, problem is each night I go to sleep I wake up and my alarm manager rtc wakeup's have mysteriously disappeared.
If you need any other information to help diagnose the issue please let me know this is my first post I have been struggling with and searching for a solution for about a week!
in my receiver this fires to stop the music playing service and also restart a new alarm for the next day:
if (intent.getAction().equals("INTENT_ACTION_ALARM_END")) {
Intent stopIntent = new Intent(context, MusicPlayer.class);
Task thisTask = (Task) intent.getSerializableExtra("thisTask");
stopIntent.putExtra("thisTask", thisTask);
context.stopService(stopIntent);
Intent restartAlarmIntent = new Intent(context, MusicService.class);
restartAlarmIntent.setAction("INTENT_ACTION_ALARM_RESTART");
restartAlarmIntent.putExtra("thisTask", thisTask);
context.startService(restartAlarmIntent);
}
Here is the code I use to build and start the alarms
Intent myIntent = new Intent(this, MusicReceiver.class);
myIntent.setAction("INTENT_ACTION_ALARM_START");
myIntent.putExtra("thisTask", task);
Log.d("Intent", "Sending start intent now");
PendingIntent pendingStartIntent = buildAlarmIntent(task, "INTENT_ACTION_ALARM_START");
setSingleExactAlarm(endTime, pendingStartIntent);
myIntent = new Intent(this, MusicReceiver.class);
myIntent.setAction("INTENT_ACTION_ALARM_END");
myIntent.putExtra("thisTask", task);
Log.d("Intent", "Sending end intent now");
PendingIntent pendingStopIntent = buildAlarmIntent(task, "INTENT_ACTION_ALARM_END");
setSingleExactAlarm(endTime, pendingStopIntent);
public PendingIntent buildAlarmIntent (Task task, String action) {
PendingIntent pendingIntent;
Intent myIntent = new Intent(this, MusicReceiver.class);
myIntent.setAction(action);
myIntent.putExtra("thisTask", task);
Integer idNum = task.getId();
if (action.equals("INTENT_ACTION_ALARM_END")) {
idNum += 1000;
pendingIntent = PendingIntent.getBroadcast(this, idNum, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
} else {
pendingIntent = PendingIntent.getBroadcast(this, idNum, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
return pendingIntent;
}
private void setSingleExactAlarm(long time, PendingIntent pIntent) {
AlarmManager mAlarmManager;
mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= 19) {
mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, time, pIntent);
} else {
mAlarmManager.set(AlarmManager.RTC_WAKEUP, time, pIntent);
}
}
Here is the receiver section of my AndroidManifest
<receiver
android:name=".MusicReceiver"
android:enabled="true"
android:exported="true"
android:process=":remote">
<intent-filter>
<action android:name="INTENT_ACTION_ALARM_START" />
<action android:name="INTENT_ACTION_ALARM_END" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Thanks in advance for taking the time to look into my issue!
I have found my issue and I thought I would post it in case anyone else runs into a similar issue. My alarms were restarting themselves with the previous times I had set before. Since the time had already passed they would resolve immediately and disappear. This also caused a loop where it would try to restart it again and again but I believe the alarm manager realizes this is happening after events and stops queuing them up to prevent an infinite loop of resetting alarms that have a start time in the past. Hope this helps someone!
I do not have enough reputation to leave a comment, as I do not have a definite answer. However, Is there possibility that your phone is powering off? According to the Android documentation:
https://developer.android.com/reference/android/app/AlarmManager.html
"Registered alarms are retained while the device is asleep (and can optionally wake the device up if they go off during that time), but will be cleared if it is turned off and rebooted."
It is difficult to diagnose further without the code behind receiving BOOT_COMPLETED.
In the past I have used the following to set an alarm, and I do not have the issue you have described:
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, MyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmStartTime.getTimeInMillis(), pendingIntent);
I hope this helps, and good luck.
I have the following code which simply runs an alarm manager:
public void runAlarm(){
Intent intent = new Intent(context, MyReceiver.class);
intent.setAction(ACTION_TIMEOUT);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
setTimeOutAlarm(TIMEOUT_MINUTES,alarmIntent);
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.setExact(AlarmManager.RTC,
Calendar.getInstance().getTimeInMillis() + 3*60*1000, alarmIntent);
}
It works fine. My question is about the pending intent flag: PendingIntent.FLAG_CANCEL_CURRENT
if i run this method twice does it really cancel out the other pending intent thats already in the alarmManager? how does it know its not to cancel it ?I just want to make sure im not causing any leaks by using this flag. My intent is that i can run this code multiple times and it will keep canceling the previous pendingIntent already sent to the alarmManager instance.
But everytime i run this code the alarm count grows by one when i check with this adb command:
adb shell dumpsys alarm | grep com.your.package
so it seems the alarmManager is not canceled perhaps.
I believe you don't need to cancel the old alarm.. but just update it.
I think you can use: PendingIntent.FLAG_UPDATE_CURRENT
Please, make some tests and let me know if it works.
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
calendar.set(Calendar.HOUR_OF_DAY, 1);
PendingIntent pi = PendingIntent.getService(context, 0, new Intent(context,MyClass.class),PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 7*24*60*60*1000, pi);
I have this simple pending repeating alarm and it works just fine only when system android alarm is not set up. It doesnt matter on what time alarms are set in system Alarm app, looks like this system app stops all my pending intents. Any idea how to debug this? What can cause this problem ?
I would like to use it in paralel with system alarms.
make sure you have permission
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
For Debugging:
override onNewIntent() in your activity MyClass Activity like this:
#Override
onNewIntent(Intent intent){
android.os.Debug.waitForDebugger();
if(intent.hasExtra("alarm")){ //Put a break point here
Log.d("Alarm fired","yes");
}
}
Create you PendingIntent for firing alarm like this:
Intent intent=new Intent(context,MyClass.class);
intent.putExtra("alarm","yes");
PendingIntent pi = PendingIntent.getService(context, 0, intent,0);
So, when your alarm gets fired, control will come to onNewIntent and wait for you to attach a debugger. That time go to Attach debugger button in android studio and attach debugger to your application. And this is how you will know that you alarm has been fired.
I am trying to set two alarms which will run two different background services. I set the alarm inside the onCreate method of my activity class. But the problem is that the service classes which are extending IntentService are not getting called, i.e. their method onHandleIntent() is not getting called. This is how I set my alarms
//Creating alarm for showing notifications.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
//create an alarm for today if there is still time else schedule alarm for tomorrow.(Handled inside the one time alarm class).
//FIRST ALARM..............
Intent intent = new Intent(ActionBarTabActivity.this, ScheduleOneTimeAlarmForToday.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
//SECOND ALARM.............
Intent i = new Intent(ActionBarTabActivity.this,RemoteNotificationService.class);
PendingIntent pi = PendingIntent.getService(getApplicationContext(), 111, i, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(), 1000 * 60, pi);
I have declared the services inside the minifest file as below
<service android:name="com.nss.common.services.ScheduleOneTimeAlarmForToday" />
<service android:name="com.nss.common.services.RemoteNotificationService" />
Also the alarms run properly on my old samsung phone but when I test it on my new Asus Zenfone or any other new phone, it doesn't show up.
Edit:
My logcat shows this:
10-19 12:25:05.605 634-744/? V/AlarmManager﹕ triggered: flg=0x10000000 cmp=com.nss.zobbers/com.nss.common.services.ScheduleOneTimeAlarmForToday Pkg: com.nss.zobbers
10-19 12:25:06.846 634-744/? V/AlarmManager﹕ triggered: cmp=com.nss.zobbers/com.nss.common.services.RemoteNotificationService Pkg: com.nss.zobbers
So I don't get it, my alarm is triggered but the service it needs to call doesn't get called? I have tried many posts but couldn't find the error. Please help, thanks in advance.
I made it to work, but I won't accept it as my answer as maybe someone will tell the exact reason why it doesn't work. Well instead of directly calling services via alarmManager, I modified my code to call a broadcast receiver which then calls the respective service. Now it seems to work perfectly on different devices.
This works fine:
Intent intent = new Intent(HelloAndroid2.this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(HelloAndroid2.this, 0,
intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (12 * 1000), pendingIntent);
This doesn't work. I hear the alarm only time.
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (12 * 1000), 3 * 1000, pendingIntent);
I have also tried this, no luck:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 5);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 7000, pendingIntent);
What is the problem?
From the PendingIntent doc for FLAG_ONE_SHOT:
this PendingIntent can
only be used once. If set, after
send() is called on it, it will be
automatically canceled for you and any
future attempt to send through it will
fail.
So after the pendingIntent is fired the first time, it will be cancelled and the next attempt to send it via the alarm manager will fail
Try using FLAG_UPDATE_CURRENT
Looking at your code samples in order:
In your first sample you are using AlarmManager.set - this is strictly for one-off alarms so yes, it will only fire once. If you want to use AlarmManager.set then the last thing the code triggered should do is to set a fresh alarm (which should also use a fresh PendingIntent).
In your second example you are using a repeating alarm. You do not need to create a fresh PendingIntent each time this fires as the OS takes care of the repeating aspect of the alarm.
There is no reason why your alarm should not repeat every 3 seconds, so I would start looking at the BroadcastReceiver implementation you have written to handle the alarm.
Check that you've implemented it properly. Comment out all the code in the onReceive() method and instead just have it writing a log message. Once you see your log message appearing in the logcat every time the alarm fires, add your code back in (keeping the log message), and another log message to the end of the method. This allows you to see how long the method takes to execute - you want it to be finished before the alarm fires again to avoid any unexpected side effects.
As an aside, if you want a repeating alarm, android.os.Handler is a much more efficient approach although alarms set through AlarmManager do fire very accurately.