Alarmmanager - Fire alarm on top of every minute - android

I am trying to fire an Alarm on top of every minute. But as for some reason it doesn't want to work. It is for an Widget Clock which should update every minute. For battery reasons i've made an reciever for screen off and on. So my Alarm only fires when the screen is on. The minutes should be syncron with my System clock.
public static void startClockTickAlarm() {
AlarmManager alarmManager = (AlarmManager)_context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 1);
calendar.add(Calendar.HOUR, 1);
alarmManager.setRepeating(AlarmManager.RTC, utcMillisNextMin(), 60000, createClockTickIntent(_context));
}
public static final long utcMillisNextMin() {
Time t = new Time();
t.setToNow();
t.second = 0;
t.minute++;
System.out.println("Next Alarm: " + t.hour + ":" + t.minute + ":" + t.second);
return t.normalize(true);
}
My System.out gives me exactly what it should. For example i enable my widget at 11:30:15 the returning result is 11:31:00 - This means my alarm should firstly fire at 11:31. According to my System Clock, the alarm is 5-15 seconds too late. The seconds which the alarm fires too late are not always the same (between 5 and 15 seconds).
Thanks in advance.

Like #mighter said, API >= 19 if you must use exact timing, use the setExact() API.
if(android.os.Build.VERSION.SDK_INT < 19) {
alarmManager.setRepeating(AlarmManager.RTC, utcMillisNextMin(), 60000, createClockTickIntent(_context));
} else {
alarmManager.setExact(...);
}

There's following statement in docs:
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.
If you're running on Android 4.4.4 then this might be the reason.

Related

How to show Android Notification within a timeframe

I want to show a notification every 15 minutes only between 8:00 and 16:00. Here is the code:
Calendar calendar = Calendar.getInstance();
Calendar calendarStartOfTheDay = Calendar.getInstance();
Calendar calendarEndOfTheDay = Calendar.getInstance();
calendarStartOfTheDay.set(Calendar.HOUR_OF_DAY, 8);
calendarStartOfTheDay.set(Calendar.MINUTE, 0);
calendarStartOfTheDay.set(Calendar.SECOND, 0);
calendarEndOfTheDay.set(Calendar.HOUR_OF_DAY, 16);
calendarEndOfTheDay.set(Calendar.MINUTE, 0);
calendarEndOfTheDay.set(Calendar.SECOND, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
if (alarmManager != null && calendar.getTimeInMillis() > calendarStartOfTheDay.getTimeInMillis() && calendar.getTimeInMillis() < calendarEndOfTheDay.getTimeInMillis()) {
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis() + 15 * 60 * 1000, AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);
}
Is there a solution except checking the current time before notificationManager.notify()
If this is the only solution, wouldn't it drain your battery too much during the night?
This can be done by job scheduler in android. As alarm manager is outdated and
no longer used. Job scheduler also provide you with the flexibility of scheduling the task to run under specific conditions,
such as:
Device is charging
Device is connected to an unmetered network
Device is idle
Start before a certain deadline
Start within a predefined time window, e.g., within the next hour
Start after a minimal delay, e.g., wait a minimum of 10 minutes
you can follow this link to implement this
https://medium.com/google-developers/scheduling-jobs-like-a-pro-with-jobscheduler-286ef8510129

Android Alarms too early

