Screen On / Off 핸들링

|

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 ScreenReceiver extends 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 ExampleActivity extends 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 ScreenReceiver extends 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);