How to use Partial WakeLock

I am trying to make an audio based game in which the phones screen is primarily off. To be specific I need the app to continue to run, playing sounds and communicating with a server, even when I turn it off via the power button.

my first semi-solution was to keep the screen on using this: (executed in setup)

  runOnUiThread(new Runnable() {
    @ Override
      public void run() {
      getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }
  }
  );
//unfortunately I lost the source where I found this :-( 

However I would like the app to also “survive” the power button being pressed. From my research so far (e.g. https://developer.android.com/training/scheduling/wakelock#java) it seems that I need a “partial wakeLock.”

I have tried various variations of the following with no positive results:

import android.os.PowerManager.WakeLock;
import android.content.Context;
import android.os.PowerManager;



void setup() {
  requestPermission("android.permission.WAKE_LOCK");
  runOnUiThread(new Runnable() { //dark screen magic
    @ Override
      public void run() {
      PowerManager pm = (PowerManager)getActivity().getSystemService(Context.POWER_SERVICE);
      WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
      wakeLock.acquire();
    }
  }
  );
}

int c;
void draw() {
  println(c);  //counter to test responsiveness
  c++;
  delay(1000);
}

Does anyone know how to implement the WakeLock correctly?
Thanks for any help!

Hi, @Jessie welcome to the forum, and sorry for the late answer.
I’ve looked into this, but do you really need it?
If you use a counter in draw() the counting will stop, but if you use a thread() like in the code below, it will continue counting even when the power button pressed.
Also, the sounds of the cassette library will continue.
Maybe you can post a code that you not want to be stopped after power button pressed.

int count; 
boolean foo; 
int start_time; 

void setup() { 
  background(0, 0, 200); 
  textSize(60); 
  thread("count");
} 
void draw() { 
  background(0, 0, 200); 
  text(count, width/2, height/2); 
} 

void count() { 
  while (!foo) { 
    if (millis() - start_time > 1000) { 
      count++; 
      start_time = millis();
    }
  }
}
1 Like

Huh, I was not aware of the existence of “threads” in Processing. This did indeed solve my problem without the use of a wakelock as far as I can tell. Thanks a ton!

One more quick question because I am new here: If I do end up running into problems with this solution later on, should I start a new thread or continue this one?

Again thanks for the answer and happy coding! :slight_smile:

You can just post it here.
I will add a WakeLock code to my repo in the near future, but at the moment I’m quite busy to make the native android codes posted there, suitable for the latest Android versions (10&11) as well.

@noel, @Jessie ====
The answer and the code from @noel is useful for threading in android, which is a very good practice as Android does not like long or heavy tasks in the main ui thread; now i am not sure that this answer and this code are a solution if the user presses (as it il is explained in the post) the power management button: in this case i guess that the created thread will be killed when the phone is spent. this is a case where the partial wakeLock could be used though Android and Android doc does not like it, for battery draining reasons. As the code is very simple i dont put it; of course you have to ask permission; of course also ou have to think ro "release " the wavelock when it is not required

Ok, sorry for the long silence, I got sidetracked.
@akenaton surprisingly the thread is indeed not killed by the power button! However I do still have a problem.

While the thread is capable of doing calculations, playing sounds, etc. the keyPressed variable stops updating. I would like to be able to give the app inputs via the button on my earbuds, while the phone is in standby in my pocket. (void keyPressed(){} also stops working)
Would this be a situation where a wakeLock would be applicable? If so would you mind showing me the code? Even if it is very simple, you gotta learn it somewhere!

@Jessie ===
The code for creating a wakelock is not a problem; i put it below and you can try; but there is another problem which is the powerManagement button; this button a) does not exist for all phones; some of them use the volume button and longpress for that b) this button or this function cannot be overriden= the user (android principles) is always the master of its phone and when he kills it, the phone is killed… What is the interest of a phone if you use it as an ipod? - And so it is absolutely normal that functions like onKeyDown no more work…

import android.os.PowerManager.WakeLock;
import android.os.Bundle;
import android.os.PowerManager;
import android.app.Activity;
import android.content.Context;
import android.view.KeyEvent; //useless for now

boolean noir = false;
int count = 0;
PowerManager.WakeLock wakeLock;
PowerManager pm;
WakeLock wl;
KeyEvent event;




void settings() {
  fullScreen();
}

public void setup() {
  background(255, 0, 0);
  pm = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
  wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 
    "My wakelock");
 };

    
  void draw(){
    
    background(255, 0, 0);
    if(wl.isHeld()){
      noir = true;
    }else{
      noir = false;
    }
    
    fill(0);
    textSize(48);
    text(count, width/2, height/2);
    count++;
  };
  
  public void acquirewakeLock() {
  wl.acquire();
  println("j'acquiers le wl"+wl.isHeld());
   
      
  };
  
  public void releaseWakelock() {
  if  (noir) {
    wl.release();
  }
  println("je release le wl"+wl.isHeld());
  }
  
  public void mouseReleased(){
    
    if(noir && wl!=null){
     releaseWakelock();
    
     
    }else if(noir == false){
      acquirewakeLock();
      noir = true;
  }
  };
  
  public void onPause() {
  super.onPause();
  
println( "je pause!!!!!!!"+ count+ wl.isHeld());
  
};
2 Likes

@Jessie === and put the code you are using for keyEvent

@akenaton

Most music player apps will let you pause the music by pressing the button on your headphones. Is this not the same?

As a basic example of what I want to do, I would like to be able to start an app and put the phone in my pocket. Then every time I press the button on my Headphones I want to log my current GPS position.
The Problem: once I block the screen (press the power button) the GPS position stops updating and the headphone button press is not received.
I thought a partial wakeLock would fix this.

I am not sure what you mean by keyEvent (I’m new to android), but I’ve been using void keyPressed() {} to detect the headphone button.

Unfortunately your code does not do what I expected.
When I run it, I get a red screen with a number counting up. If I touch the screen, I get alternating true and false messages for the state of the wakeLock in the console. When the screen turns off (after waiting a minute, or pressing the power button) the console prints the last number the counter showed. After re-enabling the screen the counter continues where it left off (does not keep counting while screen is off) This happens regardless of the state of the wakeLock.
I expected the counter to continue in the background… Did I misunderstand how the wakeLock works?

Thank you for your help!

@Jesse === players can stop (or not!) the music but music cannot continue (i hope) when the phone is down (powerManagment.
In the basic example you describe if the GPS stops working that is exactly because you press this button THAT like others with Android cannot be overriden: the user must be allways FREE to leave your app or kill the phone
As for the code i have put (and generally about partial wakelock) this code starts the wl and kills him when you fire some event: in this case it is mouseReleased() but it could be another event. If i added the release part of wl it is because Android asks for it for battery draining reason and you can understand that.
Normally you use partial wavelock when some long time running and important operation is on: as for me i have used it in an app which GPS results are very importants because the app calculates (CPU) the distance for a danger for the user at each moment; yet the wl is released after some time, by myself or automatically by Android when the battery level becomes too low.
So in each case a) you have to know the event which starts the wl; it can be a lot of things (not only a key or button event): eg if you have a service running with a broadcast receiver - and also b) an event which releases it.
Is this event can be the pw managment button? -I dont think so and have explained why. Is this event can be fired by your ears buds, i dont know; first thing is : in your KeyDown (when the phone runs normally of course) what is the keyCode or event returned? second thing is how this button works? Does it changes only the volume? Or (long press) it calls to power managment and stops the phone running?

@akenaton I’m worried we might have a misunderstanding about what buttons we are talking about.
By “power button” I mean the button I press to get to the lockscreen or put the phone in standby. NOT turning the phone all the way off (which would happen on long press; again not this. I mean only short press).
By the button on my earbuds I mean the pause/play button found on most earbuds/headphones/speekers etc. which starts stops the music.

In your example code, why did the state of the wake lock have no apperent effect?

I don’t know what a keyCode is, but println(key) prints “” (an unrenderable character) and println(int(key)) prints “65535” when I press the pause/play earbud button, but I don’t see how this is relevant.

@Jessie === Ah! ok so you are not at all attempting to override the powerManagment button which acts on a long press and that is a good new for me!!! and for you: you want only to capture a short press on your éarbuds… That could be done with the key code but “65535” is very weird, it seems that P5 is unable to get it because according to the keycode list, 287 is the last one (you can see here: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/KeyEvent.java (i think that this link is or will be useful for someone!) - And that is bad news because this is the event which has to start the wakelock (or release it). Now thre is another thing i am afraid to misunderstand : is only music playing or stopping (or GPS??" that you want when pressing this button (shortly!) . I ask that because media player can solve that (it can start a wakelock) ; last question is= when you press the volume button wihout the ears buds what code is returned?
As for my code it was only a simple example for showing how to start a partial wake lock and as you have seen it releases also it (there is a boolean for that: “noir”) and according what you have explained i ll try to give another example…

Maybe something to try?

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if(keyCode == KeyEvent.KEYCODE_HEADSETHOOK){
        //handle click
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

@noel===
have you tried this code?
as for me it fires error till i comment override and calls not super but the activity.
and for beginning i think that it could be more simple && sure to try with KEYCODE-POWER (keycode==26)
but i get nothing

@akenaton ok, so I found out instead of println(int(key)) I need to use println(keyCode). This returns 24 and 25 for the Volume keys and 79 for the headphones.

The sound and GPS were just examples, sorry if that caused confusion.
The project I need this for is a game which you can play with the phone in your pocket. The Idea is, that the phone keeps track of your GPS location and tells you to go North/East/South/West through the headphones. When you get to imaginary points of interest you can interact with them by using the button on the headphones. The whole thing is multiplayer, so a server is also involved.

For this to work, I need to read GPS, react to the Button and talk to a server, all while the phone is on standby. I have already gotten it (mostly) working with the phone on, now I just need to find a way to keep it running in standby.

@noel
I am afraid I don’t really know how to implement your code to test it. Could you explain what it is supposed to do? Thanks for the Help!

Actually, I wanted to show the keyCode to search for.
If you write:

import: android.view.KeyEvent:
println(KeyEvent.KEYCODE_HEADSETHOOK);

it will print number 79

@Jessie === ok, that is a good new, the value returned is ok (i mean is possible, knowing that long press+sound = 26) and that is an event we can use; have you tried the code by noel?

@akenaton
I’m afraid I still can’t get @noel’s code to work. It’s giving me the following error:
The method onKeyDown(int, KeyEvent) of type sketch_210117a must override or implement a supertype method

But (correct me if I’m wrong) it seems you are trying to find a way to read the button, not fix my main problem which is keeping the app running in the background. It seems to me that the example wakelock code you gave me was going in the right direction…

@Jessie === try to un comment override, it could work; yes you are right, i want to get this event but that is connected with your main intent: because the wakelock must be fired by some action; in the code i have put the event was “mouseReleased” but it was only to show, the real event is this ear device when you push the button…

@akenaton
I got it to work, but I had to remove both the @Override and the super.
The code returned 79