Información general de sensores

La mayoría de los dispositivos con Android tienen sensores integrados que miden el movimiento, la orientación y diversas condiciones ambientales. Estos sensores pueden proporcionar datos sin procesar con alta precisión y exactitud, y son útiles si deseas supervisar el movimiento o posicionamiento tridimensional del dispositivo, o si deseas supervisar los cambios en el entorno cercano a un dispositivo. Por ejemplo, un juego puede hacer un seguimiento de las lecturas del sensor de gravedad de un dispositivo para inferir gestos y movimientos complejos del usuario, como inclinación, sacudida, rotación o balanceo. Del mismo modo, una aplicación meteorológica podría usar el sensor de temperatura y el sensor de humedad de un dispositivo para calcular e informar el punto de rocío, o una aplicación de viajes podría usar el sensor de campo geomagnético y el acelerómetro para informar una orientación de brújula.

La plataforma de Android admite tres amplias categorías de sensores:

  • Sensores de movimiento

    Estos sensores miden las fuerzas de aceleración y las fuerzas de rotación en tres ejes. Esta categoría incluye acelerómetros, sensores de gravedad, giroscopios y sensores de vectores de rotación.

  • Sensores ambientales

    Estos sensores miden varios parámetros ambientales, como la temperatura y la presión del aire, la iluminación y la humedad. Esta categoría incluye barómetros, fotómetros y termómetros.

  • Sensores de posición

    Estos sensores miden la posición física de un dispositivo. Esta categoría incluye sensores de orientación y magnetómetros.

Puedes acceder a los sensores disponibles en el dispositivo y adquirir datos de sensores sin procesar con el framework de sensores de Android. El framework de sensores proporciona varias clases e interfaces que te ayudan a realizar una amplia variedad de tareas relacionadas con los sensores. Por ejemplo, puedes usar el marco de trabajo del sensor para las siguientes tareas:

  • Determina qué sensores están disponibles en un dispositivo.
  • Determinar las capacidades de un sensor individual, como su rango máximo, fabricante, requisitos de energía y resolución
  • Adquiere datos sin procesar del sensor y define la velocidad mínima con la que adquirirás los datos del sensor.
  • Registra y cancela el registro de oyentes de objetos de escucha de eventos que supervisan los cambios del sensor.

En este tema, se proporciona una descripción general de los sensores que están disponibles en la plataforma de Android. También se proporciona una introducción al marco de trabajo del sensor.

Introducción a los sensores

El marco de trabajo del sensor de Android permite acceder a muchos tipos de sensores. Algunos de estos sensores se basan en hardware y otros en software. Los sensores basados en hardware son componentes físicos integrados en un dispositivo de teléfono o tablet. Derivan sus datos midiendo directamente propiedades ambientales específicas, como la aceleración, la intensidad del campo geomagnético o el cambio angular. Los sensores basados en software no son dispositivos físicos, aunque imitan a los sensores basados en hardware. Los sensores basados en software obtienen sus datos de uno o más sensores basados en hardware y, a veces, se denominan sensores virtuales o sintéticos. El sensor de aceleración lineal y el sensor de gravedad son ejemplos de sensores basados en software. En la tabla 1, se resumen los sensores que admite la plataforma de Android.

Solo unos pocos dispositivos con Android tienen todos los tipos de sensores. Por ejemplo, la mayoría de los teléfonos celulares y las tablets tienen un acelerómetro y un magnetómetro, pero menos dispositivos tienen barómetros o termómetros. Además, un dispositivo puede tener más de un sensor de un tipo determinado. Por ejemplo, un dispositivo puede tener dos sensores de gravedad, cada uno con un rango diferente.

Tabla 1: Tipos de sensores compatibles con la plataforma de Android

