AlarmManager triggers way too soon - android

I let my background service send the geo data of the device to an API.
private static long LOCATION_INTERVAL = 1800000;
Is supposed to be the interval for the location service and the AlarmManager.
The first alarm I fire in MainActivity like this
Intent i = new Intent(this, typeof(LocationService));
PendingIntent pending = PendingIntent.GetService(this, 1, i,
PendingIntentFlags.CancelCurrent);
AlarmManager alarm = (AlarmManager)GetSystemService(AlarmService);
alarm.SetExact(AlarmType.RtcWakeup, 30000, pending);
Then, in the Service itself, I re-trigger the alarm all the time like this
Intent intent = new Intent(this, typeof(LocationService));
PendingIntent pending = PendingIntent.GetService(this, 100, intent,
PendingIntentFlags.CancelCurrent);
AlarmManager alarm = (AlarmManager)GetSystemService(AlarmService);
alarm.SetExact(AlarmType.RtcWakeup,
LOCATION_INTERVAL, pending);
Problem: The service gets called way too soon (+/- every minute!).
Question: How can I make my alarm manager stick to LOCATION_INTERVAL?

Could you please check the solution below and let me know the results?
If does not work, I delete the answer....
ISSUE
I believe the error is here:
alarm.SetExact(int type, long triggerAtMillis, PendingIntent operation);
triggerAtMillis: time in milliseconds that the alarm should go off, using the appropriate clock (depending on the alarm type).
So, your are using 1800000 as triggerAtMillis. However, 1800000 is following date in UTC: Thu Jan 01 1970 00:30:00
Since this is an old date, the alarm is fired immediately.
Solution
Maybe, you should update your code as follows:
In MainActivity, I believe that you want to fire the alarm immediately. So, create it as follows:
alarm.SetExact(AlarmType.RtcWakeup, Calendar.getInstance().getTimeInMillis(), pending);
In your service, it seems that you want to trigger your alarm after 1800000. So, you have to use:
alarm.SetExact(AlarmType.RtcWakeup, Calendar.getInstance().getTimeInMillis() + LOCATION_INTERVAL, pending);
This way, alarm will be fired 30 minutes after current time (current time + LOCATION_INTERVAL).
Keep in mind that second parameter is the date in milliseconds... It is a number which represents an whole date (and not only an interval)...

Related

Android AlarmManager.set(...): notification never received when battery low

I'm attempting to use AlarmManager to schedule a delayed check in my app. (Specifically, N minutes after a user approaches a location, I want to check whether they're still there, and if so send them a notification.)
I've implemented this by checking to see whether they've entered the region in my location update receiver and, if they have, scheduling like so:
Intent geofenceIntent = new Intent(context, GeofenceReceiver.class)
// ...intent contents not important...
PendingIntent pi = PendingIntent.getBroadcast(context, 0, geofenceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar c = Calendar.getInstance();
c.add(Calendar.SECOND, getGeofenceDelaySeconds());
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi);
Log.v("Scheduling notification check for "+c.getTime());
When the battery level is high (say, 50%), everything works like a charm. But when it's low (say, 10%), I get location updates, they schedule the alarm seemingly-successfully, but that alarm never actually triggers!
What gives? Does Android stop sending certain types of updates when it's trying to conserve power? How can I work around this (short of actually keeping my app active for the duration of the delay, which causes obvious issues with battery life)?
It turns out that this is related to the use of the real-time clock.
Although I could not find the documentation it quotes (it's not in AlarmManager), this StackOverflow answer suggests that AlarmManager.RTC_WAKEUP alarms do not trigger if the phone is in power-saving mode. AlarmManager.ELAPSED_REALTIME_WAKEUP alarms do not seem to suffer this problem, so I was able to fix the issue by switching to:
Intent geofenceIntent = new Intent(context, GeofenceReceiver.class)
// ...intent contents not important...
PendingIntent pi = PendingIntent.getBroadcast(context, 0, geofenceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
long millis = SystemClock.elapsedRealtime() + 1000 * getGeofenceDelaySeconds();
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, millis, pi);

Alarm SET OFF AND ON in Android

I am creating a clock application that has alarm feature too. The time is showing up properly and I am also setting multiple alarm properly.
I am creating multiple alarm using different id and also saving the same into Database so that I can view the list of alarms in a listview. Now I am trying to set ON and OFF functionality for my alarm. I have a problem there.
On itemclick if alarm is ON it switches OFF with the help of:
Intent intent = new Intent(Main.this,TaskRecieverForAlarm.class);
PendingIntent pi = PendingIntent.getBroadcast(Main.this, Integer.parseInt(cont[0]), intent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.cancel(pi);
The above code cancels the alarms perfectly fine.
To switch ON the alarm I am using:
Intent intent = new Intent(Main.this, TaskRecieverForAlarm.class);
intent.putExtra("AlarmDate", cont[1]);
intent.putExtra("key", Integer.parseInt(cont[0]));
PendingIntent sender = PendingIntent.getBroadcast(Main.this, Integer.parseInt(cont[0]) , intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
if(type.equalsIgnoreCase("daily"))
{
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1440*60000 ,sender);
}
else if(type.equalsIgnoreCase("weekly"))
{
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender); am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 7*1440*60000 ,sender);
}
Now as soon as I click the OFF to ON, alarm triggers and calls the TASKReceiverFORAlarm (broadcast receiver) even though the alarm time is 4 or 5 hours from the current time. I am not sure where I am going wrong?
Can somebody help me out?
Thanks!
I think I found the answer here:
public void setRepeating (int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
Added in API level 1
Schedule a repeating alarm. Note: for timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler. If there is already an alarm scheduled for the same IntentSender, it will first be canceled.
Like set(int, long, PendingIntent), except you can also supply a rate at which the alarm will repeat. This alarm continues repeating until explicitly removed with cancel(PendingIntent). If the time occurs 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.
If an alarm is delayed (by system sleep, for example, for non _WAKEUP alarm types), a skipped repeat will be delivered as soon as possible. After that, future alarms will be delivered according to the original schedule; they do not drift over time. For example, if you have set a recurring alarm for the top of every hour but the phone was asleep from 7:45 until 8:45, an alarm will be sent as soon as the phone awakens, then the next alarm will be sent at 9:00.
If your application wants to allow the delivery times to drift in order to guarantee that at least a certain time interval always elapses between alarms, then the approach to take is to use one-time alarms, scheduling the next one yourself when handling each alarm delivery.
Parameters
type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP}, RTC or RTC_WAKEUP.
triggerAtMillis time in milliseconds that the alarm should first go off, using the appropriate clock (depending on the alarm type).
intervalMillis interval in milliseconds between subsequent repeats of the alarm.
operation Action to perform when the alarm goes off; typically comes from IntentSender.getBroadcast().
The way you use that function is:
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1440*60000 ,sender);
Try this one:
//The only variable here is the desired hour of the alarm, which
// has to be obtained in milliseconds
long alarmSetAt = // The hour of the Alarm for the current date in milliseconds
long time = cal.getTimeInMillis() - alarmSetAt;
if(time > 0){
time = -time + cal.getTimeInMillis();
}
else{
time = time + cal.getTimeInMillis() + 1440*60000;
}
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1440*60000 ,sender);

Stop a service at specific time

I am starting my service using below code repeatedly. My service starts at 8am everyday. And AlarmManager repeates at every 1 min. I want to stop this sevice at 6pm. how can I do this ?
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent loggerIntent = PendingIntent.getBroadcast(this, 0,new Intent(this,AlarmReceiver.class), 0);
Calendar timeOff9 = Calendar.getInstance();
timeOff9.set(Calendar.HOUR_OF_DAY, 08);
timeOff9.set(Calendar.MINUTE, 00);
timeOff9.set(Calendar.SECOND, 00);
//--------------------------------------------------------------------------------------------------------------------
long duration = userinterval * 60 * 1000;
manager.setRepeating(AlarmManager.RTC_WAKEUP,timeOff9.getTimeInMillis(), duration, loggerIntent);
In order to cancel at 6pm exactly, I would consider 2 options:
Each time the alarm triggers (i.e. every 1 minute), check the time, and cancel if time is after 6PM.
Set a once-off alarm in AlarmManager to go off at 6PM exactly. In that alarm, cancel.
I prefer option 2 for simplicity, and modularity of each code block. So for me, I would use (2) in my proof-of-concept code, while working on the solution.
But option 1 is better from a resources point of view, as the Android system only needs to remember a single alarm. I would use (1) in my final production code.
This way of working is just my personal preference, and most ppl probably will say to use (1) right away from the start.
The details about cancelling are below...
As for how to cancel an alarm, you don't often beat an answer by #commonsware....
Below answer copied from How to cancel this repeating alarm?
Call cancel() on AlarmManager with an equivalent PendingIntent to the one you used with setRepeating():
Intent intent = new Intent(this, AlarmReceive.class);
PendingIntent sender = PendingIntent.getBroadcast(this,
0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(sender);

Android AlarmManager Triggering

I have an alarm which I can schedule to go off at a certain time. The thing is, when I shedule it into the future, it works at exactly the minute I set it for. It works as it should. But the problem is, if I schedule it in the past, it goes off immediately.
For example, if it is now 3:30pm and I schedule it for 3:35pm, it fires at 3:35pm. But if it is 3:30pm and I schedule it for 3:25pm, it fires immediately since it is in the past.
What I want it to do is, if it is int he past, just ignore it until the interval time passes.
Here is the code:
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(context, ApplicationClass.AlertNotifyID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
long milliSeconds24Hours = 86400000; //86400000 which is 24 hours in milliseconds
am.setRepeating(AlarmManager.RTC_WAKEUP, GetNotificationTime(context), milliSeconds24Hours, sender);
You need to get it to check if the scheduled time is in the past, and if so set your alarm to start the next day.

Android repeating alarm not working

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.

Categories

Resources