Bienvenidos sean a este post, hoy hablaremos sobre los sensores disponibles en nuestros dispositivos los cuales nos permitiran conocer a nuestro mundo exterior, estos no incluyen el microfono, camara y GPS. Los sensores son manipulados por medio del paquete android.hardware y a traves de las clases Sensor, SensorEvent y SensorManager, la interfaz para utilizarla es SensorEventListener, veamos la siguiente tabla con algunos de los sensores disponibles:

Tipo Constantes Funcion Dim. Unid.
Acelerometro TYPE_ACCELEROMETER Mide aceleraciones por gravedad y cambio de movimiento 3 m/s
Gravedad TYPE_GRAVITY Mide la aceleracion debida a la gravedad 3 m/s
Acelerometro lineal TYPE_LINEAR_ACCELERATION Mide las aceleraciones sin tener en cuenta la gravedad 3 m/s
Giroscopio TYPE_GYROSCOPE Mide los cambios de rotacion 3 rad/s
Vector de rotacion TYPE_ROTATION_VECTOR Es para detectar rotaciones 3 a
dimen
sional
Orientacion TYPE_ORIENTATION Direccion a la que apunta el dispositivo (obsoleto) 3 grado
Campo magnetico TYPE_MAGNETIC_FIELD Brujula, detectar campos magneticos 3 uT
Luz ambiental TYPE_LIGHT Luz ambiental, ideal para ajustar el brillo de pantalla 1 lx
Proximidad TYPE_PROXIMITY Distancia a un objeto, ideal para saber si esta cerca de la oreja 1 cm
Presion atmosferica TYPE_PRESSURE Barometro, se puede crear un altimero con el 1 hPa
Temperatura ambiental TYPE_AMBIENT_TEMPERATURE Mide la temperatura del aire 1 °C
Temperatura interna TYPE_TEMPERATURE Para evitar sobrecalentamientos (Obsoleta) 1 °C
Humedad relativa TYPE_RELATIVE_HUMIDITY Mide el punto de rocio, humedad absoluta y relativa 1 %
Movimiento significativo TYPE_SIGNIFICANT_MOTION Detecta si el dispositivo ha sido movido trig
ger
Detector de pasos TYPE_STEP_DETECTOR Detecta cuando el usuario da un paso tri
ger
Contador de pasos TYPE_STEP_COUNTER Cuenta la cantidad de pasos realizados desde el ultimo reinicio 1 paso
Frecuencia cardiaca TYPE_HEART_RATE Monitorea el ritmo cardiaco en pulsos por minuto 1 rpm

Como pueden ver nuestros dispositivos pueden obtener bastante informacion desde los sensores pero algunos son mas nuevos que otros, aca les paso el detalle desde que version de API se implementaron las constantes anteriores, esto es fundamental a la hora de crear nuestro proyecto porque necesitaran estar como minimo con esa version para poder trabajar con ella, pasemos al detalle:

  • API 3:
    TYPE_ACCELEROMETER, TYPE_GYROSCOPE, TYPE_ORIENTATION, TYPE_MAGNETIC_FIELD, TYPE_PROXIMITY, TYPE_PRESSURE, TYPE_TEMPERATURE
  • API 9:
    TYPE_GRAVITY, TYPE_LINEAR_ACCELERATION, TYPE_ROTATION_VECTOR
  • API 14:
    TYPE_AMBIENT_TEMPERATURE, TYPE_RELATIVE_HUMIDITY
  • API 18:
    TYPE_SIGNIFICANT_MOTION
  • API 19:
    TYPE_STEP_DETECTOR, TYPE_STEP_COUNTER
  • API 20:
    TYPE_HEART_RATE

