One of the things that makes developing for mobile devices different from other platforms is that a mobile phone or tablet is packed full of sensors and other hardware that developers can take advantage of for data input. In this tutorial you will be introduced to the Android sensor framework. You'll learn how to detect what sensors are available on a device and how to read data from those sensors.
Device Sensors
There are three major categories of base sensors to be aware of: motion, environmental, and device position. Motion sensors detect changes in forces around the three axes of the device: X, Y, and Z, as shown here:
Motion sensors include the gyroscope, accelerometer, and rotational vector sensors.
Environmental sensors gather information about the environment that the phone is in. This includes humidity and ambient temperature sensors, light detection, and barometers.
The final category of base sensors, device position, does exactly what you'd expect: it detects the position of the device. This category includes orientation sensors and the magnetometer.
Any sensor that doesn't fall under one of the base categories is considered a composite sensor. These sensors aren't actually sensors in the traditional sense, but instead gather their data from multiple other physical sensors on a device and aggregate it. Examples include the step counter, gravity sensor, and rotational vector sensor.
Reading Sensor Data
Now that you know a little about the types of sensors in mobile devices, it's time to start reading data from actual hardware. Let's start by discovering what sensors are available on a device.
Discovering Sensors on Device
In order to access the sensors on a device, you will need to use the SensorManager
class, which you can retrieve as a system service from an Activity
.
mSensorManager = (SensorManager) getSystemService( Context.SENSOR_SERVICE );
Once you have a SensorManager
, you can retrieve a default Sensor
based on type, or retrieve a List
of Sensor
objects based on a type parameter. For this example we'll retrieve a List
of all Sensor
objects, like so:
List<Sensor> sensorList = mSensorManager.getSensorList( Sensor.TYPE_ALL );
You'll notice that we used TYPE_ALL
here. If we only want a specific subset of sensors, we can pass in any of the supported type attributes, such as the items in the following, noninclusive, list.
TYPE_AMBIENT_TEMPERATURE TYPE_DEVICE_PRIVATE_BASE TYPE_GAME_ROTATION_VECTOR TYPE_GEOMAGNETIC_ROTATION_VECTOR TYPE_GRAVITY TYPE_GYROSCOPE TYPE_GYROSCOPE_UNCALIBRATED TYPE_HEART_BEAT TYPE_HEART_RATE TYPE_LIGHT TYPE_LINEAR_ACCELERATION TYPE_MAGNETIC_FIELD TYPE_MAGNETIC_FIELD_UNCALIBRATED TYPE_MOTION_DETECT
Once you have the Sensor
(s) that you want to work with, you can start retrieving data from them.
Sensor Event Listeners
Each Sensor
object contains information about the physical hardware for that sensor, such as power, input delay, name, type, and vendor. If you want to retrieve information from that sensor, however, you will need to register a SensorEventListener
that will be called at set intervals with new information readings.
mSensorManager.registerListener( this, mSensor, SensorManager.SENSOR_DELAY_UI );
There are four specified reading speeds: fastest, game, normal, and UI. Some will allow you to read information more often, but will consume more power from the device. The less frequently a sensor is polled, the less power it will use.
Once a SensorEventListener
is registered, the listener's onSensorChanged
method will be called with a new SensorEvent
every time the sensor is polled. SensorEvent
wraps the Sensor
object that provides it with data, as well as information about the time, the accuracy of the sensor, and the actual input data.
The input data is stored in an array of float
s called values
. The length of values
can vary depending on the sensor. For example, the accelerometer will have three values (X, Y, and Z input), whereas a barometer will only have one value. When you use sensor data, understanding what data is available and how it's stored in the values
array will be important for understanding how you will build out your app, while also avoiding crashes from issues, such as an ArrayIndexOutOfBoundsException
.
@Override public void onSensorChanged(SensorEvent sensorEvent) { Log.e("Tuts+", "Accuracy: " + sensorEvent.accuracy ); Log.e("Tuts+", "Timestamp: " + sensorEvent.timestamp); Log.e("Tuts+", "Accelerometer X: " + sensorEvent.values[0]); Log.e("Tuts+", "Accelerometer Y: " + sensorEvent.values[1]); Log.e("Tuts+", "Accelerometer Z: " + sensorEvent.values[2]); }
The above code segment, when run with the device accelerometer, will provide output like this:
E/Tuts+: Accuracy: 3 E/Tuts+: Timestamp: 572565573007319 E/Tuts+: Accelerometer X: 0.80444336 E/Tuts+: Accelerometer Y: 1.7597351 E/Tuts+: Accelerometer Z: 9.425964
And since the listener is providing input over time, it can be fed into a graph to display information similar to the following (though the graphing library itself is out of the scope of this tutorial).
Event Triggers
While a SensorEventListener
will continue to provide information over time, a TriggerEventListener
will listen for an event and then immediately disable itself. This sort of listener is used for things such as significant motion. You can add a TriggerEventListener
to the SensorManager
like so.
mSensorManager.requestTriggerSensor(new TriggerEventListener() { @Override public void onTrigger(TriggerEvent triggerEvent) { Log.e("Tuts+", "onTrigger"); for(int i = 0; i < triggerEvent.values.length; i++ ) { Log.e("Tuts+", "item " + i + ": " + triggerEvent.values[i]); } } }, mSensor);
If the Sensor
passed to requestTriggerSensor
is a significant motion sensor, then the above will have an output when the device is moved like so:
E/Tuts+: onTrigger E/Tuts+: item 0: 1.0
One thing to note with both SensorEventListener
and TriggerEventListener
is that they should be unregistered from your SensorManager
when you are done using them, such as in onDestroy
within your Fragment
or Activity
classes, in order to prevent leaks in your application.
Conclusion
In this tutorial you have been introduced to Android's sensor framework. You have learned how to find sensors on a device and gather information from them. Using this, you can create complex apps that are aware of their environment, special input, and actions from users. Learning to use sensor data well will open a lot of interesting features and functionalities that you can use for your applications.
Comments