Sensor Tipo Descripción Usos comunes
TYPE_ACCELEROMETER Hardware Mide la fuerza de aceleración en m/s2 que se aplica a un dispositivo en los tres ejes físicos (x, y, z), incluida la fuerza de gravedad. Detección de movimiento (agitación, inclinación, etc.).
TYPE_AMBIENT_TEMPERATURE Hardware Mide la temperatura ambiente de la habitación en grados Celsius (°C). Consulta la siguiente nota. Supervisión de la temperatura del aire.
TYPE_GRAVITY Software o hardware Mide la fuerza de gravedad en m/s2 que se aplica a un dispositivo en los tres ejes físicos (x, y, z). Detección de movimiento (agitación, inclinación, etc.).
TYPE_GYROSCOPE Hardware Mide la velocidad de rotación de un dispositivo en rad/s alrededor de cada uno de los tres ejes físicos (x, y, z). Detección de rotación (agitación, giro, etc.).
TYPE_LIGHT Hardware Mide el nivel de luz ambiental (iluminación) en lx. Control del brillo de la pantalla.
TYPE_LINEAR_ACCELERATION Software o hardware Mide la fuerza de aceleración en m/s2 que se aplica a un dispositivo en los tres ejes físicos (x, y y z), sin incluir la fuerza de gravedad. Supervisión de la aceleración a lo largo de un solo eje.
TYPE_MAGNETIC_FIELD Hardware Mide el campo geomagnético ambiental para los tres ejes físicos (x, y, z) en μT. Creación de una brújula.
TYPE_ORIENTATION Software Mide los grados de rotación de un dispositivo alrededor de los tres ejes físicos (x, y, z). A partir del nivel de API 3, puedes obtener la matriz de inclinación y la matriz de rotación de un dispositivo usando el sensor de gravedad y el sensor de campo geomagnético junto con el método getRotationMatrix(). Determinación de la posición del dispositivo.
TYPE_PRESSURE Hardware Mide la presión del aire del ambiente en hPa o mbar. Supervisa los cambios de la presión del aire.
TYPE_PROXIMITY Hardware Mide la proximidad de un objeto en cm en relación con la pantalla de un dispositivo. Por lo general, este sensor se usa para determinar si un teléfono se sostiene cerca de la oreja de una persona. Posición del teléfono durante una llamada.
TYPE_RELATIVE_HUMIDITY Hardware Mide en valor de porcentaje (%) la humedad relativa del ambiente. Supervisa el punto de condensación, la humedad absoluta y la humedad relativa.
TYPE_ROTATION_VECTOR Software o hardware Mide la orientación de un dispositivo proporcionando los tres elementos del vector de rotación del dispositivo. Detección de movimiento y detección de rotación.
TYPE_TEMPERATURE Hardware Mide la temperatura del dispositivo en grados Celsius (°C). La implementación de este sensor varía según el dispositivo, y se reemplazó por el sensor TYPE_AMBIENT_TEMPERATURE en el nivel de API 14. Supervisión de temperaturas.

Marco de trabajo del sensor

Puedes acceder a estos sensores y adquirir datos del sensor sin procesar con el marco de trabajo del sensor de Android. El framework de sensores forma parte del paquete android.hardware y, además, incluye las siguientes clases e interfaces:

SensorManager
Puedes usar esta clase para crear una instancia del servicio del sensor. Esta clase proporciona varios métodos para acceder a los sensores y enumerarlos, registrar y cancelar el registro de los objetos de escucha de eventos de sensores, y adquirir información de orientación. Esta clase también proporciona varias constantes de sensores que se usan para informar la precisión de los sensores, establecer las tasas de adquisición de datos y calibrar los sensores.
Sensor
Puedes usar esta clase para crear una instancia de un sensor específico. Esta clase proporciona varios métodos que te permiten determinar las capacidades de un sensor.
SensorEvent
El sistema usa esta clase para crear un objeto de evento de sensor, que proporciona información sobre un evento de sensor. Un objeto de evento de sensor incluye la siguiente información: los datos sin procesar del sensor, el tipo de sensor que generó el evento, la exactitud de los datos y la marca de tiempo del evento.
SensorEventListener
Puedes usar esta interfaz para crear dos métodos de devolución de llamada que reciban notificaciones (eventos de sensor) cuando cambien los valores o la precisión del sensor.

