Esse artigo faz parte da revista WebMobile edição 25. Clique aqui para ler todos os artigos desta edição

 

tyle="mso-bidi-font-style: normal">
Para que serve:

Os serviços baseados em localização são usados por empresas de telefonia e de tecnologia para personalizar e fornecer mais possibilidades em seus produtos e serviços utilizando dados de localização do cliente.

 


Em que situação o tema é útil:

Serviços baseados em localização estão se tornando cada vez mais comuns, e essa nova demanda abre um mercado para desenvolvimento de aplicações desse tipo.

 

É cada vez mais comum encontrar Serviços Baseados em Localização (do inglês, Location-Based Services, ou simplesmente LBS), pois atualmente existe uma grande demanda por aplicativos que utilizem informações de localização.

De posse de um dispositivo móvel que disponha dos recursos necessários para obter sua localização, é possível encontrar sua exata localização em um mapa, descobrir a melhor rota entre dois pontos, buscar por serviços próximos de onde você se encontra, como postos de gasolina, restaurantes, etc.

Recentemente o Google lançou um novo serviço, chamado de Google Latitude. Esse serviço permite que pessoas possam compartilhar sua localização com seus amigos. Fim da privacidade? Obviamente não, pois o serviço pode ser desativado a qualquer momento.

Os LBS também permitem que as operadoras cobrem por ligações com tarifas diferenciadas dependendo da localização do usuário. Por exemplo, um cliente poderia realizar uma chamada com uma tarifa reduzida se estivesse a determinada distância de sua casa, permitindo que seu celular sirva como um telefone residencial.

Também é possível rastrear pessoas, definindo áreas onde essas pessoas possam estar, e enviando e-mails ou SMS caso elas saiam dessa área pré-definida. Outra aplicação interessante é o uso da localização em serviços de emergência, dessa forma o usuário não precisaria saber onde está exatamente para pedir socorro.

São inúmeras as aplicações que esses serviços baseados em localização podem nos oferecer. Nesse sentido, iremos desenvolver um aplicativo móvel capaz de capturar sua localização periodicamente, e enviá-las a um servidor, que irá armazená-las e mostrar sua rota no Google Maps.

Location API

A Location API (JSR 179) é uma especificação genérica que permite aos desenvolvedores construírem aplicações que utilizem dados de localização. Ela introduz o pacote javax.microedition.location, que dispõe de diversas classes que permitem obter dados como longitude, latitude, altura, velocidade, entre outras informações.

Para utilizar a Location API, é necessária a configuração Connected Device Configuration (CDC) ou a versão 1.1 da Connected Limited Device Configuration (CLDC). Isso acontece porque essa API utiliza números em ponto flutuante.

Existem basicamente duas formas de descobrir se seu dispositivo móvel possui a Location API. Você pode entrar no site do fabricante de seu dispositivo e procurar nas especificações técnicas dele se existe suporte à JSR 179 – Location API for Java Micro Edition. Por exemplo, para celulares Nokia é possível buscar as especificações no Fórum Nokia (veja Links). Nesse site, é possível ver que, por exemplo, o Nokia N73 dá suporte a essa API.

Outra forma de obter informações sobre as APIs que estão disponíveis no seu dispositivo móvel é visitar o site JME Polish (veja Links). Nele você pode buscar por seu dispositivo e ver quais APIs estão disponíveis nele, ou buscar pelas APIs e ver quais celulares dão suporte a ela.

Obtendo a Localização

O dispositivo móvel precisa prover pelo menos uma forma de captura da localização. Existem basicamente três formas. Cada uma possui diferentes características no que diz respeito à precisão da localização, custo envolvido, consumo de bateria, tempo de resposta, entre outras. Cada uma dessas características podem ser previamente configuradas para se adequar às necessidades da aplicação, como por exemplo, definir que a captura da localização não pode envolver custos.

A primeira forma é utilizando a rede da operadora de telefonia. O dispositivo móvel pode usar essa rede para determinar uma posição aproximada a partir da célula onde ele se encontra. Quanto maior a célula, menor a precisão da posição. Vale salientar que, como você estará usando a rede de sua operadora de telefonia, ela poderá cobrar pelo serviço de localização.

Alguns dispositivos móveis já possuem um receptor GPS (Sistema de Posicionamento Global) integrado, permitindo obter a localização de forma mais precisa (com margem de erro de 4 a 40 metros) e sem custos por parte da operadora. A desvantagem nesse caso é o custo que o receptor GPS agrega ao dispositivo, além do maior consumo de bateria.

