I set the alarm like this:
registerReceiver(wakeUpReceiver, new IntentFilter("com.example.yay"));
pi = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent("com.example.yay"), 0);
am = (AlarmManager)(getSystemService(Context.ALARM_SERVICE));
if (android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.KITKAT) {
am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+30*1000, pi);
} else {
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+30*1000, pi);
}
And it works if the device is awake, but if I turn off the screen, it doesn't turn on the screen (but wakeUpReceiver's onReceive() gets called)
What do I need to put in the manifest? AlarmManager docs don't seem to mention anything relevant to permissions or intent filter or anything like that. Maybe I'm just misunderstanding the docs as usual?
And yes, I've read all the other similar questions, but they're not helping.
You can use Wakelock to achieve this:
Different Levels Wake Locks:
FULL_WAKE_LOCK - Keep the screen at full brightness, keyboard
back-light illuminated, and the CPU running. SCREEN_BRIGHT_WAKE_LOCK -
Keeps the screen at full brightness and the CPU running.
SCREEN_DIM_WAKE_LOCK - Keeps the screen ON but lets it dim and the CPU
running. PARTIAL_WAKE_LOCK - Keeps the CPU running
Android permission for Wakelock:
Since wake locks has huge impact on battery life your application needs to request WAKE_LOCK permission in order to create them.
Create Wake Locks
To create a wake lock call newWakeLock on the Power manger as follows:
PowerManager.WakeLock wakeLock ;
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock( PowerManager.SCREEN_DIM_WAKE_LOCK, "My wakelook");
Release Wake lock
wakeLock.release();
Its very important to release wakelock or else it will drain the battery.
As answered above use wakelock create WakeLock in onReceive().
Or I suggest you to use WakefulBroadcastReceiver.
This will make sure that ur phone is awake during service.
WakefulBroadcastReceiver is the best option for the 2nd thing, about wakelocks - u can check on google some examples that show how to use alarm manager with wakelocks.
Ofc, ur service can done it's work, but sometimes sleep can occour, so I suggest you to implement it even if ur tests don't show the problem, better too keep it safe.
Are you sure onReceive() being called? Create some logs and do some tests. For now there can be 2 problems: or sleep is not calling onReceive() (here check the power managment options on your phone, I had problem with "Stamina" on my phone, which was blocking my alarms) or your phone is falling asleep before u do your work (then wakelocks/WakefulBroadcastReceiver).
Also AlarmManager will not "light up" ur screen, only CPU.
To turn on the screen use getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
or android:keepScreenOn="true" in layout.
The method suggested by another user SCREEN_DIM_WAKE_LOCK was deprecated in API level 17, keep it in mind!
For more:
https://developer.android.com/training/scheduling/wakelock.html
Related
It seems there are a few questions related to the subject topic but I haven't found a clear yes/no answer to this.
I have a foreground service that calls setExactAndAllowWhileIdle to start a BroadcastService. Below is the code in the Broadcast Receiver.
public class StepCountUpdaterAlarm extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "myExampleApp::UpdateSteps");
wakeLock.acquire(3);
StepCounterHandler handler = StepCounterHandler.getInstance();
new TaskRunner().executeAsync(
new SetStepsForDay(SaveSharedPreference.getMemberId(context),
handler.getCumulativeSteps()),result -> {
handler.setAlarm(context);
if(isTimeToReset())
handler.resetStepsCounter();
});
wakeLock.release();
}
In the setExactAndAllowWhileIdle documentation it states:
When the alarm is dispatched, the app will also be added to the
system's temporary power exemption list for approximately 10 seconds
to allow that application to acquire further wake locks in which to
complete its work.
but in the Doze mode documentation it states this as a restriction:
The system ignores wake locks.
Does that mean acquiring a partial wake lock for 3 minutes in the 10 second window provided by an alarm dispatched by setExactAndAllowWhileIdle in Doze mode will effectively be useless or will it work fine?
In my case, the Broadcast Receiver will send data to my remote server via that async task, and after that it will set the alarm again and reset my steps counter. Will this work and if it wont, what are my alternatives for sending a network request in doze mode and executing follow up code?
EDIT: Testing by debugging my app shows that when forcing a device into idle mode, i still have network access and can send data to my server. The Doze mode documentation states how to force to app into the idle state which i am fairly sure is synonymous with doze mode. Yet this is supposed to be a restriction so I am clueless as to how this could be working.
A WakeLock won't help you much if the device is in Doze mode. setExactAndAllowWhileIdle will wake your device up if you have used either AlarmManager.ELAPSED_REALTIME_WAKEUP or AlarmManager.RTC_WAKEUP as the alarm type.
However, from Android 12 you need SCHEDULE_EXACT_ALARM permission to set exact alarms. And if you are planning to release the app to PlayStore there are some acceptable use cases for setting an exact alarm. Make sure your app complies with these policies.
Yes, Doze will ignore your wakelock. However with setExactAndAllowWhile Idle you will be worken up at the correct time, and you'll have that 10s window to do any processing you wish.
My IntentService gets fired from 2 places, either by an Alarm or by the Activity and since the duration is related to the amount of data it needs do fetch from the web, from what I understood, I need to keep a partial wakelock.
Here's my implementation:
#Override
protected void onHandleIntent(Intent intent) {
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WakeLock");
try {
wakeLock.setReferenceCounted(false);
wakeLock.acquire(3600000);
///other code here
}
catch{
}
finally{
if (wakeLock.isHeld()) {
wakeLock.release();
}
}
My question is: will this work good enough? Will the finally make sure that the wakelock is released in any circumstances? From what I know onHandleIntent handles intent one after another, so there is no risk in having 2 intents/2 wakelocks in the same time.
Later edit:
The IntentService is called in 2 ways:
from my Activity, like
startService(new Intent(context, MyService.class).putExtra()..);
2 from a triggered Alarm using a PendingIntent
PendingIntent pendingIntent = PendingIntent.getService(context, someId, myServiceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Will the service have enough time to aquire wakelock when ran from the Alarm?
Whether you need to keep wake-lock or not should not be related to the amount of work your Service does - theoretically, device can go to sleep even if the amount of work is small.
Wake-locks should be considered only if you absolutely must ensure that device can't sleep while the Service is running. Cases like this are very rare. Some examples:
Alarm clock applications (need to wake you up even if the device is sleeping)
Real time messaging applications (need to notify you about new messages even if the device is sleeping)
Most applications don't have such a strict timing requirements. For example, the following are NOT good reasons to use wake locks:
Periodic synchronization of data with the server (should be delayed until device awakes)
Displaying current user's location on map (can be obtained when device awakens; but wake-lock will be needed for applications that monitor user's entire route)
If you really need to ensure that the device doesn't sleep during Service execution, then you need to acquire a wake-lock (one of the several types). Let's assume that this is the case here.
You want to be able to start the "wakeful" Service from application's UI (Activity), and using AlarmManager.
Starting from UI
Since the device should be completely awake in order for the user to interact with UI, you can safely assume that if you start the Service in response to UI interaction it will have a chance to acquire a wake-lock (but do it as soon as the Service is started).
Your solution covers this case.
Starting from AlarmManager
Unfortunately, there is no guarantee (at least no documented guarantee) that when AlarmManager starts the Service it will hold a wake lock and allow the Service to acquire its own wake-lock. This means that the device can go to sleep after alarm fired, but before your Service had a chance to acquire the wake-lock.
This means that your solution will "break" in this case.
The only documented scheme in which AlarmManager will help you with wake-locks involves broadcasts:
The Alarm Manager 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 Alarm Manager releases this wake lock.
This means that the phone will in some cases sleep as soon as your
onReceive() method completes. If your alarm receiver called
Context.startService(), it is possible that the phone will sleep
before the requested service is launched. To prevent this, your
BroadcastReceiver and Service will need to implement a separate wake
lock policy to ensure that the phone continues running until the
service becomes available.
This is where WakefulBroadcastReceiver comes in very handy.
Note that if you use this scheme, then there is no need to support a different one for "UI initiated" case - use the same approach in both cases.
You might also want to take a look at this library developed by #CommonsWare (I didn't use it myself though).
I'm struggling with AlarmManager.setExact() for couple of days. My application needs exact alarms and works fine on older Androids with AlarmManager.setRepeating().
I've read that it has changed since API 19 and updated my code accordingly.
Here is the code responsible for setting an alarm:
PendingIntent pi = PendingIntent.getBroadcast(context.getApplicationContext(), alarmOrder+1, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getAlarmManager(context).setExact(AlarmManager.RTC_WAKEUP, alarmTimeMillis, pi);
}
else {
getAlarmManager(context).setRepeating(AlarmManager.RTC_WAKEUP, alarmTimeMillis, AlarmManager.INTERVAL_DAY, pi);
}
Broadcast receiver starts new activity with alarm screen:
#Override
public void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AlarmTimeReceiver");
wl.acquire();
Intent alarmIntent = new Intent(context, AlarmActivity.class);
alarmIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(alarmIntent);
//Release the lock
wl.release();
}
The thing is that while testing on Android 4.4 device connected via USB cable all works fine. Alarm starts on specified time all the time (with screen turned on/off). Unfortunately, when I disconnect device from computer, alarm starts correctly only when screen is turned on. When I turn screen off, alarms starts in inexact time.
Have I missed something? Have any of you experienced similar situation?
It runs correctly on Android < 19
Not really.
A _WAKEUP alarm guarantees -- via a framework-managed WakeLock -- that the device will stay awake until onReceive() returns. Then, the framework releases the WakeLock, and the device can fall back asleep... if there are no other outstanding WakeLocks.
Your WakeLock, as written, is pointless. It merely duplicates the framework-managed WakeLock without adding value.
startActivity() is asynchronous. The activity will not be anywhere near started by the time onReceive() ends and the framework-managed WakeLock (and your additional one) are released. Now, sometimes, your activity will get a chance to start up anyway, because the device does not fall back asleep quickly. I presume that you are using android:keepScreenOn or the equivalent in the activity, so once you get to that point, there is another WakeLock outstanding, and the device cannot fall back asleep automatically.
However, sometimes the device will indeed fall back asleep before your activity starts up. That might have changed with Android 5.0 -- it would not surprise me in the least if Android is more aggressive about putting the device back to sleep more quickly. So, while your previous approach might have worked 90% of the time, it may be a lot less now. However, your previous approach did not work 100% of the time.
We see the same thing with services. In fact, this scenario is a lot more common there. That's why, back in April 2009, I created the WakefulIntentService, and why in August 2013, Google released WakefulBroadcastReceiver. Both offer a pattern for acquiring the WakeLock in onReceive() but then not releasing it until the service's work is finished.
Neither of those solutions will work out of the box for you, as both are tied inextricably to services. However, you can use those as a source of ideas for rolling your own. You need to move your WakeLock into a static data member (ick), and only release() it once your activity is far enough along that it has its own WakeLock. For example, if you are calling setKeepScreenOn() on a View in Java code, once that is done, I would expect that it is safe to release your original WakeLock. Then, the framework can take over and release the keep-screen-on WakeLock based upon user input.
I am bit confused after going through the questions & answers in Stackoverflow about WakefulIntentService. I just would like to get some knowledge on this topics to make sure my understanding is correct, please feel free to correct me, if I am wrong.
I built a small application, where I am using a background Service that keeps playing music whenever the user shakes the mobile. I tested after the device is locked and screen is turned off and it works as expected.
What I am hearing from this forum, the service might turn off as soon the device goes to asleep. Is that true? In my case, it works always, Am I missing something?
What is the need of WakeFulIntentService? When do we need to use WakefulIntentService?
I tried running a timer in a Service, though the device is locked and screen is turned off and my timer is running pretty much I can say for sure. Because I used to get notification whenever my timer trips.
What I am hearing from this forum, the service might turn off as soon the device goes to asleep. Is that true?
Yes.
In my case, it works always
Then something else on your device is keeping the device from falling asleep. Perhaps use adb shell dumpsys power to see what WakeLocks are outstanding.
What is the need of WakeFulIntent Service? When do we need to use WakefulIntentService?
The device may fall asleep if the user is inactive and nothing is keeping the device awake. A WakeLock is used to ensure the device stays awake. For transactional-type work (e.g., downloading a file), WakefulIntentService combines an IntentService and a WakeLock to make keeping the device awake as long as necessary (and only as long as necessary) relatively easy.
WakefulIntentService is not suitable for use with services that need to run indefinitely, such as a music player. For those, manage your own WakeLock.
I used the code below in an app.
Make sure your service is sticky:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
//this service will run until we stop it
return START_STICKY;
}
I you want your phone to be awake constantly u can use this code below:
private WakeLock wl;
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "whatever");
wl.acquire();
Don't forget the permissions in your manifest.
<uses-permission android:name="android.permission.WAKE_LOCK" />
When the screen turns off, my application service is paused.
I start my service with the following code:
if (mSharedPrefs.getBoolean("prefAutoUpdatesMain", false)) {
Intent svc = new Intent(this, MyService.class);
startService(svc);
}
How can I can avoid the service pause?
What I have to do in MyService is to download some data from Internet. If I have understand the process I have to follow is:
Acquire wakeLock
Download data
Release wakeLock
In downloading data method there are no reference to wakeLock, it is the application to have the wakeLock, is it correct?
Wake locks are reference counted by default. I think it is better a wakeLock without reference counting, to be sure to release it, am I wrong?
A partial WakeLock is what you want. It will hold the CPU open, even if the screen is off.
To acquire:
PowerManager mgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
To release:
wakeLock.release();
WakeLock also supports reference counting so you may have multiple things in your service that require wake functionality, and the device can sleep when none of them are active.
Things to watch out for:
If you use reference counting, make sure all control paths through your application will properly acquire/release...finally blocks come in handy here.
Also be sure to hold WakeLocks infrequently and for short periods of time. They add up in terms of battery use. Acquire your lock, do your business, and release as soon as possible.
You need a partial wake lock.
Detailed example here in a previous question:
Wake locks android service recurring
I'm just using a foregrgound service.