3.1: Sensor basics
Contents:
- Introduction
- About sensors
- Discovering sensors and sensor capabilities
- Handling different sensor configurations
- Monitoring sensor events
- Related practical
- Learn more
Most Android-powered devices have built-in sensors that measure motion, orientation, and various environmental conditions. These sensors are capable of providing raw data with high precision and accuracy, and are useful if you want to monitor three-dimensional device movement or positioning, or you want to monitor changes in the ambient environment near a device.
For example, a game might track readings from a device's gravity sensor to infer complex user gestures and motions, such as tilt, shake, rotation, or swing. Likewise, a compass app might use the geomagnetic field sensor and accelerometer to report a compass bearing.
About sensors
The Android platform supports three major categories of sensors:
- Motion sensors, to measure device motion. These sensors include accelerometers, gravity sensors, gyroscopes, and rotational vector sensors.
- Environmental sensors, to measure various environmental conditions, such as ambient air temperature and pressure, illumination, and humidity. These sensors include barometers, photometers (light sensors), and thermometers.
- Position sensors, to measure the physical position of a device. This category includes magnetometers (geomagnetic field sensors) and proximity sensors.
The device camera, fingerprint sensor, microphone, and GPS (location) sensor all have their own APIs and are not considered "sensors" for the purposes of the Android sensor framework. You learn more about location in a different chapter.
Hardware and software sensors
Sensors can be hardware- or software-based. Hardware-based sensors are physical components built into a handset or tablet device. Hardware sensors derive their data by directly measuring specific environmental properties, such as acceleration, geomagnetic field strength, or angular change.
Software-based sensors are not physical devices, although they mimic hardware-based sensors. Software-based sensors derive their data from one or more of the hardware-based sensors and are sometimes called virtual sensors or composite sensors . The proximity sensor and step counter sensors are examples of software-based sensors.
The Android sensor framework
You can access available sensors and acquire raw sensor data in your app with the Android sensor framework. The sensor framework, part of the android.hardware
package, provides classes and interfaces to help you perform a wide variety of sensor-related tasks. With the Android sensor framework you can:
- Determine which sensors are available on a device.
- Determine an individual sensor's capabilities, such as its maximum range, manufacturer, power requirements, and resolution.
- Acquire raw sensor data and define the minimum rate at which you acquire sensor data.
- Register and unregister sensor event listeners that monitor sensor changes.
The following classes are the key parts of the Android sensor framework:
SensorManager
: Represents the Android sensor service. This class provides methods for accessing and listing sensors, registering and unregistering sensor event listeners, and acquiring orientation information. This class also provides several sensor constants. The constants are used to represent sensor accuracy, data acquisition rates, and sensor calibration.Sensor
: Represents a specific sensor. This class provides methods that let you determine sensor's capabilities.SensorEvent
: Represents information about a sensor event. A sensor event includes the raw sensor data, the type of sensor that generated the event, the accuracy of the data, and the timestamp for the event.SensorEventListener
: An interface that includes callback methods to receive notifications (sensor events) when a sensor has new data or when sensor accuracy changes.
Sensor types and availability
Few Android-powered devices have every type of sensor. For example, most handset devices and tablets have an accelerometer and a magnetometer, but many fewer devices have barometers or thermometers. Also, a device can have more than one sensor of a given type. For example, a device can have two gravity sensors, each one having a different range. The Sensor
class defines the sensor types listed in the table below.
Sensor availability can also vary between Android versions, because the Android sensors have been introduced over the course of several platform releases.
The following table summarizes the sensors that the Android platform supports.
Sensor | Used for |
TYPE_ACCELEROMETER | Motion detection (shake, tilt, and so on). |
TYPE_AMBIENT_TEMPERATURE | Monitoring air temperature. |
TYPE_GRAVITY | Motion detection (shake, tilt, and so on). |
TYPE_GYROSCOPE | Rotation detection (spin, turn, and so on). |
TYPE_LIGHT | Controlling screen brightness. |
TYPE_LINEAR_ACCELERATION | Monitoring acceleration along a single axis. |
TYPE_MAGNETIC_FIELD | Creating a compass. |
TYPE_ORIENTATION | Determining device position. |
TYPE_PRESSURE | Monitoring air pressure changes. |
TYPE_PROXIMITY | Phone position during a call. |
TYPE_RELATIVE_HUMIDITY | Monitoring ambient humidity (relative and absolute), and dew point. |
TYPE_ROTATION_VECTOR | Motion and rotation detection. |
TYPE_TEMPERATURE | Monitoring temperatures. |
Sensors and the Android emulator
The Android emulator includes a set of virtual sensor controls that let you to test sensors such as the accelerometer, the ambient temperature sensor, the magnetometer, the proximity sensor, the light sensor, and more.
The Accelerometer tab lets you test your app against changes in device position, orientation, or both. For example, you can simulate device motion such as tilt and rotation. The control simulates the way accelerometers and magnetometers respond when you move or rotate a real device. As you adjust the device in the emulators, the Resulting Values fields change accordingly. These fields show the values that an app can access.
The Additional sensors tab can simulate various position and environment sensors. In this tab you adjust the following sensors to test them with your app:
- Ambient temperature: This environmental sensor measures ambient air temperature.
- Magnetic field: This position sensor measures the ambient magnetic field at the x -axis, y -axis, and z -axis. The values are in microtesla (μT).
- Proximity: This position sensor measures the distance of the device from an object. For example, this sensor can notify a phone that a face is close to the phone to make a call.
- Light: This environmental sensor measures illuminance.
- Pressure: This environmental sensor measures ambient air pressure.
- Relative humidity: This environmental sensor measures ambient relative humidity.
Discovering sensors and sensor capabilities
The Android sensor framework lets you determine at runtime which sensors are available on a device. The framework also provides methods that let you determine the capabilities of a sensor, such as its maximum range, its resolution, and its power requirements.
Identifying sensors
To identify the device sensors you must first access the sensor manager, an Android system service. Create an instance of the SensorManager
class by calling the getSystemService()
method and passing in the SENSOR_SERVICE
argument.
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
To get a listing of all the device sensors, use the getSensorList()
method and the sensor type TYPE_ALL
.
List<Sensor> deviceSensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
To list all of the sensors of a specific type, use another sensor type constant, for example TYPE_PROXIMITY
, TYPE_GYROSCOPE
, or TYPE_GRAVITY
.
To determine whether a specific type of sensor exists on a device, and to get a Sensor
object that represents that sensor, use the getDefaultSensor()
method and pass in the type constant for a specific sensor. If a device has more than one sensor of a given type, the system designates one of the sensors as the default sensor. If a default sensor does not exist for a given type of sensor, the method call returns null
, which means the device does not have that type of sensor.
For example, the following code checks whether there's a magnetometer on a device:
private SensorManager mSensorManager;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
// Success! There's a magnetometer.
}
else {
// Failure! No magnetometer.
}
Identifying sensor features
Use the public methods of the Sensor
class to determine the capabilities and attributes of individual sensors. These methods useful if you want your app to behave differently based on which sensors or sensor capabilities are available on a device. For example, you can use the getResolution()
and getMaximumRange()
methods to obtain a sensor's reported resolution and maximum range of measurement. You can also use the getPower()
method to obtain a sensor's power requirements.
The getVendor()
and getVersion()
methods are particularly useful. Use these methods to optimize your app for different manufacturer's sensors or different versions of a sensor. For example, maybe your app needs to monitor device motion such as tilt and shake. In this case you could create two sets of data-filtering rules and optimizations: one set of rules and optimizations for newer devices that have a specific vendor's gravity sensor, and a second set of rules and optimizations for devices that do not have a gravity sensor and have only an accelerometer.
A streaming sensor is one that senses and reports new data as fast as possible. The getMinDelay()
method returns the minimum time interval (in microseconds) that a sensor can use to sense data. Any sensor that returns a non-zero value for the getMinDelay()
method is a streaming sensor. Streaming sensors sense data at regular intervals and were introduced in Android 2.3 (API Level 9). If a sensor returns zero when you call getMinDelay()
, it means that the sensor is not a streaming sensor. Non-streaming sensors only report data when that data has changed.
The getMinDelay()
method lets you determine the maximum rate at which a sensor can acquire data. If your app requires high data-acquisition rates or a streaming sensor, use getMinDelay()
to determine whether a sensor meets your app's requirements. Then turn on or turn off the relevant features in your app accordingly.
Handling different sensor configurations
Android does not specify a standard sensor configuration for devices, which means device manufacturers can incorporate any sensor configuration that they want into their Android-powered devices. As a result, devices include a variety of sensors in a wide range of configurations. If your app relies on a specific type of sensor, you have to ensure that the sensor is present on a device so your app can run successfully.
You have two options for ensuring that a given sensor is present on a device:
- Detect sensors at runtime, then turn on or turn off app features as appropriate.
- Use Google Play filters to target devices with specific sensor configurations.
Detecting sensors at runtime
If your app uses a specific type of sensor but doesn't rely on it, you can use the sensor framework to detect the sensor at runtime, then turn off or turn on app features as appropriate. For example, a weather app might use the temperature sensor, pressure sensor, GPS sensor, and geomagnetic field sensor to display the temperature, barometric pressure, location, and compass bearing. You can use the sensor framework to detect the absence of the pressure sensor at runtime and then turn off the portion of your app's UI that displays pressure.
Using Google Play filters to target specific sensor configurations
If you publish your app on Google Play, use the <uses-feature>
element in your app manifest file to filter your app from devices that do not have the appropriate sensor configuration for your app. The <uses-feature>
element has several hardware descriptors that let you filter apps based on the presence of specific sensors. The sensors you can list include: accelerometer, barometer, compass (geomagnetic field), gyroscope, light, and proximity.
The following is an example manifest entry that filters out apps that do not have an accelerometer:
<uses-feature android:name="android.hardware.sensor.accelerometer"
android:required="true"
/>
If you add this element and descriptor to your app's manifest, users see your app on Google Play only if their device has an accelerometer.
About the android:required
attribute:
- Set the descriptor to
android:required="true"
only if your app relies entirely on a specific sensor. - If your app uses a sensor for some functionality but can run without the sensor, list the sensor in the
<uses-feature>
element and set the descriptor toandroid:required="false"
. Doing this helps ensure that devices can install your app even if they do not have that particular sensor.
Monitoring sensor events
The Android system generates sensor events each time the sensor has new data. To monitor sensor events in your app, you must:
- Implement the
SensorEventListener
interface, which includes theonSensorChanged()
andonAccuracyChanged()
callback methods. - Register sensor event listeners for the specific sensor you want to monitor.
- Get sensor types and values from the
SensorEvent
object, and update your app accordingly.
Implement the SensorEventListener interface
To monitor raw sensor data, implement the SensorEventListener
interface's two callback methods: onAccuracyChanged()
and onSensorChanged()
.
public class SensorActivity extends Activity implements SensorEventListener { ... }
When a sensor's accuracy changes, the Android system calls onAccuracyChanged()
method and passes in two arguments:
- A
Sensor
object to identify the sensor that changed. - A new accuracy, one of five status constants:
SENSOR_STATUS_ACCURACY_LOW
,SENSOR_STATUS_ACCURACY_MEDIUM
,SENSOR_STATUS_ACCURACY_HIGH
,SENSOR_STATUS_UNRELIABLE
, orSENSOR_STATUS_NO_CONTACT
.
An example of a change in sensor accuracy might be a heart-rate monitor. If the sensor stopped reporting a heartbeat, the accuracy would be SENSOR_STATUS_NO_CONTACT
. If the sensor was reporting an unrealistically low or high heartbeat, the accuracy might be SENSOR_STATUS_UNRELIABLE
. You could override onAccuracyChanged()
to catch these changes in accuracy and report errors to the user.
@Override
public final void onAccuracyChanged(Sensor sensor, int accuracy) {
// Do something here if the sensor accuracy changes.
}
The Android system calls the onSensorChanged()
method when the sensor reports new data, passing in a SensorEvent
object. The SensorEvent
object contains information about the new sensor data, including the accuracy of the data, the sensor that generated the data, the timestamp at which the data was generated, as well as the actual new data itself.
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
// Do something here if sensor data changes
}
You learn more about the onSensorChanged()
method and sensor event objects below.
Register listeners
To receive sensor events, you must register a listener for that event in your app. Sensors generate a lot of data at a very high rate, and they use power and battery when they do. Registering a particular sensor enables your app to handle only specific events at a specific rate. To preserve device resources, unregister the listener when you don't need it, for example when your app pauses.
To register a listener, use the SensorManager
.registerListener()
method. This method takes three arguments:
- An app or activity
Context
. You can use the current activity (this
) as the context. - The
Sensor
object to listen to. Use theSensorManager.
getDefaultSensor()
method in youronCreate()
to get aSensor
object. A delay constant from the
SensorManager
class. The data delay (or sampling rate) controls the interval at which sensor events are sent to your app via theonSensorChanged()
callback method. Make sure that your listener is registered with the minimum amount of new data that it needs.The default data delay (
SENSOR_DELAY_NORMAL
) is suitable for monitoring typical screen orientation changes and uses a delay of 200,000 microseconds (0.2 seconds). You can specify other data delays, such asSENSOR_DELAY_GAME
(20,000 microseconds or 20 milliseconds),SENSOR_DELAY_UI
(60,000 microseconds or 60 milliseconds), orSENSOR_DELAY_FASTEST
(no delay, as fast as possible).
Register your sensor listeners in the onStart()
lifecycle method, and unregister them in onStop()
. Don't register your listeners in onCreate()
, as that would cause the sensors to be on and sending data (using device power) even when your app was not in the foreground. To make sure sensors only use power when your app is running in the foreground, register and unregister your sensor listeners in the onStart()
and onStop()
methods.
The onStart()
and onStop()
methods are a better choice for registering listeners than onResume()
and onPause()
. As of Android 7.0 (API 24), apps can run in multi-window mode (split-screen or picture-in-picture mode). Apps running in this mode are paused (onPause()
has been called) but still visible on screen. Use onStart()
and onStart()
to ensure that sensors continue running even if the app is in multi-window mode.
@Override
protected void onStart() {
super.onStart();
if (mIsLightSensorPresent) {
mSensorManager.registerListener(this, mSensorLight,
SensorManager.SENSOR_DELAY_UI);
}
}
@Override
protected void onStop() {
super.onStop();
mSensorManager.unregisterListener(this);
}
Handle sensor data changes
To handle changes to sensor data, override the onSensorChanged()
callback from the SensorEventListener
class. The onSensorChanged()
method is passed a SensorEvent
object that contains information about the event. Your implementation typically will need two pieces of data from the SensorEvent
object:
sensor
: The sensor that generated the event, as aSensor
object.values
: The data the sensor generated, as an array of floats. Different sensors provide different amounts and types of data in that array. For example, the light sensor produces only one piece of data, which is stored invalues[0]
. The values for other sensors may have additional data—for example, the values array from the accelerometer includes data for the x -axis, y -axis, and z -axis invalues[0]
,values[1]
, andvalues[2]
, respectively.
onSensorChanged()
method quite often. As a best practice, do as little as possible within the onSensorChanged()
method so you don't block it. If your app requires you to do any data filtering or reduction of sensor data, perform that work outside of the onSensorChanged()
method.
This example shows an onSensorChanged()
method that handles changes to the light sensor.
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
// The sensor type (as defined in the Sensor class).
int sensorType = sensorEvent.sensor.getType();
// The current value of the sensor.
float currentValue = sensorEvent.values[0];
// Event came from the light sensor.
if (sensorType == Sensor.TYPE_LIGHT)
{
// Get the light sensor string from the resources, fill
// in the data placeholder
String str_current = getResources().getString(
R.string.label_light, currentValue);
mTextSensorLight.setText(str_current);
}
}
Related practical
The related practical documentation is in Working with Sensor Data.
Learn more
Android developer documentation:
Android API Reference: