Android,
A Complete Course, From
Basics to Enterprise Edition
Android, A Complete Course, From Basics to Enterprise
Edition
1.1 Dialoguer avec les capteurs
Cet
article est extraie du livre « Android, A Complete Course »,
disponible sur Android2ee.com.
Les
exemples ou les programmes présents dans cet ouvrage sont fournis pour
illustrer les descriptions théoriques. Ce code est libre de toute utilisation
mais n'est pas distribuable.
La
distribution du code est reservée au site :
La
propriété intellectuelle du code appartient à :
L’utilisation
de ces codes est sous votre unique responsabilité et personne d’autre que vous
ne pourra être tenu responsable des préjudices ou dommages de quelques natures
que ce soit pouvant résulter de son utilisation.
Tous
les noms de produits ou marques cités dans cet ouvrage sont des marques déposés
par leurs propriétaires respectifs.
Publié par http://android2ee.com
Titre Original : Android, A Complete Course, From
Basics to Enterprise Edition. Édition Française.
ISBN : 979-10-90388-00-0
Copyright © 2011 by Mathias Séguy
Aucune
représentation ou reproduction, même partielle, autre que celles prévues à
l’article L. 122-5 2° et 3° a) du code de la propriété intellectuelle ne peut
être faite sans l’autorisation expresse de Mathias Seguy ou, le cas échéant,
sans le respect des modalités prévues à l’article L. 122-10 dudit code
Les capteurs Android sont un nouvel axe d’interconnexion entre le monde et les applications.
Les capteurs référencés sont (et leur type associé se préfixant par Type_) :
· L’accéléromètre (Accelerometer),
· Le gyroscope (Gyroscope),
· Le luxmètre (Light),
· Le lecteur de champ magnétique (Magnetic_Field),
· La boussole (Orientation),
· Le baromètre (Pressure),
· Le lecteur de proximité (Proximity),
· Le thermomètre (Temperature).
Chacun de ces capteurs envoient des informations spécifiques à ses propres mesures, mais la gestion des capteurs est normalisée au moyen d’un même pattern.
Pour gérer les capteurs le SensorManager est la classe principale à utiliser.
Pour bien comprendre les données renvoyées par ces capteurs, la java doc est parfaite :
http://developer.android.com/reference/android/hardware/SensorManager.html
Et http://developer.android.com/reference/android/hardware/SensorEvent.html
Pour lister ou récupérer un capteur particulier, il suffit d’instancier le SensorManager et ses méthodes getSensorList ou getDefaultSensor.
/**
* The sensor manager */
SensorManager
sensorManager;
/* *
(non-Javadoc) * * @see android.app.Activity#onCreate(android.os.Bundle)
*/
@Override
protected
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Instanciate the SensorManager
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
// The find out which sensor are installed
listSensor();
}
/*
(non-Javadoc) * @see android.app.Activity#onPause() */
@Override
protected void
onPause() {
super.onPause();
//Unregister your listener
}
/************************************************************************************/
/** List existing Sensors
****************************************************************/
/************************************************************************************/
/** * Find the list of all the sensor, find a specific sensor or find
all the sensor of a specific type */
private void
listSensor() {
// First you can find all the sensors installed:
List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
// The associated string description
StringBuffer sensorDesc = new
StringBuffer();
for
(Sensor sensor : sensors) {
sensorDesc.append("New sensor detected : \r\n");
sensorDesc.append("\tName: "
+ sensor.getName() + "\r\n");
sensorDesc.append("\tType: "
+ getType(sensor.getType()) + "\r\n");
sensorDesc.append("Version: "
+ sensor.getVersion() + "\r\n");
sensorDesc.append("Resolution (in the sensor unit): " + sensor.getResolution() + "\r\n");
sensorDesc.append("Power in mA used by this sensor while in
use" + sensor.getPower() +
"\r\n");
sensorDesc.append("Vendor: "
+ sensor.getVendor() + "\r\n");
sensorDesc.append("Maximum range of the sensor in the sensor's
unit." +
sensor.getMaximumRange() + "\r\n");
sensorDesc.append("Minimum delay allowed between two events in
microsecond"
+ "
or zero if this sensor only returns a value when the data it's measuring
changes"
+
sensor.getMinDelay() + "\r\n");
}
Toast.makeText(this,
sensorDesc.toString(), Toast.LENGTH_LONG).show();
// Find a specific sensor:
Sensor gyroscopeDefault =
sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
// Find all the sensor of a specific type:
List<Sensor> gyroscopes
= sensorManager.getSensorList(Sensor.TYPE_GYROSCOPE);
}
/**
* @param
type
* the integer type
* @return the
type as a string
*/
private
String getType(int
type) {
String strType;
switch
(type) {
case
Sensor.TYPE_ACCELEROMETER: strType = "TYPE_ACCELEROMETER";break;
case
Sensor.TYPE_GRAVITY:strType = "TYPE_GRAVITY";break;
case
Sensor.TYPE_GYROSCOPE: strType = "TYPE_GYROSCOPE"; break;
case
Sensor.TYPE_LIGHT:strType = "TYPE_LIGHT";break;
case
Sensor.TYPE_LINEAR_ACCELERATION:strType = "TYPE_LINEAR_ACCELERATION";
break;
case
Sensor.TYPE_MAGNETIC_FIELD:strType = "TYPE_MAGNETIC_FIELD";break;
case
Sensor.TYPE_ORIENTATION:strType = "TYPE_ORIENTATION";break;
case
Sensor.TYPE_PRESSURE:strType = "TYPE_PRESSURE";break;
case
Sensor.TYPE_PROXIMITY: strType = "TYPE_PROXIMITY"; break;
case
Sensor.TYPE_ROTATION_VECTOR: strType = "TYPE_ROTATION_VECTOR";break;
case
Sensor.TYPE_TEMPERATURE:strType = "TYPE_TEMPERATURE";break;
default: strType = "TYPE_UNKNOW";break;
}
return
strType;
}
Pour cela, il suffit de créer un SensorEventListener et de l’enregistrer auprès du SensorManager
/**
* The sensor manager */
SensorManager
sensorManager;
/* *
(non-Javadoc) * * @see
android.app.Activity#onCreate(android.os.Bundle) */
@Override
protected
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Instanciate the SensorManager
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
// Define a sensor listener
implementSensorListener();
}
/* (non-Javadoc) * @see android.app.Activity#onPause() */
@Override
protected void
onPause() {
super.onPause();
//Unregister your listener
}
/**************************************************************************************/
/** SensorListener ***********************************************************************/
/**************************************************************************************/
private void
implementSensorListener() {
// First define the sensor you want to listen (you can listen for a
bunch of sensors)
final
Sensor listenedSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
// Then define your Listener
final
SensorEventListener sensorOrientationListener = new
SensorEventListener() {
@Override
public void
onSensorChanged(SensorEvent event) {
// First insure you are listening the right sensor
if (event.sensor.equals(listenedSensor))
{
// Find the associated accuracy
int
accuracy = event.accuracy;
switch
(accuracy) {
case
SensorManager.SENSOR_STATUS_ACCURACY_LOW:
case
SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM:
case
SensorManager.SENSOR_STATUS_ACCURACY_HIGH:
case
SensorManager.SENSOR_STATUS_UNRELIABLE:
default: break;
}
// Find the timestamp in nanosecond
long timestamp
= event.timestamp;
// Retrieve the associated values (cf javadoc)
float[] val
= event.values;
//do something with those informations
}
}
@Override
public void
onAccuracyChanged(Sensor sensor, int accuracy) {
// First insure you are listening the right sensor
if(sensor.equals(listenedSensor)){
switch
(accuracy) {
case
SensorManager.SENSOR_STATUS_ACCURACY_LOW:
case
SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM:
case
SensorManager.SENSOR_STATUS_ACCURACY_HIGH:
case
SensorManager.SENSOR_STATUS_UNRELIABLE:
default:
break;
}
//do something with those informations
}
}
};
//Register your sensor Listener in the sensorManager:
//Choose the rate: The defaukt rate
int
rate=SensorManager.SENSOR_DELAY_NORMAL;
//the rate to use for Games
rate=SensorManager.SENSOR_DELAY_GAME;
//the
fastest rate that can be set
rate=SensorManager.SENSOR_DELAY_FASTEST;
//The
rate to use to update the UI
rate=SensorManager.SENSOR_DELAY_UI;
//And
then register
sensorManager.registerListener(sensorOrientationListener,
listenedSensor, rate);
}
Chaque capteur renvoie un vecteur de données sous forme de flottant (ce vecteur peut être d’une à trois dimensions).
Le tableau ci-dessous synthétise la sémantique associée à ses vecteurs :
Nom |
Dimension du vecteur |
Unité |
Sémantique |
Values[] |
Accelerometer |
3 |
m/s2 |
Mesure de l’accélération (gravité incluse) |
[0] axe x [1] axe y [2] axe z |
Gyroscope |
3 |
Radian/second |
Mesure la rotation en termes de vitesse autour de chaque axe |
[0] vitesse angulaire autour de x [1] vitesse angulaire autour de y [2] vitesse angulaire autour de z |
Light |
1 |
Lux |
Mesure de la luminosité |
[0]valeur |
Magnetic_Field |
3 |
µTesla |
Mesure du champ magnétique |
[0] axe x [1] axe y [2] axe z |
Orientation |
3 |
degrès |
Mesure l’angle entre le nord magnétique |
[0] Azimut entre l’axe y et le nord [1] Rotation autour de l’axe x (-180,180) [2] Rotation autour de l’axe y (-90,90) |
Pressure |
1 |
KPascal |
Mesure la pression |
[0]valeur |
Proximity |
1 |
mètre |
Mesure la distance entre l’appareil et un objet cible |
[0]valeur |
Temperature |
1 |
Celsius |
Mesure la température |
[0]valeur |
Pour utiliser certains de ces capteurs un minimum de connaissance en physique est nécessaire.
Il n’y a rien de miraculeux, le code ci-dessous vous présente cette utilisation.
/**
* The sensor manager */
SensorManager
sensorManager;
/* *
(non-Javadoc) * * @see android.app.Activity#onCreate(android.os.Bundle)
*/
@Override
protected
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Instanciate the SensorManager
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
//temperaturePressureAndLight
simpleSensors();
}
/* (non-Javadoc) * @see android.app.Activity#onPause() */
@Override
protected void
onPause() {
super.onPause();
//Unregister your listener
}
/*****************************************************************************************/
/** Simple sensors
**************************************************************************/
/*****************************************************************************************/
/**
* We suppose Temperature,
Pressure and Light are on the device.
* This method shows how to use
them
*/
private void
simpleSensors(){
// First define the sensor you want to listen (you can listen for a
bunch of sensors)
final
Sensor lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
final
Sensor temperatureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
final
Sensor pressureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
// Then define your Listener
final
SensorEventListener sensorOrientationListener = new
SensorEventListener() {
@Override
public void
onSensorChanged(SensorEvent event) {
// First insure you are listening the right sensor
if (event.sensor.equals(lightSensor))
{
lightChanged(event.values[0]);
}else if(event.sensor.equals(temperatureSensor))
{
temperatureChanged(event.values[0]);
}else if(event.sensor.equals(pressureSensor))
{
pressureChanged(event.values[0]);
}
}
@Override
public void
onAccuracyChanged(Sensor sensor, int accuracy) {
//don't care something with those informations
}
};
//Register your sensor Listener in the sensorManager:
//Choose the rate: The defaukt rate
int
rate=SensorManager.SENSOR_DELAY_UI;
//And
then register
sensorManager.registerListener(sensorOrientationListener,
lightSensor, rate);
sensorManager.registerListener(sensorOrientationListener,
temperatureSensor, rate);
sensorManager.registerListener(sensorOrientationListener,
pressureSensor, rate);
}
/** * @param value */
private void
lightChanged(float
value){
//You
can use the Sensor Manager to know the intensity in human words
if(value<SensorManager.LIGHT_NO_MOON){}
else if(value<SensorManager.LIGHT_FULLMOON){}
else if(value<SensorManager.LIGHT_CLOUDY){}
else if(value<SensorManager.LIGHT_SUNRISE){}
else if(value<SensorManager.LIGHT_OVERCAST){}
else if(value<SensorManager.LIGHT_SHADE){}
else if(value<SensorManager.LIGHT_SUNLIGHT){}
else if(value<SensorManager.LIGHT_SUNLIGHT_MAX){}
else{}
Toast.makeText(this, "new luminosity :"+value+"
lux", Toast.LENGTH_SHORT).show();
}
/** * @param value */
private void
temperatureChanged(float
value){
Toast.makeText(this, "new temperature :"+value+"°C", Toast.LENGTH_SHORT).show();
}
/** * @param value */
private void
pressureChanged(float
value){
Toast.makeText(this, "new pressure :"+value+"°KP
(KiloPascal)", Toast.LENGTH_SHORT).show();
}
Mettez vous à la physique, ici, le problème n’est pas l’informatique mais la physique sous-jacente que vous allez manipuler.
L’accéléromètre permet de mesurer le champ d’accélération qui entoure l’appareil. Ce champ étant tridimensionnel, les valeurs sont renvoyées sous forme d’un vecteur (x,y,z). À partir de l’accélération, vous ne pouvez détecter directement le vecteur vitesse. Pour cela, vous devez obtenir une vitesse référence (aucun mouvement) puis recalculer votre vitesse courante en utilisant les valeurs de l’accéléromètre et le temps entre deux mesures.
Remarque : si l’accéléromètre est
suffisamment précis, vous pouvez connaitre l’altitude grâce à lui :
Altitude=
Remarque : L’exemple Android suivant
montre une application où des billes sont dirigées par l’accéléromètre. http://developer.android.com/resources/samples/AccelerometerPlay/src/com/example/android/accelerometerplay/AccelerometerPlayActivity.html