30

as mentioned here, when the screen goes off, the onStop() of current Activity will be called. I need to check the screen on/off status when the onStop() of my Activity is called. so I have registered a BroadcastReceiver for these actions(ACTION_SCREEN_ON AND ACTION_SCREEN_OFF) to record the current on/off status(and they work properly, I have logged!).
but when I turn off the screen and check the on/off status in the onStop , it says the screen is on. why? I think the receiver must receive the ACTION_SCREEN_OFF before onStop is called so what's wrong?

Community
  • 1
  • 1
Soheil
  • 1,676
  • 7
  • 34
  • 65
  • 1
    "I think the receiver must receive the ACTION_SCREEN_OFF before onStop is called so what's wrong?" -- I have no idea why you would assume that. Use `Log` statements, or breakpoints, to see which gets called first. Better yet, redesign your app to not care whether `onStop()` is being called because the screen is being turned off, as compared to any other reason. – CommonsWare Oct 13 '13 at 21:04
  • @CommonsWare the app must be able to differ between different situations that `onStop` gets called in them, so I must know whether turning the screen off has caused `onStop` to be called or another thing. any better solution? – Soheil Oct 13 '13 at 21:09
  • "the app must be able to differ between different situations that onStop gets called in them" -- why? What difference does it make to your app whether the screen is turned off, or the user pressed HOME, or the user pressed BACK, or the user took an incoming phone call, or the user tapped on a notification, or the user did anything else that caused your activity to no longer be visible? The screen turning off is not normally a special case. – CommonsWare Oct 13 '13 at 21:14
  • because I'm developing an unlocker app and any thing that causes a call to `onStop` should be handled in my app, so I'm trying to define any situation that `onStop` is called, so that I can differ between pressing home button and others. anyhow! let's comeback to my first question! do you have any idea? – Soheil Oct 13 '13 at 21:23
  • What are you trying to do in `onStop` when the screen us on or off? Maybe there's an easier or other way to get the job done. – jboi Oct 13 '13 at 21:24
  • @jboi I've mentioned it just in my previous comment above! – Soheil Oct 13 '13 at 21:31

4 Answers4

75

You can try to use PowerManager system service for this purpose, here is example and official documentation (note this method was added in API level 7):

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean isScreenOn = pm.isScreenOn();

EDIT:

isScreenOn() method is deprecated API level 21. You should use isInteractive instead:

boolean isScreenOn = pm.isInteractive();

http://developer.android.com/reference/android/os/PowerManager.html#isInteractive()

Alexander Semenov
  • 1,513
  • 13
  • 20
3

As mentioned in this answer to a similar question. In API 21 and above we can use the DisplayManager to determine the state of the display. This has the advantage of supporting the querying of multiple displays:

DisplayManager dm = (DisplayManager) 
context.getSystemService(Context.DISPLAY_SERVICE);
for (Display display : dm.getDisplays()) {
    if (display.getState() != Display.STATE_OFF) {
        return true;
    }
}
return false;

Depending upon your circumstance it might be more appropriate to query the display that a particular view is being displayed on:

myView.getDisplay().getState() != Display.STATE_OFF
Rem-D
  • 627
  • 6
  • 15
  • It works but I have a question. I used this code inside onStop(). When I leave app(not killing it completly), it returns true as I expected. But when I close the device it doesn't return false. Only if I return the app and close the device while app is foreground, it returns false. What I want is I want to check the status while the app is in background state. – Abdulsamet Kılınçarslan Feb 07 '21 at 15:02
  • @AbdulsametKılınçarslan So this code gets called when you send the app to the background. But then when you close the device it isn't getting the called? I believe if this code is in onStop() then it's because onStop() will only get called when the activity is destroyed. Which will only happen once. You may need to do what the OP of this post is doing and use a broadcast receiver instead to listen to screen off events. – Rem-D Feb 08 '21 at 12:07
1

If you want to manually check the screen state instead of the broadcast receiver, you should consider some situations.

  • Screen may be active with Doze mode (Samsung's Always-on-Display feature)
  • VR mode may be active

In order to check that the screen is not turned off and the user is actively using the phone, the screen state must not be Display.STATE_OFF and not in the keyguardManager.isKeyguardLocked() state.

public static boolean isDeviceActive(
        @NonNull DisplayManager displayManager,
        @NonNull KeyguardManager keyguardManager
) {
    for (Display display : displayManager.getDisplays()) {
        if (display.getState() != Display.STATE_OFF) {
            return !keyguardManager.isKeyguardLocked();
        }
    }
    return false;
}
Atakan Yildirim
  • 684
  • 11
  • 22
0
PowerManager pm = (PowerManager) mMainActivity.getSystemService(Context.POWER_SERVICE);
boolean isScreenOn = Utils.hasLollipop() ? pm.isInteractive() : pm.isScreenOn();
Mary Seo
  • 9
  • 1
  • 1
    what is Utils.hasLollipop? how does this answer the question in a better way ? – Jawad Dec 19 '19 at 04:26
  • @Jaward `public static boolean hasLollipop() { return Build.VERSION.SDK_INT >= 21; }` isScreenOn() is deprecated, but isInteractive() cannot under 21. – Mary Seo Dec 19 '19 at 05:20