Andres Canella
Andres Canella

Reputation: 3716

Activate proximity Monitoring while occluded to shut down iphone screen

Needs

I want to turn the screen off when the user places his iphone upside down on q desk. At the same time I do not want to have the proximity monitor enabled all the time as this is very uncomfortable for the user and miss fires a lot of times depending on how you grab the device.

What for

This is to leave at night and save battery and screen life while still running the app.

The workaround

I am thinking of is to use the accelerometer to determin if the face is down, if so activate the proximity censor. Simple stuff...

The problem

In practice the workaround does not work, It seams that if the censor is "occluded" when you activate it, it will not register its current state.

Refresh UIDevice some how?

What I'm Using

-(id)init {
    if ((self = [super init])) 
    {
        NSLog(@"Init ShakerAnalizer");
        accelerometer = [UIAccelerometer sharedAccelerometer];
        accelerometer.delegate = self;
        accelerometer.updateInterval = 5.0f;
    }
    return self;
}

-(void)accelerometer:(UIAccelerometer *)accel didAccelerate:(UIAcceleration *)acceleration
{
    if (accelerometer) 
    {        
        NSLog(@"Accelerometer Z:::  %f", acceleration.z);

        if (acceleration.z > kFlippedThreshold) 
            device.proximityMonitoringEnabled = YES;
        else
            device.proximityMonitoringEnabled = NO;
    }
}

Upvotes: 4

Views: 918

Answers (2)

SG1
SG1

Reputation: 2901

You don't want to be monitoring for the flip event itself; rather, you want to watch for the state of being flipped.

Here is a complete implementation, in which you simply call monitorForFaceDownOnSurfaceStatus: when you want (maybe all the time, maybe not) and fill in setFaceDownOnSurface: to handle that state (maybe setting screen brightness to minimum as in my example):

- (BOOL)canEnableProximityMonitoring
{
    UIDevice *device = [UIDevice currentDevice];

    BOOL wasEnabled = device.proximityMonitoringEnabled;
    BOOL could;
    device.proximityMonitoringEnabled = YES;
    could = device.proximityMonitoringEnabled;
    device.proximityMonitoringEnabled = wasEnabled;

    return could;
}

BOOL isMonitoringForFaceDown = NO;
- (void)monitorForFaceDownOnSurfaceStatus:(BOOL)shouldMonitor
{
    if ( ![self canEnableProximityMonitoring] ) {
        return;
    }

    UIDevice *device = [UIDevice currentDevice];
    if ( shouldMonitor ) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
        [device beginGeneratingDeviceOrientationNotifications];
    } else {
        [device endGeneratingDeviceOrientationNotifications];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
    }

    if ( isMonitoringForFaceDown != shouldMonitor ) {
        isMonitoringForFaceDown = shouldMonitor;
        [self deviceOrientationChanged:nil];
    }
}

UIDeviceOrientation oldOrientation = UIDeviceOrientationUnknown;
- (void)deviceOrientationChanged:(NSNotification *)note
{
    if ( !note ) {
        [self monitorProximityState:NO];
        return;
    }

    UIDevice *device = [UIDevice currentDevice];
    UIDeviceOrientation newOrientation = device.orientation;
    if ( newOrientation != oldOrientation ) {
        oldOrientation = newOrientation;
        [self monitorProximityState:(oldOrientation == UIDeviceOrientationFaceDown)];
    }
}

BOOL isMonitoringProximity = NO;
- (void)monitorProximityState:(BOOL)shouldMonitor
{   
    UIDevice *device = [UIDevice currentDevice];
    if ( shouldMonitor ) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(proximityStateChanged:) name:UIDeviceProximityStateDidChangeNotification object:nil];
        device.proximityMonitoringEnabled = YES;
    } else {
        device.proximityMonitoringEnabled = NO;
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceProximityStateDidChangeNotification object:nil];
    }

    if ( isMonitoringProximity != shouldMonitor ) {
        isMonitoringProximity = shouldMonitor;
        [self proximityStateChanged:nil];
    }
}

BOOL oldProximityState = NO;
- (void)proximityStateChanged:(NSNotification *)note
{
    if ( !note ) {
        [self setFaceDownOnSurface:NO];
        return;
    }

    UIDevice *device = [UIDevice currentDevice];
    BOOL newProximityState = device.proximityState;
    if ( newProximityState != oldProximityState ) {
        oldProximityState = newProximityState;
        [self setFaceDownOnSurface:newProximityState];
    }
}

float oldBrightness;
- (void)setFaceDownOnSurface:(BOOL)isFaceDownOnSurface
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        oldBrightness = [UIScreen mainScreen].brightness;
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(brightnessChanged:) name:UIScreenBrightnessDidChangeNotification object:[UIScreen mainScreen]];
    });

    float newBrightness = 0;
    if ( isFaceDownOnSurface ) {
        oldBrightness = [UIScreen mainScreen].brightness;
    } else {
        newBrightness = oldBrightness;
    }

    [UIApplication sharedApplication].idleTimerDisabled = isFaceDownOnSurface;
    [UIScreen mainScreen].wantsSoftwareDimming = isFaceDownOnSurface;
    [UIScreen mainScreen].brightness = newBrightness;
}

- (void)brightnessChanged:(NSNotification *)note
{
    oldBrightness = [UIScreen mainScreen].brightness;
}

Upvotes: 2

Andres Canella
Andres Canella

Reputation: 3716

Using the accelerometer to determin if phone is facing down to activate the proximity censor works well. Using a fast refresh rate to determin when the phone flips is crusial as if you activate the proximity censor when already occluded the screen will stay on. Once the phone is fasing down you can lower the refresh rate to save battery.

Upvotes: 0

Related Questions