Como é do conhecimento geral os telemóveis Android têm um sensor designado de acelerómetro. Este sensor permite avaliar os movimentos a que o dispositivo está sujeito num sistema de três eixos. O eixo dos x permite avaliar a inclinação do dispositivo para a esquerda ou para a direita. O eixo dos y é controlado pela inclinação do dispositivo para a frente ou para trás. O eixo dos z reflete o movimento para cima e para baixo.
Para este pequeno projeto vamos fazer um labirinto cujo objetivo é levar uma esfera até ao buraco inclinando o dispositivo tal como se se trata-se um jogo físico.
Primeiro vamos criar um projeto novo.
Na atividade principal (MainActivity) vamos implementar uma função que fica associada ao sensor, é o que se designa por SensorEventListener.
Assim alteramos a declaração da class para
public class MainActivity extends Activity implements SensorEventListener{
De seguida na função onCreate temos de "capturar" o sensor, para isso criamos um objeto SensorManager e outro objeto Sensor.
Posto isto temos de implementar a função onSensorChanged, que vai receber os valores do sensor sempre que este sofrer alterações.
public void onSensorChanged(SensorEvent event) { //recolher os três valores para as variáveis x=event.values[0]; y=event.values[1]; z=event.values[2]; }
Com estas funções implementadas vamos passar à fase gráfica, para implementar a interface vamos utilizar uma ImageView que depois associamos ao xml do layout do programa.
Vamos, então, adicionar uma class nova que vai implementar a lógica e os gráficos.
public class ecran extends ImageView{
Nesta class vamos implementar a função onSizeChanged que vai permitir saber o tamanho do ecrã, para, em função desse tamanho, implementarmos as paredes do labirinto.
Precisamos, ainda, da função onDraw, que além de desenhar tudo no ecrã vai calcular a posição da esfera em função dos valores do sensor. Como o sensor é controlado na MainActivity é necessário implementar três métodos públicos na MainActivity para podermos aceder aos valores do sensor. Primeiro um método que nos dá a instancia atual.
public static MainActivity getInstance(){ return instance; }
Este método vai permitir à class ecran, que é a que desenha no ecrã do dispositivo, ter acesso aos outros dois métodos, um que devolve o valor x e outro para o valor y do sensor.
public float getX() { return x; } public float getY() { return y; } No projeto também está implementado o método para o z mas não é utilizado.
Para as paredes do labirinto criei um vetor de retângulos. As paredes são definidas por código e desenhadas com a cor vermelha.
A função principal é a onDraw que trata de: 1º desenhar o buraco de saída do labirinto. 2º desenhar as paredes. 3º receber os valores da inclinação do dispositivo. 4º calcular a nova posição da esfera calculado se esta bate em alguma parede. 5º se a esfera está suficientemente perto do buraco para declarar vitória.
É um layout linear que associa a class ecran ao ecrã.
Em resumo: este projeto demonstra como desenhar no ecrã utilizando as funções gráficas do sistema operativo Android, desde imagens a figuras geométricas bem como escrever texto e ainda a utilização do sensor acelerómetro.
Neste post vamos criar um programa que permite controlar um i-Racer com um dispositivo Android através do Bluetooth. Para quem ainda não conhece este pequeno carro fica aqui um vídeo.
O i-Racer responde a um conjunto limitado de comandos em hexadecimal cujo significado pode ser encontrado aqui.
O objetivo é demonstrar o funcionamento do envio dos comandos através do Bluetooth, para isso vamos implementar quatro comandos: andar para a frente, andar para trás, virar rodas para direita e virar rodas para a esquerda. Os restantes comandos são igualmente fáceis de implementar basta alterar os códigos enviados ao i-Racer.
Para começar a interface. O design:
Em execução:
Resumindo: - oito botões; - duas listviews, uma onde estão os botões a outra para apresentar os dispositivos Bluetooth emparelhados e detetados.
Agora uma classe para controlar as comunicações. Os tutoriais da google sobre o Bluetooth do Android são muito completos mas também algo complexos, ainda que isso seja normal quando estamos a criar programas de comunicação entre dispositivos.
Para este pequeno dispositivo nós só temos de enviar os comandos não temos de receber, assim a classe criada permite abrir um canal de comunicação, estabelecer uma ligação, enviar dados, devolver o estado da ligação e terminar a ligação.
O código é algo complexo mas está comentado e envia mensagens para o Log de modo que a que seja mais fácil fazer o debug da aplicação.
package edu.pjcferreira.btremote; import java.io.IOException; import java.io.OutputStream; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.util.Log; public class ConnectThread extends Thread{ private BluetoothAdapter mBluetoothAdapter;//dispositivo local private BluetoothSocket mmSocket; private BluetoothDevice mmDevice; //dispositivo remoto private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); //para ligar a uma board serial tem que ser com este UUID private int estado; private OutputStream mmOutStream=null; //recebe o dispositivo remoto ao qual ligar public ConnectThread(BluetoothDevice device){ BluetoothSocket tmp=null; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mmDevice=device; estado=-1; try{ Log.d("BT","Abre o canal de ligação"); tmp=mmDevice.createRfcommSocketToServiceRecord(MY_UUID); mmSocket=tmp; estado=0; Log.d("BT","Canal aberto!"); }catch(IOException e){ estado=-1; } } //método para enviar os comandos public void enviar(byte x){ if (mmOutStream==null){ try{ mmOutStream=mmSocket.getOutputStream(); }catch(IOException e){ return; } } try{ mmOutStream.write(x); }catch(IOException ee){ return; } Log.d("BT","ENVIADO COM SUCESSO!"); } //função que devolve o estado da ligação public String getEstado(){ return Integer.toString(estado); } //estabelece a ligação public void run(){ mBluetoothAdapter.cancelDiscovery(); try{ mmSocket.connect(); Log.d("BT","LIGADO"); estado=1; }catch(IOException connectException){ try{ mmSocket.close(); Log.d("BT","ERRO A LIGAR"); estado=-1; }catch(IOException closeException){} } return; } //termina a ligação public void cancel(){ try{ mmSocket.close(); estado=-1; }catch(IOException e){} } }
Agora com esta classe podemos iniciar a comunicação mas primeiro precisamos de verificar se o dispositivo tem Bluetooth, isso é feito na função onCreate que se apresenta a seguir.
Esta função também regista uma função callback para que quando os dispositivos Bluetooth são encontrados poderem ser adicionados à listview. O código dessa função é este:
private final BroadcastReceiver mReceiver = new BroadcastReceiver(){
public void onReceive(Context context, Intent intent){