Diferencia entre revisiones de «PDM Avanzado Xeolocalización»

De MediaWiki
Ir a la navegación Ir a la búsqueda
(Página creada con «==Introdución== A xeolocalización e un servizo que nos proporciona Android e vai permitir saber cal é a nosa posición en forma de coordenadas (latitude e lonxitude)....»)
 
(Emulador)
 
Línea 38: Línea 38:
 
===Emulador===
 
===Emulador===
  
* Se estades a utilizar o emulador, deberedes ir á vista DDMS e premer sobre a lapela '''Emulator Control''':
+
* Se estades a utilizar o emulador, deberedes premer sobre os puntos suspensivos:
  
 
[[Imagen:PDM_Avanzada_GPS_2.jpg | 800px | center]]
 
[[Imagen:PDM_Avanzada_GPS_2.jpg | 800px | center]]

Revisión actual del 14:22 10 nov 2019

Introdución

A xeolocalización e un servizo que nos proporciona Android e vai permitir saber cal é a nosa posición en forma de coordenadas (latitude e lonxitude).


Temos diferentes formas de obter a localización:

  • Localización por GPS.
  • A través das antenas de telefonía móbil.
  • Mediante puntos de acceso WIFI cercanos.

Cada unha destas formas leva consigo consumo de baterías e precesión diferentes.

Veremos máis adiante que podemos solicitar información ó noso dispositivo para que nos indique cal é o provedor que se adapta a algún criterio indicado por nos (como precisión alta, por exemplo).


Envío de coordenadas GPS ó dispositivo

Na práctica que imos desenvolver nesta unidade imos ter que enviarlle ó dispositivo información GPS falsa para simular que nos estamos movendo.

Para facelo, teremos que ter en conta o tipo de dispositivo:

Dispositivo real ou máquina de VirtuaBox

  • Se o dispositivo é real ou estades a utilizar a máquina virtual suministrada (neste caso o software xa está instalado):
O funcionamento desta aplicación é moi sinxelo.
  • Primeiro deberemos abrir dita aplicación, antes de executar a aplicación que queiramos enganar.
  • Unha vez aberta debemos mover o mapa (co rato, arrastrando) e cando esteamos situados no punto que nos interesa premer o botón Set Location.
  • Ó facelo a aplicación se minimiza e aparece unha icona (parte inferior dereita). Podemos volver a abrila dende alí.
  • Se queremos saír da aplicación debemos premer o botón de Stop.
PDM Avanzada GPS 3.jpg

Emulador

  • Se estades a utilizar o emulador, deberedes premer sobre os puntos suspensivos:
PDM Avanzada GPS 2.jpg
Nesta pantalla podedes escribir as coordenadas GPS e enviarllas ó dispositivo premendo o botón de 'Send'. Existen arquivos GPX e KML que se poden xerar ou descargar de Internet e son un conxunto de coordenadas GPS que se envían cada certo tempo de forma automática.

Xeolocalización

Permisos nececesarios

O primeiro de todo será engadir ó arquivo AndroidManifiest.xml os permisos necesarios.

Estes son:

1 	<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2 	<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />


Formas de localización: Provedores

Os provedores de localización (Location Providers) vannos servir para obter a información sobre a localización do dispositivo.

Os máis coñecidos son os de GPS e localización mediante telefonía, pero podemos ter outros.

A clase que imos utilizar para obter os provedores é a clase LocaltionManager.

Para obtela teremos que poñer:

1 LocationManager locManager = (LocationManager)getSystemService(LOCATION_SERVICE);

e para obter os provedores:

1 List<String> listaProviders = locManager.getAllProviders();

Isto devolve todos os nomes (String) dos provedores do dispositivo. Temos que ter en conta que nesta lista aparecerán provedores ós que poda que non teñamos acceso (por non ter os permisos postos no AndroidManifiest) e provedores que pode que non estean activados.


Unha vez temos os nomes podemos obter as características específicas de cada un.

Lembrar que comentamos antes que cada provedor pode ter características de precisión, consumo de enerxía.

1 LocationProvider locProv = locManager.getProvider(LocationManager.GPS_PROVIDER);

