Questions about Alarm Manager behavior and wakelocks - android

I'm using alarm manager in my service to set non-waking alarms every 15 seconds to execute a certain task. I don't want to wake the phone up as the task isn't time critical, so i'm using the ELAPSED_REALTIME flag to set the alarm. Here's the code:
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), 15 * 1000, intentRecurringChecks);
What I'm noticing in my logs is that the task is getting executed every 15 seconds. Does this mean the phone is staying awake even though it's screen has been turned off for half an hour? Is there a way I can be sure my application's not the one waking up the phone?
I've search about this topic but I can't find a proper answer.
Thanks for your help.

First, you shouldn't use AlarmManager for such timeouts. This is explicitly mentioned in documentation (read the bold part). It's better to use Handler based timers in your case. Here is an example: Repeat a task with a time delay?.
Second, when device is connected via USB, its not going to deep sleep mode. You should disconnect your device wait a minute or two. Attach it back and analyze the logs.

Related

Any way to prevent alarm from firing if it did not run because of doze mode?

This Doze mode makes it quite hard for me to implement proper alarms system. Basically I want to allow my user to run a webservice call each 15 or 30 minutes for instance. So let's say the user sets the app to run the alarm each 30 minutes. While the device is normal use, the alarms will fire more or less exact (I'm using setRepeating) but it's good enough for my purpose.
When the device is dozing, as per docs, my repeating alarms do not fire, BUT when the device exits doze mode, all the alarms that did not run, run one after another(or similar). So I end up in the morning with maybe 4-6 alarms fired one after another, all fetching the same data from the webservice. Or same thing when a maintenance window occurs...
Is there a way to tell the doze mode that if my alarm did not fire at required time, to not run it at all? Or if there are multiple alarms that did not fire, only fire the last one?
LE: I had an error in code which ran the alarm too often, that is why I had the impression that postponed alarms will all run one after another...

setExactAndAllowWhileIdle - is not exact as of developer reference

AlarmManager on API19 has the method setExact() to set an exact alarm.
Exact means --> If I set an alarm to 2:01 pm it will be triggered at 2:01 pm
On API 23 - Marhsmwallow (6.0) there is a new method setExactAndAllowWhileIdle(), but as of the reference it is not EXACT because it will trigger only every minute and in low power idle mode only every 15 minutes.
Exact != every 15 minutes :-)
So how can I achieve an exact alarm with AlarmManager in 6.0?
If a user adds a reminder or a calendar appointment and wants to be informed 10 minutes before the event it should show the alarm EXACT 10 minutes before the event. With setExactAndAllowWhileIdle() this seems is not possible.
Reference Link:
http://developer.android.com/reference/android/app/AlarmManager.html#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent)
So how can I achieve an exact alarm with AlarmManager in 6.0?
You are welcome to try setAlarmClock(), as AFAIK it is unaffected by Doze mode. Otherwise, AlarmManager is not a viable option for you. Even having your app on the battery optimization whitelist will not help, as AlarmManager behavior does not change based on the whitelist.
You are welcome to use GCM, as a high-priority message should give you an opportunity to alert the user. This, of course, requires network connectivity.
The only offline solution that I am aware of — and that I am presently testing — is to have the user add your app to the battery optimization whitelist, then use a foreground service (to try to keep your process around), a ScheduledExecutorService (for the timing), and a partial WakeLock (to keep the CPU on). This will be fairly devastating to the user's battery.
Using setExactAndAllowWhileIdle() for a one-time alarm will fire exactly on the given time even in Doze idle mode. So this probably is the way to go.
Problems start, if you want to repeat the alarm at a rate of < 15 min (or set any other at a time < 15 min away from the last one), as this will not work in Doze idle mode, where such alarms are forced to the next 15 min or are executed when idle maintenance starts, which happens for about ten minutes first after 1 hour, then after another 2 hours, then after another 4 hours and so on.
- EDIT -
As of today Nov 17, Dianne Hackborn writes in this Post's comments:
"For what it's worth, the minimum time between while idle alarms will be changing to 9 minutes at some point relatively soon (even on devices running the current Marshmallow builds)."
This doesn't change anything fundamentally though.
Here are my discussion with Ian Lake on Google+!
setExactAndAllowWhileIdle() is exact and should work.
The 15 minutes time frame is wrong in the java doc.
I was trying to create an automation system running in the background. My frequency range was between 1-15 minutes. My wish was not to use a foreground service. By looking at the name of the method "setExactAndAllowWhileIdle", I thought that yeah it is safe to go with one-time alarms, scheduling the next one when done.
However, I couldn't find a way to run code in doze mode with alarms running more frequent than 15 minutes. Instead, I choose to start a foreground service when doze mode gets activated and stop that foreground service when phone awakes. User won't be seeing your foreground notification while using his/her phone. I don't care much about the ones in doze mode.
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(intent.getAction().equals("android.os.action.DEVICE_IDLE_MODE_CHANGED")){
if (pm.isDeviceIdleMode()) {
//startAutomationForegroundService();
} else {
//stopAutomationForegroundService();
return;
}
AutomationReceiver.completeWakefulIntent(intent);
return;
}
}
You need to register "android.os.action.DEVICE_IDLE_MODE_CHANGED" intent filter into your WakefulBroadcastReceiver. Care putting it into manifest may not help.

