Pegando a posição GPS no Android
Um recurso muito interessante de se manipular em um dispositivo mobile é o seu posicionamento GPS(Global Positioning System) que fornece coordenadas de Latitude e Longitude permitindo criar aplicações que com base onde você está se comporta de maneira diferente ou gera resultados diferentes.Para começarmos devemos saber que um dispositivo Android possui uma classe para trabalharmos com localização, a classe LocationManager
, esta classe não deve ser instanciada por nós, mas sim recuperada do sistema através do método:
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Para ela funcionar corretamente devemos adicionar no nosso AndroidManifest.xml
as seguintes permissões
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Para acessar somente a localização pela Rede.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Para acessar a localização pela Rede e pelo GPS do dispositivo
Como vimos nas permissões acima podemos pegar a posição do dispositivo de diversas fontes, que chamamos de location provider, podemos listar todos os location provider através do siguinte método:
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
for(String provider : locationManager.getAllProviders()){
Toast.makeText(getApplicationContext(), provider, Toast.LENGTH_LONG).show();
}
Normalmente deve retornar 3 tipos de location provider:
- passive(CellID, WiFi MACID): Este provider utiliza a posição adquirida por outro programa ou serviço, sem propriamente pedir uma nova posição para o sistema. Pode ser representado pela constante LocationManager.PASSIVE_PROVIDER.
- network (AGPS, CellID, WiFi MACID): Este provider utiliza a disponibilidade de torres de celular e pontos de acesso Wi-Fi para determinar uma posição. Pode ser representado pela constante LocationManager.NETWORK_PROVIDER.
- gps (GPS, AGPS): Este provider utiliza os satélites GPS para determinar uma posição. Pode demorar um tempo para determinar a posição. Pode ser representado pela constate LocationManager.GPS_PROVIDER.
Precisão | Uso de Energia | Tecnologia |
---|---|---|
20ft ou 6m | Alta | GPS, Provider: gps
|
200ft ou 60m | Média Baixa | GPS assistido (AGPS), Provider: network
|
5300ft ou 1.6km | Baixa | CellID lookup/WiFi MACID lookup, Provider: network or passive
|
Pegando uma posição
Agora que já sabemos as características dos provideres de onde pegar a posição do dispositivo vamos fazer uma unica requisição:
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER , new LocationListener() {
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
Toast.makeText(getApplicationContext(), "Status alterado", Toast.LENGTH_LONG).show();
}
@Override
public void onProviderEnabled(String arg0) {
Toast.makeText(getApplicationContext(), "Provider Habilitado", Toast.LENGTH_LONG).show();
}
@Override
public void onProviderDisabled(String arg0) {
Toast.makeText(getApplicationContext(), "Provider Desabilitado", Toast.LENGTH_LONG).show();
}
@Override
public void onLocationChanged(Location location) {
TextView latitude = (TextView) findViewById( R.id.latitude);
TextView longitude = (TextView) findViewById( R.id.longitude);
TextView time = (TextView) findViewById( R.id.time);
TextView acuracy = (TextView) findViewById( R.id.Acuracy);
TextView provider = (TextView) findViewById( R.id.provider);
if( location != null ){
latitude.setText( "Latitude: "+location.getLatitude() );
longitude.setText( "Longitude: "+location.getLongitude() );
acuracy.setText( "Precisão: "+location.getAccuracy()+"" );
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
time.setText( "Data:"+sdf.format( location.getTime() ) );
provider.setText( location.getProvider());
}
}
}, null );
Como vemos na linha 3 chamamos o método requestSingleUpdate
de nosso locationManager
que recebe dois parâmetros, o primeiro é qual provider ele de deverá utiliza e o segundo parâmetro devera ser um objeto que implemente LocationListener
do qual serão chamados certos métodos quando determinados eventos acontecerem.
A interface LocationListener
nos obriga a implementar os seguintes métodos:
- onProviderDisabled(String provider): será chamado quando o provider for desabilitado pelo usuário. Pode ser um bom lugar para iniciar uma nova requisição de posição por outro provider.
- onProviderEnabled (String provider): será chamado quando o provider for habilitado pelo usuário.
- onStatusChanged (String provider, int status, Bundle extras): será chamado quando o status do provider for alterado ou seja quando o provider for incapaz de travar uma posição ou se o ele foi recentemente disponível após um período de indisponibilidade. Como parâmetro status será passado uma das constantes
LocationProvider.OUT_OF_SERVICE
se o serviço está fora e não há previsão para voltar,LocationProvider.TEMPORARILY_UNAVAILABLE
se o serviço está indisponível mas deve voltar em breve eLocationProvider.AVAILABLE
se o serviço esta disponível agora. - onLocationChanged (Location location): será chamando quando uma posição for travada, passando como parâmetro para o método um objeto
Location
que representa a posição com todas as suas informações.
Location
O objeto Location
que o método onLocationChanged
recebe de parâmetro e representa a posição travada e podemos chamar os seguintes métodos para pegarmos as suas informações.
- location.getLatitude(): Retorna a coordenada de latitude.
- location.getLongitude(): Retorna a coordenada de longitude.
- location.getTime(): Retorna o tempo UTC de quando a posição foi travada, em millisegundos desde Janeiro 1, 1970.(O mesmo modo de armazenamento de tempo da classe
Date
). - location.getAltitude(): Retorna a altitude em metros se disponível, senão retorna 0.0 .
- getProvider() Retorna qual provider que gerou a posição. Útil quando utilizamos o provider passive.
- getSpeed(): Retorna a velocidade de deslocamento em metros se disponível, senão 0.0 .
- location.getAccuracy(): Retorna a precisão aproximada do ponto em metros. A precisão é dada traçando um circulo tendo como o centro a latitude e longitude e a accuracy como raio há a probabilidade de 68% da posição verdadeira esta dentro deste circulo.
Pegando sequencia de posições
Em alguns casos precisamos de posições periódicas, ou das posições de x em x metros para traçar uma rota por exemplo, para isso temos um outro método no objeto LocationManager
o requestLocationUpdates
.
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
long tempo = 1000 * 5; //5 minutos
float distancia = 30; // 30 metros
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER , tempo , distancia, new LocationListener() {
@Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
Toast.makeText(getApplicationContext(), "Status alterado", Toast.LENGTH_LONG).show();
}
@Override
public void onProviderEnabled(String arg0) {
Toast.makeText(getApplicationContext(), "Provider Habilitado", Toast.LENGTH_LONG).show();
}
@Override
public void onProviderDisabled(String arg0) {
Toast.makeText(getApplicationContext(), "Provider Desabilitado", Toast.LENGTH_LONG).show();
}
@Override
public void onLocationChanged(Location location) {
TextView numero = (TextView) findViewById( R.id.numero);
TextView latitude = (TextView) findViewById( R.id.latitude);
TextView longitude = (TextView) findViewById( R.id.longitude);
TextView time = (TextView) findViewById( R.id.time);
TextView acuracy = (TextView) findViewById( R.id.Acuracy);
if( location != null ){
locs.add(location);
numero.setText( "Número de posições travadas: "+locs.size() );
latitude.setText( "Latitude: "+location.getLatitude() );
longitude.setText( "Longitude: "+location.getLongitude() );
acuracy.setText( "Precisão: "+location.getAccuracy()+"" );
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
time.setText( "Data:"+sdf.format( location.getTime() ) );
}
}
}, null );
Como podemos ver fizemos alteração em apenas uma linha onde trocamos o método chamado e passamos dois novos parâmetros:requestLocationUpdates(String provider, long minTime, float minDistance, LocationListener listener)
- minTime: tempo minimo entre as atualizações de posição, em milissegundos
- minDistance: distância minima entre as atualizações, em metros.
Neste ponto podemos acrescentar que será atualizada a posição se o tempo minimo for ultrapassado ou a distância o que vier primeiro.
Para pararmos de receber atualização de posições devemos chamar o método removeUpdates
passando o LocationListener
que utilizamos para pedir os updates:
locationManager.removeUpdates( listener );
Testando no Emulador
No emulador do SDK podemos para fim de teste enviar posições “fake” para testar nossa aplicação, para isso devemos ir perspectiva DDMS(se ela não está aparecendo vá em Windows -> Open Perspective -> Other… ) na aba Emulator Control rolando a janela verá a seguinte seção.
Basta inserir as coordenadas e clicar em send que elas serão enviadas pelo provider GPS para a aplicação.
Bom pessoal este é o básico, o resto é com vocês 🙂
Referências
- http://developer.android.com/guide/topics/location/strategies.html
- http://developer.android.com/reference/android/location/LocationManager.html
- http://developerlife.com/tutorials/?p=1375