Keep display on when the proximity sensor is covered
Asked Answered
A

5

16

I want to intercept the proximity sensor without turning off the display.

I know by the documentation that I have two Bool variables:

proximityMonitoringEnabled
proximityState

and this code

[UIDevice currentDevice].proximityMonitoringEnabled = YES;

When the proximity sensor detects something it turns off the display, same way it does when you're holding the phone to your ear when on a phone call.

How do I keep the display on when the proximity sensor is covered?

Ablation answered 26/11, 2014 at 11:20 Comment(1)
Hi, thank for the answer. Ok, with your code i can know the state of the proximity sensor, but if the state is "YES", is the display still not visible?Ablation
S
8

After reading different forums on the topic, its currently not possible for us in the public api to prevent the iPhone screen from going black when the proximity sensor is covered. The only thing you can do with the sensor is tell when its covered or not thru the notification center but again you can't control its natural behavior (When it dims/blacks out the screen).

Shaper answered 2/12, 2014 at 22:53 Comment(1)
Interestingly, Google and also PeekCalendar were able to use the functionality and still get their apps published by apple - see peekcalendar.comMotivation
P
7

Apple’s documentation notes that “Not all iPhone OS devices have proximity sensors.” To determine if the device your app is running supports proximity monitoring, set the proximityMonitoringEnabled property to YES, then check its value:

UIDevice *device = [UIDevice currentDevice];
[device setProximityMonitoringEnabled:YES];

if (device.proximityMonitoringEnabled == YES) {
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(proximityChanged:) 
                                                 name:@"UIDeviceProximityStateDidChangeNotification"
                                               object:device];
}

- (void) proximityChanged:(NSNotification *)notification {
    UIDevice *device = [notification object];
    NSLog(@"In proximity: %i", device.proximityState);
}

Source: http://www.whatsoniphone.com/blog/new-in-iphone-30-tutorial-series-part-4-proximity-detection/

Will help to detect current state of sensor.

Public API that allows screen dim:

[UIScreen mainScreen].wantsSoftwareDimming = YES;
[UIScreen mainScreen].brightness = $your_brightness_value;

Found here: Change to wantsSoftwareDimming in iOS 6?

Purifoy answered 26/11, 2014 at 11:24 Comment(4)
hi, so i can reply only now. I'm able to do something when the sensor is covered, but the display still off!Ablation
@SimonePistecchia Why don't you update your question with what you tried so that we can further help you better.Vaccinia
Simone Pistecchia, edited my answer how to dim screen using public API.Purifoy
The question asks how to keep the screen on while still being able to detect proximity using the proximity sensor. This answer results in the screen still turning off.Motivation
C
6

Although there is no public API to do this, you can hook into IOKit's IOHIDEventSystem and listen for screen dimming notifications:

// Create and open an event system.
IOHIDEventSystemRef system = IOHIDEventSystemCreate(NULL);

// Set the PrimaryUsagePage and PrimaryUsage that the AppleProxShim service uses
int page = 65280;
int usage = 8;

// Create a dictionary to match the service with
CFStringRef keys[2];
CFNumberRef nums[2];
keys[0] = CFStringCreateWithCString(0, "PrimaryUsagePage", 0);
keys[1] = CFStringCreateWithCString(0, "PrimaryUsage", 0);
nums[0] = CFNumberCreate(0, kCFNumberSInt32Type, &page);
nums[1] = CFNumberCreate(0, kCFNumberSInt32Type, &usage);
CFDictionaryRef dict = CFDictionaryCreate(0, (const void**)keys, (const void**)nums, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
// Get the total of matching services with the above criteria
CFArrayRef srvs = (CFArrayRef)IOHIDEventSystemCopyMatchingServices(system, dict, 0, 0, 0, 0);

// Get the service
IOHIDServiceRef serv = (IOHIDServiceRef)CFArrayGetValueAtIndex(srvs, 0);
int interval = 1 ;

// Set an interval of 1 , to activate the sensor  
IOHIDServiceSetProperty((IOHIDServiceRef)serv, CFSTR("ReportInterval"), CFNumberCreate(0, kCFNumberSInt32Type, &interval));

// add your event handler
IOHIDEventSystemOpen(system, handle_event, NULL, NULL, NULL);
int defaultInterval = 0;
IOHIDServiceSetProperty((IOHIDServiceRef)serv, CFSTR("ReportInterval"), CFNumberCreate(0, kCFNumberSInt32Type, &defaultInterval));

// close handles and release the IOHIDEventSystemRef
IOHIDEventSystemClose(system, NULL);
CFRelease(system);

Your event handler function pointer will look something like this:

void handle_event(void* target, void* refcon, IOHIDServiceRef service, IOHIDEventRef event) {
    if (IOHIDEventGetType(event) == kIOHIDEventTypeProximity) { // Proximity Event Received
        // not necessary, but if you want the value from the sensor, get it from IOHIDEventGetIntegerValue
        int proximityValue = IOHIDEventGetIntegerValue(event, (IOHIDEventField)kIOHIDEventFieldProximityDetectionMask); // Get the value of the ProximityChanged Field (0 or 64)

        // Call dimScreen with the boolean NO
        int (*SBSSpringBoardServerPort)() = (int (*)())dlsym(RTLD_DEFAULT, "SBSSpringBoardServerPort");
        int port = SBSSpringBoardServerPort(); 
        void (*_SBDimScreen)(int _port,BOOL shouldDim) = (void (*)(int _port,BOOL shouldDim))dlsym(RTLD_DEFAULT, "SBDimScreen");

        // This is where the logic to dim the screen based on the sensor value would go.  In this case, I'm hardcoding NO instead of the value of proximityValue from above
        // BOOL dim = proximityValue == 0 ? NO : YES;
        _SBDimScreen(port, NO); 
    }
}

Calling _SBDimScreen may not even be necessary, as having an empty function pointer may stop all proximity sensor events.

Code modified from the command line tool example on the AppleProxShim page on the iPhoneDevWiki.

Christean answered 20/4, 2016 at 17:22 Comment(5)
Thank you for such a great answer! Hopefully it will become possible without using IOKit at some point.Cephalonia
Thanks @DanielStorm, good luck! Will update if this is ever exposed with a public API.Christean
How do you implement C++ code like this with a swift application?Motivation
@Christean Are there any good tutorials on implementing private API usage in non Objective-C applications?Motivation
Will your app be rejected in the App Store if you use this method?Motivation
V
0

Use the following API to enable/disable the proximity sensor.

[UIDevice currentDevice].proximityMonitoringEnabled = NO; // Disables the Proximity Sensor and won't turnoff the display when sensor covered

[UIDevice currentDevice].proximityMonitoringEnabled = YES; // Enables the Proximity Sensor and will turnoff the display when sensor covered

Not all iOS devices have proximity sensors. To determine if proximity monitoring is available, attempt to enable it. If the value of the proximityMonitoringEnabled property remains NO, proximity monitoring is not available.

Vang answered 24/2, 2016 at 8:58 Comment(1)
I have tested it with iPhone 6 with iOS 9.2.1.Vang
R
0

fo swift / iOS 10 / xcode 8.2

UIDevice.current.isProximityMonitoringEnabled = true/false..
Refraction answered 4/2, 2017 at 11:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.