“A sensor is a device that detects events or changes in quantities and provides a corresponding output, generally as an electrical or optical signal; for example, a thermocouple converts temperature to an output voltage.” – Wikipedia

Introduction

Before we jump into the Android Sensor Framework, let’s take a brief step back and examine some basic concepts with regards to sensors. As humans, we have five senses: sight, hearing, taste, smell and touch. These give us the ability to receive input of various kinds to understand and analyze the world around us. The same principle applies to a mobile device. Mobile devices have lots of sensors which allow them to understand and analyze the world around them. However, unlike human senses, smartphones have many more sensor types available. There are over three hundred different types of sensors which exist for different domains and industries. Smartphones today contain just the bare minimum of these various sensors. In the near future mobile devices will likely have many more sensors built in., In fact, few companies like Samsung have started mounting more and more sensors in the device. For example, the Samsung Galaxy S5 contains ten different sensors. Sensors are becoming an essential part of the mobile device. If you ask me what the major differences are between a feature phone and smartphone, my first response would be “sensors.” Sensors are one of the main features that distinguishes a feature phone and a smartphone.  One way to interpret the “smart” in smartphone would be:

 

S = Sensors
M = Multi-Tasking
A = Applications
R = Real-Time (almost)
T = Touch Screen

 

Android Sensor Concepts

Android devices have many sensors, such as an accelerometer, a light sensor, or a proximity sensor. Availability of sensors are different per model and OEM, and even which version of Android the device is running. Before diving into the Android Sensor API, it’s important to understand some of the basic nomenclature.  In general, sensors can broken down by category and type as follows

 

Sensor Categories

Within Android, sensors can be broken down into three broad categories:

  1. Environmental Sensors: These sensors provide environment details like light sensor, proximity sensor, temperature sensor, etc.
  2. Motion Sensors: These sensors provide motion information acceleration, rotation etc.
  3. Position Sensors: These sensors provide the physical location of the device

 

Sensors Types

Additionally, sensors can also be broken down into two major types:

  1. Hardware based sensor: These sensors are physically present sensor devices within the mobile device
  2. Software based sensor: These sensors are not physically available in the device, but appear as though they are physically available. Software based sensors derive or calculate their data based on one or more physical sensors. These types of sensors are often called virtual sensors. The Android gravity sensor is the best example of the software based sensor as it is derived from the accelerometer data.

 

Common Android Sensors

Android continues to evolve and new sensors are added to the system definition as time progresses. The table below outlines the sensors commonly found in Android based mobile devices as of Android 5.0. Remember, not all mobile devices contain each of these sensors. The Android Compatibility Definition Document (or Android CDD) defines which sensors are required vs. optional as well as tolerance details for each. This means OEMs have some latitude to pick which sensors are present in a given device. For example, the Samsung Galaxy S5 includes a heart rate sensor as well as a hall effect (magnetic field) sensor, but not all other Android devices may include these specific sensors. See Section 7.3 of the Android CDD for more information on required vs. optional components.

Android Defined Sensors

SensorTypeDescription
AccelerometerHardwareAcceleration detection along 3D axis, typically with relation to the force of gravity
Ambient TemperatureHardwareMonitors the room or environment temperature
Device TemperatureHardwareMonitors the temperature of the device itself
GravityHardware or SoftwareMeasures the force of gravity on the device, in 3D
GyroscopeHardwareRotational force detection
LightHardwareDetects the amount of light around the device
Linear AcclerationHardware or SoftwareMonitors the acceleration along each 3D axis, without a gravity component
Magnetic FieldHardwareMagnetic field detection, typically used for compass
OrientationSoftwareDetects the orientation of the device relative to the earth or landscape or portrait mode
PressureHardwareMonitors the barometric (air) pressure
ProximityHardwareMonitors objects close to the mobile device
Relative HumidityHardwareMonitors the relative humidity of the air around the mobile device
Heart RateHardwareMeasures the heart rate of the user of the device

 

Sensor APIs

Android has powerful set of APIs to report the sensor information and data. The sensor APIs are found in the android.hardware package. The first step to start utilizing sensors in your app is to get the SensorManager object. SensorManager is one of the system provided services, and can be fetched using the Context.getSystemService() method. In the simple example I’ll walk you through in this article, I’ll be using a couple of activities, both of which will interact with the SensorManager. In both cases, the Activity‘s onCreate() will get the SensorManager object and stash it off in a private member field:

public class MainActivity extends ActionBarActivity implements AdapterView.OnItemClickListener {
    private SensorManager mSensorManager;
    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        ...
    }
}

The SensorManager object provides several APIs with which we can access and get information about sensors in our Android device. There are four primary methods worth explaining for our usage purposes:

  • getDefaultSensor: Get the default Sensor object for a specific sensor type
  • getSensorList: Get the list of all sensors or a all sensors of a specific sensor type present in the mobile device
  • registerListener: Register a callback interface to be notified of new sensor data
  • unregisterListener: Remove a previous callback interface registration for your app

In the demo application, I’m going to display a list of all sensors present on the device. Each device is different, so a good first step when dealing with sensors is to get a list of all sensors or a list of all sensors of the type needed. To do this, we call the manager’s getSensorList() method. It will return an array of Sensor objects. Each instance of the Sensor class represents a single sensor and relevant information. The Sensor class contains constants for each of the sensor types defined by the system. To retrieve all sensors we need to use Sensor.TYPE_ALL constant.

public class MainActivity extends ActionBarActivity implements AdapterView.OnItemClickListener {
    private SensorManager mSensorManager;
    private List<Sensor> mSensors;
    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        mSensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
        ...
    }
}

From here we can examine each sensor in the system. The Sensor object provides us with details about the specific sensor, such as its name, type and vendor. For our purposes, we are going to log this data and also display it on screen using a ListView. For brevity, the code below logs each sensor’s information.

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        if (mSensors != null) {
            Log.i(TAG, "Dump of all sensors on device");
            for(Sensor curSensor : mSensors) {
                Log.i(TAG, "Name: " + curSensor.getName());
                Log.i(TAG, "Vendor: " + curSensor.getVendor());
                Log.i(TAG, "Version: " + curSensor.getVersion());
                Log.i(TAG, "Type: " + curSensor.getType());
            }
        }
    }

Android Sensor list

Now that we have a list of all sensors, how do we actually use one? As of Android 4.4 (KitKat), the different sensor types are each SHOULD include or MAY include requirements in the CDD. Let’s pick a simple example which is almost always present in Android devices: the light sensor. The system generally uses this to automatically control screen brightness based on the surrounding light level. The unit to measure light intensity is SI lux. Raw data which we receive from the light sensor usually requires no calibration, filtering or processing, making it straightforward to use. To use a sensor, we first need to get its corresponding Sensor object. In the demo code, I get this directly from the sensor list. However, if you are interested in a specific type of sensor, you can just ask the SensorManager for the default sensor of that type:

    mySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);

Once we have the Sensor object, we can start receiving data from it. The Android Sensor APIs define a SensorEventListener interface, which we need to implement in a class and register with the manager. The SensorEventListener interface defines two methods which are called at the appropriate time:

  • onSensorChanged: when the sensor reports data to Android, the system calls back our class with the data encapsulated in a SensorEvent class. The SensorEvent object contains information about the sensor data including accuracy of the data, the sensor data and timestamp at which the data was received. The data itself is device dependent and provided as an array of floats.
  • onAccuracyChanged: if sensor accuracy has changed, the system notifies the listener at this method. Accuracy is represented by one of four status constants: SENSOR_STATUS_ACCURACY_LOW, SENSOR_STATUS_ACCURACY_MEDIUM, SENSOR_STATUS_ACCURACY_HIGH, or SENSOR_STATUS_UNRELIABLE.

In order to start receiving data for the sensor, an instance of our app’s SensorEventListener needs to be registered with the SensorManager via the registerListener() method. At this point in time we can also request the frequency at which we receive sensor data. Note that the frequency is simply a request to the system, it is not a guarantee. To assist with specifying the frequency, the system provides several constants: SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME, and SENSOR_DELAY_FASTEST. You can also specify your own frequency, in microseconds. When the app no longer wishes to receive data, it must call the manager’s unregisterListener() method. From an Activity, it usually makes sense to register in onResume() and unregister in onPause().

    @Override
    protected void onResume() {
        super.onResume();
        if (mSensor != null) {
            mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
        }
    }

    @Override
    protected void onPause() {
        if (mSensor != null) {
            mSensorManager.unregisterListener(this);
        }

        super.onPause();
    }

Now that we are receiving sensor data and have the details, we can display it on screen and also watch the data change. In the case of the light sensor, you should be able to find it near the top of your device. Below, I’m using a Nexus 7 (2012) where the light sensor is near the top-center of the device. The raw data value is changing because I’m moving my finger in front of the sensor then away from it repeatedly.

Recap

We’ve now taken a quick look at the basics of using Android sensors. The first step is getting the SensorManager.  From there we were able to detect sensor devices present on the system and show some details about them.  Given a specific sensor, it is straightforward to ask that the system notify the app of any new data values. Next time I’ll explore some of the more advanced usage of sensors, such as power management considerations, trigger events and wake events.

The sources for the demo code used in this article can be found at this GitHub repository:

https://github.com/hiq-larryschiefer/SensorSample.git