Existem ainda alguns receptores GPS avulsos, que funcionam a bateria e capturam periodicamente a localização, enviando-a via Bluetooth para um computador ou celular. A edição nº 11 da revista WebMobile apresenta o artigo “JavaME usando GPS”, que explica como utilizar um receptor GPS avulso com um celular que possua Bluetooth, sem a necessidade da Location API.

Estrutura da Location API

A Figura 1 apresenta o diagrama de classes de algumas das classes da Location API. Existem muitas outras classes, mas para efeitos de simplificação, apenas as classes utilizadas nesse artigo serão apresentadas. Se quiser mais detalhes sobre as classes disponíveis na Location API, nada melhor do que a própria especificação da JSR 179 (veja Links).

 

Figura 1. Diagrama das classes da Location API usadas no exemplo

 

·                     LocationProvider: É responsável por abstrair a forma de captura de localização (apresentadas anteriormente) e fornecer a localização geográfica atual sempre que lhe for solicitada, com base nos critérios definidos na classe Criteria;

·                     Criteria: Define critérios, ou seja, pré-condições para a obtenção da localização. Os critérios são: precisões horizontal e vertical, tempo de resposta, consumo de bateria, custo envolvido, velocidade e curso, altitude e informações sobre endereços;

·                     Location: Representa uma localização e contém informações como coordenadas geográficas, precisão, velocidade, direção de movimento e informações sobre o método de captura usado. Os objetos dessa classe são fornecidos pela classe LocationProvider;

·                     QualifiedCoordinates: Representa as coordenadas geográficas latitude, longitude e altitude, associados a seus respectivos valores de precisão. Objetos dessa classe compõem objetos da classe Location.

Construindo a Aplicação Móvel de Localização

Agora iremos construir o aplicativo que irá executar no dispositivo móvel. Esse aplicativo será responsável por capturar a localização periodicamente, e enviar essas posições para o servidor.

Nesse ponto, estamos assumindo que o leitor possui conhecimentos suficientes sobre programação em Java para dispositivos móveis, bem como as ferramentas utilizadas nesse exemplo. O foco desse artigo é explicar o uso da Location API, e apresentar uma aplicação que pode ser desenvolvida com ela.

Para criar esse aplicativo, utilizaremos a IDE NetBeans 6.5.1. Crie o projeto do tipo “Aplicativo Móvel”, defina um nome para o projeto, nesse exemplo usaremos “MobileLocator”, e configure para usar CLDC 1.1 e MIDP 2.0.

Para esse aplicativo teremos o MIDlet MobileLocationApp, que será a principal classe da nossa aplicação, e será responsável por gerenciar ciclo de vida, bem como o controle de formulários apresentados.

Também iremos construir dois formulários: o ConfigForm, que é o formulário apresentado quando a aplicação for iniciada, e permitirá ao usuário configurar os critérios de localização. O segundo formulário é o ConsoleForm, que apresentará apenas um “console”, onde serão mostradas as mensagens ao longo da execução do aplicativo.

É uma boa prática de programação para dispositivos móveis usar threads para chamadas de entrada e saída que bloqueiam a aplicação, isso evita que ela fique aparentemente “travada”, enquanto na verdade está executando uma operação de I/O. No nosso caso, teremos duas operações de I/O, a captura da localização atual e o envio da mesma para o servidor. Portanto, iremos criar duas threads: LocatorThread, responsável por capturar a localização, e a HttpClientThread, responsável por enviar os dados para o servidor.

Por fim, teremos a classe LocationVO, que segue o padrão de projeto Value Object (VO), e representa uma localização específica.

A Classe LocationVO

Por uma questão de didática, vamos começar pelo mais simples. Irei apresentar primeiramente a classe LocationVO, que é usada para representar uma localização do usuário. O código-fonte simplificado dessa classe pode ser visualizado na Listagem 1.

Observe que é uma classe simples, que possui atributos referentes à localização. Observe também que o método toString está sendo sobrescrito, nele está sendo representado o estado do objeto no formato XML. Isso será útil quando esse objeto precisar ser enviado para o servidor.

 

Listagem 1. Código-fonte da classe LocationVO

package br.com.webmobile.mobilelocator;

 

public class LocationVO {

    private int id;

    private float course;

    private double latitude;

    private double longitude;

    private float altitude;

    private float speed;

    private long timestamp;

 

    public LocationVO() {}

 

    public LocationVO(float course, double latitude, double longitude, float altitude, float speed, long timestamp) {

        this.course = course;

        this.latitude = latitude;

        this.longitude = longitude;

        this.altitude = altitude;

        this.speed = speed;

        this.timestamp = timestamp;

    }

   

    public String toString() {

        String cls = "";

        cls += "" + course + "";

        cls += "" + latitude + "";

        cls += "" + longitude + "";

        cls += "" + altitude + "";

        cls += "" + speed + "";

        cls += "" + timestamp + "";

        cls += "";

        return cls;

    }

 

    // Métodos getters e setters

}

Construindo as Threads

Cada uma das threads possuem um propósito bem definido que são apresentados adiante.

A Classe LocatorThread

Essa classe será responsável por capturar, periodicamente, a posição atual do usuário. Seu código-fonte pode ser visualizado na Listagem 2.

O método construtor basicamente instância alguns dos atributos da classe, definindo valores padrão e criando a thread HttpClientThread, que será usada sempre que for capturada uma nova posição, e essa precisar ser enviada para o servidor.

O método setOptions é usado para configurar os parâmetros para captura da localização do usuário. Ele é invocado quando o formulário de configuração (ConfigForm) é totalmente preenchido, e recebe todos os dados informados pelo usuário. Dada essa configuração, é criado o objeto Criteria, no qual são definidos os critérios para localização. Feito isso, o método getInstance da classe LocationProvider é usado para obter um provedor de localização.

Essa thread pode estar em três estados possíveis: parado, em espera e em execução. O estado da thread é controlado por duas variáveis booleanas: alive e running.

·                     Parado: A aplicação ainda está iniciando, o objeto da thread já foi criado porém seu método start ainda não foi invocado;

·                     Em espera: O usuário está definindo os parâmetros da aplicação no formulário de configuração (ConfigForm), e portanto, apesar do método start já ter sido invocado, a thread ainda não está capturando as posições. Nesse estado, os atributos alive e running são verdadeiro e falso, respectivamente;

·                     Em execução: O usuário já definiu as configurações e inicializou a captura de posições. Nesse estado, os atributos alive e running são ambos verdadeiros.

Todo esse controle do ciclo de vida da thread tem influência na execução do método run. Observe que a execução desse método não é concluída enquanto alive for verdadeiro (estado de espera), mas o código que usa a Location API (dentro da condição if) só é executado quando running também é verdadeiro (estado de execução).

Quando a thread está no estado de execução, o método getLocation da classe LocationProvider é usado para capturar a posição atual, nele é informado o tempo limite de espera para captura (definido pelo usuário no formulário de configuração). Em seguida, é verificado se a posição é válida.

Feito isso, a localização capturada é comparada com a última localização (se houver), se a distância entre elas for menor do que aquela configurada pelo usuário, então ela não será enviada para o servidor. Isso evita que posições sejam enviadas quando o usuário estiver praticamente parado, diminuindo os custos com o envio de dados através da rede da operadora.

Se a localização capturada estiver longe o suficiente da última posição enviada, então essa nova posição é tida como a última e enviada para o servidor. Para isso, é criado o objeto LocationVO com os dados da localização capturada, e passado para a classe HttpClientThread (método setLocation).

A classe LocatorThread possui ainda três métodos, que são usados para controlar seu ciclo de vida. O método init inicializa a captura das posições. O método pause paralisa a captura de posições e o método destroy finaliza a thread.

 

Listagem 2. Código-fonte da classe LocatorThread

package br.com.webmobile.mobilelocator.threads;

 

import br.com.webmobile.mobilelocator.*;

import br.com.webmobile.mobilelocator.threads.HttpClientThread;

import javax.microedition.location.Criteria;

import javax.microedition.location.Location;

import javax.microedition.location.LocationException;

import javax.microedition.location.LocationProvider;

 

public class LocatorThread extends Thread {

    private Criteria criteria;

    private LocationProvider locProvider;

    private HttpClientThread client;

    private MobileLocatorApp app;

    private Location lastLocation;

    private boolean alive;

    private boolean running;

    private int timeout;

    private int delay;

    private int minimalDistance;

 

    public LocatorThread(MobileLocatorApp app) {

        this.app = app;

        client = new HttpClientThread(app);

        alive = true;

        running = false;

...

Quer ler esse conteúdo completo? Tenha acesso completo