Getting Android Sensor Events While The Screen is Off

April 3, 2012

So you want to continue to get sensor events in your Android service, even after the screen turns off? Well that’s too damn bad, kid, cause you can’t. No, I’m just kidding.

But you’ll probably need a work-around for Android Issue 3708. In this document I describe what I had to do to get it working on my platform. My assumption is you’ve already been Googling around, and so have a little background on this, but are still scratching your head as to why it’s not working. Hopefully, you won’t be in that position after reading this!


Some relic platforms of the past might have skated by holding just a PARTIAL_WAKE_LOCK. For me this was necessary, but not sufficient. Even while holding the lock, my service ceased to receive notifications via onSensorChanged() nor onAccuracyChanged().

Re-register Your Listeners When The Screen Goes Off

Some then propose to take action when the screen turns off. In this post on StackOverflow, for example, the author proposes un-registering and re-registering to receive sensor events at that time.

Use a Delayed Thread, for the Above

The above two techniques are ultimately what I’ve used to solve the problem, except I had to make one additional modification. When the BroadcastReceiver receives an ACTION_SCREEN_OFF Intent, I queue a thread to run 500ms in the future, instead of running immediately. This ensures that most other activities surrounding the screen off will have completed. So at that time, 500ms later, we un-register and re-register our service as a sensor event listener.

This is how I’ve implemented the BroadcastReceiver:

    public BroadcastReceiver mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "onReceive("+intent+")");

            if (!intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 

            Runnable runnable = new Runnable() {
                public void run() {
                    Log.i(TAG, "Runnable executing.");

            new Handler().postDelayed(runnable, SCREEN_OFF_RECEIVER_DELAY);

You may have to play with the value of SCREEN_OFF_RECEIVER_DELAY — for me, 500 (milliseconds) was the minimal value that would get it working.

See the Code In An Example App

I’ve posted an example app which includes the above code. It shows a foreground service holding a PARTIAL_WAKE_LOCK, doing the re-registration business mentioned above. The result is a service which continues to receive sensor events even after the screen goes off (for whatever reason.)

Well, it worked for me at least. Does it work for you? (Please comment below.)


27 responses to “Getting Android Sensor Events While The Screen is Off”

  1. Qi Zhenyu says:

    Thanks your sharing, it works for me.
    On my HTC G14 phone, it only works after using the “Delayed Thread”.

    I search the web for whole day, and even want to give up, now seems it works again.

    Thanks very much again.

  2. T-T says:

    It doesn’t works for me.
    my phone is meizu MX,android 2.3.5

    05-02 20:26:31.003: DEBUG/com.whh.test.sensor.TheService(22091): ———–onSensorChanged————-
    05-02 20:26:31.003: DEBUG/com.whh.test.sensor.TheService|ACCELEROMETER(22091): -5.161899
    05-02 20:26:31.028: DEBUG/PhoneInterfaceManager(226): [PhoneIntfMgr] processKeyEvent…
    05-02 20:26:31.028: DEBUG/PhoneInterfaceManager(226): [PhoneIntfMgr] makeProcessKeyEventResult: handled = false, hungup = false
    05-02 20:26:31.193: DEBUG/com.whh.test.sensor.TheService(22091): ———–onSensorChanged————-
    05-02 20:26:31.193: DEBUG/dalvikvm(143): GC_EXPLICIT freed 33K, 49% free 6775K/13255K, external 6729K/9009K, paused 155ms
    05-02 20:26:31.203: DEBUG/com.whh.test.sensor.TheService(22091): ———–onSensorChanged————-
    05-02 20:26:31.203: DEBUG/com.whh.test.sensor.TheService|ACCELEROMETER(22091): -5.2959743
    05-02 20:26:31.393: DEBUG/com.whh.test.sensor.TheService(22091): ———–onSensorChanged————-
    05-02 20:26:31.403: DEBUG/com.whh.test.sensor.TheService(22091): ———–onSensorChanged————-
    05-02 20:26:31.403: DEBUG/com.whh.test.sensor.TheService|ACCELEROMETER(22091): -5.2385135
    05-02 20:26:31.488: DEBUG/dalvikvm(143): GC_EXPLICIT freed 2K, 49% free 6772K/13255K, external 9009K/9009K, paused 60ms
    05-02 20:26:31.553: DEBUG/dalvikvm(143): GC_EXPLICIT freed activate(handle: 3, enabled: 0)
    05-02 20:26:31.833: DEBUG/Sensors(143): gp2ap:enable():handle is 3, what is 0, en is 0.
    05-02 20:26:31.843: DEBUG/Sensors(143): enable():close device.
    05-02 20:26:31.848: DEBUG/SurfaceFlinger(143): About to give-up screen, flinger = 0x2c27a0
    05-02 20:26:31.868: DEBUG/TestForLock(143): onScreenTurnedOff(2)—PowerManagerService1335961591871
    05-02 20:26:31.868: DEBUG/TestForLock(143): doKeyguard: showing the lock screen—PowerManagerService1335961591871
    05-02 20:26:31.868: DEBUG/Pms-Moses(143): Am going to Sleep, reson:2—PowerManagerService1335961591870
    05-02 20:26:31.873: DEBUG/TestForLock(143): handleShow: systemReady = true, mBootComplete = true
    05-02 20:26:31.873: DEBUG/TestForLock(143): show begin
    05-02 20:26:31.873: DEBUG/TestForLock(143): keyguard view is null, creating it…
    05-02 20:26:32.003: DEBUG/dalvikvm(143): GC_EXTERNAL_ALLOC freed 32K, 49% free 6784K/13255K, external 9009K/9009K, paused 88ms
    05-02 20:26:32.018: INFO/LedTest(143): buttonlight breakFlashLight
    05-02 20:26:32.033: INFO/com.whh.test.sensor.TheService(22091): *****onReceive(Intent { act=android.intent.action.SCREEN_OFF flg=0x40000000 })——
    05-02 20:26:32.163: VERBOSE/LockViewBase(143): ***** LOCK ATTACHED TO WINDOW
    05-02 20:26:32.163: VERBOSE/LockViewBase(143): Cur orient=1, new config={ scale=1.0 themeChanged=0 themeChangedFlags=0 imsi=460/1 loc=zh_CN touch=3 keys=1/1/2 nav=1/1 orien=1 layout=18 uiMode=17 seq=48}
    05-02 20:26:32.163: DEBUG/Sliding(143): onAttachedToWindow:25
    05-02 20:26:32.163: DEBUG/ChargingEdotView(143): resetViewStatus, mPluggedIn = true
    05-02 20:26:32.198: DEBUG/TestForLock(143): show end
    05-02 20:26:32.213: DEBUG/WindowManager(143): Input focus has changed to Window{406d3950 Keyguard paused=false}
    05-02 20:26:32.218: DEBUG/ContactsApp(223): updateScreenShotBuffer()…
    05-02 20:26:32.228: DEBUG/LedLightsService(143): Intent.ACTION_KEYGUARD_LOCK0
    05-02 20:26:32.533: INFO/com.whh.test.sensor.TheService(22091): Runnable executing.
    05-02 20:26:32.533: DEBUG/Sensors(143): sensors_poll_context_t->activate(handle: 2, enabled: 0)
    05-02 20:26:32.533: DEBUG/Sensors(143): akm:enable() handle 2, en 0.
    05-02 20:26:32.533: DEBUG/AKMD2(143): akm_enable_sensor():enable sensor type 2.
    05-02 20:26:32.563: INFO/AKMD2(143): AK8975/B for Android end.
    05-02 20:26:32.563: DEBUG/AKMD2(143): akmd2 : Compass Closed.
    05-02 20:26:32.563: DEBUG/AKMD2(143): akm_set_delay():200000000 ns.
    05-02 20:26:32.563: DEBUG/Sensors(143): sensors_poll_context_t->activate(handle: 0, enabled: 0)
    05-02 20:26:32.563: DEBUG/Sensors(143): akm:enable() handle 0, en 0.
    05-02 20:26:32.563: DEBUG/AKMD2(143): akm_enable_sensor():enable sensor type 1.
    05-02 20:26:32.633: DEBUG/AKMD2(143): acc thread end…
    05-02 20:26:32.633: DEBUG/AKMD2(143): acc Closed.
    05-02 20:26:32.638: INFO/com.whh.test.sensor.TheService(22091): *****************registerListener()**************
    05-02 20:26:32.638: DEBUG/Sensors(143): sensors_poll_context_t->activate(handle: 0, enabled: 1)
    05-02 20:26:32.638: DEBUG/Sensors(143): akm:enable() handle 0, en 1.
    05-02 20:26:32.638: DEBUG/AKMD2(143): akm_enable_sensor():enable sensor type 1.
    05-02 20:26:32.638: DEBUG/AKMD2(143): acc_enable(): acc phread create success!
    05-02 20:26:32.638: DEBUG/AKMD2(143): akm_set_delay():200000000 ns.
    05-02 20:26:32.638: DEBUG/Sensors(143): akm:setDelay():handle 0, delay 200000000 ns.
    05-02 20:26:32.638: DEBUG/AKMD2(143): akm_set_delay():200000000 ns.
    05-02 20:26:32.638: DEBUG/Sensors(143): akm:setDelay():handle 0, delay 200000000 ns.
    05-02 20:26:32.638: DEBUG/AKMD2(143): akm_set_delay():200000000 ns.
    05-02 20:26:32.638: DEBUG/Sensors(143): sensors_poll_context_t->activate(handle: 2, enabled: 1)
    05-02 20:26:32.638: DEBUG/Sensors(143): akm:enable() handle 2, en 1.
    05-02 20:26:32.638: DEBUG/AKMD2(143): akm_enable_sensor():enable sensor type 2.
    05-02 20:26:32.638: DEBUG/AKMD2(143): akm_enable(): phread create success!
    05-02 20:26:32.638: DEBUG/AKMD2(143): akm_set_delay():200000000 ns.
    05-02 20:26:32.638: DEBUG/Sensors(143): akm:setDelay():handle 2, delay 200000000 ns.
    05-02 20:26:32.638: DEBUG/AKMD2(143): akm_set_delay():200000000 ns.
    05-02 20:26:32.638: DEBUG/Sensors(143): akm:setDelay():handle 2, delay 200000000 ns.
    05-02 20:26:32.638: DEBUG/AKMD2(143): akm_set_delay():200000000 ns.
    05-02 20:26:32.648: DEBUG/AKMD2(143): acc_thread_main: ***acc*** thread start with delay = 200000000
    05-02 20:26:32.663: DEBUG/AKMD2(143): akm_thread_main: ***akm*** thread start with delay = 200000000
    05-02 20:26:32.663: INFO/AKMD2(143): AK8975/B for Android v 2.0.0.—- (Library: v1.2.3.114) started.
    05-02 20:27:05.128: DEBUG/dalvikvm(308): GC_EXPLICIT freed 90K, 46% free 4378K/8007K, external 14900K/16847K, paused 91ms

  3. Martin says:

    Does not work on (most) HTCs. The darn thing seems to be handled on the driver level and hotwired to the screen.

  4. I recently solved a similar issue using a similar path used by you. The problem is that it drains the battery.

  5. Masthaka says:

    Worked without issues on 4.0.4 Karbonn device!


  6. Marco says:

    I must admit that after spending DAYS searching for a solution to this issue, all hope appeared to be lost. That is until I saw this. Thank you so much for taking the time to try to help others like me. You’ve made my day!

    Note: tested on Samsung Galaxy S3 running android version 4.1.1.

  7. frank says:

    Do we install the zip in doing a flash? Or how do we implement this?

  8. Jameson says:

    @Frank — not sure what you mean?

  9. frank says:

    my apologies, still very much a noob at this. the link “” has a zip file download link. is this zip installable like a rom or software via custom recovery is what i meant to ask. again i apologize for the dumb question, just want this fix bad and not sure how to do it.

  10. Jameson says:

    Ah gotcha — ?

    That is a link to source code for an Android application, which demonstrates the method described in this blog post. You would have to compile the code into an application in order to see it working. But the code is meant only to be demonstrative — in and of itself, it’s not particularly useful.

  11. sam says:

    Looks like after 2 years people are still finding this code useful. Unfortunately it’s only effective on a handful of my tested devices. Has anyome found a permanent solution?

  12. Chris says:

    Great Solution,
    realy simple but works like a charm.
    Thank you

  13. Roberto says:

    GREAT!! It works on Samsung Galaxy Ace, OS 4.3.6

  14. Rakesh says:

    Thanks a lot…..:)

  15. Sean says:

    Thank You!

    It still works great.

    Tested on Galaxy Note 2, Android 4.3.

  16. Jigar says:

    This doesn’t work for SensorEvent.TYPE_STEP_COUNTER. When screen is off, i am not receiving any step_counter events.

  17. Carmen says:

    Congratulation, it’s a very interesting and helpful post.
    Just a question: is it possible to implement the broadcast receiver in a class different from the sensor event listener class? What I mean is, how could I deregister/register sensor event listeners if the broadcast receiver is not an inner class? I need to know that because in my application I want to have different services running in background, and they all implement the sensor event listener interface, so I don’t want to replicate the broadcast receiver code in all these classes. How could I do? Thank you

  18. Ashish says:

    I am getting a crash using github sample project, please help –

    12-15 22:05:36.594: E/AndroidRuntime(18272): Process: org.nosemaj.service_lock_test, PID: 18272
    12-15 22:05:36.594: E/AndroidRuntime(18272): Bad notification for startForeground: java.lang.RuntimeException: icon must be non-zero
    12-15 22:05:36.594: E/AndroidRuntime(18272): at$H.handleMessage(
    12-15 22:05:36.594: E/AndroidRuntime(18272): at android.os.Handler.dispatchMessage(
    12-15 22:05:36.594: E/AndroidRuntime(18272): at android.os.Looper.loop(
    12-15 22:05:36.594: E/AndroidRuntime(18272): at
    12-15 22:05:36.594: E/AndroidRuntime(18272): at java.lang.reflect.Method.invokeNative(Native Method)
    12-15 22:05:36.594: E/AndroidRuntime(18272): at java.lang.reflect.Method.invoke(
    12-15 22:05:36.594: E/AndroidRuntime(18272): at$
    12-15 22:05:36.594: E/AndroidRuntime(18272): at
    12-15 22:05:36.594: E/AndroidRuntime(18272): at dalvik.system.NativeStart.main(Native Method)

  19. Jameson says:

    @Ashish — the fancier way to do it is to use the NotificationBuilder, and supply an explicit icon. That will probably solve your problem.

  20. Roberto says:

    Great solution, but not always functioning.
    Work great on Samsung Next Turbo GT-S5570I with Android 2.3.6 but don’t work on Samsung XCover 2 with Android 4.1.2.

    I add this permission on manifest to write on file system.

    and i change onSensorChanged to write on a file.

    public void onSensorChanged(SensorEvent event) {
    Log.i(TAG, “onSensorChanged().”);
    String filename = “sdcard/VerticalMan/log/ServiceLockTest.log”;
    File file = new File(filename);

    String strOut = todayTimeStamp() + ” read sensor : ” + event.sensor.getType()+”\n”;
    try {
    if (!file.exists())
    FileWriter fw = new FileWriter(file,true);
    } catch (Exception e) {
    // TODO Auto-generated catch block
    In this way i can check easy if the test app receive the sensor event.
    If i press Power-Button on Next Turbo the file increase dimensions, but in XCover the app stop the file trace.

    Same one have a suggestions ?

  21. Roberto says:

    I solve the problem, set SCREEN_OFF_RECEIVER_DELAY to 1000.

  22. Priyanka says:

    I want to switch on my device using shake. I tried to follow your comments but i am getting following error-( Bad notification for startForeground: java.lang.RuntimeException: icon must be non-zero).’

    What should i do here? Shall i send my code to you?

  23. Jameson says:

    @Priyanka — please see comment 19, above.

  24. amir says:

    thanks too much :) your source code save my life 😀

    thanks again :)

  25. Craig Poxon says:

    Good stuff.

    Presumably the service is killed by using stored intent the was created for the startService?

    Also, isn’t the Service missing a super.destroy() in the onDestroy() event?

Leave a Reply