“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:
- Environmental Sensors: These sensors provide environment details like light sensor, proximity sensor, temperature sensor, etc.
- Motion Sensors: These sensors provide motion information acceleration, rotation etc.
- Position Sensors: These sensors provide the physical location of the device
Sensors Types
Additionally, sensors can also be broken down into two major types:
- Hardware based sensor: These sensors are physically present sensor devices within the mobile device
- 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
Sensor | Type | Description |
---|---|---|
Accelerometer | Hardware | Acceleration detection along 3D axis, typically with relation to the force of gravity |
Ambient Temperature | Hardware | Monitors the room or environment temperature |
Device Temperature | Hardware | Monitors the temperature of the device itself |
Gravity | Hardware or Software | Measures the force of gravity on the device, in 3D |
Gyroscope | Hardware | Rotational force detection |
Light | Hardware | Detects the amount of light around the device |
Linear Accleration | Hardware or Software | Monitors the acceleration along each 3D axis, without a gravity component |
Magnetic Field | Hardware | Magnetic field detection, typically used for compass |
Orientation | Software | Detects the orientation of the device relative to the earth or landscape or portrait mode |
Pressure | Hardware | Monitors the barometric (air) pressure |
Proximity | Hardware | Monitors objects close to the mobile device |
Relative Humidity | Hardware | Monitors the relative humidity of the air around the mobile device |
Heart Rate | Hardware | Measures 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 defaultSensor
object for a specific sensor typegetSensorList
: Get the list of all sensors or a all sensors of a specific sensor type present in the mobile deviceregisterListener
: Register a callback interface to be notified of new sensor dataunregisterListener
: 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()); } } }
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 aSensorEvent
class. TheSensorEvent
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 offloat
s.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
, orSENSOR_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