quarta-feira, abril 30, 2014

Comunicação Bluetooth entre Arduino e Android - Software do Android, parte 2

Na parte anterior vimos como garantir queo Bluetooth está presente e ligado no dispositivo Android. O passo seguinte, que veremos neste post, é descobrir quais são os dispositivos que estão no alcance do rádio.

A procura de dispositivos é iniciada pelo método startDiscovery() do objeto BluetoothAdapter. Este método retorna imediatamente, a procura em si roda em background. O nosso programa é informado do andamento da busca através de notificações:
  • BluetoothDevice.ACTION_FOUND informa que um device foi encontrado. Os dados do device são fornecidos através de um objeto BluetoothDevice.
  • BluetoothAdapter.ACTION_DISCOVERY_FINISHED informa que a procura foi encerrada. A procura encerra-se automaticamente após cerca de doze segundos.
O objeto  BluetoothDevice que recebemos em ACTION_FOUND nos informa o nome do device (que já vimos como configurar no nosso módulo) e o endereço MAC (definido na fábrica e, em princípio, único). Não sei exatamente em que condições, mas já me aconteceu do nome vir com null.

Podemos usar várias estratégias para escolher com qual dispositivo iremos no comunicar. Uma opção é ir montando um lista à medida que os dispositivos são encontrados e apresentá-la para o usuário fazer a escolha. Outra opção é usarmos o nome. Uma terceira é usarmos o endereço MAC.

O processo de procura consome bateria e processamento e portanto não deve ser mantido em execução desnecessariamente. Se estamos usando um método automático para escolha do dispositivo, é interessante interromper a procura, através do método cancelDiscovery() assim que a procura encontrá-lo. Normalmente todos os dispositivos são encontrados bem antes dos doze segundos.

Se você quer se conectar a um dispositivo fixo, e conhece o MAC dele, você pode pular a etapa de busca e criar diretamente um objeto BluetoothDevice através do método getRemoteDevice (address) do objeto BluetoothAdapter. O parâmetro address é um String no formato "00:11:22:33:AA:BB", com as letras em maiúscula.

Vejamos um exemplo simples de tudo isto. O programa (que você encontra nos arquivos do blog em BTDiscovery.zip) apresenta um botão para disparar a procura e uma lista para mostrar os dispositivos encontrados. Eis o código:
public class MainActivity extends ListActivity {
 
 private static final int REQUEST_ENABLE_BT = 1; 
 
 private Button btnDiscovery;
 private ArrayAdapter<String> mAdapter;
 private List<String> lstDispId;
 private List<BluetoothDevice> lstDisp;
 private Boolean procurando = false;
 private BluetoothAdapter mBtAdapter;

 // Criação da atividade
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  
  // Inicia a tela
  setContentView(R.layout.activity_main);
  btnDiscovery = (Button) findViewById(R.id.btnDiscovery);
  btnDiscovery.setEnabled(false);
  btnDiscovery.setOnClickListener(disparaDiscovery);
  lstDispId = new ArrayList<String>();
  lstDisp = new ArrayList<BluetoothDevice>();
  mAdapter = new ArrayAdapter<String> (this, R.layout.item, 
                                  R.id.txtDisp, lstDispId);
  setListAdapter(mAdapter);
  
  // Pegar as notificações
  IntentFilter filter = new IntentFilter();  
  filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
  filter.addAction(BluetoothDevice.ACTION_FOUND);
  filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
  registerReceiver(mReceiverBT, filter);  
  
  // Inicia Bluetooth
  mBtAdapter = BluetoothAdapter.getDefaultAdapter();
  if (mBtAdapter == null) {
   Toast.makeText(this, R.string.semBT, Toast.LENGTH_LONG).show();
  } else if (mBtAdapter.isEnabled()) {
   btnDiscovery.setEnabled(true);
  } else {
         // Pede para ligar o Bluetooth  
         Intent enableBtIntent = new Intent(
                          BluetoothAdapter.ACTION_REQUEST_ENABLE);  
         startActivityForResult (enableBtIntent, REQUEST_ENABLE_BT);  
  }
  
 }

 // Encerramento da atividade
 @Override
 public void onDestroy() {
  super.onDestroy();
  if (procurando) {
   mBtAdapter.cancelDiscovery();
  }
 }

 // Trata retorno do pedido de ativação do Bluetooth
    public boolean onActivityResult(int requestCode, int resultCode) {  
        if (requestCode == REQUEST_ENABLE_BT) {  
            if (resultCode == Activity.RESULT_OK) {  
                // Autorizado acesso ao Bluetooth
             btnDiscovery.setEnabled(true);
            } else if (resultCode == Activity.RESULT_CANCELED) {  
                // Negado acesso ao Bluetooth  
            }  
            return true;  
        }  
        return false;  
    }
    
    // Trata botão Procura
    private final OnClickListener disparaDiscovery = new OnClickListener() {

  @Override
  public void onClick(View v) {
   lstDispId.clear();
   lstDisp.clear();
   mAdapter.notifyDataSetChanged();
   if (mBtAdapter.startDiscovery()) {
    btnDiscovery.setEnabled(false);
    procurando = true;
   } else {
    Toast.makeText(MainActivity.this, R.string.erroDiscovery, 
                                      Toast.LENGTH_LONG).show();
   }
  }
    };

    // Trata notificações
    private final BroadcastReceiver mReceiverBT = new BroadcastReceiver() {  
        public void onReceive(Context context, Intent intent) {  
            String action = intent.getAction();  
            if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {  
                // estado mudou  
                int estado = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,-1);  
                if ((estado == BluetoothAdapter.STATE_ON)) {  
                    // Ligou Bluetooth
                 btnDiscovery.setEnabled(true);
                } else if (estado == BluetoothAdapter.STATE_OFF) {  
                    // Desligou Bluetooth
                 btnDiscovery.setEnabled(false);
              if (procurando) {
               mBtAdapter.cancelDiscovery();
               procurando = false;
              }
                }  
            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
             // Encerrou procura
             procurando = false;
             mAdapter.notifyDataSetChanged();
             btnDiscovery.setEnabled(true);
            } else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
             // Achou um device
             BluetoothDevice device = intent.getParcelableExtra(
                      BluetoothDevice.EXTRA_DEVICE);
             String ident;
             if (device.getName() == null) {
              ident = "?";
             } else {
              ident = device.getName();
             }
             ident +=  " (" + device.getAddress() + ")";
             lstDispId.add(ident);
             lstDisp.add(device);
            }
        }  
    };    
}

Nenhum comentário: