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);
Related
I had created alarm manager which invoke after 2 minutes which I want. But currently, i'm not able to set it more than 20 seconds. if I set for 20 seconds it returns output but if I set it for more than 20 I'm not able to set. I want to set it for 2 minutes. kindly help me.
I had added alarm fire code
AlarmManager manager = (AlarmManager) ContextGetter.getContext().getSystemService(Context.ALARM_SERVICE);
Intent intnt = new Intent(ContextGetter.getContext(), AlarmBroadcastReceiver.class);
intnt.setAction("com.demo.alarmEvent");
PendingIntent pending = PendingIntent.getBroadcast(ContextGetter.getContext(), 0, intnt, 0);
manager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+ 30*1000, pending);
kindly help me
i want it set it only once.
I also tried with this one.
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intnt = new Intent(EnterSysNumber.getInstance(), AlarmReceiver.class);
intnt.setAction("com.demo.Enter_number");
PendingIntent pending = PendingIntent.getBroadcast(getApplicationContext(), 0, intnt, 0);
manager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 120000, pending);
In Android N you'll run into Doze mode. Doze is a deep sleep mode to save battery power. It will prevent your service to preserve battery power.
AlarmManager and using setExactAndAllowWhileIdle when in low-power idle modes this duration may be significantly longer, such as 15 minutes.. But this is NOT suggested for any Play Store app, you will kill your user's battery.
I'm working on an app that involves an AlarmManager, and I can't seem to get it to fire. I was using a Handler originally, but I switched over to the AlarmManager so that I can wake the phone up from sleep.
Here's what I have so far:
int timeBetweeninMillis = 3 * 60000;
if (ManagerService.serviceRunning) {
Intent alarmIntent = new Intent(AlarmReceiver.ACTION_RECEIVE);
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 400, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, (SystemClock.elapsedRealtime() + timeBetweeninMillis), alarmPendingIntent);
}
The AlarmManager either won't fire or will fire extremely late (like 10 minutes after).
The app is written with API 16 and is being tested on a phone with API 19.
Thank you for your help!
There's an issue with new PendingIntents recycling existing PendingIntents that might cause issues with AlarmManager.
To workaround that, I always add a unique value to all my PendingIntents, this one-liner does the trick in most cases:
Intent alarmIntent = new Intent(AlarmReceiver.ACTION_RECEIVE);
alarmIntent.setData(Uri.parse("custom://" + System.currentTimeMillis())); // MAKE INTENT UNIQUE
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 400, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, (SystemClock.elapsedRealtime() + timeBetweeninMillis), alarmPendingIntent);
Also, I don't know what's ManagerService.serviceRunning in your code, but I would add some log to the else case to make sure you're actually running that code block.
EDIT:
try using mAlarmManager.setExactAndAllowWhileIdle instead of mAlarmManager.set this will force AlarmManager to call your code exactly when requested, and prevent device idle time from interfering with the alarm.
See:
https://developer.android.com/reference/android/app/AlarmManager.html#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent)
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)...
We are using following code for repeating task:
Intent alarmIntent = new Intent(MainActivity.this, TestReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
int interval=15000;
manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
Will this drains battery?
I suggest you to read:
Scheduling Repeating Alarms
Here you'll find all your answers!
The sort answer "no". The waiting alarm feature doesn't consume the battery.
But, obviously, if the interval is about several seconds the device will consume battary (if you try to call very often). In other cases this is the best way to do the work. If you want to recall the service namely 15 seconds and calculations are huge the devices will never sleep. In this case this will consume.
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);