Uma das coisas mais legais de se desenvolver aplicações e jogos para celulares é a mobilidade que eles nos proporcionam. Uma tecnologia que está cada vez mais presente nos celulares mais populares no Brasil é o Bluetooth. Por isso, hoje vou falar um pouquinho sobre como desenvolver aplicações com essa tecnologia em Java ME.
Bluetooth é uma tecnologia utilizada para criar pequenas redes sem fio, também chamadas de WPANs (Wireless Personal Area Network). O alcance das redes Bluetooth normalmente é de 10 metros. Não vou filosofar muito sobre a pilha de protocolos, potências, etc. Informações mais detalhadas acesse o site oficial da tecnologia Bluetooth.
Antes de qualquer coisa precisaremos saber se o dispositivo para qual iremos desenvolver suporta a JSR-082. É ela que define o uso da tecnologia Bluetooth com Java ME. Consulte o site do fabricante para obter essa informação. Caso seu telefone não implemente essa JSR, você poderá testar esse exemplo no WTK.
O esquema abaixo demonstra como é estabelecida uma conexão entre dispositivos Bluetooth.
Note que primeiramente devemos estabelecer quem é o servidor. Ele ficará visível para que outros dispositivos o encontrem, aguardará por clientes e os proverá um serviço. O cliente por sua vez terá mais trabalho. Ele primeiro procurará por dispositivos (inquiry) disponíveis em sua área de alcance. Esses podem ser mouses, teclados, antenas ou qualquer outro dispositivo Bluetooth. Após obter essa lista de dispositivos, escolheremos um e verificaremos se ele está disponibilizando o serviço que nos interessa. Se estiver, a conexão entre os dois será estabelecida.
Agora, mãos à obra! Vamos listar agora as classes mais importantes do pacote javax.microedition.bluetooth.*:
LocalDevice - Representa o dispositivo Bluetooth local. É um singleton que pode ser obtido pelo método getLocalDevice(). Com ele podemos, entre outras coisas, dizer se o nosso aparelho será visível para os outros dispositivos, obter o endereço ou o nome do seu dispositivo Bluetooth entre outras.
LocalDevice myPhone = LocalDevice.getLocalDevice();
System.out.println(myPhone.getFriendlyName());
DiscoveryListener - Interface que é notificada quando os eventos de busca de dispositivos e serviços acontecem. Ela tem quatro métodos:
/*
Método chamado quando um dispositivo é econtrado.
Devemos armazenar (em um Vector por exemplo) o
remoteDevice para podermos buscar pelo serviço.
*/
void deviceDiscovered(RemoteDevice remoteDevice,
DeviceClass deviceClass);
/*
Método que é chamado quando a busca de dispositivos
termina.
discType - indica o resultado da busca:
INQUIRY_COMPLETED - Busca terminada com sucesso.
INQUIRY_TERMINATED - Busca cancelada.
INQUIRY_ERROR - Erro na busca.
*/
void inquiryCompleted(int discType);
/*
Método chamado quando a busca do serviço termina.
transID - Id da transação de busca pelo serviço
respCode - indica o resultado da busca:
SERVICE_SEARCH_TERMINATED - Busca cancelada.
SERVICE_SEARCH_ERROR - Erro na busca.
SERVICE_SEARCH_NO_RECORD - Dispositivo não tem o
serviço solicitado.
SERVICE_SEARCH_DEVICE_NOT_REACHABLE - Dispositivo
remoto está fora do alcance.
SERVICE_SEARCH_COMPLETED - Serviço encontrado com
sucesso.
*/
void serviceSearchCompleted(int transID, int respCode);
/*
Método chamando quando o serviço procurado é encontrado.
transID - Id da transação de busca pelo serviço
serviceRecord - informações do serviço encontrado.
*/
void servicesDiscovered(int transID, ServiceRecord[] serviceRecord);
DiscoveryAgent - Obtido através da instância do LocalDevice é o responsável por realizar a busca de dispositivos remotos na área de alcance do dispositivo local e de localizar o serviço no dispositivo remoto.
DiscoveryAgent agent = myPhone.getDiscoveryAgent();
agent.startInquiry(DiscoveryAgent.GIAC,
classeQueImplementeDiscoveryListener);
Com a chamada do startInquiry, cada vez que um dispositivo for encontrado a classe que implementa DiscoveryListener será notificada através do método deviceDiscovered. E quando o inquiry terminar o método inquiryCompleted será chamado.
RemoteDevices - representa um dispositivo Bluetooth remoto. Objetos dessa classe são retornados quando se realiza um inquiry (busca por dispositivos). Então devemos armazena-los em memória para que possamos fazer a busca de serviços com esse objeto através do objeto discoveryAgent.
agent.searchServices(null, uuidSet, remoteDevice,
classeQueImplementeDiscoveryListene);
Com a chamada desse método, quando o serviço procurado for encontrado a classe que implementa DiscoveryListener será notificada através do método servicesDiscovered, e quando a busca por serviços terminar o método serviceSearchCompleted será chamado.
Abrindo uma conexão (Servidor)
Lembrando que toda conexão utilizando GCF (Generic Connection Framework) deve ser feita em uma Thread separada, segue abaixo um trecho de código que abre uma conexão servidora e fica aguardando por conexões de clientes.
localDevice = LocalDevice.getLocalDevice();
int initialDiscoveredMode =
localDevice.getDiscoverable();
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
StreamConnectionNotifier notifier =
(StreamConnectionNotifier) Connector.open(
"btspp://localhost:0000000000000000000BE3125CDAE");
connection = notifier.acceptAndOpen();
execute(connection);
Antes de abrir a conexão, o dispositivo é colocado em modo de descoberta para que outros possam encontra-lo. Depois é aberta a conexão servidora (localhost) utilizando "btspp" que é o protocolo de comunicação (BlueTooth Serial Port Profile). O número gigante :) após os ":" é o identificador do serviço UUID. O método execute trata os dados vindos do outro dispositivo. Segue abaixo o seu código:
protected void execute(StreamConnection conn){
try {
os = connection.openDataOutputStream();
is = connection.openDataInputStream();
String message;
while (true){
message = is.readUTF();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//closeStreams();
}
}
"os" e "is" são atributos da classe e devem ser um DataOutputStream e um DataInputStream.
Por último, o método que envia as mensagens:
public void send(String message){
try {
os.writeUTF(message);
os.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
Bem pessoal, esse é só um aperitivo. Quem quiser saber mais, postem suas dúvidas.
[Editado]
Atendendo aos comentários, um exemplo bem simples pode ser baixado aqui.
[Editado 2]
E neste link vocês podem baixar um exemplo mais simplificado e comentado (mas precisando de algumas melhorias) do exemplo anterior.
4br4ç05,
nglauber