Los sensores

Bajo la denominación de sensores se engloba un conjunto de dispositivos con los que podremos obtener información del mundo exterior (en este conjunto no se incluye la cámara, el micrófono o el GPS). Como se verá en este apartado todos los sensores se manipulan de forma homogénea. Son los dispositivos de entrada más novedosos que incorpora Android y con ellos podremos implementar formas atractivas de interacción con el usuario.

Puedes ver algunos aspectos relacionados en formato poli[Media]

Sensores en dispositivos móviles

Si no dispones de un terminal físico, puedes instalar un software de emulación que te permitirá realizar las pruebas sobre el emulador, mientras desde una aplicación de tu PC cambias la orientación de un teléfono ficticio mediante el ratón. Puedes descargarte el software dehttp://www.openintents.org/en/node/6, no obstante, el proceso resulta bastante laborioso. Además, tendrás que cambiar el código de los ejemplos para adaptarlos a los requerimientos del emulador. Por lo tanto, tendrás que realizar dos programas diferentes: uno para sensores reales y otro para el emulador.

Android permite acceder a los sensores internos del dispositivo a través de las clases Sensor,SensorEvent, SensorManager, y la interfaz SensorEventListener, del paquete android.hardware.

La clase Sensor acepta ocho tipos de sensores. Aunque, los sensores disponibles varían en función del dispositivo utilizado:

 

Tipo

CONSTANTE

Utilidad

dim.

desde
API

acelerómetro

TYPE_ACCELEROMETER

medir aceleraciones por grave-dad y cambios de movimiento

3

3

campo magnético

TYPE_MAGNETIC_FIELD

brújula, detectar campor magnéticos

3

3

giroscopio

TYPE_GYROSCOPE

detectar giros

3

3

orientación

TYPE_ORIENTATION

indicar dirección a la que apunta el dispositivo

3

3

luz ambiental

TYPE_LIGHT

ajustar iluminación pantalla

1

3

proximidad

TYPE_PROXIMITY

si hay un objeto a menos de 5 cm (al hablar por teléfono)

bool
eano

3

presión atmosférica

TYPE_PRESSURE

altímetro, barómetro

1

3

temperatura interna

TYPE_TEMPERATURE

evitar sobrecalentamientos

(obsoleto desde API14)

1

3

gravedad

TYPE_GRAVITY

medir la aceleración debida a la gravedad

3

9

acelerómetro lineal

TYPE_LINEAR_ACCELERATION

medir aceleraciones descontando la gravedad

3

9

vector de rotación

TYPE_ROTATION_VECTOR

detectar giros

3

9

temperatura ambiental

TYPE_AMBIENT_TEMPERATURE

medir la temperatura del aire

1

14

humedad relativa

TYPE_RELATIVE_HUMIDITY

medir el punto de rocío, humedad absoluta y relativa.

1

14

Ejercicio paso a paso: Listar los sensores del dispositivo

No todos los dispositivos disponen de los mismos sensores. Por lo tanto, la primera tarea consiste en averiguar los sensores disponibles.

1. Crea un nuevo proyecto con nombre Sensores.

2. Añade la siguiente propiedad al TextView de res/layout/main.xml:

android:id="@+id/salida"

3. Inserta este código en la actividad principal:


public class SensoresActivity extends Activity {

    private TextView salida;

 

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        salida = (TextView) findViewById(R.id.salida);

        SensorManager sensorManager = (SensorManager) 
                                                        getSystemService(
SENSOR_SERVICE);

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

        for(Sensor sensor: listaSensores) {

             log(sensor.getName());

        }

    }

   private void log(String string) {

          salida.append(string + "\n");

   }

}

 

4. El método comienza indicando el Layout de la actividad y obteniendo el TextView salida, donde mostraremos los resultados. A continuación vamos a vamos a utilizar el método getSystemService para solicitar al sistema servicios específicos. Este método pertenece a la clase Context (Como somos Activity también somos Context) y será muy utilizados para acceder a gran cantidad de servicios del sistema. Al indicar como parámetro  SENSOR_SERVICE,  indicamos que queremos utilizar los sensores. Lo haremos a través del objeto sensorManager. En primer lugar llamamos al método getSensorList() del objeto para que nos de listaSensores, una lista de objetos Sensor. La siguiente línea recorre todos los elementos de esta lista parar llamar a su método getName() para mostrar el nombre de sensor.

5. Ejecuta el programa. Esta es una lista de los valores devueltos por el código anterior ejecutándose en el HTC Magic:

AK8976A 3-axis Accelerometer

AK8976A 3-axis Magnetic field sensor

AK8976A Orientation sensor

AK8976A Temperature sensor

6.    El AK8976A es una combinación de acelerómetro de tres ejes y magnetómetro de tres ejes. Combinando la lectura de los campos gravitatorio y magnético terrestres proporciona también información de orientación. Incluye además un sensor interno de temperatura, útil para comprobar si el móvil se está calentado demasiado.

