Android – How To Use Sensors In Android ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, We will learn how to use Android Sensors. We all must have played some Android games that includes the supports of sensors i.e. by tilting the phone some actions might happen in the game. For example, in the Temple Run game, by tilting the phone to left or right, the position of the runner changes. So, all these games are using the sensors present in your Android device. Other examples can be shaking our phone to lock the screen, finding the direction with the help of a compass, etc. All these are examples of Android sensors.

Use sensors on the device to add rich location and motion capabilities to our app, from GPS or network location to accelerometer, gyroscope, temperature, barometer, and more.

To understand the Android Sensors, we will discuss the below topics :

  • Overview
  • Sensor Coordinate System
  • Categories of Sensors
  • Android Sensor Framework
  • Perform Tasks To Use Sensor-Related APIs
  • Handling Different Sensor Configurations
  • Best Practices for Accessing and Using Sensors

A famous quote about learning is :

“The more that you read, the more things you will know. The more that you learn, the more places you’ll go.”

How To Use Android Sensors?

So Let’s begin.


Overview

In Android devices, there are various built-in sensors that can be used to measure the orientation, motions, and various other kinds of environmental conditions. In general, there are two types of sensors in Android devices:

  1. Hardware Sensors: Hardware sensors are physical components that are present in Android devices. They can directly measure various properties like field strength, acceleration, etc according to the types of the sensors and after measuring the environment properties they can send the data to Software Sensors.
  2. Software Sensors: Software sensors also know as virtual sensors are those sensors that take the help of one or more Hardware sensors and based on the data collected by various Hardware sensors, they can derive some result.

It is not necessary that all Android devices must have all the sensors. Some devices may have all sensors and some may lack one or two of them. At the same time, a particular device may have more than one sensors of the same type but with different configurations and capabilities.


Sensor Coordinate System

To express data values or to collect data, the sensors in Android devices uses a 3-axis coordinate system i.e. we will be having X, Y, and Z-axis. The following figure depicts the position of various axis used in sensors.

Coordinate system (relative to a device) that's used by the Sensor API.
Coordinate system (relative to a device) that’s used by the Sensor API.

In default orientation, the horizontal axis is represented by X-axis, the vertical axis is represented by Y-axis and the Z-axis points towards the outside of the screen face i.e towards the user. This coordinate system is used by the following sensors:

  • Acceleration sensor
  • Gravity sensor
  • Gyroscope
  • Linear acceleration sensor
  • Geomagnetic field sensor

The most important point to understand about this coordinate system is that the axes are not swapped when the device’s screen orientation changesโ€”that is, the sensor’s coordinate system never changes as the device moves. This behavior is the same as the behavior of the OpenGL coordinate system.

Another point to understand is that our application must not assume that a device’s natural (default) orientation is portrait. The natural orientation for many tablet devices is landscape. And the sensor coordinate system is always based on the natural orientation of a device.

Finally, if our application matches sensor data to the on-screen display, we need to use the getRotation() method to determine screen rotation, and then use the remapCoordinateSystem() method to map sensor coordinates to screen coordinates. We need to do this even if our manifest specifies portrait-only display.


Categories of Sensors

Following are the three broad categories of sensors in Android:

  1. Motion Sensors: The sensors that are responsible for measuring or identifying the shakes and tilts of your Android devices are called Motion sensors. These sensors measure the rotational forces along the three-axis. Gravity sensors, accelerometers, etc are some of the examples of Motion sensors.
  2. Position Sensors: As the name suggests, the Position sensors are used to determine the position of an Android device. Magnetometers, Proximity sensors are some of the examples of Position sensors.
  3. Environmental Sensors: Environmental properties like temperature, pressure, humidity, etc are identified with the help of Environmental sensors. Some of the examples of Environmental sensors are thermometer, photometer, barometer, etc.


Android Sensor Framework

