Mozilla's getting a new look. What do you think? https://mzl.la/brandsurvey

Near or far? Responding to proximity

Did you know that your mobile phone knows when you are near to it, and can even react to your presence? This article explains how the web platform can access the proximity sensors installed on mobile devices and provides an instant messaging and calls demo application that makes use of the Proximity API.

Proximity Sensors

Preventing unwanted actions on mobile phones is the most common scenario for proximity sensing: while on a call, the ear coming in contact with the screen might generate touch events. Due to this main use case, on mobile phones the proximity sensor is often implemented as a light sensor chip: the distance value is measured in centimetres, and some sensors only support binary "near" or "not near" measurement values. As will be made clear in the next section, the Proximity API was designed taking into account the characteristics of the proximity sensors installed on mobile phones.

Proximity API

The web platform defines a  Proximity API that makes it possible to react when a user is close to a device.

The Proximity API defines 2 proximity events:

  • UserProximityEvent
  • DeviceProximityEvent

UserProximityEvent

The UserProximityEvent is fired every time the state of the phone's proximity to a nearby object changes. The following example logs the UserProximityEvent's fields:

window.onuserproximity = function(event) {
  console.log(event.near);  // current user proximity state (boolean)
});

Please refer to the UserProximityEvent documentation for more details.

DeviceProximityEvent

The DeviceProximityEvent provides more information about the device's proximity sensor: the current device proximity in cm, and the maximum and the minimum sensing distance. The following example logs the DeviceProximityEvent's fields:

window.ondeviceproximity = function(event) {
  console.log(event.value); // current device proximity (cm)
  console.log(event.max);   // maximum sensing distance (cm)
  console.log(event.min);   // minimum sensing distance (cm)
});

Please refer to the DeviceProximityEvent documentation for more details.

Demo: Low Energy Messenger

Low Energy Messenger is an instant messaging and calls web app that pays very high attention to battery status. You can try out the proximity features of Low Energy Messenger using Firefox Mobile or grab the code from Github and play with it.

The core structure and behaviour of this demo, as well as an explanation of how the chat works, is covered by this MDN article about retrieving battery status information. In this article we're going to focus on how Low Energy Messenger makes use of the Proximity API in the call screen.

Note: The call screen is displayed when the call button is clicked. This action doesn't perform a real call: it only shows a static page for demo purposes: So don't worry, you're not calling me for real! :)




 

As you might have noticed in the image above, the values on the proximity box are not defined: this is the initial status of the proximity box.

The Proximity Manager

In order to handle the proximity, Low Energy Messenger provides an utility object that makes use of the Proximity API: the ProximityManager.

The ProximityManager defines 2 methods:

  • ProximityManager.userproximity
  • ProximityManager.deviceproximity

ProximityManager.userproximity registers a callback function on the UserProximityEvent:

/*
 * userproximity
 * Register a callback function on the userproximity event
 * @param {Function} callback
 */
userproximity: function(callback) {
    window.addEventListener('userproximity', callback); // Proximity API
}

ProximityManager.deviceproximity registers a callback function on the DeviceProximityEvent:

/*
 * deviceproximity
 * Register a callback function on the deviceproximity event
 * @param {Function} callback
 */
deviceproximity: function(callback) {
    window.addEventListener('deviceproximity', callback); // Proximity API
}

The call screen

Low Energy Messenger's call screen borrows the Gaia callscreen app's style and JavaScript structure.  A CallScreen object is defined to manage the view, perform the call and interact with the ProximityManager.

Let's have a look at the main DOM elements we're going to use in the CallScreen object.

/* Initialize DOM elements */
this.callScreen = document.getElementById('callscreen');

this.hangupButton = document.querySelector('button#hangup');

this.nearBox = document.getElementById('near');
this.minBox = document.getElementById('min');
this.maxBox = document.getElementById('max');
this.deviceProximityBox = document.getElementById('deviceproximity');

Responding to proximity

We want to prevent unwanted touch events while on a call by hiding the hangup button when the ear is close to the screen.

The CallScreen object uses the ProximityManager to turn the screen off and on:

/* Handle the proximity */

var self = this;

ProximityManager.userproximity(function(event) {
    
    /* Log */
    console.log(event);
    self.nearBox.innerHTML = event.near;
    
    /* Turn the screen off/on */
    if (event.near) {
        self.hideView(); // turn off the screen when the user is near
    }
    else {
        self.showView();
    }
});

ProximityManager.deviceproximity(function(event) {
    
    /* Log */
    console.log(event);
    self.minBox.innerHTML = event.min;
    self.maxBox.innerHTML = event.max;
    self.deviceProximityBox.innerHTML = event.value;

    /* Turn the screen off/on */
    if (event.value <= 1) { // turn off the screen when the device proximity is less or equal to 1 cm
        self.hideView();
    }
    else {
        self.showView();
    }
});

Thus, when the ProximityManager fires the proximity events the proximity box gets filled with proximity values.


 

Controlling the device screen

The CallScreen.hideView makes sure that the hangout button cannot be clicked.

/*
 * hideView
 * Turn off the screen
 */
hideView: function() {
    this.callScreen.setAttribute('class', 'off');
}

This is achieved by setting the off CSS class on the call screen:

section#callscreen.off {
    background: black;
}

section#callscreen.off > *:not(#proximity) {
    display: none;
}

This is how the call screen with CSS class off appears:

Last but not least, the CallScreen.showView method turns the screen on again when the user is not near or the device proximity is greater than 1 cm:

/*
 * showView
 * Turn on the screen
 */
showView: function() {
    this.callScreen.setAttribute('class', 'on');
}

Summary

As we have seen above, Low Energy Messenger hides clickable/tappable DOM elements when the ear is near to the device during a call. In Firefox OS certified applications it's possible to do something more by using the PowerManager.screenEnabled property, with which you can control the device's screen and turn the screen off and on for real. Have a look at the Power Management API documentation for more details about it.

 

Document Tags and Contributors

 Contributors to this page: chrisdavidmills, franciov, groovecoder
 Last updated by: chrisdavidmills,