Como pueden ver a medida que se fueron mejorando los dispositivos se nos permitio obtener mejores datos, y tambien nos permitio dejar de utilizar algunos, en esta tabla tenemos dos casos, el primero es TYPE_ORIENTATION si bien este se puede seguir utilizando no se utiliza porque no detecta correctamente el cambio horizontal/vertical para ello se utiliza una funcion entre el acelerometro y el campo magnetico, nuestro segundo caso es TYPE_TEMPERATURE el cual a partir de la API 14 se empezo a utilizar TYPE_AMBIENT_TEMPERATURE, si bien estos dos tipos de sensores son obsoletos todavia se pueden seguir utilizando pero no es aconsejable.
Para entender un poco mejor el concepto de sensores procedamos a hacer un ejemplo, para ello abramos Android Studio y elijamos Start a new Android Studio project, nos aparecera un cuadro donde modificaremos el campo Application name por Sensores, y en Company domain usemos example.org, el resto queda como aparece, pulsamos Next para pasar al siguiente cuadro, en el elegiremos Phone And Tablet y no les recomiendo la version mas baja de API, en este caso elijan una entre 14 y 19 (en mi caso elegi la API 19), como para tener mas posibilidades de detectar otros sensores, una vez seleccionado pulsen Next, en el siguiente cuadro elijan Empty Activity y pulsen Next para pasar al ultimo cuadro donde dejaremos todo por defecto y pulsamos Finish para crear nuestra app, una vez creada vamos a ir a nuestro layout llamado activity_main.xml donde modificaremos al TextView para agregarle la siguiente linea:

android:id="@+id/salida"

Y modificaremos la linea de texto de la siguiente forma:

android:text=""

Con esta linea agregada y la otra modificada el elemento TextView debera quedar asi:

< TextView
        android:id="@+id/salida"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=""
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" / >

Con esta modificacion realizada procederemos a modificar nuestra clase MainActivity con el siguiente codigo:

package org.example.sensores;

import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private TextView salida;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        salida = (TextView) findViewById(R.id.salida);
        SensorManager sensorAdmin = (SensorManager)
                getSystemService(SENSOR_SERVICE);
        List listaSensores = sensorAdmin.
                getSensorList(Sensor.TYPE_ALL);
        for(Sensor sensor: listaSensores){
            log(sensor.getName());
        }
    }

    private void log(String cadena){
        salida.append(cadena + "\n");
    }
}

Este codigo se encargara de mostrarnos todos los sensores, primero crearemos un enlace a nuestro TextView y lo llamaremos salida, luego en el metodo onCreate() por medio del metodo findViewById() lo vincularemos al elemento del layout, nuestro siguiente paso sera crear un objeto llamado sensorAdmin de la clase SensorManager y en este caso utilizaremos el metodo getSystemService() a asociarlo al sistema servicios, este metodo pertenece a la clase Context, luego crearemos un List (Array) de la clsae Sensor llamado ListaSensores el cual almacenara todos los tipos de sensores disponibles en nuestro equipo, luego tendremos un bucle for encargado de tomar el nombre de cada uno de los sensores y mandarlos al metodo log(), este metodo es el encargado de agregar cada atributo recibido en nuestro TextView por medio del enlace salida, si lo probamos con nuestro emulador obtendremos una salida similar a esta:

android96

Como pueden ver nos devolvio todos los sensores disponibles sobre nuestro equipo emulado o virtual, como quieran llamarlo, pero que sucederia si lo probamos sobre un equipo verdadero, obtendremos el siguiente resultado

Screenshot_20181114-194221

Como pueden ver cambiaron los sensores, les recomiendo este post donde explico como probar nuestras apps con dispositivos reales porque obviamente en estos casos es mejor poder trabajar con ellos, veamos algunos de los metodos publicos disponibles de la clase Sensor en la siguiente tabla:

Metodo Descripcion
public float getMaximumRange() Rango maximo de unidades del sensor
public float getMinDelay() Tiempo minimo entre dos eventos (en microsegundos)
public string getName() Nombre del sensor
public float getPower() Potencia del sensor mientras esta siendo usada en mA
public float getResolution() Resolucion en las unidades del sensor
public int getType() Tipo generico del sensor
public String getVendor() Devuelve el fabricante del sensor
public int getVersion() Devuelve la version del sensor

Con esto visto vamos a hacer una pequeña modificacion para poder obtener los datos de nuestros sensores, primero vayamos a nuestra clase MainActivity y agreguemos las siguientes lineas en el metodo onCreate():

listaSensores = sensorAdmin.getSensorList(Sensor.TYPE_ORIENTATION);
if(!listaSensores.isEmpty()){
    Sensor orientationSensor = listaSensores.get(0);
    sensorAdmin.registerListener(this,orientationSensor,
            SensorManager.SENSOR_DELAY_UI);
}
listaSensores = sensorAdmin.getSensorList(Sensor.TYPE_ACCELEROMETER);
if(!listaSensores.isEmpty()){
    Sensor acelerometroSensor = listaSensores.get(0);
    sensorAdmin.registerListener(this,acelerometroSensor,
            SensorManager.SENSOR_DELAY_UI);
}
listaSensores = sensorAdmin.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
if(!listaSensores.isEmpty()) {
    Sensor magneticSensor = listaSensores.get(0);
    sensorAdmin.registerListener(this, magneticSensor,
            SensorManager.SENSOR_DELAY_UI);
}
listaSensores = sensorAdmin.getSensorList(Sensor.TYPE_PROXIMITY);
if(!listaSensores.isEmpty()) {
    Sensor proximidadSensor = listaSensores.get(0);
    sensorAdmin.registerListener(this, proximidadSensor,
            SensorManager.SENSOR_DELAY_UI);
}

En este caso vamos a utilizar cuatro sensores: orientacion, acelerometro, campo magnetico y proximidad. Cada bloque es similar pero cada uno esta para cada sensor, en listaSensores conseguiremos el tipo de sensor, despues tendremos un condicional donde chequeara que listaSensores no este vacio, si es verdad creara un objeto de la clase Sensor para asignar el sensor, luego utilizara el metodo registerListener() para registrar el sensor pero en este momento no funcionara para poder implementarlo deberemos hacer la siguiente modificacion de la declaracion de la clase:

public class MainActivity extends AppCompatActivity implements 
        SensorEventListener {

Con esta implementacion podrems utilizar el registerListener(), ahora solo nos resta implementar dos metodos para poder recibir los datos, los metodos son los siguientes:

@Override
public void onAccuracyChanged(Sensor sensor, int precision){}

@Override
public void onSensorChanged(SensorEvent evento){
    switch(evento.sensor.getType()){
        case Sensor.TYPE_ORIENTATION:
            for(int i = 0; i < 3; i++)
                log("Orientacion "+i+": "+evento.values[i]);
            break;
        case Sensor.TYPE_ACCELEROMETER:
            for(int i = 0; i < 3; i++)
                log("Acelerometro "+i+": "+evento.values[i]);
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            for(int i = 0; i < 3; i++)
                log("Magnetico "+i+": "+evento.values[i]);
            break;
        default:
            for(int i = 0; i < evento.values.length; i++)
                log("Proximidad "+i+": "+evento.values[i]);
            break;
    }
}

Estos dos metodos deben estar como minimo para poder trabajar con los sensores en el primer metodo, onAccuracyChanged(), no necesitamos ejecutar ninguna instruccion sino simplemente que este entre las definiciones y por este motivo lo dejamos en blanco, es decir simplemente con las dos llaves ({}), el otro metodo (onSensorChanged()) por medio de un switch detectaremos el tipo de sensor y por medio de los cases le diremos que nos muestre los valores del mismo, en los tres primeros cases veremos los sensores de orientacion, acelerometro y campo magnetico y el default se encargara de proximidad, si compilamos nuestra app y la probamos obtendremos los siguientes valores

android97

Probemos de dar vuelta nuestro equipo para ver el resultado

android98

Y por ultimo probaremos nuestra app en un equipo real

Screenshot_20181115-103616

Como pueden ver en el equipo real van a aparecer mas y mejores datos pero el equipo virtual en general tendra lo minimo para probar nuestras apps.
En resumen, hoy nos hemos introducido en el mundo de los sensores, de como podemos obtener datos de nuestro entorno y como podemos lograr tener una mejor ubicacion de nosotros y nuestro equipo, como en estos casos es mas recomendable verificarlo en los equipos reales, espero te haya sido util sigueme en Twitter, Facebook o Google+ para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios