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:
  1. public class MainActivity extends ListActivity {  
  2.    
  3.  private static final int REQUEST_ENABLE_BT = 1;   
  4.    
  5.  private Button btnDiscovery;  
  6.  private ArrayAdapter<String> mAdapter;  
  7.  private List<String> lstDispId;  
  8.  private List<BluetoothDevice> lstDisp;  
  9.  private Boolean procurando = false;  
  10.  private BluetoothAdapter mBtAdapter;  
  11.   
  12.  // Criação da atividade  
  13.  @Override  
  14.  public void onCreate(Bundle savedInstanceState) {  
  15.   super.onCreate(savedInstanceState);  
  16.     
  17.   // Inicia a tela  
  18.   setContentView(R.layout.activity_main);  
  19.   btnDiscovery = (Button) findViewById(R.id.btnDiscovery);  
  20.   btnDiscovery.setEnabled(false);  
  21.   btnDiscovery.setOnClickListener(disparaDiscovery);  
  22.   lstDispId = new ArrayList<String>();  
  23.   lstDisp = new ArrayList<BluetoothDevice>();  
  24.   mAdapter = new ArrayAdapter<String> (this, R.layout.item,   
  25.                                   R.id.txtDisp, lstDispId);  
  26.   setListAdapter(mAdapter);  
  27.     
  28.   // Pegar as notificações  
  29.   IntentFilter filter = new IntentFilter();    
  30.   filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);  
  31.   filter.addAction(BluetoothDevice.ACTION_FOUND);  
  32.   filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);  
  33.   registerReceiver(mReceiverBT, filter);    
  34.     
  35.   // Inicia Bluetooth  
  36.   mBtAdapter = BluetoothAdapter.getDefaultAdapter();  
  37.   if (mBtAdapter == null) {  
  38.    Toast.makeText(this, R.string.semBT, Toast.LENGTH_LONG).show();  
  39.   } else if (mBtAdapter.isEnabled()) {  
  40.    btnDiscovery.setEnabled(true);  
  41.   } else {  
  42.          // Pede para ligar o Bluetooth    
  43.          Intent enableBtIntent = new Intent(  
  44.                           BluetoothAdapter.ACTION_REQUEST_ENABLE);    
  45.          startActivityForResult (enableBtIntent, REQUEST_ENABLE_BT);    
  46.   }  
  47.     
  48.  }  
  49.   
  50.  // Encerramento da atividade  
  51.  @Override  
  52.  public void onDestroy() {  
  53.   super.onDestroy();  
  54.   if (procurando) {  
  55.    mBtAdapter.cancelDiscovery();  
  56.   }  
  57.  }  
  58.   
  59.  // Trata retorno do pedido de ativação do Bluetooth  
  60.     public boolean onActivityResult(int requestCode, int resultCode) {    
  61.         if (requestCode == REQUEST_ENABLE_BT) {    
  62.             if (resultCode == Activity.RESULT_OK) {    
  63.                 // Autorizado acesso ao Bluetooth  
  64.              btnDiscovery.setEnabled(true);  
  65.             } else if (resultCode == Activity.RESULT_CANCELED) {    
  66.                 // Negado acesso ao Bluetooth    
  67.             }    
  68.             return true;    
  69.         }    
  70.         return false;    
  71.     }  
  72.       
  73.     // Trata botão Procura  
  74.     private final OnClickListener disparaDiscovery = new OnClickListener() {  
  75.   
  76.   @Override  
  77.   public void onClick(View v) {  
  78.    lstDispId.clear();  
  79.    lstDisp.clear();  
  80.    mAdapter.notifyDataSetChanged();  
  81.    if (mBtAdapter.startDiscovery()) {  
  82.     btnDiscovery.setEnabled(false);  
  83.     procurando = true;  
  84.    } else {  
  85.     Toast.makeText(MainActivity.this, R.string.erroDiscovery,   
  86.                                       Toast.LENGTH_LONG).show();  
  87.    }  
  88.   }  
  89.     };  
  90.   
  91.     // Trata notificações  
  92.     private final BroadcastReceiver mReceiverBT = new BroadcastReceiver() {    
  93.         public void onReceive(Context context, Intent intent) {    
  94.             String action = intent.getAction();    
  95.             if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {    
  96.                 // estado mudou    
  97.                 int estado = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,-1);    
  98.                 if ((estado == BluetoothAdapter.STATE_ON)) {    
  99.                     // Ligou Bluetooth  
  100.                  btnDiscovery.setEnabled(true);  
  101.                 } else if (estado == BluetoothAdapter.STATE_OFF) {    
  102.                     // Desligou Bluetooth  
  103.                  btnDiscovery.setEnabled(false);  
  104.               if (procurando) {  
  105.                mBtAdapter.cancelDiscovery();  
  106.                procurando = false;  
  107.               }  
  108.                 }    
  109.             } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){  
  110.              // Encerrou procura  
  111.              procurando = false;  
  112.              mAdapter.notifyDataSetChanged();  
  113.              btnDiscovery.setEnabled(true);  
  114.             } else if (BluetoothDevice.ACTION_FOUND.equals(action)) {  
  115.              // Achou um device  
  116.              BluetoothDevice device = intent.getParcelableExtra(  
  117.                       BluetoothDevice.EXTRA_DEVICE);  
  118.              String ident;  
  119.              if (device.getName() == null) {  
  120.               ident = "?";  
  121.              } else {  
  122.               ident = device.getName();  
  123.              }  
  124.              ident +=  " (" + device.getAddress() + ")";  
  125.              lstDispId.add(ident);  
  126.              lstDisp.add(device);  
  127.             }  
  128.         }    
  129.     };      
  130. }  

Nenhum comentário: