Skip to content

Android sensor framework

Android provides a simple set of classes which allow you to write apps that communicate with the on-board sensors. As a group, these classes form the Android sensor framework and provide a generic way to collect data from all types of integrated sensor. The main classes are:

  • SensorManager: represents the top-level sensor service; required in order to communicate with sensors
  • Sensor: represents a specific sensor; allows you to query the sensor's capabilities
  • SensorEvent: represents a single reading from a sensor
  • SensorEventListener: interface which lets an app receive and react to sensor events

The notes below summarise the main points from the official Android documentation which can be reached using the link in the further reading box.

At the top level, there is a single service class which provides you with access to all of the sensors (hardware or software) that are available on your device. The first step is to instantiate this object as shown in Figure 2.

1
2
3
4
5
6
 import android.hardware.SensorManager;
 ...
 private SensorManager mSensorManager;
 ...
 mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
 ...

Figure 2: Instantiating a SensorManager object

After importing the required class at line 1, a local variable is declared at line 3 and instantiated at line 5.

The Sensor class provides a standard API for the different types of sensor. Figure 3 demonstrates the use of the Sensor class to create a list of all available sensors (line 9), test for the existence of a particular type of sensor (line 11) and instantiate a local variable to represent that sensor if it exists (line 12).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import android.hardware.SensorManager;
import android.hardware.Sensor;
 ...
private SensorManager mSensorManager;
private Sensor mSensor;
 ...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
 ...
List<Sensor> deviceSensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
 ...
if (mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) != null){
    mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
else {
    Snackbar.make(view, "Sorry - no light sensor found", Snackbar.LENGTH_LONG)
       .setAction("Action", null).show();
}

Figure 3: Testing for and accessing particular types of sensor

SensorManager provides a range of interesting constant values as well as a small number of methods for reporting values of interest such as altitude (calculated from atmospheric pressure compared to atmospheric pressure at sea level).

Sensor is similar, but its methods provide information about the sensor only and not about the value that it is currently reading. If you want the value, then you have to listen explicitly for an onSensorChanged() event. Figure 4 illustrates how to do this.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class SensorActivity extends Activity implements SensorEventListener {
  private SensorManager mSensorManager;
  private Sensor mLight;

  @Override
  public final void onCreate(Bundle savedInstanceState) {
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
  }

  @Override
  public final void onSensorChanged(SensorEvent event) {
    float lux = event.values[0];
    // Do something with this sensor value.
  }
}

Figure 4: Getting a reading from the light sensor

The light sensor is similar to the ones you have been using with the Teensy in that it returns a single value at a time. Many of the more interesting sensors on a mobile device return three values at a time, however, one for each axis. The accelerometer is a good example of this. Note the variable assignment at line 13 in Figure 4: the SensorEvent object holds the value in an array called values[]. Here, only the first element of that array is required, but for sensors such as an accelerometer, the values would be found in the first three elements of the array.

Another interesting point to notice in Figure 4 is the reference to SensorEventListener in line 1. This is an interface declaration which tells Android that SensorActivity will include a set of methods for handling sensor events. Interfaces work in a similar way to superclasses in that they implement methods that you can override with your own code. Here there are two such methods: onCreate() comes from the Activity superclass while onSensorChanged() comes from the interface definition.

An alternative to using an interface would be to declare your own listener method as show in Figure 5:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class SensorActivity extends Activity {
  private SensorManager mSensorManager;
  private Sensor mLight;

  @Override
  public final void onCreate(Bundle savedInstanceState) {
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
    mSensorManager.registerListener(mSensorEventListener, mLight,
        SensorManager.SENSOR_DELAY_NORMAL);
  }

  private SensorEventListener mSensorEventListener = new SensorEventListener() {

    @Override
    public final void onSensorChanged(SensorEvent event) {
      float lux = event.values[0];
      // Do something with this sensor value
    }
  }
}

Figure 5: Registering a listener for sensor events

Further reading

Android sensors

Tutorial on using touch screen coordinates directly in apps

More sensor examples

Want your apps to talk?