Everything related to sensors in Android device is managed or controlled by Android Sensor Framework. By using Android Sensor Framework we can collect raw sensor data. It is a part of android.hardware package and includes various classes and interface:

  1. SensorManager: This is used to get access to various sensors present in the device to use it according to need.
  2. Sensor: This class is used to create an instance of a specific sensor.
  3. SensorEvent: This class is used to find the details of the sensor events.
  4. SensorEventListener: This interface can be used to trigger or perform some action when there is a change in the sensor values.

Following are the usages of the Android Sensor Framework:

  1. You can register or unregister sensor events.
  2. You can collect data from various sensors.
  3. You can find the sensors that are active on a device and determine its capabilities.


Perform Tasks To Use Sensor-Related APIs

In this section, we will see how we can identify various sensors present in a device and how to determine its capabilities. In a typical application we use these sensor-related APIs to perform two basic tasks:

  • Identifying sensors and sensor capabilities
  • Monitoring Sensor Events


Identifying sensors and sensor capabilities

Identifying sensors and sensor capabilities at runtime is useful if our application has features that rely on specific sensor types or capabilities. For example, we may want to identify all of the sensors that are present on a device and disable any application features that rely on sensors that are not present. Likewise, we may want to identify all of the sensors of a given type so we can choose the sensor implementation that has the optimum performance for our application.

It is not necessary that two Android devices must have the same number of sensors or the same type of sensors. The availability of sensors varies from device to device and from one Android version to other. So, we can not guarantee that two Android versions or two Android devices must have the same sensors. It becomes a necessary task to identify which sensors are present in a particular Android device.

As seen earlier, we can take the help of the Android Sensor Framework to find the sensors that are present in a particular Android device. Not only that, with the help of various methods of the sensor framework, we can determine the capabilities of a sensor like its resolution, its maximum range, and its power requirements.

Following are the steps that need to be followed to get the list of available sensors in a device:

  1. Create an instance of the SensorManager.
  2. Call the getSystemService() method and pass SENSOR_SERVICE as an argument. This SENSOR_SERVICE is used to retrieve a SensorManager to access sensors.
  3. Call the getSensorList() method to get the names of all the sensors present in the device. The parameter of this method is sensor type. Either we can use TYPE_ALL to get all the sensors available in the device or you can use a particular sensor, for example, TYPE_GRAVITY or TYPE_GYROSCOPE to get the list of sensors of that type only(we can have more than one sensors of the same type).
  4. If we are not using TYPE_ALL i.e. we want to get all the types of sensors of a particular type then we can do so by using the getDefaultSensor() method. This method returns null if there is no sensor of that type in the Android device.
//Step 1
private lateinit var sensorManager: SensorManager

//Step 2
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

//Step 3
//To get a list of all sensors, use TYPE_ALL
val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)
//Or you can use TYPE_GRAVITY, TYPE_GYROSCOPE or some other sensor
//val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY)

//Step 4
if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) {
    //There's a gravity sensor.
} else {
    //No gravity sensor.
}

Apart from finding the list of available sensors, we can also check the capability of a particular sensor i.e. we can check the resolution, power, range, etc of a particular sensor.

Sensor.getResolution() //returns a float value which is the resolution of the sensor

Sensor.getMaximumRange() //returns a float value which is the maximum range of the sensor

Sensor.getPower() //returns a float value which is the power in mA used by sensor


Monitoring Sensor Events

Monitoring sensor events is how we acquire raw sensor data. A sensor event occurs every time a sensor detects a change in the parameters it is measuring. A sensor event provides us with four pieces of information: the name of the sensor that triggered the event, the timestamp for the event, the accuracy of the event, and the raw sensor data that triggered the event.

To monitor raw sensor data we need to implement two callback methods that are exposed through the SensorEventListener interface: onAccuracyChanged() and onSensorChanged(). The Android system calls these methods whenever the following occurs:

  1. onAccuracyChanged(): This is called when there is a change in the accuracy of measurement of the sensor. This method will provide the Sensor object that has changed and the new accuracy. There are four statuses of accuracy i.e. SENSOR_STATUS_ACCURACY_LOW, SENSOR_STATUS_ACCURACY_MEDIUM, SENSOR_STATUS_ACCURACY_HIGH, SENSOR_STATUS_UNRELIABLE.
  2. onSensorChanged(): This is called when there is an availability of new sensor data. This method will provide us with a SensorEvent object that contains new sensor data.
class SensorActivity : Activity(), SensorEventListener {
    private lateinit var sensorManager: SensorManager
    private lateinit var mGravity: Sensor

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

        //gravity sensor
        mGravity = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        //If sensor accuracy changes.
    }

    override fun onSensorChanged(event: SensorEvent) {
        //If there is a new sensor data
    }

    //register
    override fun onResume() {
        super.onResume()
        mGravity?.also { gravity ->
            sensorManager.registerListener(this, gravity, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    //unregister
    override fun onPause() {
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

In this example, the default data delay (SENSOR_DELAY_NORMAL) is specified when the registerListener() method is invoked. The data delay (or sampling rate) controls the interval at which sensor events are sent to our application via the onSensorChanged() callback method. The default data delay is suitable for monitoring typical screen orientation changes and uses a delay of 200,000 microseconds. We can specify other data delays, such as SENSOR_DELAY_GAME (20,000 microsecond delay), SENSOR_DELAY_UI (60,000 microsecond delay), or SENSOR_DELAY_FASTEST (0 microsecond delay). As of Android 3.0 (API Level 11) we can also specify the delay as an absolute value (in microseconds).

The delay that we specify is only a suggested delay. The Android system and other applications can alter this delay. As a best practice, we should specify the largest delay that we can because the system typically uses a smaller delay than the one we specify (that is, we should choose the slowest sampling rate that still meets the needs of our application). Using a larger delay imposes a lower load on the processor and therefore uses less power.

There is no public method for determining the rate at which the sensor framework is sending sensor events to our application; however, we can use the timestamps that are associated with each sensor event to calculate the sampling rate over several events. We should not have to change the sampling rate (delay) once we set it. If for some reason we do need to change the delay, we will have to unregister and reregister the sensor listener.

It’s also important to note that this example uses the onResume() and onPause() callback methods to register and unregister the sensor event listener. As a best practice we should always disable sensors we don’t need, especially when our activity is paused. Failing to do so can drain the battery in just a few hours because some sensors have substantial power requirements and can use up battery power quickly. The system will not disable sensors automatically when the screen turns off.


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 can include a variety of sensors in a wide range of configurations. If our application relies on a specific type of sensor, we have to ensure that the sensor is present on a device so our app can run successfully.

We have two options for ensuring that a given sensor is present on a device:

  • Detect sensors at runtime and enable or disable application features as appropriate.
  • Use Google Play filters to target devices with specific sensor configurations.


Detecting sensors at runtime

If our application uses a specific type of sensor, but doesn’t rely on it, we can use the sensor framework to detect the sensor at runtime and then disable or enable application features as appropriate. For example, a navigation application might use the temperature sensor, pressure sensor, GPS sensor, and geomagnetic field sensor to display the temperature, barometric pressure, location, and compass bearing. If a device doesn’t have a pressure sensor, we can use the sensor framework to detect the absence of the pressure sensor at runtime and then disable the portion of our application’s UI that displays pressure. For example, the following code checks whether there’s a pressure sensor on a device:

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null) {
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}


Using Google Play filters to target specific sensor configurations

If we are publishing our application on Google Play we can use the <uses-feature> element in our manifest file to filter our application from devices that do not have the appropriate sensor configuration for our application. The <uses-feature> element has several hardware descriptors that let we filter applications based on the presence of specific sensors. The sensors we can list include: accelerometer, barometer, compass (geomagnetic field), gyroscope, light, and proximity. The following is an example manifest entry that filters apps that do not have an accelerometer:

<uses-feature android:name="android.hardware.sensor.accelerometer"
              android:required="true" />

If we add this element and descriptor to our application’s manifest, users will see our application on Google Play only if their device has an accelerometer.

We should set the descriptor to android:required="true" only if our application relies entirely on a specific sensor. If our application uses a sensor for some functionality, but still runs without the sensor, we should list the sensor in the <uses-feature> element, but set the descriptor to android:required="false". This helps ensure that devices can install our app even if they do not have that particular sensor. This is also a project management best practice that helps us keep track of the features our application uses. Keep in mind, if our application uses a particular sensor, but still runs without the sensor, then we should detect the sensor at runtime and disable or enable application features as appropriate.


Best Practices for Accessing and Using Sensors

As we design our sensor implementation, be sure to follow the guidelines that are discussed in this section. These guidelines are recommended best practices for anyone who is using the sensor framework to access sensors and acquire sensor data.


1. Only gather sensor data in the foreground

On devices running Android 9 (API level 28) or higher, apps running in the background have the following restrictions:

  • Sensors that use the continuous reporting mode, such as accelerometers and gyroscopes, don’t receive events.
  • Sensors that use the on-change or one-shot reporting modes don’t receive events.

Given these restrictions, it’s best to detect sensor events either when your app is in the foreground or as part of a foreground service.


2. Unregister sensor listeners

Be sure to unregister a sensor’s listener when we are done using the sensor or when the sensor activity pauses. If a sensor listener is registered and its activity is paused, the sensor will continue to acquire data and use battery resources unless we unregister the sensor. The following code shows how to use the onPause() method to unregister a listener:

private lateinit var sensorManager: SensorManager
...
override fun onPause() {
    super.onPause()
    sensorManager.unregisterListener(this)
}


3. Test with the Android Emulator

The Android Emulator includes a set of virtual sensor controls that allow you to test sensors such as accelerometer, ambient temperature, magnetometer, proximity, light, and more.

Emulator Sensor
Emulator Sensor

The emulator uses a connection with an Android device that is running the SdkControllerSensor app. Note that this app is available only on devices running Android 4.0 (API level 14) or higher. (If the device is running Android 4.0, it must have Revision 2 installed.) The SdkControllerSensor app monitors changes in the sensors on the device and transmits them to the emulator. The emulator is then transformed based on the new values that it receives from the sensors on our device.


4. Don’t block the onSensorChanged() method

Sensor data can change at a high rate, which means the system may call the onSensorChanged(SensorEvent) method quite often. As a best practice, we should do as little as possible within the onSensorChanged(SensorEvent) method so we don’t block it. If our application requires us to do any data filtering or reduction of sensor data, we should perform that work outside of the onSensorChanged(SensorEvent) method.


5. Avoid using deprecated methods or sensor types

Several methods and constants have been deprecated. In particular, the TYPE_ORIENTATION sensor type has been deprecated. To get orientation data we should use the getOrientation() method instead. Likewise, the TYPE_TEMPERATURE sensor type has been deprecated. We should use the TYPE_AMBIENT_TEMPERATURE sensor type instead on devices that are running Android 4.0.


6. Verify sensors before we use them

Always verify that a sensor exists on a device before we attempt to acquire data from it. Don’t assume that a sensor exists simply because it’s a frequently-used sensor. Device manufacturers are not required to provide any particular sensors in their devices.


7. Choose sensor delays carefully

When we register a sensor with the registerListener() method, be sure we choose a delivery rate that is suitable for our application or use-case. Sensors can provide data at very high rates. Allowing the system to send extra data that we don’t need wastes system resources and uses battery power.

Thatโ€™s all about in this article.


Conclusion

In this article, we learned about how to use Android Sensors. We learned about the Hardware and the Software sensors. We saw how the Android Sensor Framework can be used to determine the sensors present in the Android device. At last, we saw how to use Sensor Event Listener.

Thanks for reading ! I hope you enjoyed and learned about Sensors Concept in Android. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!๐Ÿ˜Š๐Ÿ˜Š๐Ÿ˜Š

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s