I'm using android studio to develop an application that would retrieve the time information from the database and would set an alarm to prompt the user that it's time to drink the medicine, my problem is that the alarm goes on too early
for example the retrieved time is 12:50 AM and the current time is 12:40 AM
even though there's a 10 minutes difference the alarm goes off right away
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm");
try {
Calendar Cnow = Calendar.getInstance();
long now=Cnow.getTimeInMillis();
Calendar time=Calendar.getInstance();
time.setTimeInMillis(0);
Date dTime=sdf.parse(strAlarmDate + " " + strTime1);
//example strAlarmDate="2015-09-27" and strTime1="12:50 AM" and now="12:40 AM" in millis
//dTime="...... 2015-09-27 00:50"
time.setTime(dTime);
//Date dNow=now.getTime();
//time.setTime(date);
//long trigger=time.getTimeInMillis()-now.getTimeInMillis();
long trigger=time.getTimeInMillis()-now;
if(trigger>0) {
ctr++;
Intent i = new Intent(Login.this, AlarmReceiver.class);
i.putExtra("message", strMedname);
i.putExtra("line", strLine);
final int _id = (int) System.currentTimeMillis();
PendingIntent pi = PendingIntent.getActivity(Login.this, _id, i, 0);
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
// am.set(AlarmManager.RTC_WAKEUP, trigger, pi);
// am.setExact(AlarmManager.RTC_WAKEUP, trigger, pi);
am.set(AlarmManager.RTC_WAKEUP, trigger, pi);
}
}catch(ParseException ex)
{
ex.printStackTrace();
}
The problem is that you set the alarm to go off at time trigger which is the time minus the current time.
You should pass time.getTimeInMillis() instead.
So replace the line with
am.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pi);
}
Bas van Stein is correct. AlarmManager uses an absolute time: milliseconds since epoch, January 1, 1970. You are attempting to set it to a relative time: milliseconds from the time you are setting the alarm. AlarmManager interprets that as being some time very close to epoch, around January 1, 1970, at 12:10AM. Since that time is long since past, the alarm triggers immediately.
The solution is simply to use time.getTimeInMillis() in set instead of trigger.
Some other notes for doing this kind of work, since your app is similar in intention to mine:
Most alarms since API 19 will be inexact, as Frank N. Stein pointed out. The degree of this inexactness depends on implementation and also how far in the future the alarm is created. For something like medicine which is probably at least daily, in all of my testing the alarm has fired within a minute of the intended time.
You are using the current time as the requestCode in your PendingIntent. By setting this to a number that is meaningful to your program and storing that value, you can later update or cancel this alarm by recreating the same PendingIntent.
From API level 23 and forward, urgent alarms like medication alarms should use setAndAllowWhileIdle() to ensure that their alarm goes off during low power idle states. I do not yet know if using set with RTC_WAKEUP will be sufficient to ensure this behavior.
From the official docs:
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.

Android Alarmmanager

I have a service that I would like to be executed daily in my application. The service should only be executed ONCE per day. For some reason my service gets fired several times throughout the day, I do not know what is going on. Here is my alarmmanger set up:
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,0,new Intent(this,ReviewReceiver.class),PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager)(this.getSystemService(Context.ALARM_SERVICE));
Random random = new Random();
int hour = random.nextInt(22 - 7) + 7;
int minute = random.nextInt(60 - 1) + 1;
Calendar cal = new GregorianCalendar();
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE,minute);
cal.set(Calendar.SECOND,5);
cal.set(Calendar.MILLISECOND,5);
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(),AlarmManager.INTERVAL_DAY,
pendingIntent );
I have set the alarm to randomly set itself between 7 am and 10 pm upon installation of the application.
So for example, when the alarm sets itself at 13h30, the service will be fired at that time properly. But therafter, it will get fired over and over at random intervals throughout the day. What am I doing wrong. Please help.
P.S. I have already tried using ELAPSED_TIME, ELAPSED_TIME_WAKEUP and they do not work
For Lollipop and greater (M preview also have this behavior), the alarm have a strange behavior if you don't set it in the future and at least adding 5s.
alarmManager.setInexactRepeating(
AlarmManager.RTC_WAKEUP,
now + 5s,
AlarmManager.INTERVAL_DAY,
pendingIntent );
The 5s is a known issue. and since this problem occurred (especially with my nexus 5), I am just using set() that a recall every day instead of setInexactRepeating()

Android AlarmManager hour alarm running wrong interval

Im trying to set and run an alarm that run every hour, and is set by a few variables so as it will not run instantly, if the time is greater then the 58th minute
The idea is to set it # X hour and 58 minute, so it will run every hour, at the given minute(58).
Calendar calCurrent = Calendar.getInstance();
int time = 58 ;
Calendar calx = Calendar.getInstance();
calx.set(Calendar.MINUTE, time);
calx.set(Calendar.SECOND, 5);
if (calCurrent.get(Calendar.MINUTE) > time) {
calx.add(Calendar.HOUR, +1);
}
System.out.println("Alarm is set to - " + calx.get(Calendar.HOUR)+":"+
calx.get(Calendar.MINUTE));
alarmSwap = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmSwap.setRepeating(AlarmManager.RTC_WAKEUP,
calx.getTimeInMillis(), 60 * 60 * 1000, pintent);
The code works and runs correctly for the 1st instance, then the alarm will for some reason run # 0 minute the following hour.
Timeline looks like
1:23 - Repeating Alarm Set for 1:58 (1 hour intervals)
1:58 - alarm is triggered
3:00 - alarm is triggered
I have no idea why this alarm is being triggered # :00 for the last alarm. It is not being called from anywhere else.
Any help is greatly appreciated.
All alarms are resetting after the hour clocks over the hour-
Calendar calnew = Calendar.getInstance(); calnew.add(Calendar.SECOND, +5);
alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, calnew.getTimeInMillis(),900000 , pintent);
Timeline-
1:20 triggered
1:35 triggered
1:50 triggered
2:00 triggered
2:15 triggered
2:30 triggered
From android documentation.
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.
repeating alarms are not exact after API 19. This improves androids performance as android groups alarms which are at close interval and wakes system once and finishes all alarms(from other applications also).
If you really want exact alarms the you will have to set normal one time alarm, and then set alarm again in first alarm's call.
Try this code to repeat alarm every hour
alarmSwap.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
calx.getTimeInMillis(),
AlarmManager.INTERVAL_HOUR, pintent);
Hope this will help.You can ask if you have any further queries.
This worked for me to trigger alarm after every 1hour
alarmmgr = (AlarmManager) getSystemService(ALARM_SERVICE);
long interval = 60 * 60 * 1000; // 1 hour
xassert alarmmgr != null;
alarmmgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);

Android AlarmManager - RTC_WAKEUP vs ELAPSED_REALTIME_WAKEUP

Can someone explain to me the difference between AlarmManager.RTC_WAKEUP and AlarmManager.ELAPSED_REALTIME_WAKEUP? I have read the documentation but still don't really understand the implication of using one over the other.
Example code:
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
scheduledAlarmTime,
pendingIntent);
alarmManager.set(AlarmManager.RTC_WAKEUP,
scheduledAlarmTime,
pendingIntent);
How different will the two lines of code execute? When will those two lines of code execute relative to each other?
I appreciate your help.
AlarmManager.ELAPSED_REALTIME_WAKEUP type is used to trigger the alarm since boot time:
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 600000, pendingIntent);
will actually make the alarm go off 10 min after the device boots.
There is a timer that starts running when the device boots up to measure the uptime of the device and this is the type that triggers your alarm according to the uptime of the device.
Whereas, AlarmManager.RTC_WAKEUP will trigger the alarm according to the time of the clock. For example if you do:
long thirtySecondsFromNow = System.currentTimeMillis() + 30 * 1000;
alarmManager.set(AlarmManager.RTC_WAKEUP, thirtySecondsFromNow , pendingIntent);
this, on the other hand, will trigger the alarm 30 seconds from now.
AlarmManager.ELAPSED_REALTIME_WAKEUP type is rarely used compared to AlarmManager.RTC_WAKEUP.
Despite the currently accepted and up-voted answer, AlarmManager.ELAPSED_REALTIME* types along with SystemClock.elapsedRealtime() has always been more reliable than the RTC clocks for alarms and timing.
Using ELAPSED_REALTIME_WAKEUP with AlarmManager will rely on a monotonic clock starting from boot time "and continues to tick even when the CPU is in power saving modes, so is the recommend basis for general purpose interval timing". So,
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
+ 60*1000, pendingIntent);
will make your PendingIntent fire in 1 min (60*1000 milliseconds).
Whereas, AlarmManager.RTC_WAKEUP is for the the standard "wall" time in milliseconds since the epoch. So,
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ 60*10000, pendingIntent);
may also trigger the alarm 60 seconds from now, but not reliably, because as noted in the SystemClock documentation:
The wall clock can be set by the user or the phone network (see
setCurrentTimeMillis(long)), so the time may jump backwards or
forwards unpredictably. This clock should only be used when
correspondence with real-world dates and times is important, such as
in a calendar or alarm clock application. Interval or elapsed time
measurements should use a different clock. If you are using
System.currentTimeMillis(), consider listening to the
ACTION_TIME_TICK, ACTION_TIME_CHANGED and ACTION_TIMEZONE_CHANGED
Intent broadcasts to find out when the time changes.
Also, the question only referenced only the *_WAKEUP alarms but see also the AlarmManager documentation on that to make sure you understand what the wakeup vs non-wakeup alarms provide.
Just a note. You can get the uptime millis calling:
long uptimeMillis = SystemClock.elapsedRealtime();
So if you want to fire the alarm 30 seconds from now, and you want to use the uptime clock instead of the normal clock, you can do:
long thirtySecondsFromNow = SystemClock.elapsedRealtime() + 30 * 1000;
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, thirtySecondsFromNow, pendingIntent);
Whenever you want to check for some elapsed time instead of a specific date/time, it's best to use the uptime. That's because the current time set by the user in the device can change if the user changes it using the settings.
I programmed this problem in my own project this way. in below code i am using
AlarmManager.ELAPSED_REALTIME_WAKEUP
to set alarm at a specific time.
the variable 'intentName' is used in the intentFilter to receiver this alarm. because i am firing many alarms of this type. when i cancel all alarms. i use the method cancel. given at bottom.
//to hold alarms and cancel when needed
public static ArrayList<String> alarmIntens = new ArrayList<String>();
//
public static String setAlarm(int hour, int minutes, long repeatInterval,
final Context c) {
/*
* to use elapsed realTime monotonic clock, and fire alarm at a specific time
* we need to know the span between current time and the time of alarm.
* then we can add this span to 'elapsedRealTime' to fire the alarm at that time
* this way we can get alarms even when device is in sleep mood
*/
Time nowTime = new Time();
nowTime.setToNow();
Time startTime = new Time(nowTime);
startTime.hour = hour;
startTime.minute = minutes;
//get the span from current time to alarm time 'startTime'
long spanToStart = TimeUtils.spanInMillis(nowTime, startTime);
//
intentName = "AlarmBroadcast_" + nowTime.toString();
Intent intent = new Intent(intentName);
alarmIntens.add(intentName);
PendingIntent pi = PendingIntent.getBroadcast(c, alarms++, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
//
AlarmManager am = (AlarmManager) c
.getSystemService(Context.ALARM_SERVICE);
//adding span to elapsedRealTime
long elapsedRealTime = SystemClock.elapsedRealtime();
Time t1 = new Time();
t1.set(elapsedRealTime);
t1.second=0;//cut inexact timings, seconds etc
elapsedRealTime = t1.toMillis(true);
if (!(repeatInterval == -1))
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
elapsedRealTime + spanToStart, repeatInterval, pi);
else
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, elapsedRealTime
+ spanToStart, pi);
where span function is this:
public static long spanInMillis(Time startTime, Time endTime) {
long diff = endTime.toMillis(true) - startTime.toMillis(true);
if (diff >= 0)
return diff;
else
return AlarmManager.INTERVAL_DAY - Math.abs(diff);
}
alarm cancel function is this.
public static void cancel(Context c) {
AlarmManager am = (AlarmManager) c
.getSystemService(Context.ALARM_SERVICE);
// cancel all alarms
for (Iterator<String> iterator = alarmIntens.iterator(); iterator
.hasNext();) {
String intentName = (String) iterator.next();
// cancel
Intent intent = new Intent(intentName);
PendingIntent pi = PendingIntent.getBroadcast(c, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pi);
//
iterator.remove();
}
}
Some important notes when choosing which alarm to use:(for whom who already read the upvoted votes)
The RTC_WAKEUP death valley - time change:
If the user has manually change time to the past the alarm won't go off, and future will cause the alarm to go off immediately if it past the RTC timestamp. Do not use this alarm to do any client side verification / important jobs because it have a chance to fail.
The WAKEUP meaning (Marshmallow and above)
In general - not much. Will not wakeup the device when idle or while in doze, for that alarmManager.setExactAndAllowWhileIdle or alarmManager.setAndAllowWhileIdle (Doze & Idle)

Categories

Resources