Handling Screen OFF and Screen ON Intents
Hey everyone,
Haven’t posted in a while – sorry school has been busy. Any who, this little code snippet/example will be on how to deal with the Intent.ACTION_SCREEN_OFF and the Intent.ACTION_SCREEN_ON, which will come in nifty if you’re making an application that might need to save state or respond to the user’s screen going to sleep/waking up, etc.
First, unlike other broad casted intents, for Intent.ACTION_SCREEN_OFF and Intent.ACTION_SCREEN_ON you CANNOT declare them in your Android Manifest! I’m not sure exactly why, but they must be registered in an IntentFilter in your JAVA code. And so, for this example we are going to have a receiver called ScreenReceiver, and I’m going to walk you through the differences between implementing it in a Service vs. in an Activity.
So, the receiver will simply look like:
public class ScreenReceiver extends BroadcastReceiver { // thanks Jason public static boolean wasScreenOn = true; @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { // do whatever you need to do here wasScreenOn = false; } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { // and do whatever you need to do here wasScreenOn = true; } } }
Now, the first example will be for an Activity. Because of the life-cycle of an Activity, an Activity is actually easier to deal with as right before the screen turns off onPause() is called and right when the screen turns on onResume() is called, and so naturally we will handle the screen on/off events here:
public class ExampleActivity extends Activity { @Override protected void onCreate() { // initialize receiver IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); BroadcastReceiver mReceiver = new ScreenReceiver(); registerReceiver(mReceiver, filter); // your code } @Override protected void onPause() { // when the screen is about to turn off if (ScreenReceiver.wasScreenOn) { // this is the case when onPause() is called by the system due to a screen state change System.out.println("SCREEN TURNED OFF"); } else { // this is when onPause() is called when the screen state has not changed } super.onPause(); } @Override protected void onResume() { // only when screen turns on if (!ScreenReceiver.wasScreenOn) { // this is when onResume() is called due to a screen state change System.out.println("SCREEN TURNED ON"); } else { // this is when onResume() is called when the screen state has not changed } super.onResume(); } }
Now, note that in my onPause() and onResume() methods I run a check to see that the method was called DUE TO A SCREEN STATE CHANGE. This is important as often onPause() or onResume() will get called because of other reasons – i.e. a new activity is being started on top of this one, or an incoming call might be coming in, etc – and you want to make sure that your screen change logic is only called when the screen has actually changed.
Now, something to keep in mind, is that the order of events before the system screen turns off is:
ExampleActivity.onPause() –> ScreenReceiver.onReceive()
Which is a little unintuitive as you’d think the receiver would get hit first – and so when you play around with setting booleans, etc, be aware of this little fact, and likewise when the screen turns on the order of events is:
ExampleActivity.onResume() –> ScreenReceiver.onReceive()
And so again the order of events seems a little “backwards”.
Now, for a Service, it’s a little bit different since there is no onResume() or onPause() that gets called as the Service is always “running” in the background, and so instead what you’re going to have to do is modify your receiver a little to look like:
public class ScreenReceiver extends BroadcastReceiver { private boolean screenOff; @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { screenOff = true; } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { screenOff = false; } Intent i = new Intent(context, UpdateService.class); i.putExtra("screen_state", screenOff); context.startService(i); } }
And your service will look like:
public static class UpdateService extends Service { @Override public void onCreate() { super.onCreate(); // register receiver that handles screen on and screen off logic IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); BroadcastReceiver mReceiver = new ScreenReceiver(); registerReceiver(mReceiver, filter); } @Override public void onStart(Intent intent, int startId) { boolean screenOn = intent.getBooleanExtra("screen_state", false); if (!screenOn) { // your code } else { // your code } } }
And so this is pretty self explanatory. When the screen state changes, it will notify your ScreenReceiver and from there you can set the state information into an Intent and send that data to your Service which can then handle it appropriately.
Hopefully this was useful. Let me know if you have questions.
Happy coding.
– jwei
Trackbacks
- Auto Log-out Timer Research « Team DailyDo
- lock screen sometime not display android | Build Future Repository
- Orientation listener in a service | PHP Developer Resource
- [wip][rom][cm7][zvc] lg-ls855 marquee - Page 3 - Android Forums
- check if wifi is connected every 5 minutes after screen is off : Android Community - For Application Development
- BroadCaste reciever invoking if screen is off : Android Community - For Application Development
- Handling Screen On/Off Intents | Pearls in Life
- Screen Lock from receiver : Android Community - For Application Development
- How to identify when the Android device was used last time : Android Community - For Application Development
Great idea, but the onPause code in the Activity is broken. wasScreenOn will always be true on entering the function. As you indicated, “ExampleActivity.onPause() –> ScreenReceiver.onReceive()” is the order of events. Thus, whether you entered onPause as a result of letting the screen turn off, or you entered onPause by putting another activity on top of this one, wasScreenOn will always be true.
Hey Jason,
Thanks for the catch. I think the fix is pretty simple – just initialize wasScreenOn to be TRUE. Then the rest of the logic works (correct me if I’m wrong).
– jwei
How about monitoring user inactivity? Is there a system internal inactivity timer or do I need to poke a countdown timer thread from regular methods using event listeners?
Many thanks for your article by the way! Very intuitive and clear.
It’s a useful article~~
Wow, your article is really come in handly. I was looking to turn off the shake sensor on my 9420 Thai Keyboard when the phone is locked and/or screen is off.
Thank you so much,
Solution 9420
very good ! thank you (谢谢)from china!
Thank you very much. It is a useful article.
Thank you very much! Your effort contribute to my effort!
^.^
For the life of me, I can’t get this to work, I only need a simple check if the screen is currently on or off, is there something simpler to this? I tried your instructions, didn’t work, copying the codes, didn’t work, I am not sure where I am doing wrong…
Can I just do a constant loop in my onCreate() under my Activity/Main class?
such as
onCreate()
{
while (true)
{
if (ScreenOn(or whatever is necessary to check it)
//do what i want here
else
//do anything else when screen is off
}
}
Makes sense??? :S
Morris Lee
Hey Morris,
No you shouldn’t do that for several reasons. First the while(true) will be run on the main UI thread and will basically cause your application to get stuck – at which point the OS will make the user force close your app.
I would suggest you read about the Activity life cycle – this is important to understand since it will allow you to check for various things (in this case a screen on boolean) at the appropriate times without having to do weird hacks like the one you proposed:
http://developer.android.com/reference/android/app/Activity.html
Hope this helps!
– jwei
This all works for most cases. I am making a game where if you press the HOME button(onPause) the game saves. Then when you bring the game back to the front the onResume will load it. (I do this so in case Android wants to erase all the variables i need to run the game while the user is using some other app)
However, if the screen turns off i do not want onPause to run any code. And when the screen turns back on i don’t want onResume to run any code. (Because Android will not erase the game’s variables when the screen just gets turned off)
Because you initialize wasScreenOn to be TRUE, only one part of the onPause code above will be used whether you press the HOME key or turn the screen off.
It does not make a difference if you initialize wasScreenOn to be false or true. The same problem happens.
I solved the problem by making a few changes to onCreate() and onPause()
Everything else stays the same as above
@Override
protected void onCreate() {
// initialize receiver
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
//NEW
PowerManager pm =(PowerManager) getSystemService(Context.POWER_SERVICE);
// your code
}
@Override
protected void onPause() {
// when the screen is about to turn off
// Use the PowerManager to see if the screen is turning off
if (pm.isScreenOn() == false) {
// this is the case when onPause() is called by the system due to the screen turning off
System.out.println(“SCREEN TURNED OFF”);
} else {
// this is when onPause() is called when the screen has not turned off
}
super.onPause();
}
Hope this helps
Service example above seems wrong. As You are registering receiver in Oncreate of service. And starting service from receiver… :).
Hey swapnil,
Hm not sure what you mean? I don’t think I’m starting any “services” (I presume you mean Activities in my case) in my receiver… I’m just toggling a boolean.
– jwei
Hi,
I cannot run the service, though my receiver is working fine, can you help?
OK, Now it can run. Yesterday I make a mistake of Manifest file.
how would one go about doing this from an AppWidgetProvider.
I don’t use Service, instead i opted for java.util.timer for scheduling my updates.
cheers
Dave.
damn i miss C++, multiple inheritance just gets things done
i’ll use a inner class
ty anyway
Just use Java interface instead.
I implemented your code in my application. Intent.ACTION_SCREEN_OFF fires when I manually hit the power button to turn off the screen but it does not fire when the screen saver timed out. Does this happen to anybody else?
My Eclipse reports an error with the following line
BroadcastReceiver myReceiver = new ScreenReceiver();
It gives an error cannot convert from ScreenReceiver to BroadcastReceiver??? Surly the line of code is fine, I don’t see anything wrong with it. The only change I made to ScreenReceiver was remove the static keyword as it’s not permitted. Any ideas?
I’ve fixed it now, strange problem with eclipse???
I think the way it works is that your app has to be running when your app receives Intent.ACTION_SCREEN_OFF intent. But how can you invoke your app when the screen_off?
Someone said there is no way due to google’s reason, is this true?
Great article. I used it for my app. Thank you very much from Spain !
thank you!
I follow this code and it run ok.
Thanks a lot!
Thanks, I was looking for something else. But I learned a new thing.
Wonderful job…
I need something else…maybe someone can help me…
I have an application that have to keep the screen on and avoid screen off and lock…itțs a timer…
how can I do this ?
thanks
daniel
Hey Daniel,
You’re probably looking for something along the lines of http://stackoverflow.com/questions/4263868/disabling-screen-sleep-programatically-in-android
– jwei
Please unregister the receiver that you have registered programmatically to avoid window leakage error.
kindly unregister the receiver in onDestroy method.
Thank u really use full for me
It totally worked for me! thanks a lot sir!!!!
EXACTLY what I needed. Thanks!
Hello!
I am trying to build an app that starts the time the phone is idle before the screen turns off.
Do you know how can I determine the screen is idle?
Thanks
Thank you for great information, from INDIA
Thank you kindly!!! It was concise and clear.
I think its better app architecture to have the logic in a class outside the activity, in which case the same class can extend the BroadcastReceiver saving the information ping-pong.
I don’t understand the Service approach, why not simply put the code to run in the receiver, that’s easier 😉
Hello, I have a problem with the thread of the service. Hopefully you could help me with it.
I wanna stop the service (this service has its own thread) when the screen goes off and start it again when the screen turns on.
As the services cannot be “resume” I think I have to destroy it and create it again when I switched the screen. But when I create the service again it launch a NullPointerException (“Unable to start service com.example.daemon3.DaemonService@40ff0df0 with intent {cmp=com.example.daemon3/.DaemonService (has extras) }: java.lang.NullPointerException”)
Really hope you can help me.
…
Thank you so much.
Hi Alberto,
It seems like the issue is not with my example but with the way that you’re re-starting your service.
Please see http://stackoverflow.com/questions/4679654/unable-to-start-service-service-name-with-null for the cause of your error.
Hope this helps.
– jwei
hi!
I am developing an app in which i have create three activities Main_Activity Second_Activity CustomView_Activity
here is the process in which these Activties called:
MainActivity calls Second_Activtiy and in OnCreate of Second_Activtiy I have created object of CustomView_Activity.
In Main_Activity I have a button on a LinearLayout which onClick calls Second_Activity in Second_activity OnCreate i have to keep my Screen On through Keep_Screen_On and declare other things like buttons layouts etc.
in CustomView_Activity i have creates canvas and onCanvas i have draw a Rectangle.
Now when my Second_Activity calls after Main_Activity and calling OnPause on pressing Power button my activity calls OnPause OnStop OnCreate OnResume OnRestart OnDestroy
and when i press the power button to on the screen OnResume onCreate On Restart calls.
Due to calling of OnCreate again and again my activity not performing tasks correctly.
Please anyone who can help??
first example is very clear but i am not bale to understand how the second one works. As we are starting a service from broadcastreceiver class. There should be a activity class along which a broadcastreiver is made.
Hi Shubham,
I’m not entirely sure what you mean – I presume by second example you mean the example where you are registering the broadcast receiver in a Service as opposed to an Activity. If that’s the case you’ll notice that upon starting your Service (which is essentially an Activity that runs in the background), just as how you would register a receiver in an Activity’s onCreate() method, you can do the same for a Service.
– jwei
Modifier static not allowed here (public static class UpdateService extends Service { )
Why?
What’s the error?
– jwei
I found this tutorial,, very helpful also
http://michael.theirwinfamily.net/articles/android/starting-activity-sleeping-device