Is there a away to detect the event when iOS device goes to sleep mode (when the screen gets blackened)?

Rohit Kashyap picture Rohit Kashyap · Jan 16, 2013 · Viewed 13.8k times · Source

I wanted to detect two events :

  1. Device gets locked/unlocked.
  2. Device goes to sleep and the screen blackens.

First one I have been able to achieve here: Is there a way to check if the iOS device is locked/unlocked?

Now I want to detect the second event, is there any way to do it ?

Answer

Nate picture Nate · Jan 16, 2013

You basically already have the solution, which I'm guessing you found from one of my recent answers :)

Use the com.apple.springboard.hasBlankedScreen event.

There are multiple events that occur when the screen blanks, but this one should suffice:

CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
                                NULL, // observer
                                hasBlankedScreen, // callback
                                CFSTR("com.apple.springboard.hasBlankedScreen"), // event name
                                NULL, // object
                                CFNotificationSuspensionBehaviorDeliverImmediately);

where the callback is:

static void hasBlankedScreen(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
    NSString* notifyName = (__bridge NSString*)name;
    // this check should really only be necessary if you reuse this one callback method
    //  for multiple Darwin notification events
    if ([notifyName isEqualToString:@"com.apple.springboard.hasBlankedScreen"]) {
       NSLog(@"screen has either gone dark, or been turned back on!");
    }
}

Update: as @VictorRonin said in his comment below, it should be easy to keep track yourself whether the screen is currently on or off. That allows you to determine whether the hasBlankedScreen event is occurring when the screen goes on or off. For example, when your app starts, set a variable to indicate that the screen is on. Also, any time any UI interaction occurs (button pressed, etc.), you know the screen must currently be on. So, the next hasBlankedScreen you get should indicate that the screen is off.

Also, I want to make sure we're clear on the terminology. The device locks when the screen automatically darkens due to a timeout, or when the user manually presses the power button. This happens regardless of whether the user has a Passcode configured. At that time, you will see the com.apple.springboard.hasBlankedScreen and the com.apple.springboard.lockcomplete events.

When the screen turns back on, you will see com.apple.springboard.hasBlankedScreen once again. But, you will not see com.apple.springboard.lockstate until the user has actually unlocked the device with a swipe (and maybe a passcode).


Update 2:

There's yet another way to do this. You can use an alternate set of APIs to listen for this notification, and also get a state variable when the notification comes:

#import <notify.h>

int status = notify_register_dispatch("com.apple.springboard.hasBlankedScreen",
                                      &notifyToken,
                                      dispatch_get_main_queue(), ^(int t) {
                                          uint64_t state;
                                          int result = notify_get_state(notifyToken, &state);
                                          NSLog(@"lock state change = %llu", state);
                                          if (result != NOTIFY_STATUS_OK) {
                                              NSLog(@"notify_get_state() not returning NOTIFY_STATUS_OK");
                                          }
                                      });
if (status != NOTIFY_STATUS_OK) {
    NSLog(@"notify_register_dispatch() not returning NOTIFY_STATUS_OK");
}

and you will need to keep an ivar, or some other persistent variable, to store the notification token (do not just make this a local variable in the method that registers!)

int notifyToken;

You should see the state variable, obtained via notify_get_state(), toggle between 0 and 1, which will let you distinguish between screen on and off events.

Although this document is very old, it does list which notification events have an associated state that can be retrieved via notify_get_state().

Warning: see this related question for some complications with this last technique