Como hemos visto la case Sensor nos permite manipular los sensores. A continuación se listan los métodos públicos de la clase Sensor:

public float getMaximumRange()

 

Rango máximo en las unidades del sensor

public String getName()

 

Nombre del sensor

public float getPower()

 

Potencia (mA) usada por el sensor mientras está en uso

public float getResolution()

 

Resolución en las unidades del sensor

public int getType()

 

Tipo genérico del sensor

Public String getVendor()

 

Fabricante del sensor

public int getVersion()

 

Versión del sensor

La clase SensorManager tiene además tres métodos (getInclination, getOrientation y getRotationMatrix), usados para calcular transformaciones de coordenadas.

 

Ejercicio paso a paso: Acceso a los datos del sensor

Veamos ahora como obtener la lectura de cada uno de los sensores.

1. Copia el siguiente código al final de onCreate.


listaSensores = sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);

if (!listaSensores.isEmpty()) {

       Sensor orientationSensor = listaSensores.get(0);

       sensorManager.registerListener(this, orientationSensor,
                                                                                SensorManager.
SENSOR_DELAY_UI);}

listaSensores = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);

if (!listaSensores.isEmpty()) {

       Sensor acelerometerSensor = listaSensores.get(0);

       sensorManager.registerListener(this, acelerometerSensor, 
                                                                                SensorManager.
SENSOR_DELAY_UI);}

listaSensores = sensorManager.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);

if (!listaSensores.isEmpty()) {

       Sensor magneticSensor = listaSensores.get(0);

       sensorManager.registerListener(this, magneticSensor, 
                                                                                SensorManager.
SENSOR_DELAY_UI);}

listaSensores = sensorManager.getSensorList(Sensor.TYPE_TEMPERATURE);

if (!listaSensores.isEmpty()) {

       Sensor temperatureSensor = listaSensores.get(0);

       sensorManager.registerListener(this, temperatureSensor, 
                                                                                SensorManager.
SENSOR_DELAY_UI);}

Comenzamos consultando si disponemos de un sensor de orientación. Para ello preguntamos al sistema que nos de todos los sensores de este tipo llamando a getSensorList(). Si la lista no está vacía obtenemos el primer elemento (el 0). Es necesario registrar cada tipo de sensor por separado para poder obtener información de él. El método registerListener() toma como primer parámetro un objeto que implemente el interface SensorEventListener, veremos a continuación cómo se implementa esta interfaz (se indica this porque la clase que estamos definiendo implementará este interfaz para recoger eventos de sensores). El segundo parámetro es el sensor que estamos registrando. Y el tercero indica al sistema con qué frecuencia nos gustaría recibir actualizaciones del sensor. Acepta cuatro posibles valores, de menor a mayor frecuencia tenemos: SENSOR_DELAY_NORMAL, SENSOR_DELAY_UI, SENSOR_DELAY_GAME y SENSOR_DELAY_FASTEST. Esta indicación sirve para que el sistema estime cuánta atención necesitan los sensores, pero no garantiza una frecuencia concreta.

2. Para que nuestra clase implemente el interface que hemos comentado añade a la declaración de la clase:

implements SensorEventListener

3. Para recibir los datos de los sensores tenemos que implementar dos métodos de la interfaz SensorEventListener:

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

 

@Override

public void onSensorChanged(SensorEvent evento) {

  //Cada sensor puede provocar que un thread principal pase por aquí

  //así que sincronizamos el acceso (se verá más adelante)

       synchronized (this) {

             switch(evento.sensor.getType()) {

             case Sensor.TYPE_ORIENTATION:

                    for (int i=0 ; i<3 ; i++) {

                           log("Orientación "+i+": "+evento.values[i]);

                    }

                    break;

             case Sensor.TYPE_ACCELEROMETER:

                    for (int i=0 ; i<3 ; i++) {

                           log("Acelerómetro "+i+": "+evento.values[i]);

                    }

                    break;

             case Sensor.TYPE_MAGNETIC_FIELD:

                    for (int i=0 ; i<3 ; i++) {

                           log("Magnetismo "+i+": "+evento.values[i]);

                    }

                    break;

             default:

                    for (int i=0 ; i<evento.values.length ; i++) {

                           log("Temperatura "+i+": "+evento.values[i]);

                    }

             }

       }

}

4. Cuando implementamos un interface estamos obligados a implementar todos sus métodos. En este caso son dos. Para onAccuracyChanged no queremos ninguna acción específica, pero lo tenemos que incluir.Cuando un sensor cambie se llamará al método onSensorChanged, aquí comprobamos qué sensor ha causado la llamada y leeremos los datos.

5. Verifica que el programa funciona correctamente.

 

Cuando el evento se dispara en el método onSensorChanged comprobamos qué sensor lo ha causado y leemos los datos. Los posibles valores devueltos se indican en la documentación de la clase SensorEvent[1].