New In iPhone 3.0 Tutorial Series, Part 4: Proximity Monitoring

On July 21, 2009
Seattle Beginning iPhone Programming Workshop: August 20-21.
$1200 Only $799 with “mo” coupon code and early registration discount.

When Google released their iPhone app last year it was accompanied with a bit of controversy:

Their app used an undocumented API to detect when the phone had been placed next to the speaker’s ear.

In iPhone 3.0 SDK this API is usable by any app. This short article demonstrates how to use it:

Proximity Monitoring

Apple provides a UIDevice class/singleton object that exposes properties about the physical device running your app’s code. Proximity monitoring is enabled/disabled by setting the singleton’s proximityMonitoringEnabled propery:

UIDevice *device = [UIDevice currentDevice];
device.proximityMonitoringEnabled = YES;

Device Support

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.proximityMonitoringEnabled = YES;
if (device.proximityMonitoringEnabled == YES)
	// do something

Running the code above on an iPhone 3G shows that it does support proximity monitoring; running the same code on the sim shows that it does not support proximity monitoring. (Note: the documentation appears to have a typo: it instructs you to check the proximityStatus property’s value, not the proximityMonitoringEnabled property.)

In most cases, you’ll want to provide another mechanism for triggering the functionality that holding the phone to your ear would trigger. In the case of Google’s app, you can tap a button to a voice search.

Receiving Proximity Change Notifications

The proximity monitoring event model does not use the familiar delegate approach.
Instead, proximity changes trigger notifications. In contract to delegates, notifications are used to disseminate events in situations where there may be more than one party interested in learning of the change.

Interested parties add an observer to an object whose notifications they wish to receive. The observer configures the notification center to trigger a callback when a particular event occurs. Expanding on our earlier work, this code registers a callback to be triggered when a proximity change occurs:

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

Add the call back method to complete the code. Here, we’re just logging the proximity to the console:

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

The proximityState property will not keep its YES value for more than an instant, regardless of whether the device is kept pressed to your ear. It gets set to YES, then quickly resets to NO. You’ll have to manage your own state. Using Google’s app as an example: removing the phone from the ear does not seem to be used to indicate the end of the search phrase; instead, a period of silence indicates triggers the state change.

0 responses to “New In iPhone 3.0 Tutorial Series, Part 4: Proximity Monitoring”

  1. DenVog says:

    Any idea how to detect the proximity without screen blanking?

  2. Dan Grigsby says:

    DenVog: not sure you can. It seems to do that by everywhere e.g., when you are on the phone it’s blanked. UIApplication has a property for turning off idle-timer dimming; seems like if this was going to be possible it would be set-able similarly, but I can’t find anything that indicates that you can.

  3. kensanwa says:

    In my experience, the proximityState will maintain its YES value as long as you are within about a 3.5 centimeter range of the sensor. If you touch the sensor or move out of the 3.5 centimeter range after triggering the YES proximityState, it will immediately switch to NO.