Sensores de Android en Profundidad: Proximidad y Giroscopio
Spanish (Español) translation by Nadia Castelli (you can also view the original English article)
¿Por qué esperar siempre a que los usuarios toquen botones en sus pantallas táctiles? Mediante el uso de algunos de los sensores hardware disponibles en los teléfonos Android de gama media, puedes crear apps que ofrezcan experiencias de usuario mucho más entretenidas.
El framework de sensores, que forma parte del Android SDK, te permite leer datos crudos de la mayoría de los sensores, ya sean hardware o software, de manera sencilla y consistente. En este tutorial, te enseñaré a emplear este framework para leer datos de dos sensores muy comunes: proximidad y giroscopio. Además, te presentaré el sensor de rotación del vector, un sensor compuesto que es, en la mayoría de los casos, una alternativa más fácil y más precisa al giroscopio.
Puedes tener una idea básica acerca de los sensores hardware de Android leyendo el siguiente tutorial:
Prerrequisitos
Para seguir este tutorial, necesitarás lo siguiente:
- Un dispositivo Android con sensor de proximidad y giroscopio
- La versión más reciente de Android Studio
1. Configuración del Proyecto
Si tu app es simplemente inutilizable en los dispositivos carentes de los sensores de hardware necesarios, no debería poder instalarse en los mismos. Puedes informar a Google Play y otros mercados de apps sobre los requerimientos de hardware de tu app, añadiendo una o más etiquetas <uses-feature> al archivo manifest de tu proyecto Android Studio.
La app que crearemos en este tutorial no funcionará en dispositivos que carezcan de un sensor de proximidad y un giroscopio. Por lo tanto, agrega las siguientes líneas a tu archivo manifest:
1 |
<uses-feature
|
2 |
android:name="android.hardware.sensor.proximity" |
3 |
android:required="true" /> |
4 |
<uses-feature
|
5 |
android:name="android.hardware.sensor.gyroscope" |
6 |
android:required="true" /> |
Sin embargo, ten en cuenta que, como la etiqueta <uses-feature> no previene que un usuario instale tu app manualmente mediante su archivo APK, aún debes agregar una comprobación programática de que el sensor esté disponible antes de ser usado.
2. Utilizando el Sensor de Proximidad
Para evitar toques accidentales, la pantalla táctil de tu teléfono se vuelve negra durante una llamada, cuando el teléfono está cerca de tu oreja. ¿Alguna vez te preguntaste cómo determina tu teléfono si está cerca de tu oreja? Pues, emplea el sensor de proximidad, que es un sensor de hardware que puede determinar si hay algún objeto cercano. Algunos sensores de proximidad también pueden identificar cuán lejano está dicho objeto, aunque su rango máximo suele ser de aproximadamente 5 cm.
Ahora, crearemos una activity cuyo color de fondo cambie a rojo cada vez que pases tu mano sobre el sensor de proximidad del dispositivo.
Paso 1: Obtén Acceso al Sensor de Proximidad
Para obtener acceso a cualquier sensor de hardware, necesitas un objeto SensorManager. Para crearlo, utiliza el método getSystemService() de tu clase Activity, y pásale la constante SENSOR_SERVICE.
1 |
SensorManager sensorManager = |
2 |
(SensorManager) getSystemService(SENSOR_SERVICE); |
Ahora, puedes crear un objeto Sensor para el sensor de proximidad, invocando el método getDefaultSensor() y pasándole la constante TYPE_PROXIMITY.
1 |
Sensor proximitySensor = |
2 |
sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); |
Antes de proceder, asegúrate siempre de que el objeto Sensor no sea null. Si lo es, significa que el sensor de proximidad no está disponible.
1 |
if(proximitySensor == null) { |
2 |
Log.e(TAG, "Proximity sensor not available."); |
3 |
finish(); // Close app |
4 |
}
|
Paso 2: Registra un Listener
Para poder leer los datos crudos generados por un sensor, debes asociarle un SensorEventListener invocando el método registerListener() del objeto SensorManager. Al hacerlo, también debes especificar la frecuencia con la cual deberían leerse datos del sensor.
El código siguiente registra un listener que te permite leer datos del sensor de proximidad cada dos segundos:
1 |
// Create listener
|
2 |
SensorEventListener proximitySensorListener = new SensorEventListener() { |
3 |
@Override
|
4 |
public void onSensorChanged(SensorEvent sensorEvent) { |
5 |
// More code goes here
|
6 |
}
|
7 |
|
8 |
@Override
|
9 |
public void onAccuracyChanged(Sensor sensor, int i) { |
10 |
}
|
11 |
};
|
12 |
|
13 |
// Register it, specifying the polling interval in
|
14 |
// microseconds
|
15 |
sensorManager.registerListener(proximitySensorListener, |
16 |
proximitySensor, 2 * 1000 * 1000); |
Te sugiero que registres el listener siempre dentro del método onResume() de tu activity, y elimines el registro dentro del método onPause(). Aquí puedes ver como eliminar el registro del listener:
1 |
sensorManager.unregisterListener(proximitySensorListener); |
Paso 3: Utiliza los Datos Crudos
El objeto SensorEvent, disponible dentro del método onSensorChanged(), posee un array values que contiene todos los datos crudos generados por el sensor asociado. En el caso del sensor de proximidad, el array contiene un único valor que especifica la distancia en centímetros entre el sensor y un objeto cercano.
Si el valor es igual al alcance máximo del sensor, podemos asumir con seguridad que no hay nada cerca. De manera inversa, si es menor que el alcance máximo, significa que hay algo cerca. Puedes determinar el alcance máximo de cualquier sensor de hardware usando el método getMaximumRange() del objeto Sensor asociado.
Para cambiar el color de fondo de la activity según los datos que provee el sensor de proximidad, puedes emplear el método setBackgroundColor() de la DecorView que se encuentra en el nivel superior.
En consecuencia, agrega el siguiente código dentro del método onSensorChanged() que creaste en el paso anterior:
1 |
if(sensorEvent.values[0] < proximitySensor.getMaximumRange()) { |
2 |
// Detected something nearby
|
3 |
getWindow().getDecorView().setBackgroundColor(Color.RED); |
4 |
} else { |
5 |
// Nothing is nearby
|
6 |
getWindow().getDecorView().setBackgroundColor(Color.GREEN); |
7 |
}
|
Ahora, si ejecutas la app y colocas tu mano cerca y sobre la parte superior de tu teléfono, deberías ver que la pantalla se vuelve roja.



3. Utilizando el Giroscopio
El giroscopio te permite determinar la velocidad angular de un dispositivo Android en cualquier momento dado. En palabras más sencillas, te informa cuán rápidamente está rotando el dispositivo sobre sus ejes X, Y y Z. Últimamente, incluso los teléfonos más económicos contienen un giroscopio integrado, debido a la creciente popularidad de las apps de realidad aumentada y realidad virtual.
Mediante el uso del giroscopio, puedes desarrollar apps que respondan inmediatamente a los cambios en la orientación de un dispositivo. Para verlo en acción, crearemos una activity cuyo color de fondo cambie a azul cada vez que rotes el teléfono sobre el eje Z en sentido antihorario, y a amarillo en sentido contrario.
Paso 1: Obtén Acceso al Giroscopio
Para crear un objeto Sensor para el giroscopio, todo lo que necesitas hacer es pasarle la constante TYPE_GYROSCOPE al método getDefaultSensor() del objeto SensorManager.
1 |
gyroscopeSensor = |
2 |
sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); |
Paso 2: Registra un Listener
Crear un sensor para el giroscopio no es diferente a crear uno para el sensor de proximidad. Al registrarlo, sin embargo, debes asegurarte de que su frecuencia de muestreo sea muy alta. Por lo tanto, en lugar de especificar un intervalo de sondeo en microsegundos, te sugiero que uses la constante SENSOR_DELAY_NORMAL.
1 |
// Create a listener
|
2 |
gyroscopeSensorListener = new SensorEventListener() { |
3 |
@Override
|
4 |
public void onSensorChanged(SensorEvent sensorEvent) { |
5 |
// More code goes here
|
6 |
}
|
7 |
|
8 |
@Override
|
9 |
public void onAccuracyChanged(Sensor sensor, int i) { |
10 |
}
|
11 |
};
|
12 |
|
13 |
// Register the listener
|
14 |
sensorManager.registerListener(gyroscopeSensorListener, |
15 |
gyroscopeSensor, SensorManager.SENSOR_DELAY_NORMAL); |
Paso 3: Utiliza los Datos Crudos
Los datos crudos del sensor del giroscopio consisten en tres valores float, que especifican la velocidad angular del dispositivo sobre los ejes X, Y, y Z. La unidad de estos valores es radianes por segundo. En caso de rotación en sentido antihorario sobre cualquiera de los ejes, el valor asociado con dicho eje será positivo. En caso de rotación en sentido horario, será negativo.
Como solamente estamos interesados sólo en la rotación sobre el eje Z, trabajaremos únicamente con el tercer elemento del array values del objeto SensorEvent. Si es mayor a 0.5f, podemos, en gran medida, estar seguros de que la rotación es en sentido antihorario, y colorear el fondo de azul. De manera similar, si es menor a -0.5f, podemos colorear el fondo de amarillo.
1 |
if(sensorEvent.values[2] > 0.5f) { // anticlockwise |
2 |
getWindow().getDecorView().setBackgroundColor(Color.BLUE); |
3 |
} else if(sensorEvent.values[2] < -0.5f) { // clockwise |
4 |
getWindow().getDecorView().setBackgroundColor(Color.YELLOW); |
5 |
}
|
Ahora, si ejecutas la app, sostén tu teléfono en posición vertical, e inclínalo hacia la izquierda, deberías ver cómo la activity se vuelve azul. Si lo inclinas en la dirección opuesta, debería tornarse amarilla.



Sin embargo, si inclinas demasiado el teléfono, la orientación de la pantalla cambiará a horizontal y tu activity se reiniciará. Para evitarlo, te sugiero que configures la screenOrientation de la activity en portrait, en el archivo manifest.
1 |
<activity |
2 |
android:name=".GyroscopeActivity" |
3 |
android:screenOrientation="portrait"> |
4 |
</activity> |
4. Utilizando el Sensor de Rotación del Vector
Hoy en día, la mayoría de los desarrolladores prefieren sensores software compuestos por sobre los sensores hardware. Un sensor software combina datos crudos a bajo nivel tomados de múltiples sensores de hardware, para generar datos nuevos que no sólo son sencillos de usar, sino que además son más precisos. El sensor de proximidad no posee alternativa software. El giroscopio, sin embargo, tiene dos: el sensor de rotación del vector para juegos, y el sensor de rotación del vector. En este tutorial, nos enfocaremos sólo en el último.
En el ejemplo del paso anterior, cambiamos el color de fondo de la activity cada vez que la velocidad angular sobre el eje Z era mayor a 0.5 rad/s en sentido horario o antihorario. Sin embargo, trabajar con velocidades angulares no es intuitivo. Además, no tenemos idea de cuál es el ángulo del dispositivo antes o después de la rotación.
Usando el sensor de rotación del vector, crearemos una activity cuyo color de fondo cambie solamente cuando la rotación es de un ángulo específico. Por ejemplo, podríamos cambiarlo a amarillo cada vez que su rotación—sobre el eje Z—sea mayor a 45°, a blanco cuando su rotación esté comprendida entre los -10° y los 10°, y azul cuando su rotación sea menor a -45°.
Paso 1: Configura el Sensor de Rotación del Vector
Para adquirir el sensor de rotación del vector, debes pasar la constante TYPE_ROTATION_VECTOR al método getDefaultSensor() del objeto SensorManager.
1 |
rotationVectorSensor = |
2 |
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); |
Trabajar con un sensor de software no es diferente a trabajar con un sensor de hardware. Por lo tanto, para ser capaz de leer estos datos, debes asociar un listener al sensor de rotación del vector. Puedes utilizar de nuevo la contante SENSOR_DELAY_NORMAL para el intervalo de sondeo.
1 |
// Create a listener
|
2 |
rvListener = new SensorEventListener() { |
3 |
@Override
|
4 |
public void onSensorChanged(SensorEvent sensorEvent) { |
5 |
// More code goes here
|
6 |
}
|
7 |
|
8 |
@Override
|
9 |
public void onAccuracyChanged(Sensor sensor, int i) { |
10 |
}
|
11 |
};
|
12 |
|
13 |
// Register it
|
14 |
sensorManager.registerListener(rvListener, |
15 |
rotationVectorSensor, SensorManager.SENSOR_DELAY_NORMAL); |
Paso 2: Utiliza los Datos
El sensor de rotación del vector combina datos crudos generados por el giroscopio, acelerómetro, y magnetómetro para crear un cuaternión. En consecuencia, el array values de su objeto SensorEvent contiene los siguientes cinco elementos:
- Los componentes X, Y, Z, y W del cuaternión
- La exactitud
Puedes convertir el cuaternión en una matriz de rotación, una matriz 4x4, utilizando el método getRotationMatrixFromVector() de la clase SensorManager.
1 |
float[] rotationMatrix = new float[16]; |
2 |
SensorManager.getRotationMatrixFromVector( |
3 |
rotationMatrix, sensorEvent.values); |
Si estás desarrollando una app OpenGL, puedes usar la matriz de rotación directamente para transformar objetos en un escena 3D. Por ahora, sin embargo, convertiremos la matriz de rotación en un array de orientaciones, especificando la rotación del dispositivo sobre los ejes Z, X, e Y. Para hacer esto, podemos emplear el método getOrientation() de la clase SensorManager.
Antes de invocar el método getOrientation(), debes volver a mapear el sistema de coordenadas de la matriz de rotación. Más precisamente, debes rotar la matriz de rotación de manera tal que el eje Z del nuevo sistema de coordenadas coincida con el eje Y del sistema de coordenadas original.
1 |
// Remap coordinate system
|
2 |
float[] remappedRotationMatrix = new float[16]; |
3 |
SensorManager.remapCoordinateSystem(rotationMatrix, |
4 |
SensorManager.AXIS_X, |
5 |
SensorManager.AXIS_Z, |
6 |
remappedRotationMatrix); |
7 |
|
8 |
// Convert to orientations
|
9 |
float[] orientations = new float[3]; |
10 |
SensorManager.getOrientation(remappedRotationMatrix, orientations); |
Por defecto, el array orientations contiene ángulos en radianes en lugar de grados. Si estás acostumbrado a usar radianes, eres libre de usarlo así directamente. De lo contrario, utiliza el siguiente código para convertir todos sus ángulos a grados:
1 |
for(int i = 0; i < 3; i++) { |
2 |
orientations[i] = (float)(Math.toDegrees(orientations[i])); |
3 |
}
|
Ahora puedes cambiar el color de fondo de la activity de acuerdo al tercer elemento del array orientations.
1 |
if(orientations[2] > 45) {
|
2 |
getWindow().getDecorView().setBackgroundColor(Color.YELLOW); |
3 |
} else if(orientations[2] < -45) {
|
4 |
getWindow().getDecorView().setBackgroundColor(Color.BLUE); |
5 |
} else if(Math.abs(orientations[2]) < 10) {
|
6 |
getWindow().getDecorView().setBackgroundColor(Color.WHITE); |
7 |
} |
Si ejecutas la app ahora, sostén tu teléfono en modo vertical, e inclínalo más de 45° en sentido horario o antihorario; deberías ver cómo cambia el color de fondo.



Conclusión
En este tutorial, aprendiste cómo utilizar el framework de sensores de Android para crear apps que responden a los datos generados por el sensor de proximidad y el giroscopio. También aprendiste a trabajar con el sensor de rotación del vector, una alternativa más popular al giroscopio. Siéntete libre de utilizar los sensores de manera creativa. Sin embargo, ten cuidado, ya que las apps que usan los sensores de manera ineficiente pueden drenar la batería de un dispositivo muy rápidamente.
Para aprender más sobre sensores de hardware y los datos que generan, puedes referirte a la guía oficial de la API de sensores. Y revisa nuestro contenido acerca de hardware y sensores, ¡aquí en Envato Tuts+!











