Android: Wake up screen from a service - android

I am working on an android app that listens to the surrounding voices, and executes commands.
One of the commands is waking up the screen.
In order to achieve that goal, I am using the following function, inside my service:
private void wakeupScreen() {
new AsyncTask<Void, Void, Exception>() {
#Override
protected Exception doInBackground(Void... params) {
try {
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock fullWakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "Loneworker - FULL WAKE LOCK");
fullWakeLock.acquire(); // turn on
try {
Thread.sleep(10000); // turn on duration
} catch (InterruptedException e) {
e.printStackTrace();
}
fullWakeLock.release();
} catch (Exception e) {
return e;
}
return null;
}
}.execute();
}
However, I have several problems with this code: (it runs on a service)
Using SCREEN_BRIGHT_WAKE_LOCK and FULL_WAKE_LOCK is deprecated.
The use of AsyncTask and sleep seems like a bad solution for turning the screen on, in non-blocking way.
I wonder if more elegant way exists. Any suggestions?

Apparently, there is no elegant way to achieve that goal.
I will summarize my 3 non-elegant solutions to that problem, for future readers:
Use wakelocks in asynchronously way:
private void wakeupScreen() {
new AsyncTask<Void, Void, Exception>() {
#Override
protected Exception doInBackground(Void... params) {
try {
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock fullWakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "Loneworker - FULL WAKE LOCK");
fullWakeLock.acquire(); // turn on
try {
Thread.sleep(10000); // turn on duration
} catch (InterruptedException e) {
e.printStackTrace();
}
fullWakeLock.release();
} catch (Exception e) {
return e;
}
return null;
}
}.execute();
}
Launch an activity that turns the screen on.
Simulate HOME button click. (similar to solution 2, without the need to create a custom activity, and slightly different behavior)
I found the first solution as the best for my needs.

Launch an activity, just to get the screen on under onCreate().
See the discussions at what is the proper, non-deprecated way to wake up the device?

Related

Turning on screen from receiver/service

I would like my app to be able to turn the screen on and display my app. Let's say I'm setting an alarm and every hour I want my app to be displayed for 2 mins before the device naturally sleeps.
I see that WakeLock (FULL_LOCK) and KeyguardManager are deprecated.
I have created a WakefulBroadcastReceiver and service and these are working.
#Override
protected void onHandleIntent(Intent intent) {
// I need to show the screen here!
for (int i=0; i<5; i++) {
Log.i("SimpleWakefulReceiver", "Running service " + (i + 1)
+ "/5 # " + SystemClock.elapsedRealtime());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
}
Log.i("SimpleWakefulReceiver", "Completed service # " +
SystemClock.elapsedRealtime());
SimpleWakefulReceiver.completeWakefulIntent(intent);
}
How do I programmatically turn on the screen, get past lock and display my Activity from the IntentService ?
Thanks
You can use this code to turn the screen on.
lock = ((KeyguardManager) getSystemService(Activity.KEYGUARD_SERVICE)).newKeyguardLock(KEYGUARD_SERVICE);
powerManager = ((PowerManager) getSystemService(Context.POWER_SERVICE));
wake = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG");
lock.disableKeyguard();
wake.acquire();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
You need the following permission in AndroidManifest.xml file:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
EDIT (USE THIS ONE, NOTHING IS DEPRECATED):
There is an one more alternative for doing this, for that you need to launch an activity, In the activity onCreate() you need to add the flags to the window.
For example:
#Override
protected void onCreate(Bundle savedInstanceState) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);`
}
I don't know what you're talking about, wakelock is definitely not deprecated. Certain types are no longer the Google preferred way of doing things, but normal wakelocks are still around and still the easiest way of doing this. Make sure to add the ACQUIRE_CAUSES_WAKEUP flag when taking the lock. In fact notice that a WakefulBroadcastReceiver is implemented by using wakelocks.
You can use this code to turn the screen on.
private void turnScreenOn() {
int flags = WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
getWindow().addFlags(flags);
}
You can use this code to keep it on until the wake lock is dimissed.
<uses-permission android:name="android.permission.WAKE_LOCK" />
private PowerManager mPowerManager;
private PowerManager.WakeLock mWakeLock;
#Override
public void onCreate() {
super.onCreate();
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "Service");
}
private void acquireWakeLock() {
try {
mWakeLock.acquire();
}
catch (Exception e) {
e.printStackTrace();
}
}
private void releaseWakeLock() {
try {
mWakeLock.release();
}
catch (Exception e) {
}
}

Android PowerManager wakelock wont work withouth TOAST

I have made an app that wakes up the screen when it receives a text message. I came up with the following code to wake the screen.
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean isScreenOn = pm.isScreenOn();
if(!isScreenOn ){
final PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "My tag");
wl.acquire();
Toast.makeText(getBaseContext(), "This is WAKEUP SCREEN", Toast.LENGTH_SHORT).show();
Thread timer = new Thread(){
public void run(){
try {
sleep(5000);
} catch (InterruptedException e) {
// TODO: handle exception
}finally{
wl.release();
}
}
};
timer.start();
}
Now the problem is that if I comment out or remove the statement Toast.makeText(getBaseContext(), "This is WAKEUP SCREEN", Toast.LENGTH_SHORT).show(); my screen wont wakeup. I am not sure what is the problem here... and I am using android 2.3.
Use PowerManager.SCREEN_DIM_WAKE_LOCK|PowerManager.ACQUIRE_CAUSES_WAKEUP instead of just PowerManager.SCREEN_DIM_WAKE_LOCK, and see if that helps.

Wake locks android service recurring

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.

Android - Wakelock thread is not turning the screen on

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

How can I tell if the screen is on in android?

In Android 2.2 (Level 7) the function PowerManager.IsScreenOn() returns a boolean that is true if the screen is turned on and false if the screen is turned off. I am developing code for Android 1.5 (Level 3). How do I accomplish the same task in older versions of Android?
I do not want to turn the screen on or off in my code. I just want to know what it is.
There's a better way than using BroadcastReceivers:
// If you use API20 or more:
DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
for (Display display : dm.getDisplays()) {
if (display.getState() != Display.STATE_OFF) {
return true;
}
}
return false;
// If you use less than API20:
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
if (powerManager.isScreenOn()){ return true; }
Note that Display.getState() can also return STATE_DOZE and STATE_DOZE_SUSPEND which means that the screen is on in an special way. More info on Display.getState() and his return values here: http://developer.android.com/reference/android/view/Display.html#getState()
Also note that although official documentation recommends using isInteractive() instead of isScreenOn(), if you really want to know the status of the screen, Display.getState() is a better option because of the 'special' conditions that sets the screen on while the device is not interactive.
This is how you should do it:
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
boolean result= VERSION.SDK_INT>=VERSION_CODES.KITKAT_WATCH&&powerManager.isInteractive()||VERSION.SDK_INT<VERSION_CODES.KITKAT_WATCH&&powerManager.isScreenOn();
return result;
I'm using the following function:
public boolean isInteractive() {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH
? powerManager.isInteractive()
: powerManager.isScreenOn();
}
You can accomplish this by setting up broadcast receivers for ACTION_SCREEN_ON and ACTION_SCREEN_OFF.
I'm posting this because on a HUAWAI Prism II Android 4.1.1 (API 16) device the game I'm working on had the following annoying behavior:
I'm displaying my main menu which has some animation in a SurfaceView and plays a sound once in a while.
The device goes idle, dims, and then goes dark.
It calls onDestroy on my Activity, and then while the screen is off creates my Activity again, calling onCreate!
So the problem is my animations and sounds are playing while the screen is off. What I really want to happen is for my animation loop to not run at all if the screen is off. Broadcast receivers don't work because I can't store the state from the last time the screen went off. I thought about some hacks involving static booleans but it just seemed like a kluge that may not work and have horrible edge cases. The screen is already off when my Activity is created again, so I won't get an event through the broadcast receiver that my screen is off.
I solved this using both a broadcast receiver and the code listed above.
In my onCreate, I create the broadcast receiver. This will control my animation loop when the screen turns on and off.
if (mScreenReceiver == null) {
mScreenIntentFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
mScreenIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
mScreenReceiver = new ScreenReceiver();
registerReceiver(mScreenReceiver, mScreenIntentFilter);
}
public class ScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
controlAnimLoop(false, false, true);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
controlAnimLoop(false, false, false);
}
}
}
In my controlAnimLoop, I check isScreenOn, which is this code:
private boolean isScreenOn() {
if (android.os.Build.VERSION.SDK_INT >= 20) {
// I'm counting
// STATE_DOZE, STATE_OFF, STATE_DOZE_SUSPENDED
// all as "OFF"
DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
for (Display display : dm.getDisplays ()) {
if (display.getState () == Display.STATE_ON ||
display.getState () == Display.STATE_UNKNOWN) {
return true;
}
}
return false;
}
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
return powerManager.isScreenOn();
}
MainActivity.Java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_HEADSET_PLUG);
filter.addAction(Intent.ACTION_POWER_CONNECTED);
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(new MyReceiver(), filter);
}
}
MyReciever.Java
public class MyReceiver extends BroadcastReceiver {
MainActivity mActivity;
#Override
public void onReceive(Context arg0, Intent arg1) {
mActivity = (MainActivity) arg0;
TextView tv = (TextView)mActivity.findViewById(R.id.textView1);
if(arg1.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
tv.setText("Headset Plugin ");
} else if(arg1.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
tv.setText("Power Connected ");
} else if(arg1.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
tv.setText("Power Disconnected ");
} else if(arg1.getAction().equals(Intent.ACTION_SCREEN_ON)) {
tv.setText("Screen ON ");
} else if(arg1.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
tv.setText("Screen OFF ");
}
}
}

Categories

Resources