En una aplicación típica, estas API relacionadas con sensores se usan para realizar dos tareas básicas:

  • Cómo identificar los sensores y sus capacidades

    Identificar los sensores y sus capacidades durante el tiempo de ejecución es útil si tu aplicación tiene funciones que dependen de tipos o capacidades de sensores específicos. Por ejemplo, es posible que quieras identificar todos los sensores que están presentes en un dispositivo y, luego, inhabilitar las funciones de la aplicación que dependen de los sensores que no están presentes. Del mismo modo, es posible que desees identificar todos los sensores de un tipo determinado para poder elegir la implementación de sensores que tenga el rendimiento óptimo para tu aplicación.

  • Supervisa los eventos de los sensores

    La supervisión de los eventos del sensor es la manera en la que adquieres los datos sin procesar del sensor. Se produce un evento de sensor cada vez que un sensor detecta un cambio en los parámetros que mide. Un evento de sensor te proporciona cuatro datos: el nombre del sensor que activó el evento, la marca de tiempo del evento, la precisión del evento y los datos sin procesar del sensor que activó el evento.

Disponibilidad del sensor

Si bien la disponibilidad de los sensores varía de un dispositivo a otro, también puede variar entre las versiones de Android. Esto se debe a que los sensores de Android se introdujeron en el transcurso de varias versiones de la plataforma. Por ejemplo, muchos sensores se introdujeron en Android 1.5 (nivel de API 3), pero algunos no se implementaron y no estuvieron disponibles para su uso hasta Android 2.3 (nivel de API 9). Del mismo modo, se introdujeron varios sensores en Android 2.3 (nivel de API 9) y Android 4.0 (nivel de API 14). Se dieron de baja dos sensores y se reemplazaron por sensores más nuevos y mejores.

En la tabla 2, se resume la disponibilidad de los sensores en cada una de las plataformas. Solo se enumeran cuatro plataformas porque son las que involucraron cambios en los sensores. Los sensores que se indican como obsoletos siguen estando disponibles en las plataformas posteriores (siempre que el sensor esté presente en un dispositivo), lo que se ajusta a la política de compatibilidad con versiones posteriores de Android.

Tabla 2: Disponibilidad de sensores por plataforma

Sensor Android 4.0
(API nivel 14)
Android 2.3
(API nivel 9)
Android 2.2
(API nivel 8)
Android 1.5
(API nivel 3)
TYPE_ACCELEROMETER Sí Sí Sí Sí
TYPE_AMBIENT_TEMPERATURE Sí n/a No disponible N/A
TYPE_GRAVITY Sí Sí n/a N/A
TYPE_GYROSCOPE Sí Sí n/a1 N/A1
TYPE_LIGHT Sí Sí Sí Sí
TYPE_LINEAR_ACCELERATION Sí Sí n/a N/A
TYPE_MAGNETIC_FIELD Sí Sí Sí Sí
TYPE_ORIENTATION Sí2 Sí2 Sí2 Sí
TYPE_PRESSURE Sí Sí n/a1 N/A1
TYPE_PROXIMITY Sí Sí Sí Sí
TYPE_RELATIVE_HUMIDITY Sí n/a No disponible N/A
TYPE_ROTATION_VECTOR Sí Sí n/a N/A
TYPE_TEMPERATURE Sí2 Sí Sí Sí

1 Este tipo de sensor se agregó en Android 1.5 (nivel de API 3), pero no estuvo disponible para su uso hasta Android 2.3 (nivel de API 9).

2 Este sensor está disponible, pero se marcó como obsoleto.

Identificación de sensores y capacidades de sensores

El framework de sensores de Android proporciona varios métodos que te permiten determinar con facilidad en el entorno de ejecución qué sensores están en un dispositivo. La API también proporciona métodos que te permiten determinar las capacidades de cada sensor, como su rango máximo, su resolución y sus requisitos de energía.

Para identificar los sensores que se encuentran en un dispositivo, primero debes obtener una referencia al servicio de sensores. Para ello, crea una instancia de la clase SensorManager llamando al método getSystemService() y pasando el argumento SENSOR_SERVICE. Por ejemplo:

Kotlin

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

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

A continuación, puedes obtener una lista de todos los sensores de un dispositivo llamando al método getSensorList() y usando la constante TYPE_ALL. Por ejemplo:

Kotlin

val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)

Java

List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);

Si quieres enumerar todos los sensores de un tipo determinado, puedes usar otra constante en lugar de TYPE_ALL, como TYPE_GYROSCOPE, TYPE_LINEAR_ACCELERATION o TYPE_GRAVITY.

También puedes determinar si existe un tipo específico de sensor en un dispositivo con el método getDefaultSensor() y pasando la constante de tipo para un sensor específico. Si un dispositivo tiene más de un sensor de un tipo determinado, uno de ellos debe designarse como el sensor predeterminado. Si no existe un sensor predeterminado para un tipo de sensor determinado, la llamada de método devuelve un valor nulo, lo que significa que el dispositivo no tiene ese tipo de sensor. Por ejemplo, en el siguiente código, se comprueba si hay un magnetómetro en un dispositivo:

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) {
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

Nota: Android no requiere que los fabricantes de dispositivos incorporen ningún tipo de sensor en particular en sus dispositivos con Android, por lo que estos pueden tener una amplia variedad de configuraciones de sensores.

Además de enumerar los sensores que se encuentran en un dispositivo, puedes usar los métodos públicos de la clase Sensor para determinar las capacidades y los atributos de los sensores individuales. Esto es útil si quieres que tu aplicación se comporte de manera diferente según los sensores o las capacidades de los sensores que estén disponibles en un dispositivo. Por ejemplo, puedes usar los métodos getResolution() y getMaximumRange() para obtener la resolución y el rango máximo de medición de un sensor. También puedes usar el método getPower() para obtener los requisitos de energía de un sensor.

Dos de los métodos públicos son particularmente útiles si deseas optimizar tu aplicación para sensores de diferentes fabricantes o diferentes versiones de un sensor. Por ejemplo, si tu aplicación necesita supervisar los gestos del usuario, como la inclinación y la agitación, puedes crear un conjunto de reglas de filtrado de datos y optimizaciones para los dispositivos más nuevos que tengan un sensor de gravedad de un proveedor específico, y otro conjunto de reglas de filtrado de datos y optimizaciones para los dispositivos que no tengan un sensor de gravedad y solo tengan un acelerómetro. En la siguiente muestra de código, se indica cómo puedes usar los métodos getVendor() y getVersion() para lograrlo. En este ejemplo, buscamos un sensor de gravedad que indique a Google LLC como proveedor y tenga el número de versión 3. Si ese sensor en particular no está presente en el dispositivo, intentamos usar el acelerómetro.

Kotlin

private lateinit var sensorManager: SensorManager
private var mSensor: Sensor? = null

...

sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) {
    val gravSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY)
    // Use the version 3 gravity sensor.
    mSensor = gravSensors.firstOrNull { it.vendor.contains("Google LLC") && it.version == 3 }
}
if (mSensor == null) {
    // Use the accelerometer.
    mSensor = if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    } else {
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
        null
    }
}

Java

private SensorManager sensorManager;
private Sensor mSensor;

...

sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = null;

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
    List<Sensor> gravSensors = sensorManager.getSensorList(Sensor.TYPE_GRAVITY);
    for(int i=0; i<gravSensors.size(); i++) {
        if ((gravSensors.get(i).getVendor().contains("Google LLC")) &&
           (gravSensors.get(i).getVersion() == 3)){
            // Use the version 3 gravity sensor.
            mSensor = gravSensors.get(i);
        }
    }
}
if (mSensor == null){
    // Use the accelerometer.
    if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
        mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    } else{
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
    }
}

