I have written an android daily-repeating alarm app using AlarmManager class.
The app was tested on a bunch of test devices running on android 4.2 - 5.0. Most of testing results were good except that of Sony Xperia Z2 and Xiaomi Mi 3 running on android 4.4.4:
Sony Xperia Z2: the alarm fired around 3 - 10 minutes later than the scheduled time. (A 9:10AM alarm would fire at around 9:13 - 9:20AM)
Xiaomi Mi 3: a regular 3 minute delay could be observed.
Below is the code snippet of setting alarm:
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
// if scheduled time < current time, add 1 day
if (Calendar.getInstance().compareTo(calendar) == 1) {
calendar.add(Calendar.DATE, 1);
}
int alarmIntentId = 0;
int flag = PendingIntent.FLAG_UPDATE_CURRENT;
long repeatInterval = AlarmManager.INTERVAL_DAY;
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, alarmIntentId, intent, flag);
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), repeatInterval, alarmIntent);
Does anyone have ideas and solutions about this delay issue? There are couple of other alarm apps that works on Sony and Xiamo like "Timely". Any advises would be greatly appreciated.
The alarm delivery is inexact since API 19, use the setExact(int, long, PendingIntent) Method for an exact alarm and set this on every day new.
Have you note this?
http://developer.android.com/reference/android/app/AlarmManager.html
Summary:
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
setRepeat Method:
Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.
Looking at the documentation here
I see the following line
Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.
So I guess by definition it is not exact.
Targeted API version changed to 18 and it has all worked.
Related
I am developing an application for Android Lollipop and KitKat devices. The application needs to call an API in every predefined interval (Based on the interval received from server). I am doing this using AlarmManager class.
But the problem is it works till some time then stops.
Say for example If I set to start the alarm at 08:00 AM with an interval of 30 minutes it works till 11:00AM (aprx) and then alarm doesn't trigger.
If I set a long interval (eg : 8 hours from current time, still same issue happens, not reiggering even once )
Code
public void setRepeatedAlarm(Context context, int requestCode, long next, long interval, Intent intent) {
PendingIntent sender = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.RTC_WAKEUP, next, interval, sender);
}
Function calling
AlarmHandleManager.get().setRepeatedAlarm(this, Constants.SchedulerRequestCodes.UPLOAD_LOG, date.getTime(), AlarmManager.INTERVAL_DAY, intent);
Let me know if any one can figure out the issue.
Have seen a bug reported in lollipop in Google bug tracker, If that is the case let me know if there is any alternative solution for this.
i don't think it's a bug since it's already mentioned in the official documentation
Note: As of API 19, all repeating alarms are inexact. Because this method has been available since API 3, your application can safely call it and be assured that it will get similar behavior on both current and older versions of Android.
Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.
Note: Beginning with API 19 (Build.VERSION_CODES.KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, android.app.PendingIntent) and setExact(int, long, android.app.PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
If the following line of code is used, the Alarm is triggered immediately by AlarmManager, which is normal since Android documentation states that if an Alarm is set in the past it will be triggered immediately.
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60*60*24*1000, alarmIntent);
Meanwhile, by setting it to trigger 1 minute later, using the code here after adding +60*1000 to System.currentTimeMillis(), the Alarm will not be triggered 1 minute later, as it should (actually the Alarm will never be triggered, even after waiting for 10 additional minutes - perhaps it will the day after, when repeating, but I have not tested this yet).
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+60*1000, 60*60*24*1000, alarmIntent);
Depending on your API level.
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS
will shift alarms in order to minimize wakeups and battery use. There
are new APIs to support applications which need strict delivery
guarantees; see setWindow(int, long, long, PendingIntent) and
setExact(int, long, PendingIntent). Applications whose
targetSdkVersion is earlier than API 19 will continue to see the
previous behavior in which all alarms are delivered exactly when
requested.
https://developer.android.com/reference/android/app/AlarmManager.html
I have to call a service in every day on a particular time.obviously i had choose AlarmManager for waking up my service.and all working well other than AlarmManager triggering immediately when i set the past time.but it's working fine when i set time after current time.
For better clarification i will say an example.
WORKING ATTEMPT : Current time is 09.00 AM am setting schedule as
10.00 AM.And AlarmManager doing his job perfectly.
FAILURE ATTEMPT :Current time is 10.00 AM am setting schedule as
09.00 AM.And AlarmManager calls the services immediately.
Actually i need to invoke my service tomorrow 09.00 AM as the scheduled time is past.
I referred some query almost matching this one but it wasn't good enough.What i am doing wrong ?
My Code
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY,10);
calendar.set(Calendar.MINUTE, 00);
calendar.set(Calendar.SECOND, 00);
Intent myIntent = new Intent(MainActivity.this, MyReceiver.class);
myIntent.putExtra(ACTION, ACTION_SC_1);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, REQUEST_CODE_SC_1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getBaseContext().getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
Dont use alarm manager use GcmNetworkManager which was introduced in the last IO. It will work like a charm and you will have the ability to set in to inexact alarm so u wont need to wakeup the device. From the google IO site : Google Play Services has added the GCM Network Manager which functions mostly like JobScheduler, but extends to prior releases before Lollipop.
From the documentation
Like set(int, long, PendingIntent), except you can also supply a period at which the alarm will automatically repeat. This alarm continues repeating until explicitly removed with cancel(PendingIntent). If the stated trigger time is in the past, the alarm will be triggered immediately, with an alarm count depending on how far in the past the trigger time is relative to the repeat interval.
It is working intentionally like this.
As Bonatti said above, this is documented behaviour of the API when you set a time in the past.
You will need logic in your app to push out the alarm by 24hrs if it is already past 10am at the time when you want to set the alarm.
The easiest way to do this is probably to use the Calendar object as you have, then query
if (calendar.after(SystemClock.currentTimeMillis()) {
// Push alarm out til tomorrow.
calendar.add(Calendar.DAY_OF_MONTH, 1);
}
If you need the alarm to be triggered at 9AM sharp, don't use setRepeating() as it will not launch at the exact time since Android KitKat (this is also documented, you should really read the docs).
Use Calendar to build the timestamp from your desired alarm time. Check if the result timestamp is smaller than the current timestamp System.currentTimeMillis(), in that case it's in the past so add 24 hours to it to schedule it for the next day.
Finally, use AlarmManager.set() on older versions or AlarmManager.setExact() on newer versions of Android to schedule your alarm. Once the alarm goes off, you can schedule the next one using the same technique.
I am trying to create a repeating alarm manager call and I have found that for Android 4.1, 4.2 it does not get triggered the first time and I need to wait for the interval to see the process works:
public void startScheduler() {
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 100, // now
AlarmManager.INTERVAL_FIFTEEN_MINUTES, // Interval
getSchedulerPendingIntent());
}
This only works when reached the AlarmManager.INTERVAL_FIFTEEN_MINUTES but not the "triggerAtMillis" argument. The thing is that this works on Android 4.4 and Android 5.0.
If I change the setInexactRepeating with setRepeating it work perfectly on Android 4.1 and 4.2, so:
public void startScheduler() {
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 100, // now
AlarmManager.INTERVAL_FIFTEEN_MINUTES, // Interval
getSchedulerPendingIntent());
}
Works perfect for Android 4.1, 4.2, 4.3, 4.4 and 5.0. The only drawback is that for Android Api 19 and above it will work as an inexactRepeating and for android API 19 and below work as expected.
Is it make any relevant difference? I am missing something?
Thanks in advance!
Quoting the documentation for setInexactRepeating(), specifically the triggerAtMillis parameter:
time in milliseconds that the alarm should first go off, using the appropriate clock (depending on the alarm type). This is inexact: the alarm will not fire before this time, but there may be a delay of almost an entire alarm interval before the first invocation of the alarm.
IOW, this would appear to be working as expected.
I would like to make a delay(10 min) for user then after it, user can edit something.
to do this,I created a setAlarm function :
public void setAlarm(Context context,int user,int time) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, sef_time.class);
intent.putExtra(ONE_TIME, Boolean.FALSE);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
am.set(AlarmManager.RTC, 1000*60*time , pi);
}
everything works fine, but my alarm manager has a delay.
for example:
setAlarm(.....,int 10);
It has a delay : 00:10:03 second or 00:10:10 second 00:10:20 second !
where is my wrong ?
As you can see here:
Beginning in API 19, the trigger time passed to this method is treated
as inexact: the alarm will not be delivered before this time, but may
be deferred and delivered some time later. The OS will use this policy
in order to "batch" alarms together across the entire system,
minimizing the number of times the device needs to "wake up" and
minimizing battery use. In general, alarms scheduled in the near
future will not be deferred as long as alarms scheduled far in the
future.
With the new batching policy, delivery ordering guarantees are not as
strong as they were previously. If the application sets multiple
alarms, it is possible that these alarms' actual delivery ordering may
not match the order of their requested delivery times. If your
application has strong ordering requirements there are other APIs that
you can use to get the necessary behavior; see setWindow(int, long,
long, PendingIntent) and setExact(int, long, PendingIntent).
Applications whose targetSdkVersion is before API 19 will continue to
get the previous alarm behavior: all of their scheduled alarms will be
treated as exact.
If it's very important that the alarm be exact, use setExact (When the device's SDK is 19 or above).
The easiest way to make system have a delay and then sound an alarm at the exact specified time is using setExact(), and the code can be something like this.
am.setExact(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + (time_you_want_to_delay_in_milliseconds) ,pi);