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.
Related
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.
I have a situation in my application. I am calling a service using an alarm. The alarm wakes up every 5 min and calls the service.
But it may so happen that the user might close my app and I am allowing the functionality of the service to work even if the user is not using my app.
To stop the service there are two ways either the user comes back to the app and presses a button which will cancel the alarm OR the second way is say after x time I want to stop the service i.e cancel the alarm from a broadcast receiver.
Now how can I do the second way ? When I tried to get reference of the AlarmManager it is giving me error of Null Pointer. (I am accessing this alarm manager from a broadcast receiver)
Can anyone give me suggestion on how to cancel repeating alarms from outside the activity context ?
Thanks :)
You can stop your service like this
context.stopService(new Intent(context, YourService.class))
Also in order to cancel the alarm you can do this
Intent intent = new Intent(this, YourClass.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1253, intent, PendingIntent.FLAG_UPDATE_CURRENT| Intent.FILL_IN_DATA);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
I hope this might help you
In your BroadcastReceiver try this:
public void onReceive(Context context, Intent intent) {
context.stopService(new Intent(context, YourService.class));
}
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?
I have an alarm to reset a data connection say every 15 minutes. The problem is, once the phone is rebooted, the application gets killed and the alarm (service) doesn't trigger anymore.
(This is not a duplicate, the other similar questions on SO do not solve my problem.)
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver
android:name="com.sang.mobiledata.ResetBroadcastReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Broadcast Receiver:
public void onReceive(Context context, Intent intent) {
// if(CONN_ACTION.equals(intent.getAction())) {
if (intent.getAction().equalsIgnoreCase(
"com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE")) {
MainActivity objMain = new MainActivity();
objNetwork.setMobileDataEnabled(context, false);
objNetwork.setMobileDataEnabled(context, true);
}
if (intent.getAction().equalsIgnoreCase(
"android.intent.action.BOOT_COMPLETED")) {
// code to restart/resume/retain alarm
Code to fire alarm (on the onClick):
Intent myIntent = new Intent(
"com.sang.mobiledata.IntentAction.RECEIVE_RESETCONN_UPDATE");
myIntent.putExtra("FLAG_KEY", false);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, myIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) this
.getSystemService(Context.ALARM_SERVICE);
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
long interval = intHrs * 3600000 + intMins * 60000;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), interval, pi);
long mins = interval / 60000;
Toast.makeText(
MainActivity.this,
"Data Connection will be reset every " + mins
+ " minute(s).", Toast.LENGTH_SHORT).show();
}
Any suggestions please?
Read the AlarmManager document, there it is written, that AlarmManager will not hold alarms after reboot.
As per the Android Developers,
.... 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.
And regarding BOOT_COMPLETED, they write:
... This is broadcast once, after the system has finished booting. It can be used to perform application-specific initialization, such as installing alarms. You must hold the RECEIVE_BOOT_COMPLETED permission in order to receive this broadcast.
As for permission is concerned, you have already registered that. Well what probably happening is, the service BOOT_COMPLETED is being used locally, with the application. The reboot of the mobile is system activity, which is not overridden to accomplish re-registry of the alarms being saved. But I am not sure. So, you need to do something when execution comes in hand of BOOT_COMPLETED.
Read Automatically starting Services in Android after booting, this might help you with it.
What I did was, I registered all the alarms and formed a database, using SQLite; On restart, I use to reset all the alarms. Well that worked for me. If you want to go with my process then,
Make a database for your alarms, and save them there. Write your application in such a way that, when the phone restarts, the AlarmManager resets all the alarms. This is how it works.
In Automatically starting Services in Android After booting again. It is written:
Also note that as of Android 3.0 the user needs to have started the application at least once before your application can receive android.intent.action.BOOT_COMPLETED events.
My app needs to execute a specific task every hour. It does not matter if app is runing, suspended, or even closed.
When app is running or suspended, I can do it by just scheduling an AlarmManager broadcastreceiver. But when the application is closed, I have to call "unregisterReceiver" to not leak an intent, and app will never be wake up (or something) to process the task.
Then, the question is: how to schedule an alarmmanager task that I don't need to unregister, so it will be called even if my application is closed?
Use AlarmManager.setRepeating(int type, long triggerAtTime, long interval, PendingIntent operation) for this. Set the type to AlarmManager.RTC_WAKEUP to make sure that the device is woken up if it is sleeping (if that is your requirement).
Something like this:
Intent intent = new Intent("com.foo.android.MY_TIMER");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
long now = System.currentTimeMillis();
long interval = 60 * 60 * 1000; // 1 hour
manager.setRepeating(AlarmManager.RTC_WAKEUP, now + interval, interval,
pendingIntent); // Schedule timer for one hour from now and every hour after that
You pass a PendingIntent to this method. You don't need to worry about leaking Intents.
Remember to turn the alarm off by calling AlarmManager.cancel() when you don't need it anymore.
Don't register a Receiver in code for this. Just add an <intent-filter> tag to the manifest entry for your BroadcastReceiver, like this:
<receiver android:name=".MyReceiver">
<intent-filter>
<action
android:name="com.foo.android.MY_TIMER"/>
</intent-filter>
</receiver>
You need to user an Android Component Called Service for this. From the service code you can schedule your Task using the AlarmManager with PendingIntent Class for every hours. As your AlarmManger is declared in the Service Components it doesn't require any GUI and will get execute in background, till you have battery in your device.