Otro método útil es getMinDelay(), que devuelve el intervalo de tiempo mínimo (en microsegundos) que un sensor puede usar para detectar datos. Cualquier sensor que devuelva un valor distinto de cero para el método getMinDelay() es un sensor de transmisión. Los sensores de transmisión detectan datos a intervalos regulares y se introdujeron en Android 2.3 (nivel de API 9). Si un sensor devuelve cero cuando llamas al método getMinDelay(), significa que no es un sensor de transmisión, ya que solo informa datos cuando hay un cambio en los parámetros que detecta.

El método getMinDelay() es útil porque te permite determinar la velocidad máxima a la que un sensor puede adquirir datos. Si ciertas funciones de tu aplicación requieren altas tasas de adquisición de datos o un sensor de transmisión, puedes usar este método para determinar si un sensor cumple con esos requisitos y, luego, habilitar o inhabilitar las funciones relevantes en tu aplicación según corresponda.

Precaución: La tasa máxima de adquisición de datos de un sensor no es necesariamente la tasa a la que el framework de sensores entrega datos de sensores a tu aplicación. El framework de sensores informa datos a través de eventos de sensores, y varios factores influyen en la velocidad a la que tu aplicación recibe eventos de sensores. Para obtener más información, consulta Cómo supervisar los eventos del sensor.

Cómo supervisar los eventos del sensor

Para supervisar los datos de sensores sin procesar, debes implementar dos métodos de devolución de llamada que se exponen a través de la interfaz SensorEventListener: onAccuracyChanged() y onSensorChanged(). El sistema Android llama a estos métodos cada vez que ocurre lo siguiente:

En el siguiente código, se muestra cómo usar el método onSensorChanged() para supervisar los datos del sensor de luz. En este ejemplo, se muestran los datos de sensores sin procesar en un TextView que se define en el archivo main.xml como sensor_data.

Kotlin

