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:
01
public class ScreenReceiverextends BroadcastReceiver {
02
03
// thanks Jason
04
public static boolean wasScreenOn =true;
05
06
@Override
07
public void onReceive(Context context, Intent intent) {
08
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
09
// do whatever you need to do here
10
wasScreenOn =false;
11
}else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
12
// and do whatever you need to do here
13
wasScreenOn =true;
14
}
15
}
16
17
}
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:
01
public class ExampleActivityextends Activity {
02
03
@Override
04
protected void onCreate() {
05
// initialize receiver
06
IntentFilter filter =new IntentFilter(Intent.ACTION_SCREEN_ON);
07
filter.addAction(Intent.ACTION_SCREEN_OFF);
08
BroadcastReceiver mReceiver =new ScreenReceiver();
09
registerReceiver(mReceiver, filter);
10
// your code
11
}
12
13
@Override
14
protected void onPause() {
15
// when the screen is about to turn off
16
if (ScreenReceiver.wasScreenOn) {
17
// this is the case when onPause() is called by the system due to a screen state change
18
System.out.println("SCREEN TURNED OFF");
19
}else {
20
// this is when onPause() is called when the screen state has not changed
21
}
22
super.onPause();
23
}
24
25
@Override
26
protected void onResume() {
27
// only when screen turns on
28
if (!ScreenReceiver.wasScreenOn) {
29
// this is when onResume() is called due to a screen state change
30
System.out.println("SCREEN TURNED ON");
31
}else {
32
// this is when onResume() is called when the screen state has not changed
33
}
34
super.onResume();
35
}
36
37
}
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:
01
public class ScreenReceiverextends BroadcastReceiver {
02
03
private boolean screenOff;
04
05
@Override
06
public void onReceive(Context context, Intent intent) {
07
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
08
screenOff =true;
09
}else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
10
screenOff =false;
11
}
12
Intent i =new Intent(context, UpdateService.class);
13
i.putExtra("screen_state", screenOff);
14
context.startService(i);
15
}
16
17
}
And your service will look like:
01
public static class UpdateServiceextends Service {
02
03
@Override
04
public void onCreate() {
05
super.onCreate();
06
// register receiver that handles screen on and screen off logic
07
IntentFilter filter =new IntentFilter(Intent.ACTION_SCREEN_ON);
08
filter.addAction(Intent.ACTION_SCREEN_OFF);
09
BroadcastReceiver mReceiver =new ScreenReceiver();
10
registerReceiver(mReceiver, filter);
11
}
12
13
@Override
14
public void onStart(Intent intent,int startId) {
15
boolean screenOn = intent.getBooleanExtra("screen_state",false);
16
if (!screenOn) {
17
// your code
18
}else {
19
// your code
20
}
21
}
22
}
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