Neste caso estamos a utilizar unha constante definida na clase LocationManager que ten de valor 'gps'. Esta cadea sería unha das que teríamos na lista de provedores do paso anterior.

Agora sobre dito provedor podemos:

  • Obter a súa precisión: Método getAccuracy():
Devolve un valor que pode ser comparado con:
  • Criteria.ACCURACY_FINE: Precisión alta.
  • Criteria.ACCURACY_COARSE: Precisión media.
  • Criteria.ACCURACY_LOW: Precisión baixa.


  • Saber se se pode obter a altitude: Método supportsAltitude(): Devolve un boolean.
  • Saber se se pode obter información da velocidade: Método supportsSpeed(): Devolve un boolean.

.... Nota: Veremos máis adiante que a información da velocidade e altitude as podemos obter do obxecto pertencente á clase Location.

  • Obter o seu nivel de consumo de batería: Método getPowerRequirement():
Devolve un valor que pode ser comparado con:
  • Criteria.POWER_HIGH: Alto consumo de enerxía.
  • Criteria.POWER_MEDIUM: Medio consumo de enerxía.
  • Criteria.POWER_LOW: Baixo consumo de enerxía.


Obter o mellor provedor: Criterios de selección

Máis información en: http://developer.android.com/reference/android/location/Criteria.html

Existe una forma de, en base a unha serie de criterios (consumo, precisión...), obter un provedor que se adapte a eles.

Por exemplo:

1 Criteria filtro = new Criteria();
2 filtro.setAccuracy(Criteria.ACCURACY_FINE);
3 filtro.setAltitudeRequired(true);

Agora podemos chamar ós métodos que nos van devolver os nomes dos provedores que cumpran os criterios anteriores:

1 String provConFiltro= locManager.getBestProvider(filtro, false);

ou ben:

1 List<String> listaProvConFiltro = locManager.getProviders(filtro, false);

Nota: A segunda forma pode devolver máis dun.

O segundo parámetro é un boolean que indica se queremos que teña en conta aqueles provedores que se atopan desactivados.

E por que vou querer obter un provedor desactivado ?

Porque vou a informar ó usuario desa circunstancia e darlle a opción de activalo (por exemplo o uso do GPS).


Como activar un provedor

Unha vez que sabemos cal provedor queremos utilizar teremos que saber se dito provedor (partimos que base que enviamos false como segundo parámetro ó método getProvider, como vimos antes) está activo e informar ó usuario de que o active.

Para isto dispoñemos do método isProviderEnabled(String provedor).

Algúns dos nomes que podemos utilizar (se queremos buscar por un provedor concreto):

  • LocationManager.NETWORK_PROVIDER. Localización pola rede de telefonía.
  • LocationManager.GPS_PROVIDER. Localización por GPS.

Por exemplo:

1 if (!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
2     Toast.makeText(getApplicationContext(), "O GPS non está activo", Toast.LENGTH_LONG).show();
3 }


No caso de non estar activo podemos dar ó usuario a opción de activalo chamando á activity:

1 startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));

Obtendo a localización: Interface LocationListener

Subscrición a un provedor

En Android,a forma de obter a localización a través dun provedor escollido no paso anterior, consiste en subscribirse ás notificacións de cambio de posición.

Unha vez subscrito automaticamente chamará a certo método en base a unha serie de criterios establecidos previamente (cambio de posición, cada certo tempo,...)

Non sabemos cando teremos a primeira información xa que dependeremos dos criterios elixidos e do tempo que tarde o dispositivo en empezar a recibir datos (por exemplo, cando activamos o GPS ten que esperar a localizar as sinais dos satélites,...)


Unha forma de obter unha localización inicial é chamando ó método getLastKnownLocation(String provider) o cal devolve a última localización rexistrada do provedor indicado:

1 		Location location = locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

Este método non devolve a posición actual, non solicita unha nova posición ó provedor de localización.

Este método se limita a devolver a última posición que se obtivo a través do provedor que se lle indica como parámetro.

Temos que ter coidado con dito método xa que pode devolver null se nunca obtivemos unha localización có provedor indicado.



Para subscribirnos ó servizo de notificacións do provedor debemos facer uso do método requestLocationUpdates() da clase LocationManager.

Este método está sobrecargado e temos varias posibilidades. Nos imos ver unha delas.

  • public void requestLocationUpdates (String provider, long minTime, float minDistance, LocationListener listener)
Este método leva 4 parámetros:
  • String provider: Nome do provedor.
  • long minTime: Tempo en mseg que pasará ata enviar novos datos de localización. Se se pon 0 non terá en conta este criterio. O fai aproximadamente (non é exacto).
  • float minDistance: Distancia en metros que ten haber dende a última posición enviada. Se se pon 0 non terá en conta este criterio. O fai aproximadamente (non é exacto).
  • LocationListener listener: Clase que implementa dita interface. Dentro desta interface teremos diferentes métodos.

Xa vimos no curso de iniciación as diferentes formas de implementar unha interface.

Por exemplo:

1 LocationManager locManager = (LocationManager)getSystemService(LOCATION_SERVICE);
2 locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,0,100,this);

Neste caso estamos a subscribirnos ó provedor GPS para que envío notificacións cada vez que nos movemos máis de 100 metros con respecto a unha localización anterior.

A activity onde se atopa o código anterior ten que implementar a interface LocationListener.

Interface LocationListener

Tal como comentamos antes, cando chamamos ó método requestLocationUpdates debemos indicar a clase que implementa a interface LocationListener.

Ó facelo, obriga a interface a implementar os seguintes métodos:

  • onLocationChanged(location). Chamado cada vez que se recibe unha actualización da posición.
  • onProviderDisabled(provider). Chamado cando o provedor se deshabilita.
  • onProviderEnabled(provider). Chamado cando el provedor se habilita.
  • onStatusChanged(provider, status, extras). Chamado cada vez que o provedor cambia o seu estado, que pode variar entre OUT_OF_SERVICE, TEMPORARILY_UNAVAILABLE,AVAILABLE.

Exemplo de código:

 1 	@Override
 2 	public void onLocationChanged(Location location) {
 3 		// TODO Auto-generated method stub
 4 		// location.getLatitude(): obtemos a nova latitude
 5                 // location.getLongitude(): obtemos a nova lonxitude
 6 	}
 7 
 8 
 9 	@Override
10 	public void onProviderDisabled(String provider) {
11 		// TODO Auto-generated method stub
12 		Toast.makeText(getApplicationContext(), "O provedor " + provider + " xa non está activo", Toast.LENGTH_LONG).show();
13 	}
14 
15 
16 	@Override
17 	public void onProviderEnabled(String provider) {
18 		// TODO Auto-generated method stub
19 		Toast.makeText(getApplicationContext(), "O provedor " + provider + " está activo", Toast.LENGTH_LONG).show();
20 		
21 	}
22 
23 
24 	@Override
25 	public void onStatusChanged(String provider, int status, Bundle extras) {
26 		// TODO Auto-generated method stub
27 		Toast.makeText(getApplicationContext(), "O provedor " + provider + " cambió  de estado:" + String.valueOf(status), Toast.LENGTH_LONG).show();
28 		
29 	}


Dentro deste código cabe sinalar o método:

  • public void onLocationChanged(Location location)

Como comentamos, o obxecto da clase Location vai ter a información sobre a nosa localización.



Eliminado a subscrición a un provedor

Para parar de 'escoitar' notificacións dun provedor debemos chamar ó método removeUpdates(String provedor).

Por exemplo:

1 locManager.removeUpdates(LocationManager.GPS_PROVIDER);

Loxicamente teremos que facer isto antes de saír da aplicación para liberar os recursos.

Caso práctico

Nesta práctica imos a recoller nunha lista os cambios de posición GPS cando nos movamos máis de 300 metros.

Teremos un botón para empezar a recoller datos (subscribirnos) e outro botón para o contrario (eliminar subscrición).

PDM Avanzada GPS 1.jpg


Tal como comentamos antes:

  • Teremos que ter instalar e executada a aplicación 'Fake GPS' ou ben utilizar un emulador.
  • Teremos que engadir no arquivo AndroidManifiest.xml os permisos necesarios.


Creamos a activity

  • Nome do proxecto: UD10_01_Xeo
  • Nome da activity: UD10_01_Xeo.java


Código do layout xml

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     tools:context="${relativePackage}.${activityClass}" >
 6 
 7     <Button
 8         android:id="@+id/UD10_01_btnRexistrarGPS"
 9         android:layout_width="wrap_content"
10         android:layout_height="wrap_content"
11         android:layout_alignParentTop="true"
12         android:layout_centerHorizontal="true"
13         android:text="REXISTRAR GPS" />
14 
15     <Button
16         android:id="@+id/UD10_01_btnPararRexistro"
17         android:layout_width="wrap_content"
18         android:layout_height="wrap_content"
19         android:layout_below="@+id/UD10_01_btnRexistrarGPS"
20         android:layout_centerHorizontal="true"
21         android:layout_marginTop="16dp"
22         android:text="PARAR REXISTRO GPS" />
23 
24         <ListView
25         android:id="@+id/UD10_01_lstListaCoordGPS"
26         android:layout_width="match_parent"
27         android:layout_height="wrap_content"
28         android:background="@android:color/darker_gray"
29         android:layout_centerHorizontal="true"
30         android:layout_marginTop="10dp"
31         android:layout_below="@+id/UD10_01_btnPararRexistro" >
32         
33     </ListView>
34     
35 </RelativeLayout>


Código da clase UD10_01_Xeo
Obxectivo: Subscribirse ó provedor GPS e rexistrar as coordenadas GPS.

  1 import java.util.ArrayList;
  2 
  3 import android.app.Activity;
  4 import android.app.AlertDialog;
  5 import android.content.DialogInterface;
  6 import android.content.Intent;
  7 import android.location.Criteria;
  8 import android.location.Location;
  9 import android.location.LocationListener;
 10 import android.location.LocationManager;
 11 import android.os.Bundle;
 12 import android.view.View;
 13 import android.view.View.OnClickListener;
 14 import android.widget.ArrayAdapter;
 15 import android.widget.Button;
 16 import android.widget.ListView;
 17 import android.widget.Toast;
 18 
 19 public class UD10_01_Xeo extends Activity implements LocationListener{
 20 
 21 	private ArrayList<String> localizacions;
 22 	private ArrayAdapter<String> adaptador;
 23 	
 24 	private LocationManager locManager;
 25 	private String provedor;
 26 	
 27 	private void obterprovedores(){
 28 		Criteria filtro = new Criteria();
 29 		filtro.setAccuracy(Criteria.ACCURACY_FINE);
 30 
 31 		locManager = (LocationManager)getSystemService(LOCATION_SERVICE);
 32 		
 33 		provedor = locManager.getBestProvider(filtro, false);	// Se non está activo o avisamos e chamamos a activity para activalo 
 34 //		provedor = LocationManager.NETWORK_PROVIDER;	=> Exemplo concreto sen filtro
 35 		
 36 		if (provedor==null){
 37 			Toast.makeText(getApplicationContext(), "Non existen provedores dispoñibles.", Toast.LENGTH_LONG).show();
 38 			finish();
 39 		}
 40 		if (!locManager.isProviderEnabled(provedor)){
 41 			Toast.makeText(getApplicationContext(), "O " + provedor + " non está activo", Toast.LENGTH_LONG).show();
 42 			dialogoAlertaNonGPS();
 43 		}
 44 		else{
 45 			Toast.makeText(getApplicationContext(), "provedor atopado:" + provedor, Toast.LENGTH_LONG).show();
 46 		}
 47 	}
 48 
 49 	private void dialogoAlertaNonGPS() {
 50 		final AlertDialog.Builder builder = new AlertDialog.Builder(this);
 51 		builder.setMessage(
 52 				"O GPS parece desactivado, queres activalo ?")
 53 				.setCancelable(false)
 54 				.setPositiveButton("Si",
 55 						new DialogInterface.OnClickListener() {
 56 							@Override
 57 							public void onClick(DialogInterface arg0, int arg1) {
 58 								// TODO Auto-generated method stub
 59 								startActivity(new Intent(
 60 										android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
 61 								
 62 							}
 63 						})
 64 				.setNegativeButton("Non", new DialogInterface.OnClickListener() {
 65 
 66 					@Override
 67 					public void onClick(DialogInterface dialog, int which) {
 68 						// TODO Auto-generated method stub
 69 						dialog.cancel();
 70 						UD10_01_Xeo.this.finish();
 71 						
 72 					}
 73 				});
 74 		final AlertDialog alert = builder.create();
 75 		alert.show();
 76 	}
 77 
 78 	private void xestionarEventos(){
 79 		
 80 		Button btnRexistrar = (Button)findViewById(R.id.UD10_01_btnRexistrarGPS);
 81 		btnRexistrar.setOnClickListener(new OnClickListener() {
 82 			
 83 			@Override
 84 			public void onClick(View arg0) {
 85 				// TODO Auto-generated method stub
 86 				locManager.requestLocationUpdates(provedor,0,100,UD10_01_Xeo.this);
 87 				Toast.makeText(getApplicationContext(), "Comenzado a rexistrar...", Toast.LENGTH_SHORT).show();
 88 
 89 				Location last =locManager.getLastKnownLocation(provedor); 
 90 				if (last!=null)
 91 					localizacions.add("ULTIMA COÑECIDA: LAT:" + String.valueOf(last.getLatitude()) + " - LONX:" + String.valueOf(last.getLongitude()));
 92 
 93 			}
 94 		});
 95 		
 96 		Button btnPararRexistrar = (Button)findViewById(R.id.UD10_01_btnPararRexistro);
 97 		btnPararRexistrar.setOnClickListener(new OnClickListener() {
 98 			
 99 			@Override
100 			public void onClick(View v) {
101 				// TODO Auto-generated method stub
102 				locManager.removeUpdates(UD10_01_Xeo.this);
103 				Toast.makeText(getApplicationContext(), "Parando de rexistrar...", Toast.LENGTH_SHORT).show();
104 			}
105 		});
106 		
107 	}
108 	
109 	
110     @Override
111     protected void onCreate(Bundle savedInstanceState) {
112         super.onCreate(savedInstanceState);
113         setContentView(R.layout.activity_ud10_01__xeo);
114     
115         localizacions = new ArrayList<String>();
116         adaptador = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, localizacions);
117         ListView listaGPS = (ListView)findViewById(R.id.UD10_01_lstListaCoordGPS);
118         listaGPS.setAdapter(adaptador);
119         
120         obterprovedores();	
121         xestionarEventos();
122     }
123 
124 
125 	@Override
126 	public void onLocationChanged(Location location) {
127 		// TODO Auto-generated method stub
128 		localizacions.add("LATITUDE:" + String.valueOf(location.getLatitude()) + " - LONXITUDE:" + String.valueOf(location.getLongitude()));
129 		adaptador.notifyDataSetChanged();
130 	}
131 
132 
133 	@Override
134 	public void onProviderDisabled(String provider) {
135 		// TODO Auto-generated method stub
136 		Toast.makeText(getApplicationContext(), "O provedor " + provider + " xa non está activo", Toast.LENGTH_LONG).show();
137 	}
138 
139 
140 	@Override
141 	public void onProviderEnabled(String provider) {
142 		// TODO Auto-generated method stub
143 		Toast.makeText(getApplicationContext(), "O provedor " + provider + " está activo", Toast.LENGTH_LONG).show();
144 		
145 	}
146 
147 
148 	@Override
149 	public void onStatusChanged(String provider, int status, Bundle extras) {
150 		// TODO Auto-generated method stub
151 		
152 	}
153 }
  • Liña 21: Array onde gardamos a lista de coordenadas GPS e que se van cargar na ListView.
  • Liña 22: Adaptador asociado ó ListView.
  • Liña 25: Nome do provedor a utilizar.
  • Liñas 27-47: Obtemos un provedor en base ó criterio de precisión alta. Gardamos o nome do provedor atopado la propiedade provedor.
  • Liñas 49-76: Caixa de diálogo que aparece en caso de que o provedor estea inactivo.
  • Liña 86: Subscribimos ó provedor ó facer click no botón.
  • Liña 102: Eliminamos a subscrición do provedor ó facer click no botón.
  • Liña 128: Engadimos á lista de localizacións a nova localización.
  • Liña 129: Notificamos ó adaptador que hai un cambio nos datos para que a lista se recargue.




-- Ángel D. Fernández González e Carlos Carrión Álvarez -- (2014).