class SensorActivity : Activity(), SensorEventListener {
    private lateinit var sensorManager: SensorManager
    private var mLight: Sensor? = null

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

        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
    }

    override fun onSensorChanged(event: SensorEvent) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        val lux = event.values[0]
        // Do something with this sensor value.
    }

    override fun onResume() {
        super.onResume()
        mLight?.also { light ->
            sensorManager.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

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

Java

public class SensorActivity extends Activity implements SensorEventListener {
    private SensorManager sensorManager;
    private Sensor mLight;

    @Override
    public final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
    }

    @Override
    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
    }

    @Override
    public final void onSensorChanged(SensorEvent event) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        float lux = event.values[0];
        // Do something with this sensor value.
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

En este ejemplo, el retraso de los datos predeterminado (SENSOR_DELAY_NORMAL) se especifica cuando se invoca el método registerListener(). La demora de los datos (o tasa de muestreo) controla el intervalo en el que se envían los eventos de sensor a tu aplicación a través del método de devolución de llamada onSensorChanged(). La demora de datos predeterminada es adecuada para supervisar los cambios típicos de orientación de la pantalla y usa una demora de 200,000 microsegundos. Puedes especificar otros retrasos de datos, como SENSOR_DELAY_GAME (retraso de 20,000 microsegundos), SENSOR_DELAY_UI (retraso de 60,000 microsegundos) o SENSOR_DELAY_FASTEST (retraso de 0 microsegundos). A partir de Android 3.0 (nivel de API 11), también puedes especificar la demora como un valor absoluto (en microsegundos).

El retraso que especificas es solo un retraso sugerido. El sistema Android y otras aplicaciones pueden alterar esta demora. Como práctica recomendada, debes especificar el retraso más grande que puedas, ya que el sistema suele usar un retraso menor que el que especificas (es decir, debes elegir la tasa de muestreo más lenta que aún satisfaga las necesidades de tu aplicación). Si usas un retraso mayor, se impone una carga menor en el procesador y, por lo tanto, se consume menos energía.

No hay un método público para determinar la velocidad a la que el framework del sensor envía eventos de sensor a tu aplicación. Sin embargo, puedes usar las marcas de tiempo asociadas con cada evento de sensor para calcular la tasa de muestreo en varios eventos. No deberías tener que cambiar la tasa de muestreo (retraso) una vez que la configures. Si, por algún motivo, necesitas cambiar la demora, tendrás que cancelar el registro del objeto de escucha del sensor y volver a registrarlo.

También es importante tener en cuenta que, en este ejemplo, se usan los métodos de devolución de llamada onResume() y onPause() para registrar y cancelar el registro del objeto de escucha de eventos del sensor. Como práctica recomendada, siempre debes inhabilitar los sensores que no necesites, en especial cuando la actividad esté pausada. De lo contrario, la batería se puede agotar en solo unas horas, ya que algunos sensores tienen requisitos de energía considerables y pueden consumir la batería rápidamente. El sistema no inhabilitará los sensores automáticamente cuando se apague la pantalla.

Cómo controlar diferentes configuraciones del sensor

Android no especifica una configuración de sensores estándar para los dispositivos, lo que significa que los fabricantes pueden incorporar cualquier configuración de sensores que deseen en sus dispositivos con Android. Como resultado, los dispositivos pueden incluir una variedad de sensores en una amplia gama de configuraciones. Si tu aplicación depende de un tipo específico de sensor, debes asegurarte de que este se encuentre en el dispositivo para que la app pueda ejecutarse correctamente.

Tienes dos opciones para garantizar que un sensor determinado esté presente en un dispositivo:

  • Detecta sensores en el tiempo de ejecución y habilita o inhabilita las características de la aplicación según corresponda.
  • Usa los filtros de Google Play para apuntar a dispositivos con configuraciones de sensor específicas.

En las siguientes secciones, se analiza cada una de las opciones.

Detecta los sensores en el tiempo de ejecución

Si tu aplicación usa un tipo específico de sensor, pero no depende de él, puedes usar el framework de sensores para detectarlo durante el tiempo de ejecución y, luego, inhabilitar o habilitar las funciones de la aplicación según corresponda. Por ejemplo, una aplicación de navegación podría usar el sensor de temperatura, el sensor de presión, el sensor de GPS y el sensor de campo geomagnético para mostrar la temperatura, la presión barométrica, la ubicación y la orientación de la brújula. Si un dispositivo no tiene un sensor de presión, puedes usar el framework de sensores para detectar la ausencia del sensor de presión durante el tiempo de ejecución y, luego, inhabilitar la parte de la IU de tu aplicación que muestra la presión. Por ejemplo, el siguiente código verifica si hay un sensor de presión en un dispositivo:

Kotlin

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.
}

Java

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

Usa los filtros de Google Play para orientar configuraciones específicas de sensores

Si publicas tu aplicación en Google Play, puedes usar el elemento <uses-feature> en tu archivo de manifiesto para filtrar tu aplicación de los dispositivos que no tienen la configuración de sensores adecuada para tu aplicación. El elemento <uses-feature> tiene varios descriptores de hardware que te permiten filtrar aplicaciones según la presencia de sensores específicos. Los sensores que puedes incluir son los siguientes: acelerómetro, barómetro, brújula (campo geomagnético), giroscopio, luz y proximidad. A continuación, se muestra un ejemplo de entrada de manifiesto que filtra las apps que no tienen un acelerómetro:

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

Si agregas este elemento y descriptor al manifiesto de tu aplicación, los usuarios verán tu aplicación en Google Play solo si su dispositivo tiene un acelerómetro.

Solo debes establecer el descriptor en android:required="true" si tu aplicación depende por completo de un sensor específico. Si tu aplicación usa un sensor para alguna funcionalidad, pero se ejecuta sin él, debes incluirlo en el elemento <uses-feature>, pero establecer el descriptor en android:required="false". Esto ayuda a garantizar que los dispositivos puedan instalar tu app, incluso si no tienen ese sensor en particular. Esta también es una práctica recomendada de administración de proyectos que te ayuda a hacer un seguimiento de las funciones que usa tu aplicación. Ten en cuenta que, si tu aplicación usa un sensor en particular, pero se ejecuta sin él, debes detectarlo durante el tiempo de ejecución y, luego, inhabilitar o habilitar las funciones de la aplicación según corresponda.

