20

I'm trying to start a service that runs in the background that is listening for ACTION_SCREEN_OFF and when it finds ACTION_SCREEN_OFF, starts my activity.

I read somewhere you need to create a BroadcastReceiver because putting it in the manifest XML doesn't work. However I have no idea where to get started after much searching.

Alexis Pigeon
  • 7,423
  • 11
  • 39
  • 44
Peter
  • 5,071
  • 24
  • 79
  • 115

2 Answers2

45

You cannot declare ACTION_SCREEN_ON and ACTION_SCREEN_OFF in the AndroidManifest.xml. You are only allowed to catch them while your activity is running.

Here's an example.

The BroadcastReceiver:

public class ScreenReceiver extends BroadcastReceiver {

    public static boolean wasScreenOn = true;

    @Override
    public void onReceive(final Context context, final 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;
        }
    }

}

The Activity:

public class ExampleActivity extends Activity {

    private BroadcastReceiver mReceiver = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // initialize receiver
        final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        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
            Log.e("MYAPP", "SCREEN TURNED OFF");
        } else {
            // this is when onPause() is called when the screen state has not changed
        }
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // only when screen turns on
        if (!ScreenReceiver.wasScreenOn) {
            // this is when onResume() is called due to a screen state change
            Log.e("MYAPP", "SCREEN TURNED ON");
        } else {
            // this is when onResume() is called when the screen state has not changed
        }
    }

    @Override
    protected void onDestroy() {
        if (mReceiver != null) {
            unregisterReceiver(mReceiver);
            mReceiver = null;
        }
        super.onDestroy();
    }

}

You could probably solve your question by listening to these events from a Service.

DragonWork
  • 2,415
  • 1
  • 18
  • 20
  • 4
    The problem here is that the activity's `onResume()` and `onPause()` are called before the `BroadcastReceiver.onReceive()`. – Renato Lochetti Nov 14 '12 at 15:46
  • That's not a problem. Therefor we set the status of the screen into a variable (`wasScreenOn`). – DragonWork Nov 14 '12 at 16:34
  • Am I missing something here? When you exit your Activity with the back button or the home button, ScreenReceiver.wasScreenOn is TRUE so your onPause() will think that the screen is turning off when in fact your Activity is just pausing. – Akos Cz Dec 29 '12 at 04:56
  • 3
    btw, the code above came from the following article http://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/ – Akos Cz Dec 29 '12 at 05:09
  • 1
    The correct solution is in the comments section of the above article. The PowerManager should be used to check state of the screen in the onPause() method rather than ScreenReceiver.wasScreenOn. – Akos Cz Dec 29 '12 at 05:13
  • @AkosCz `onPause()` won't set `ScreenReceiver.wasScreenOn` to `false`. So there is no problem. We listen to `Intent.ACTION_SCREEN_ON` and `Intent.ACTION_SCREEN_OFF`, and only these actions will change the boolean `wasScreenOn`. When we set the screen off, the application lifecycle will go to pause state. Therefor we're checking the boolean in `onPause()`. – DragonWork Jan 26 '13 at 23:59
  • This leaks the receiver for me. Where do you unregister it? – Chuck D May 17 '13 at 19:35
  • Try unregistering in `onDestroy()`. – DragonWork May 19 '13 at 08:23
0

I am using callback from ScreenReceiver to resolve problem onResume() and onPause(). These are called before the BroadcastReceiver.onReceive().

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129