I am having trouble with wakelocks. Basically, I had the wakelock running in my timer thread, a doInBackground of an AsyncTask for the entire duration of my app (it is a background app for taking performance measurements). Then I decided I only want the screen to wakeup every 10 minutes or so for a second or so. So I created another class extending AsyncTask and put the code below into it's doInBackground, but now the screen doesn't turn back on. I should note that I start this thread and two other threads that are AsyncTask with doInBackground methods from onCreate.
Here is my new inner class doing the waking up: Essentially all it is supposed to do is wake the phone screen up every 10 minutes for a bit until my other two background threads set their booleans true.
private class WakeUp extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, getClass().getName());
do{
try {
Thread.sleep(WAKEUP_EVERY); //600000ms
} catch (InterruptedException e) {
e.printStackTrace();
}
wl.acquire();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
wl.release();
}while(!timeCompleted || !transferCompleted);
return null;
}
}
You've forgotten to tell the wake lock to turn on the screen using the ACQUIRE_CAUSES_WAKEUP flag. As per the documentation:
Normal wake locks don't actually turn on the illumination. Instead, they cause the illumination to remain on once it turns on (e.g. from user activity). This flag will force the screen and/or keyboard to turn on immediately, when the WakeLock is acquired. A typical use would be for notifications which are important for the user to see immediately.
See ACQUIRE_CAUSES_WAKEUP for more details :D
Related
My app runs smoothly on the emulator - everything working exactly as it should - but not on my phone.
In my app, I use both a countdownTimer which ticks every minute, and an alarm manager, which should ensure that the user will be notified of whatever it needs to be notified of, should the phone be asleep.
Once the receiver receives the Alarm manager's broadcast, I acquire a partial wake lock for 5 seconds (which is even more than should be needed).
I checked, and wakelock.isHeld() returns true. I have the necessary permission, and the onReceive doesn't take that long (it is not at all computationally expensive).
And yet, the countdownTimer doesn't catch up. nothing else is fired until I actually unlock the phone and look at the app.
Any ideas why? I can't for the life of me figure this one out.
edit: Tried moving the wakelock (wl) declaration outside of the function (and even to the outer class), even though things worked as they were on the emulator (and from what I understand it shouldn't make a difference anyway, which it, indeed, did not :( )
code:
public class Class1 extends Binder {
public static class Class1A extends BroadcastReceiver
{
public void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp");
//Acquire the lock
wl.acquire(5 * 1000); //5 seconds to expiration
// Do a few things
}
/// Some more code setting up the alarm
}
private class ReminderHandler extends CountDownTimer {
#Override
public void onTick(long millisUntilFinished) {
logTxt.append("\nTicked. ");
}
#Override
public void onFinish() {
GregorianCalendar tmp = new GregorianCalendar();
logTxt.append("\nCountdown completed at "+ frmtr.format(tmp.getTime()));
}
public ReminderHandler(int Len)
{
super((((long) Len)*60*1000),60*999);
}
}
}
}
As I said, the alarm is received, I acquire a wakelock successfully, but the onTick doesn't happen until I actually unlock the phone and open the app.
Well, this is not an answer I am happy with, but for now, this is all I have:
It seems the it takes more than 5 seconds (and even more than the 15 seconds I later gave it to test this) for the CountdownTimer to catch up (even if it should have only had 1 onTick and 1 onFinish call to catch up to).
I simply released the wakelock in the onFinish. I don't like this (since if there is some bug, it could end up holding the wakelock for way too long), but for now, this is all I can do.
I building a Android based SMS Server.
It shall request server (each x seconds) for new SMSes to send (in an infinite loop).
The Android device will be always plugged-in via USB to the server.
The fetching of the new messages is running as a service and I need it to run 24/7.
Since battery draining is not an issue here, how should I use the WakeLock?
As I read some articles about the partial lock it seems to be sufficient.
But yet I did not find any clues when should I call the wakeLock.acquire(); and wakeLock.release();
I do not suppose that it could work like that:
while(true){
wakeLock.acquire();
//Do stuff
wakeLock.release();
Thread.sleep(10000);
}
Considering the idea... Any inputs would be greatly apperciated. For example does it make sense to scheduler a daily restart of the phone so it will not get stucked? etc...
As explained here, various type of lock can be used. If you want to be always on, then you can acquire it outside the loop :
boolean end = false;
wakeLock.acquire();
while(!end){
//Do stuff
Thread.sleep(10000);
}
wakeLock.release();
But you shouldn't really use a loop for that, try an handler instead to do repeating tasks :
http://developer.android.com/reference/android/os/Handler.html
Example :
private class MyRunnable implements Runnable {
#Override
public void run() {
// Do stuff
handler.postDelayed(new MyRunnable(), 100000);
}
}
Handler handler = new android.os.Handler();
handler.postDelayed(new MyRunnable(), 1000000);
The handler is useful if you need to do a repeating task often and with a short period. If there period is longer (like few hours), use the AlarmManager :
Alarm Manager Example
That is a good example of what you can do, and they also use a wakelock for their tasks.
use the bellow way to wake up the device
private void wakeUpTheDevice()
{
pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wL = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK|PowerManager.ACQUIRE_CAUSES_WAKEUP, "wakeupdevice");
if ((wL != null) && // we have a WakeLock
(wL.isHeld() == false) ){ // but we don't hold it
wL.acquire();
}
}
I have the following code in my BroadcastReceiver's onReceive function.
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) return;
if (action.equals(ACTION_ALARM)) {
Intent alarmPopup = new Intent(context, AlarmPopup.class);
int vibrateDuration = context.getSharedPreferences(PREF, 0)
.getInt(VIBRATE_DURATION, DEFAULT_VIBRATE_DURATION)
alarmPopup.putExtra(VIBRATE_DURATION, vibrateDuration);
alarmPopup.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(alarmPopup);
}
}
This code starts activity AlarmPopup as it receives alarm manager's broadcast.
Once the AlarmPopup activity is started, it shows a typical alarm message and vibrates during vibrateDuration passed through Intent#putExtra.
In AlarmPopup's onCreate method, the activity holds WakeLock to make the device keep turning on.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
wl = getLock(this);
if (!wl.isHeld()) {
Log.d(PREF, "Alarm popup acquires wake lock");
wl.acquire();
thread.run();
}
.
.
.
}
getLock is a synchronized method that manages WakeLock as WakefulIntentService does.
private static volatile PowerManager.WakeLock wlStatic = null;
synchronized private static PowerManager.WakeLock getLock(Context context) {
if (wlStatic == null) {
PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wlStatic = mgr.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.ON_AFTER_RELEASE, PREF);
wlStatic.setReferenceCounted(true);
}
return wlStatic;
}
Now here is the problem: even though context.startActivity(alarmPopup) is called, startActivity rarely does not start the activitiy or starts not on time, usually 1-2 minutes later.
It seems that OS kills my AlarmPopup activitiy in the middle of its creation or let the activity be created a little bit later than the time when startActivity was actually called.
What is really interesting is, when the above problem happens, sometimes the log message "Alarm popup acquires wake lock" is recorded and sometimes it is not even recorded. I think, in this case, OS kills the activity while it executes the first or second line of onCreate method.
How can I solve this problem?
Should I put some dummy code that holds the CPU at the end of onReceive while the AlarmPopup activity is being created by another thread?
It seems that OS kills my AlarmPopup activitiy in the middle of its creation or let the activity be created a little bit later than the time when startActivity was actually called.
No. The device simply fell asleep. startActivity() is an asynchronous operation. The WakeLock held by the OS for the AlarmManager work (assuming that you are, indeed, using AlarmManager) will be released when onReceive() returns. onCreate() of your activity will not have run by the time onReceive() returns. Hence, the device might fall asleep in the window of time between the end of onReceive() and when you acquire your WakeLock in onCreate().
How can I solve this problem?
Acquire the WakeLock in onReceive().
I am trying to turn on and off the display after a certain action happens (Lets just worry about turning the screen off for now). From what I understand from wake lock, this is what I have:
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
When I read other posts on stackoverflow and else where, they seem to tell me that PARTIAL_WAKE_LOCK will turn the screen off. But if I read the SDK it says that it will only allow the screen to be turned off. I think this isn't right.
There are two choices for turning the screen off:
PowerManager manager = (PowerManager) getSystemService(Context.POWER_SERVICE);
// Choice 1
manager.goToSleep(int amountOfTime);
// Choice 2
PowerManager.WakeLock wl = manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Your Tag");
wl.acquire();
wl.release();
You will probably need this permission too:
<uses-permission android:name="android.permission.WAKE_LOCK" />
UPDATE:
Try this method; android turns off the screen once the light level is low enough.
WindowManager.LayoutParams params = getWindow().getAttributes();
params.flags |= LayoutParams.FLAG_KEEP_SCREEN_ON;
params.screenBrightness = 0;
getWindow().setAttributes(params);
The following is copied from SDK document.
If you want to keep screen on, I think SCREEN_BRIGHT_WAKE_LOCK is enough.
Flag Value CPU Screen Keyboard
PARTIAL_WAKE_LOCK On* Off Off
SCREEN_DIM_WAKE_LOCK On Dim Off
SCREEN_BRIGHT_WAKE_LOCK On Bright Off
FULL_WAKE_LOCK On Bright Bright
For me those methods didn't work. So I used other scenario (not trivial) to make my screen off.
Android has 2 flags that responsible to be awake:
Display --> Screen TimeOut
Application --> Development --> Stay awake while charging check box.
I used followed flow:
1st of all save your previous configuration, for example screen timeout was 1 min and Stay awake while charging checked.
After, I uncheck Stay awake while charging and set screen timeout to minimal time.
I register to broadcast receiver service to get event from android that screen turned off.
When I got event on screen off, I set previous configuration to default: screen timeout was 1 min and Stay awake while charging checked.
Unregister receiver
After 15 sec. device sleeps
Here is snippets of code:
BroadcastReceiver
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* Catch Screen On/Off
* */
public class BroadcastReceiverScreenListener extends BroadcastReceiver{
private BroadCastListenerCallBackItf mBroadCastListenerCallBack = null;
public BroadcastReceiverScreenListener(
BroadCastListenerCallBackItf broadCastListenerCallBack) {
this.mBroadCastListenerCallBack = broadCastListenerCallBack;
}
#Override
public void onReceive(Context arg0, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
mBroadCastListenerCallBack.broadCastListenerCallBack__ScreenOff_onResponse();
}
}
}
Interface used as callback
public interface BroadCastListenerCallBackItf {
public void broadCastListenerCallBack__ScreenOff_onResponse();
}
2 methods from main class:
....
AndroidSynchronize mSync = new AndroidSynchronize();
....
public void turnScreenOff(int wait){
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadCastListenerCallBackItf broadCastListenerCallBack = this;
BroadcastReceiver mReceiver = new BroadcastReceiverScreenListener(broadCastListenerCallBack);
m_context.registerReceiver(mReceiver, filter);
//set Development --> disable STAY_ON_WHILE_PLUGGED_IN
Settings.System.putInt(
m_context.getContentResolver(),
Settings.System.STAY_ON_WHILE_PLUGGED_IN,
0 );
// take current screen off time
int defTimeOut = Settings.System.getInt(m_context.getContentResolver(),
Settings.System.SCREEN_OFF_TIMEOUT, 3000);
// set 15 sec
Settings.System.putInt(m_context.getContentResolver(),
Settings.System.SCREEN_OFF_TIMEOUT, 15000);
// wait 200 sec till get response from BroadcastReceiver on Screen Off
mSync.doWait(wait*1000);
// set previous settings
Settings.System.putInt(m_context.getContentResolver(),
Settings.System.SCREEN_OFF_TIMEOUT, defTimeOut);
// switch back previous state
Settings.System.putInt(
m_context.getContentResolver(),
Settings.System.STAY_ON_WHILE_PLUGGED_IN,
BatteryManager.BATTERY_PLUGGED_USB);
m_context.unregisterReceiver(mReceiver);
}
public void broadCastListenerCallBack__ScreenOff_onResponse() {
mSync.doNotify();
}
....
AndroidSynchronize class
public class AndroidSynchronize {
public void doWait(long l){
synchronized(this){
try {
this.wait(l);
} catch(InterruptedException e) {
}
}
}
public void doNotify() {
synchronized(this) {
this.notify();
}
}
public void doWait() {
synchronized(this){
try {
this.wait();
} catch(InterruptedException e) {
}
}
}
}
[EDIT]
You need to register permission:
android.permission.WRITE_SETTINGS
Per this link, You can also turn the screen off like this:
Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 1000);
1000 is in milliseconds which means 1 second, you can replace it with any value as desired.
Needed permission:
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
try -
wakeLock.acquire(1000); // specify the time , it dims out and eventually turns off.
I have this application that needs to run a service (background) that beeps periodically.
The phone needs to beep the entire day for 5 seconds every one minute (used a handler in the service). I have implemented this service which does this perfectly, but when the phone goes into deep sleep mode, the execution stops of this handler stops. Using this answer from the question in SO, I managed to use wake locks and it works fine. But when I explicitly put the phone in deep sleep mode, the handler stops executing. Where do I place the wakelock in the service. Code snippet below.
public class PlaySound extends Service{
PowerManager.WakeLock wl ;
PowerManager pm;
private SoundManager mSoundManager;
boolean wakeUpFlag = false;
#Override
public void onCreate(){
super.onCreate();
mSoundManager = new SoundManager();
mSoundManager.initSounds(getBaseContext());
mSoundManager.addSound(1, R.raw.sound);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startservice();
return START_STICKY;
}
private void startservice() {
System.out.println("Started the service");
timer.scheduleAtFixedRate( new TimerTask() {
public void run() {
toastHandler.sendEmptyMessage(0);
}
}, 0, 60000);
}
private final Handler toastHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
result =start();
System.out.println("result"+result);
close();
}
};
protected void close() {
try {
if(wakeUpFlag){
wl.release();
System.out.println("Released the wakelock");
}
if(!pm.isScreenOn()){
System.out.println("Screen is off - back to sleep");
pm.goToSleep(1000);
}
else{
System.out.println("Screen is on - no need to sleep");
}
bs.close();
writer.close();
System.out.println("Closed socket and writer");
System.out.println("Size of file:"+f.length()/1024);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
public void start(){
try{
wakeUpFlag = false;
pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
if(!pm.isScreenOn()) {
wakeUpFlag = true;
wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,"CollectData");
System.out.println("Screen off - wake lock acquired");
wl.acquire();
}
else{
System.out.println("Screen on - no need of wake lock");
}
}
catch(Exception e){
e.printStackTrace();
}
mSoundManager.playSound(1);
}
I dont think you are using the correct flag accorinding to the android documentation fior PowerManager:
*If you hold a partial wakelock, the CPU will continue to run, irrespective of any timers and even after the user presses the power button. In all other wakelocks, the CPU will run, but the user can still put the device to sleep using the power button.
In other words, try using PARTIAL_WAKE_LOCK as this is the only one that gurantees the cpu to run
Follow the pattern Mark Murphy provides with the WakefulIntentService. I would suggest picking up his books, not only for the detailed explanation of this class and example he includes in one of them, but for the other wealth of information you'll find in them.
I just recently implemented this pattern for my main app and this class works like a charm.
I think you'd be better off using android.app.AlarmManager to schedule a wakeup alarm. Be careful though - you don't want to do any long-running work in your onReceive() method as that's normally called on the main thread, and will hang your activity. You'll still need to acquire the wakelock for the duration of your task to prevent the phone sleeping part-way through.