Sistema de coordenadas del sensor

En general, el marco de trabajo del sensor utiliza un sistema de coordenadas estándar de 3 ejes para expresar valores de datos. Para la mayoría de los sensores, el sistema de coordenadas se define en relación con la pantalla del dispositivo cuando este se sostiene en su orientación predeterminada (consulta la figura 1). Cuando un dispositivo se sostiene en su orientación predeterminada, el eje X es horizontal y apunta hacia la derecha, el eje Y es vertical y apunta hacia arriba, y el eje Z apunta hacia el exterior de la pantalla. En este sistema, las coordenadas detrás de la pantalla tienen valores Z negativos. Los siguientes sensores utilizan este sistema de coordenadas:

Figura 1: Sistema de coordenadas (relativo a un dispositivo) que usa la API de Sensor

El punto más importante que debes comprender sobre este sistema de coordenadas es que los ejes no se intercambian cuando cambia la orientación de la pantalla del dispositivo, es decir, el sistema de coordenadas del sensor nunca cambia a medida que se mueve el dispositivo. Este comportamiento es el mismo que el del sistema de coordenadas de OpenGL.

Otro punto que debes comprender es que tu aplicación no debe suponer que la orientación natural (predeterminada) de un dispositivo es vertical. La orientación natural de muchos dispositivos tablet es horizontal. Además, el sistema de coordenadas del sensor siempre se basa en la orientación natural de un dispositivo.

Por último, si tu aplicación hace coincidir los datos de los sensores con la pantalla, debes usar el método getRotation() para determinar la rotación de la pantalla y, luego, el método remapCoordinateSystem() para asignar las coordenadas de los sensores a las coordenadas de la pantalla. Debes hacerlo incluso si tu manifiesto especifica que solo se muestre en modo vertical.

Nota: Algunos sensores y métodos usan un sistema de coordenadas relativo al marco de referencia del mundo (en lugar del marco de referencia del dispositivo). Estos sensores y métodos devuelven datos que representan el movimiento o la posición del dispositivo en relación con la Tierra. Para obtener más información, consulta el método getOrientation(), el método getRotationMatrix(), el sensor de orientación y el sensor de vector de rotación.

Límite de frecuencia de los sensores

Para proteger información posiblemente sensible sobre los usuarios, si la app se orienta a Android 12 (nivel de API 31) o versiones posteriores, el sistema establece un límite en la frecuencia de actualización de los datos a partir de ciertos sensores de movimiento y de posición. Estos datos incluyen valores registrados por el acelerómetro, el giroscopio y el sensor de campo geomagnético del dispositivo.

El límite de frecuencia de actualización depende de la manera en que accedes a los datos del sensor:

Si tu app necesita recopilar datos de sensores de movimiento con mayor frecuencia, debes declarar el permiso HIGH_SAMPLING_RATE_SENSORS, como se muestra en el siguiente fragmento de código. De lo contrario, si tu app intenta recopilar datos de sensores de movimiento con una frecuencia más alta sin declarar este permiso, se produce una SecurityException.

AndroidManifest.xml

<manifest ...>
    <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>
    <application ...>
        ...
    </application>
</manifest>

Prácticas recomendadas para acceder a los sensores y usarlos

Cuando diseñes la implementación de sensores, asegúrate de seguir los lineamientos que se analizan en esta sección. Estos lineamientos son prácticas recomendadas para cualquier persona que use el framework de sensores para acceder a ellos y adquirir sus datos.

Recopila solo datos de los sensores en segundo plano

En los dispositivos que ejecutan Android 9 (nivel de API 28) o versiones posteriores, las apps que se ejecutan en segundo plano tienen las siguientes restricciones:

  • Los sensores que usan el modo de informes continuo, como los acelerómetros y los giroscopios, no reciben eventos.
  • Los sensores que usan los modos de informes on-change o one-shot no reciben eventos.

Dadas estas restricciones, es mejor detectar eventos de sensores cuando tu app está en primer plano o como parte de un servicio en primer plano.

Cancela el registro de los objetos de escucha de los sensores

Asegúrate de cancelar el registro del objeto de escucha de un sensor cuando termines de usarlo o cuando se pause su actividad. Si se registra un objeto de escucha de sensor y se pausa su actividad, el sensor seguirá adquiriendo datos y usando recursos de la batería, a menos que canceles el registro del sensor. En el siguiente código, se muestra cómo usar el método onPause() para cancelar el registro de un objeto de escucha:

Kotlin

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

Java

private SensorManager sensorManager;
...
@Override
protected void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
}

Para obtener más detalles, consulta la información de unregisterListener(SensorEventListener).

Haz una prueba con Android Emulator

Android Emulator incluye un conjunto de controles de sensores virtuales que te permiten probar sensores como el acelerómetro, la temperatura ambiente, el magnetómetro, la proximidad, la luz y mucho más.

El emulador usa una conexión con un dispositivo Android que ejecuta la app SdkControllerSensor. Ten en cuenta que esta app solo está disponible en dispositivos que ejecutan Android 4.0 (nivel de API 14) o versiones posteriores. (Si el dispositivo ejecuta Android 4.0, debe tener instalada la revisión 2). La app de SdkControllerSensor supervisa los cambios en los sensores del dispositivo y los transmite al emulador. Luego, el emulador se transforma según los valores nuevos que recibe de los sensores de tu dispositivo.

Puedes ver el código fuente de la app de SdkControllerSensor en la siguiente ubicación:

$ your-android-sdk-directory/tools/apps/SdkController

Para transferir datos entre tu dispositivo y el emulador, sigue estos pasos:

  1. Verifica que la depuración por USB esté habilitada en tu dispositivo.
  2. Conecta el dispositivo a la máquina de desarrollo con un cable USB.
  3. Inicia la app SdkControllerSensor en tu dispositivo.
  4. En la app, selecciona los sensores que quieras emular.
  5. Ejecuta el siguiente comando adb:

  6. $ adb forward tcp:1968 tcp:1968
    
  7. Inicia el emulador. Ahora deberías poder aplicar transformaciones al emulador moviendo tu dispositivo.

Nota: Si los movimientos que realizas en tu dispositivo físico no transforman el emulador, intenta volver a ejecutar el comando adb del paso 5.

Para obtener más información, consulta la guía de Android Emulator.

No bloquees el método onSensorChanged()

Los datos del sensor pueden cambiar a una velocidad alta, lo que significa que es posible que el sistema llame al método onSensorChanged(SensorEvent) con bastante frecuencia. Como práctica recomendada, debes hacer lo menos posible dentro del método onSensorChanged(SensorEvent) para no bloquearlo. Si tu aplicación requiere que realices algún filtrado o reducción de datos de sensores, debes realizar ese trabajo fuera del método onSensorChanged(SensorEvent).

Evita usar métodos o tipos de sensores obsoletos

Varios métodos y constantes ya no están disponibles. En particular, el tipo de sensor TYPE_ORIENTATION dejó de estar disponible. Para obtener datos de orientación, debes utilizar el método getOrientation() en su lugar. Del mismo modo, el tipo de sensor TYPE_TEMPERATURE dejó de estar disponible. En su lugar, debes usar el tipo de sensor TYPE_AMBIENT_TEMPERATURE en los dispositivos que ejecutan Android 4.0.

Comprueba los sensores antes de usarlos

Siempre comprueba que existe un sensor en un dispositivo antes de intentar obtener datos de él. No asumas que un sensor existe simplemente porque es un sensor de uso frecuente. No es necesario que los fabricantes de dispositivos proporcionen sensores específicos en sus dispositivos.

Elige los retrasos del sensor con cuidado

Cuando registres un sensor con el método registerListener(), asegúrate de elegir una tasa de entrega adecuada para tu aplicación o caso de uso. Los sensores pueden proporcionar datos a ritmos muy rápidos. Permitir que el sistema envíe datos adicionales que no necesitas desperdicia recursos del sistema y consume batería.