TimerTask vs AlaramManager, Which one should I use?

I am working on an application which triggers an action (say toast message) every 10 minutes after the screen is ON and stops the action after the screen is OFF.
I have used TimerTask for this purpose.
Shall I start using AlaramManager instead of TimerTask or shall I keep using TimerTask ?
I know the difference between the two but can't figure out which to use.
Cant' agree with the nikis' answer
Timer and AlarmManager are solutions addressed to satisfy different needs.
Timer is still a "task" that means this is a thread of your application that means that some component of your application must be running on device to keep timer alive.
If you set timer for 10 minutes events - you can't be sure if your application will not be disposed by system in some moment. If device will be turned into the sleep mode your timer can be stopped. To prevent behavior like that you have to use PowerLock's and drain battery
AlarmManager is system service (runs outside your application) that means that the pending intent will be sent even if your application is killed after setting the alarm.
Some examples:
You have to blink some "led" on the view every 1 s - use Timer - you need it only when application is in foreground, there are short intervals - no point in using AlarmManager for task like that.
You have run some task once after 10 s - Handler.postDelay(); will be the best solution for that, and the job will be done on main thread (UI).
You have to check every 10 minutes if there is some new content on device that you are supposed to push to the server - use AlarmManager - your application does not need to be alive all the time, just let system to start job you want every 10 minutes - that's all.
In most cases you should definitely use AlarmManager, because (from the docs):
The AlarmManager holds a CPU wake lock as long as the alarm receiver's onReceive() method is executing. This guarantees that the phone will not sleep until you have finished handling the broadcast. Once onReceive() returns, the AlarmManager releases this wake lock. This means that the phone will in some cases sleep as soon as your onReceive() method completes.
Although you don't need to fire any event while screen is off, AlarmManager still saves the battery by grouping alarms, when you use setInexactRepeating (but this is not important for you, because your interval is 10 minutes). And moreover, it can fire an event is app is not running. I vote for AlarmManager, because it's good practice, but considering your conditions, you can leave Timertask.
BTW, you can also use Handler, which I believe will be the best choice.

Updating widget frequently using alarm manager

I have a widget that I need to update frequently with new content only while the device is awake.
I will use an alarm manager for this and set alarm type to either ELAPSED_REALTIME or RTC, as suggested on "App Widgets" guidelines on android developer site.
The problem is that I need to update the widget every 5 seconds (probably configurable) while the screen is on.
Wherever I searched people say that 5 seconds is insane, but I haven't yet really understand if this is gonna be a problem if I update only when the device is awake. Is there a different approach I can take to this problem? How clock widgets do this?
While experimenting I realized that when the screen goes off the alarm still triggers.
It stops triggering only when the device goes into deep sleep, in which case 5 seconds are too few anyway for the device to have time to go into sleep.
So what I did is filter the SCREEN_ON broadcast and schedule the alarm every 5 seconds. Then filter SCREEN_OFF broadcast and cancel the alarm.

Run Command/Service on first occasion of day

I'm writing a simple Widget for Android which displays information which changes for every day. So the widget needs to be refreshed on midnight. The whole refreshing is implemented as a service and runs nicely, the problem is the invocation:
The only solution I found is to use the AlarmManager to a add an exact reoccurring timer on midnight each day. Then aquire a partial Wake-Lock, to make sure the device stays awake and run the code. This should work as expected but due to the usage of the wake lock, I am waking the device, so I am searching for a slimmer version:
There is no need to wake the device up on exact midnight, it is enough if I receive a timer event the first time the Device is up again on a new day. If the device is sleeping, nobody can look on the widget, so it is ok if the widget updates whenever the device is switched on again.
In other words: How do I run a service on the first moment of a day when the device is not sleeping, thus preventing a wakeup? I still need the device to stay awake than for period of time.
How can this bis done?
You can tell the AlarmManager to delay your invocation until the device wakes up anyway.
Then don't use a WakeLock in the.

Categories

Resources