La plataforma Android dispone de un interesante sistema de posicionamiento que combina varias tecnologías:
Sistema de localización global basado en GPS. Este sistema solo funciona si disponemos de visibilidad directa de los satélites.
Sistema de localización basado en la información recibida de las torres de telefonía celular y de puntos de acceso Wi-Fi. Funciona en el interior de los edificios.
Estos servicios se encuentran totalmente integrados en el sistema y son usados por gran variedad de aplicaciones. Por ejemplo, la aplicación Locale[1] de Android puede adaptar la configuración del teléfono según donde se encuentre. Podría por ejemplo poner el modo de llamada en vibración cuando estemos en el trabajo.
El sistema de posicionamiento global, GPS, fue diseñado inicialmente con fines militares pero hoy en día es ampliamente utilizado para uso civil. Gracias al desfase temporal de las señales recibidas por varios de los 31 satélites desplegados, este sistema es capaz de posicionarnos en cualquier parte del planeta con una precisión de 15 metros.
El GPS presenta un inconveniente; solo funciona cuando tenemos visión directa de los satélites. Para solventar este problema, Android combina esta información con la recibida de las torres de telefonía celular y de puntos de acceso Wi-Fi.
Ejercicio paso a paso: El API de localización de Android.
En este ejercicio crearemos una aplicación que es capaz de leer información de localización del dispositivo y actualizarla cada vez que se produce un cambio.
1. Crea un nuevo proyecto con los siguientes datos:
Project Name: Localizacion
Package Name: org.example.localizacion
Minimun Requiered SDK: API 7: Android 2.1 (Eclair)
Compile With: API 19: Android 4.4
2. Por razones de privacidad acceder a la información de localización está en principio prohibido a las aplicaciones. Si estas desean hacer uso de este servicio han de solicitar el permiso adecuado. En concreto hay que solicitarACCESS_FINE_LOCATION para acceder a cualquier tipo de sistema de localización o ACCESS_FINE_LOCATION para acceder al sistema de localización basado en redes. Puedes hacerlo a través de los cuadros de diálogos, como se muestra a continuación:
o añadiendo la siguiente línea en el fichero AndroidManifest.xml dentro de la etiqueta <application>:
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"/>
Por lo tanto en este ejemplo vamos autilizar, tanto la localización fina, que nos proporciona el GPS, como una menos precisa,que nos proporcionada las torres de telefonía celular y las redes WiFi.
3. Sustituye el fichero res/layout/activity_main.xml por:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/salida"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
En este ejemplo nos limitaremos a mostrar en modo de texto la información obtenida desde el API de localización. Para ello usaremos un TextView dentro de un ScrollView, tal y como se muestra en la siguiente pantalla:
4. Abre la clase MainActivity y copia el siguiente código:
public class MainActivity extends Activity implements LocationListener {
private static final long TIEMPO_MIN = 10 * 1000 ; // 10 segundos
private static final long DISTANCIA_MIN = 5 ; // 5 metros
private static final String[] A = { "n/d", "preciso", "impreciso" };
private static final String[] P = { "n/d", "bajo", "medio","alto" };
private static final String[] E = { "fuera de servicio",
"temporalmente no disponible ","disponible" };
private LocationManager manejador;
private String proveedor;
private TextView salida;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
salida = (TextView) findViewById(R.id.salida);
manejador = (LocationManager) getSystemService(LOCATION_SERVICE);
log("Proveedores de localización: \n ");
muestraProveedores();
Criteria criterio = new Criteria();
criterio.setCostAllowed(false);
criterio.setAltitudeRequired(false);
criterio.setAccuracy(Criteria.ACCURACY_FINE);
proveedor = manejador.getBestProvider(criterio, true);
log("Mejor proveedor: " + proveedor + "\n");
log("Comenzamos con la última localización conocida:");
Location localizacion = manejador.getLastKnownLocation(proveedor);
muestraLocaliz(localizacion);
}
La primera línea que nos interesa es la llamada a getSystemService(LOCATION_SERVICE) que crea el objeto manejador de tipo LocationManager. La siguiente llamada a muestraProveedores() también es un método definido por nosotros, que listará todos los proveedores de localización disponibles.
En las tres siguientes líneas vamos a seleccionar uno de estos proveedores de localización. Comenzamos creando un objeto de la clase Criteria, donde se podrá indicar las características que ha de tener el proveedor buscado. En este ejemplo indicamosque no ha de tener coste económico, ha de poder objener la altura y ha de tener precisión fina. Para consultar otras restricciones, consultar documentación denla clase Criteria[1]. Con estas restricciones parece que estamos intersados en el proveedor basado en GPS, aunque de no estar disponible, se seleccionará otro que cumpla el mayor número de restricciones. Para seleccionar el proveedor usaremos el método getBestProvider(). En este método hay que indicar el criterio de selección y un valor booleano, donde indicamos si solo nos interesa los sistemas que el usuario tenga actualmente habilitados. Nos devolverá un Stringcon el nombre del proveedor seleccionado.
La siguiente línea hace una llamada al método log() que será definido más adelante. Simplemente muestra por el TextView, salida, el texto indicado.
Algunos proveedores, como el GPS, puedentardar un cierto tiempo en darnos una primera posición. No obstante, Android recuerda la última posición que fue devuelta por este proveedor. Es lo que nos devuelve la llamada a getLastKnownLocation(). El método muestraLocaliz() será definido más tarde y muestra en pantalla una determinada localización.
5. Copia a continuación el resto del código:
// Métodos del ciclo de vida de la actividad
@Override protected void onResume() {
super.onResume();
// Activamos notificaciones de localización
manejador.requestLocationUpdates(proveedor, TIEMPO_MIN, DISTANCIA_MIN, this);
}
@Override protected void onPause() {
super.onPause();
manejador.removeUpdates(this);
}
// Métodos de la interfaz LocationListener
public void onLocationChanged(Location location) {
log("Nueva localización: ");
muestraLocaliz(location);
}
public void onProviderDisabled(String proveedor) {
log("Proveedor deshabilitado: " + proveedor + "\n");
}
public void onProviderEnabled(String proveedor) {
log("Proveedor habilitado: " + proveedor + "\n");
}
public void onStatusChanged(String proveedor, int estado,
Bundle extras) {
log("Cambia estado proveedor: " + proveedor + ", estado="
+ E[Math.max(0,estado)] + ", extras=" + extras +"\n");
}
// Métodos para mostrar información
private void log(String cadena) {
salida.append(cadena + "\n");
}
private void muestraLocaliz(Location localizacion) {
if (localizacion == null)
log("Localización desconocida\n");
else
log(localizacion.toString() + "\n");
}
private void muestraProveedores() {
log("Proveedor de localización: \n");
List<String> proveedores = manejador.getAllProviders();
for (String proveedor : proveedores) {
muestraProveedor(proveedor);
}
}
private void muestraProveedor(String proveedor) {
LocationProvider info = manejador.getProvider(proveedor);
log("LocationProvider[ "+"getName=" + info.getName()
+ ", isProviderEnabled="
+ manejador.isProviderEnabled(proveedor)+", getAccuracy="
+ A[Math.max(0, info.getAccuracy())]+ ", getPowerRequirement="
+ P[Math.max(0, info.getPowerRequirement())]
+", hasMonetaryCost=" + info.hasMonetaryCost()
+ ", requiresCell=" + info.requiresCell()
+ ", requiresNetwork=" + info.requiresNetwork()
+ ", requiresSatellite=" + info.requiresSatellite()
+ ", supportsAltitude=" + info.supportsAltitude()
+ ", supportsBearing=" + info.supportsBearing()
+ ", supportsSpeed=" + info.supportsSpeed()+" ]\n");
}
}
Para conseguir que se notifiquen cambios de posición hay que llamar al métodorequestLocationUpdates() y para indicar que se dejen de hacer las notificaciones hay que llamar aremoveUpdates(). Dado que queremos ahorrar batería nos interesa que se reporten notificaciones solo cuando la aplicación esté activa. Por lo tanto tenemos que reescribir los métodos onResume() yonPause().
El método requestLocationUpdates() dispone de 4 parámetros: el nombre del proveedor, el tiempo entre actualizaciones en ms (se recomienda valores mayores de 60.000 ms), la distancia mínima (de manera que si es menor, no se notifica) y un escuchador de evenos que implemente el interfaceLocationListener.
Como nuestra actividad es un LocationListener tenemos que implementar los siguientes métodos:onLocationChanged() se activará cada vez que se obtenga una nueva posición. Los otros tres métodos pueden ser usados para cambiar de proveedor en caso de que se active uno mejor o deje de funcionar el actual. Sería buena idea llamar de nuevo aquí al método getBestProvider().
El resto del código resulta fácil de interpretar.
6. Verifica el funcionamiento del programa, si es posible con un dispositivo real con el GPS activado.
[1] http://developer.android.com/reference/android/location/Criteria.html