Top Banner

of 30

Deitel_Android_17.pdf

Oct 09, 2015

Download

Documents

Marlon Janke
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
  • ObjetivosNeste captulo, voc vai:OO Usar Bluetooth para estabelecer uma conexo peer-to--peer entre dois aparelhos e transferir informaes de um para outro.

    OO Usar a classe BluetoothAdapter para verificar se o Bluetooth est habilitado em um aparelho.

    OO Iniciar um Intent que pede permisso ao usurio para habilitar o Bluetooth, se ainda no estiver habilitado.

    OO Iniciar um Intent que pede permisso ao usurio para tornar um aparelho detectvel via Bluetooth, podendo receber uma conexo.

    OO Usar a classe BluetoothServerSocket para esperar uma conexo de outro aparelho.

    OO Usar a classe BluetoothDevice para estabelecer uma conexo com outro aparelho.

    OO Usar a classe BluetoothSocket para transmitir dados entre aparelhos.

    OO Usar objetos JSONObject para criar e analisar dados formatados em JSON.

    Aplicativo Address Book melhorado

    Conectando dispositivos via Bluetooth, usando JSONObject para criar e analisar dados

    formatados em JSON

    17

  • 2 Android para Programadores

    17.1 IntroduoO aplicativo Enhanced Address Book adiciona verso do aplicativo do Captulo 10 a capa-cidade de os usurios transferirem contatos entre aparelhos usando redes Bluetooth. Voc vai usar vrias classes do pacote android.bluetooth para determinar se o Bluetooth est ha-bilitado e para estabelecer uma conexo entre dois aparelhos. Uma vez estabelecida a co-nexo, voc vai obter um OutputStream no aparelho remetente para enviar os dados e um InputStream no aparelho receptor para l-los. Os dados sero transferidos no formato JSON voc vai formatar os dados enviados e analisar (via parsing) os dados recebidos usando objetos JSONObject. Tambm vai usar objetos Intent para disparar atividades internas do Android que pedem ao usurio permisso para habilitar o adaptador Bluetooth de um aparelho e para tornar o aparelho detectvel por outros aparelhos, para que uma conexo possa ser estabeleci-da. Para mais detalhes sobre desenvolvimento de Bluetooth no Android visite:

    http://developer.android.com/guide/topics/wireless/bluetooth.html

    17.2 Teste do aplicativo Enhanced Address Book[Observao: voc deve testar este aplicativo com dois aparelhos, pois o emulador do Android no suportava Bluetooth quando este livro foi produzido.]

    Abrindo e executando o aplicativoAbra o Eclipse e importe o projeto do aplicativo Enhanced Address Book. Para importar o projeto:

    1. Selecione File > Import para exibir a caixa de dilogo Import. 2. Expanda o n General, selecione Existing Projects into Workspace e, em seguida, cli-

    que em Next >. 3. direita do campo de texto Select root directory:, clique em Browse e, em seguida,

    localize e selecione a pasta Enhanced Address Book. 4. Clique em Finish para importar o projeto. 5. Ative o aplicativo Enhanced Address Book. No Eclipse, clique com o boto direito

    do mouse no projeto EnhancedAddressBook na janela Package Explorer e, em se-guida, selecione Run As > Android Application no menu que aparece. Voc precisar repetir esse passo para cada aparelho em que executar este aplicativo para teste.

    Res

    umo 17.1 Introduo

    17.2 Teste do aplicativo Enhanced Address Book

    17.3 Viso geral das tecnologias 17.4 Construo dos arquivos de interface

    do usurio e de recursos 17.4.1 Criao do projeto 17.4.2 AndroidManifest.xml 17.4.3 addressbook_menu.xml: menu da

    Activity AddressBook

    17.4.4 view_contact_menu.xml: menu da Activity ViewContact

    17.4.5 device_chooser.xml: layout da ListActivity DeviceChooser

    17.4.6 device_layout.xml: layout dos itens de ListView do ListView da ListActivity DeviceChooser

    17.5 Construo do aplicativo 17.5.1 Activity AddressBook

    atualizada 17.5.2 Activity ViewContact

    atualizada 17.5.3 Activity DeviceChooser

    17.6 Para finalizar

  • Captulo 17 Aplicativo Address Book melhorado 3

    Preparando um aparelho para receber um contatoPara receber um contato de outro aparelho que esteja executando o aplicativo Enhanced Address Book, abra o menu enquanto v a lista de contatos e, em seguida, toque no item de menu Receive Contact do aparelho (Fig. 17.1(a)). Uma caixa de dilogo pede sua per-misso para tornar o aparelho detectvel. Toque em Yes para torn-lo detectvel por 120 segundos (Fig. 17.1(b)). Agora, outro aparelho poder se conectar com esse e enviar um contato. Quando um contato for recebido, aparecer um Toast no aparelho receptor e o novo contato ser exibido na lista de contatos.

    a) Toque em Receive Contact no menu para receber um contato de outro aparelho.

    b) Toque em Yes na caixa de dilogo para tornar o aparelho detectvel e permitir que ele receba um contato.

    Fig. 17.1 | A seleo do item de menu Receive Contact no aparelho receptor faz o Android perguntar se o aparelho deve ficar detectvel por 120 segundos.

    Enviando um contatoPara enviar um contato para outro aparelho que esteja executando o aplicativo Enhan-ced Address Book, primeiramente selecione o contato que voc deseja enviar, para ver seus detalhes. Na tela de detalhes do contato, abra o menu e toque em Transfer Contact (Fig. 17.2). Isso exibe a Activity DeviceChooser (Fig. 17.3), a qual procura imediata-mente aparelhos Bluetooth prximos se o Bluetooth estiver habilitado no aparelho que ativou DeviceChooser. medida que aparelhos so descobertos, eles aparecem no ListView da Activity DeviceChooser. Voc tambm pode recomear a busca de ou-tros aparelhos, tocando no boto Scan for compatible devices, na parte inferior da tela. Quando vir outro aparelho que esteja executando o aplicativo Enhanced Address Book, toque no nome do aparelho a fim de enviar o contato para ele. Os dois aparelhos preci-sam estar executando o aplicativo para que a transferncia ocorra. A Figura 17.4 mostra a lista de contatos do aparelho receptor antes e depois que o contato recebido.

  • 4 Android para Programadores

    Toque em Transfer Contact para enviar as informaes desse contato para outro aparelho

    Fig. 17.2 | Selecionando o item de menu Transfer Contact no aparelho remetente.

    Toque no nome de umaparelho para transferir

    um contato para ele

    Toque neste boto para procurar aparelhos prximos novamente

    Fig. 17.3 | Lista de aparelhos Bluetooth prximos exibida no aparelho remetente.

  • Captulo 17 Aplicativo Address Book melhorado 5

    17.3 Viso geral das tecnologiasEsta seo apresenta as novas tecnologias utilizadas no aplicativo Enhanced Address Book. As classes Bluetooth esto localizadas no pacote android.bluetooth.

    Obtendo uma referncia para o adaptador BluetoothNeste aplicativo, usamos o mtodo esttico getDefaultAdapter de BluetoothAdapter para obter um objeto que representa o adaptador Bluetooth do aparelho. Voc vai usar esse objeto para determinar se o Bluetooth est habilitado, para captar conexes de outros aparelhos e para localizar outros aparelhos Bluetooth.

    Detectando outros aparelhos BluetoothPara procurar aparelhos Bluetooth prximos, voc vai usar o mtodo startDiscovery de BluetoothAdapter. O Android executar a tarefa de descoberta para voc e o notificar quando forem encontrados aparelhos e quando a tarefa de descoberta estiver concluda.

    Recebendo objetos Intent via broadcast para aparelhos descobertos e concluso de descobertaPara obter os resultados da descoberta, voc se registrar para receber dois objetos Intent via broadcast:

    O objeto Intent da ao BluetoothAdapter.ACTION_FOUND transmitido para cada aparelho Bluetooth descoberto. O Intent inclui como extra um objeto Bluetooth-Device representando um aparelho com capacidade para Bluetooth.

    O objeto Intent da ao BluetoothAdapter.ACTION_DISCOVERY_FINISHED transmi-tido quando a busca de aparelhos est concluda.

    Contatorecentemente

    recebido

    a) Lista de contatos antes de receber o novo contato b) Lista de contatos aps receber o novo contato

    Fig. 17.4 | Contatos do aparelho receptor antes e depois de receber o novo contato.

  • 6 Android para Programadores

    Captando conexesVoc vai usar uma thread separada para captar pedidos de conexo recebidos de outros apa-relhos que estejam executando o aplicativo Enhanced Address Book. Nessa thread, voc vai chamar o mtodo listenUsingRfcommWithServiceRecord de BluetoothAdapter, o qual retor-na um BluetoothServerSocket que pode ser usado para comear a captar conexes. O m-todo accept de BluetoothServerSocket bloqueia a thread a partir da qual chamado e capta os pedidos de conexo Bluetooth recebidos. Quando uma conexo recebida, retornado um objeto BluetoothSocket. Esse objeto contm um elemento InputStream e um elemento OutputStream para comunicao com o outro aparelho. Conforme voc ver, o mtodo listenUsingRfcommWithServiceRecord recebe como argumento um identificador exclusivo que outros aparelhos devem usar para se conectar com este aplicativo no aparelho receptor.

    Conectando-se com outro aparelhoPara se conectar com outro aparelho, voc vai usar o mtodo createRfcommSocket-ToServiceRecord da classe BluetoothDevice, o qual retorna um BluetoothSocket para comunicao com o aparelho remoto. Esse mtodo exibe como argumento um iden-tificador globalmente exclusivo correspondente ao passado para o mtodo listenUsing-RfcommWithServiceRecord de BluetoothAdapter isso ajuda a garantir que a conexo seja estabelecida somente com outro aparelho que esteja executando o aplicativo Enhanced Address Book. Se o BluetoothSocket for recuperado, chamamos seu mtodo connect para abrir uma conexo com o aparelho remoto.

    Transferindo um contatoDepois que estabelecemos uma conexo, usamos o BluetoothSocket para obter um InputStream no aparelho receptor para ler o contato e um OutputStream no aparelho remetente para enviar o contato. O mtodo read de InputStream usado para obter o contato recebido do aparelho remoto. Para enviar um contato, passamos para o mtodo send de OutputStream um buffer de bytes representando as informaes desse contato.

    Usando objetos JSONObject para transmitir e receber dadosUsamos um JSONObject (pacote org.json) para formatar os dados de um contato como um objeto String a fim de enviar e extrair os dados do contato no aparelho receptor.

    17.4 Construo dos arquivos de interface do usurio e de recursosNesta seo voc vai criar os arquivos de layout da interface grfica do usurio do aplicativo Enhanced Address Book e modificar alguns daqueles que criou no aplicativo Address Book do Captulo 10. Nas subsees a seguir, mostramos somente os arquivos novos e alterados.

    17.4.1 Criao do projeto

    Comece excluindo de seu espao de trabalho Eclipse o projeto EnhancedAddressBook que foi testado na Seo 17.2. Para fazer isso, no Package Explorer, clique com o boto direito do mouse no projeto e selecione Delete. Na caixa de dilogo que aparece, certifique-se de que Delete project contents on disk no esteja marcado e, em seguida, clique em OK. En-to, no sistema de arquivos de seu computador, copie a pasta AddressBook do aplicativo

  • Captulo 17 Aplicativo Address Book melhorado 7

    Address Book, mude o nome da cpia para EnhancedAddressBook e, em seguida, importe o projeto EnhancedAddressBook para seu espao de trabalho usando os passos da Seo 17.2.

    17.4.2 AndroidManifest.xml

    A Figura 17.5 mostra o arquivo AndroidManifest.xml deste aplicativo. Existem trs itens novos nesse arquivo. As linhas 67 especificam dois elementos :

    android.permission.BLUETOOTH (linha 6) permite que o aplicativo se conecte com ou-tros aparelhos com Bluetooth habilitado que estejam conectados com esse aparelho.

    android.permission.BLUETOOTH_ADMIN (linha 7) permite que o aplicativo descubra outros aparelhos com Bluetooth habilitado e se conecte com eles.

    As linhas 2223 especificam um elemento para a nova Activity DeviceChooser.

    1 2 5 6 7 8 9 11 13 14 15 16 17 18 20 22 23 24 25

    Fig. 17.5 | AndroidManifest.xml.

    17.4.3 addressbook_menu.xml: menu da Activity AddressBook

    A Figura 17.6 mostra o menu de AddressBook atualizado. O item receiveContactItem (linhas 812) permite ao usurio dizer ao aplicativo para que receba um contato de outro aparelho. Selecionar esse item faz com que o aplicativo pergunte ao usurio se pode tornar esse aparelho detectvel. Se o usurio disser que sim, ento o aplicativo tentar captar uma conexo de outro aparelho. Se receber uma, ler o contato do outro aparelho.

    1 2 3

  • 8 Android para Programadores

    17.4.4 view_contact_menu.xml: menu da Activity ViewContact

    A Figura 17.7 mostra o menu atualizado da Activity ViewContact. O item de menu transferItem (linhas 1317) permite ao usurio enviar um contato para outro aparelho. Selecionar esse item de menu faz com que o aplicativo exiba a Activity DeviceChooser (Seo 17.5.3), a qual procura e exibe uma lista de aparelhos Bluetooth prximos. Ento, o usurio pode escolher o aparelho para o qual vai transferir o contato, o que faz a Acti-vity ViewContact enviar o contato em uma thread separada.

    1 2 3 8 13 18

    Fig. 17.7 | Menu da Activity ViewContact.

    17.4.5 device_chooser_layout.xml: layout da ListActivity DeviceChooser

    A Figura 17.8 mostra o layout personalizado da subclasse DeviceChooser de ListActi-vity. Como sempre, ao criar um layout personalizado para uma ListActivity, certifi-que-se de incluir um elemento ListView e de configurar seu atributo android:id como @android:id/list.

    4 android:title="@string/menuitem_add_contact" 5 android:icon="@drawable/ic_menu_add"6 android:titleCondensed="@string/menuitem_add_contact"7 android:alphabeticShortcut="a">8 13

    Fig. 17.6 | Menu da Activity AddressBook.

  • Captulo 17 Aplicativo Address Book melhorado 9

    17.4.6 device_layout.xml: layout dos itens de ListView do ListView da ListActivity DeviceChooser

    A Figura 17.9 mostra o componente TextView personalizado que usado para exibir cada item do ListView da Activity DeviceChooser.

    1 2

    Fig. 17.9 | Layout do item de ListView do ListView da Activity DeviceChooser.

    17.5 Construo do aplicativoNesta seo, discutiremos apenas as classes modificadas e a nova classe do aplicativo Enhan-ced Address Book. As classes AddEditContact e DatabaseConnector no mudaram em relao ao Captulo 10; portanto, no so mostradas aqui. Para as classes AddressBook (Seo 17.5.1) e ViewContact (Seo 17.5.2), mostramos somente as partes que foram alteradas as defini-es de classe completas pode ser vistas abrindo-se os arquivos de cdigo-fonte do projeto. Mostramos a classe DeviceChooser completa (Seo 17.5.3), a qual ativada pela ListActi-vity ViewContact quando o usurio opta por enviar um contato para outro aparelho.

    17.5.1 Activity AddressBook atualizada

    A classe AddressBook (Figs. 17.1017.15) contm as atualizaes que permitem ao apli-cativo habilitar o adaptador Bluetooth do aparelho caso ainda no esteja habilitado e receber um novo contato de outro aparelho.

    Instruo package, instrues import e camposA Figura 17.10 contm a instruo package, as instrues import e os campos da classe. Discutiremos as novas classes e interfaces medida que as encontrarmos ao longo da

    1 2 5 10 13 17

    Fig. 17.8 | Layout da subclasse DeviceChooser de ListActivity.

  • 10 Android para Programadores

    classe. As linhas 3940 declaram uma constante do tipo UUID (identificador universal-mente exclusivo). Usamos uma conexo Bluetooth peer-to-peer entre dois aparelhos que esto executando esse aplicativo e que esto prximos entre si (normalmente, em torno de 9 a 90 metros, dependendo do aparelho). Conforme voc vai ver, esse UUID ajuda a garantir que a conexo entre os aparelhos seja proveniente desse aplicativo em execuo em outro aparelho. Existem muitos geradores de UUID na Web usamos o que est em:

    www.guidgenerator.com

    A linha 43 declara um nome constante que associado ao UUID. Quando o usu-rio selecionar o item de menu Receive Contact dessa Activity, a Activity registrar o par nome/UUID no servidor SDP (Service Discovery Protocol) do aparelho, o qual atribuir um canal de comunicao que usado por aparelhos remotos para se conec-tarem. Ento, um aparelho remoto pode usar o UUID para consultar o servidor SDP no aparelho que est esperando para receber um contato. Se o servidor SDP encontrar o UUID, retornar o canal de comunicao apropriado para que o aparelho remoto possa iniciar uma conexo peer-to-peer.

    As constantes nas linhas 4647 so passadas para startActivityForResult ao se iniciar objetos Intent que habilitam o adaptador Bluetooth do aparelho e permitem que ele seja descoberto por outro aparelho Bluetooth, respectivamente. A linha 50 de-clara a varivel BluetoothAdapter que usada para interagir com o adaptador Bluetooth do aparelho. O Handler (linha 52) usado a partir de threads que no so da interface grfica do usurio nessa Activity para garantir que objetos Toast sejam exibidos na thread da interface grfica do usurio. As variveis de instncia restantes so da classe AddressBook do Captulo 10.

    1 // AddressBook.java2 // Atividade principal do aplicativo Address Book.3 package com.deitel.addressbook;45 import java.io.IOException;6 import java.io.InputStream;789101112 import android.app.ListActivity;13141516 import android.content.Context;17 import android.content.Intent;18 import android.database.Cursor;19 import android.os.AsyncTask;20 import android.os.Bundle;21 import android.os.Handler;22 import android.util.Log;23 import android.view.Menu;24 import android.view.MenuInflater;25 import android.view.MenuItem;

    import java.util.UUID;

    import org.json.JSONException;import org.json.JSONObject;

    import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothServerSocket;import android.bluetooth.BluetoothSocket;

    Fig. 17.10 | Instruo package, instrues import e campos de AddressBook.

  • Captulo 17 Aplicativo Address Book melhorado 11

    Mtodos onCreate e onResume atualizados da ActivityAs linhas 74 e 76 do mtodo onCreate (Fig. 17.11, linhas 5977) so novas neste aplica-tivo. A linha 74 chama o mtodo esttico getDefaultAdapter da classe BluetoothAdapter para obter uma referncia para o adaptador Bluetooth padro dos aparelhos. A linha 76 cria o Handler para exibir os objetos Toast na thread da interface grfica do usurio.

    26 import android.view.View;27 import android.widget.AdapterView;28 import android.widget.AdapterView.OnItemClickListener;29 import android.widget.CursorAdapter;30 import android.widget.ListView;31 import android.widget.SimpleCursorAdapter;32 import android.widget.Toast;3334 public class AddressBook extends ListActivity 35 {36 private static String TAG = AddressBook.class.getName();373839404142 // nome desse servio para descoberta de servio43 private static final String NAME = "AddressBookBluetooth";4445 // constantes passadas para startActivityForResult 46 private static final int ENABLE_BLUETOOTH = 1; 47 private static final int REQUEST_DISCOVERABILITY = 2; 4849 // BluetoothAdapter d acesso aos recursos Bluetooth5051 private boolean userAllowedBluetooth = true;52 private Handler handler; // para exibir Toasts de threads que no so

    // da interface grfica do usurio5354 public static final String ROW_ID = "row_id"; // chave extra do Intent55 private ListView contactListView; // ListView da ListActivity56 private CursorAdapter contactAdapter; // adaptador para ListView57

    // UUID de aplicativo exclusivo, gerado em http://www.guidgenerator.com/public static final UUID MY_UUID = UUID.fromString("6acc0a73-afc3-4483-a3a8-94be2c0dfc52");

    private BluetoothAdapter bluetoothAdapter = null;

    Fig. 17.10 | Instruo package, instrues import e campos de AddressBook.

    58 // chamado quando a atividade criada59 @Override60 public void onCreate(Bundle savedInstanceState) 61 {62 super.onCreate(savedInstanceState); // chama onCreate de super63 contactListView = getListView(); // obtm o componente ListView interno64 contactListView.setOnItemClickListener(viewContactListener); 6566 // mapeia o nome de cada contato em um TextView no layout do ListView67 String[] from = new String[] { "name" };

    Fig. 17.11 | Mtodos onCreate e onResume atualizados da Activity. (continua)

  • 12 Android para Programadores

    O mtodo onResume (linhas 8097) chama o mtodo isEnabled de BluetoothAdapter (linha 86) para determinar se o Bluetooth est habilitado. Se no estiver, o objeto Intent de BluetoothAdapter.ACTION_REQUEST_ENABLE (linhas 8990) passado para startActivityFor-Result a fim de pedir para o sistema ativar a Activity usada para habilitar comunicao com Bluetooth. O mtodo onActivityResult (Fig. 17.13) receber o resultado dessa Activity.

    Mtodo onOptionsItemSelected atualizado da ActivityAtualizamos o mtodo onOptionsItemSelected com um novo caso para o item de menu Receive Contact (Fig. 17.12, linhas 159174). Se o BluetoothAdapter estiver habilitado, as linhas 163166 perguntam ao usurio se podem tornar esse aparelho detectvel por outros aparelhos. O objeto Intent de BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE (linhas 163164) passado para startActivityForResult a fim de pedir para o sistema ativar a Activity usada para tornar o aparelho detectvel por outros aparelhos. O mtodo onActivityResult (Fig. 17.13) receber o resultado dessa Activity. Se o usurio permitir que o aplicativo torne o aparelho detectvel, ele ficar detectvel por 120 segundos, por padro. Isso pode ser personalizado adicionando-se um extra ao Intent para a chave BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION com um valor em segundos (0 significa que o aparelho permanece sempre detectvel). Se o BluetoothAdapter no estiver habili-tado, simplesmente exibimos um Toast indicando que o Bluetooth no est habilitado.

    68 int[] to = new int[] { R.id.contactTextView };69 contactAdapter = new SimpleCursorAdapter(70 AddressBook.this, R.layout.contact_list_item, null, from, to);71 setListAdapter(contactAdapter); // configura o adaptador de

    // contactView7273 // obtm o adaptador Bluetooth padro 74 bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();7576 handler = new Handler(); // para exibir Toasts na thread da

    // interface grfica77 } // fim do mtodo onCreate7879 // chamado quando essa Activity retorna do segundo plano80 @Override81 protected void onResume() 82 {83 super.onResume(); // chama o mtodo onResume de super8485 // pede para que o Bluetooth seja habilitado, caso ainda no esteja86 if (!bluetoothAdapter.isEnabled()) 87 {88 // cria e inicia um Intent para pedir que o usurio habilite

    // o Bluetooth8990919293 } // fim do if9495 // cria uma nova GetContactsTask e a executa 96 new GetContactsTask().execute((Object[]) null);97 } // fim do mtodo onResume

    Intent enableBluetoothIntent = new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE);

    startActivityForResult(enableBluetoothIntent,ENABLE_BLUETOOTH);

    Fig. 17.11 | Mtodos onCreate e onResume atualizados da Activity.

  • Captulo 17 Aplicativo Address Book melhorado 13

    Sobrescrevendo o mtodo onActivityResult de ActivityQuando o mtodo onActivityResult (Fig. 17.13) chamado em resposta ao Intent BluetoothAdapter.ACTION_REQUEST_ENABLE ativado em onResume (Fig. 17.11), as linhas 208219 exibem um Toast indicando se o Bluetooth foi habilitado. Quando o mtodo chamado em resposta ao Intent BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE em onOptionsItemSelected (Fig. 17.12), se o usurio permitiu que o aparelho se tornasse descobrvel, a linha 225 chama listenForContact (Fig. 17.14) para captar (esperar por) uma conexo de outro aparelho, em uma thread separada; caso contrrio, exibimos um Toast indicando que o aparelho no descobrvel.

    147 // trata a escolha do menu de opes148 @Override149 public boolean onOptionsItemSelected(MenuItem item) 150 {151 switch (item.getItemId())152 {153 case R.id.addContactItem: 154 // cria novo Intent para ativar a Activity AddEditContact155 Intent addNewContact = 156 new Intent(AddressBook.this, AddEditContact.class);157 startActivity(addNewContact); // inicia a Activity AddEditContact158 break;159 case R.id.receiveContactItem:160 if )(161 {162

    163164165166167 } // fim do if168 else // o usurio no permitiu que o adaptador Bluetooth fosse

    // habilitado169 {170 Toast.makeText(this, 171 R.string.no_bluetooth,172 Toast.LENGTH_LONG).show();173 } // fim do else174 break;175 } // fim do switch176177 return super.onOptionsItemSelected(item); // chama o mtodo de super178 } // fim do mtodo onOptionsItemSelected

    bluetoothAdapter.isEnabled()

    // ativa Intent para pedir capacidade de descoberta por 120 // segundosIntent requestDiscoverabilityIntent = new Intent(

    BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); startActivityForResult(requestDiscoverabilityIntent,

    REQUEST_DISCOVERABILITY);

    Fig. 17.12 | Mtodo onOptionsItemSelected atualizado da Activity.

    198 // chamado com o resultado de startActivityForResult199 @Override200 protected void onActivityResult(int requestCode, int resultCode,201 Intent data)202 {203 super.onActivityResult(requestCode, resultCode, data);

    Fig. 17.13 | Sobrescrevendo o mtodo onActivityResult de Activity. (continua)

  • 14 Android para Programadores

    Mtodo listenForContact e classe aninhada ReceiveContactTaskO mtodo listenForContact e a classe aninhada ReceiveContactTask (Fig. 17.14) so novas neste aplicativo. O mtodo listenForContact (linhas 238244) simplesmente ativa a AsyncTask ReceiveContactTask (linhas 247347) a qual comea a esperar por uma conexo de outro aparelho que esteja executando o aplicativo Enhanced Address Book e, se receber uma, l as novas informaes de contato desse outro aparelho.

    204205 switch (requestCode) // processa o resultado com base em requestCode206 {207 case ENABLE_BLUETOOTH: // tentou habilitar Bluetooth208 if (resultCode == RESULT_OK) // Bluetooth foi habilitado209 {210 Toast.makeText(this, 211 R.string.bluetooth_enabled,212 Toast.LENGTH_LONG).show(); 213 } // fim do if214 else // Bluetooth no foi habilitado215 {216 userAllowedBluetooth = false;217 Toast.makeText(this, R.string.no_bluetooth,218 Toast.LENGTH_LONG).show(); 219 } // fim do else220 break;221 // tentou tornar o aparelho descobrvel 222 case REQUEST_DISCOVERABILITY: 223 if (resultCode != RESULT_CANCELED) // o usurio deu permisso224 {225 listenForContact(); // comea a esperar por uma conexo226 } // fim do if227 else // o usurio no permitiu a capacidade de descoberta228 {229 Toast.makeText(this, 230 R.string.no_discoverability,231 Toast.LENGTH_LONG).show(); 232 } // fim do else233 break;234 } // fim do switch235 } // fim do mtodo onActivityResult236

    Fig. 17.13 | Sobrescrevendo o mtodo onActivityResult de Activity.

    237 // comea a esperar por um contato enviado de outro aparelho238 private void listenForContact()239 {240 // inicia tarefa de segundo plano para esperar uma conexo 241 // e receber um contato242 ReceiveContactTask task = new ReceiveContactTask();243 task.execute((Object[]) null);244 } // fim do mtodo listenForContact

    Fig. 17.14 | Mtodo listenForContact e classe aninhada ReceiveContactTask.

  • Captulo 17 Aplicativo Address Book melhorado 15

    245 246 // thread que capta pedidos de conexo recebidos247 private class ReceiveContactTask 248 extends AsyncTask 249 {250 251 252 253 // espera conexo, recebe contato e atualiza lista de contatos254 @Override255 protected Object doInBackground(Object... params)256 {257 try258 {259 260 261 262 263 264 displayToastViaHandler(AddressBook.this, handler, 265 R.string.waiting_for_contact);266267 268 269 270 271 272 273 // cria um array de bytes para conter as informaes de

    // contato recebidas274 byte[] buffer = new byte[1024];275 int bytes; // nmero de bytes lidos276 277 278 279 280 if (bytes != -1) // um contato foi recebido281 {282 DatabaseConnector databaseConnector = null;283 284 // converte readMessage em JSONObject285 try286 {287 288 289 290 291 // cria novo DatabaseConnector292 databaseConnector = 293 new DatabaseConnector(getBaseContext());294 295 // abre o banco de dados e adiciona o contato nele296 databaseConnector.open(); // conecta ao banco de dados297

    private BluetoothServerSocket serverSocket; // espera conexoprivate BluetoothSocket socket; // usado para processar conexo

    // obtm BluetoothServerSocket de bluetoothAdapter serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord( NAME, MY_UUID);

    // espera conexo BluetoothSocket socket = serverSocket.accept();

    // obtm InputStream para receber contato InputStream inputStream = socket.getInputStream();

    // l do InputStream e armazena os dados em bufferbytes = inputStream.read(buffer);

    // cria JSONObject a partir dos bytes lidosJSONObject contact = new JSONObject(new String(buffer, 0, buffer.length));

    Fig. 17.14 | Mtodo listenForContact e classe aninhada ReceiveContactTask. (continua)

  • 16 Android para Programadores

    298 // adiciona o contato299300301302303304305 // atualiza a lista de contatos306 new GetContactsTask().execute((Object[]) null);307 displayToastViaHandler(AddressBook.this, handler, 308 R.string.contact_received);309 } // fim do try310 catch (JSONException e) // problema na formatao JSON311 { 312 displayToastViaHandler(AddressBook.this, handler, 313 R.string.contact_not_received);314 Log.e(TAG, e.toString());315 } // fim do catch316 finally // garante que a conexo com o banco de dados

    // seja fechada317 {

    318 if (databaseConnector != null)319 databaseConnector.close(); // fecha a conexo320 } // fim do finally321 } // fim do if322 } // fim do try323 catch (IOException e) 324 { 325 Log.e(TAG, e.toString());326 } // fim do catch327 finally // garante que BluetoothServerSocket e BluetoothSocket

    // sejam fechados328 {329 try330 {331 // se BluetoothServerSocket no for null, fecha-o332 if (serverSocket != null)333334335 // se BluetoothSocket no for null, fecha-o336 if (socket != null)337338 } // fim do try339 catch (IOException e) // problema ao fechar um socket340 {341 Log.e(TAG, e.toString());342 } // fim do catch343 } // fim do finally344345 return null;346 } // fim do mtodo doInBackround347 } // fim da classe aninhada ReceiveContactTask 348

    databaseConnector.insertContact( contact.getString("name"), contact.getString("email"), contact.getString("phone"), contact.getString("street"), contact.getString("city"));

    serverSocket.close();

    socket.close();

    Fig. 17.14 | Mtodo listenForContact e classe aninhada ReceiveContactTask.

  • Captulo 17 Aplicativo Address Book melhorado 17

    A ligao em rede com Bluetooth semelhante baseada em sockets padro. A linha 250 declara um BluetoothServerSocket, que ser usado para esperar uma conexo de outro aparelho. A linha 251 declara um BluetoothSocket se recebemos uma conexo, ento pode-mos usar os mtodos de BluetoothSocket para obter referncias para o InputStream, a fim de obter leitura de outro aparelho, e para o OutputStream, a fim de escrever em outro aparelho.

    O mtodo doInBackground de AsyncTask (linhas 254346) primeiramente chama o mtodo listenUsingRfcommWithServiceRecord de BluetoothAdapter com as constantes decla-radas nas linhas 3940 e 43 (Fig. 17.10), para registrar o aplicativo no servidor SDP (Service Discovery Protocol) do Android e obter um objeto BluetoothServerSocket. Em seguida, a li-nha 268 chama o mtodo accept em BluetoothServerSocket para comear a esperar por uma conexo de outro aparelho. Quando uma conexo recebida, esse mtodo retorna um Blue-toothSocket que pode ser usado para se comunicar com o outro aparelho. Nessa Activity, simplesmente precisamos ler um contato do outro aparelho, de modo que a linha 271 obtm o InputStream do BluetoothSocket. A linha 278 l os bytes do contato do aparelho remetente.

    Neste aplicativo, usamos dados formatados em JSON (apresentados no Captulo 14) para transferir o contato entre os aparelhos. As linhas 288289 convertem os bytes do conta-to em um objeto String e, ento, criam um JSONObject a partir desse objeto String. Usamos a classe DatabaseConnector do Captulo 10 para inserir o novo contato no banco de dados. As linhas 298303 usam o mtodo getString de JSONObject para extrair os dados do contato e pass-los para o mtodo insertContact de DatabaseConnector. Ento, a linha 306 inicia uma AsyncTask para atualizar a lista de contatos. O bloco finally nas linhas 327343 garan-te que BluetoothServerSocket e BluetoothSocket sejam fechados depois que a transferncia estiver concluda (ou se ocorrer um problema durante a transferncia).

    [Observao: possvel que a linha 278 leia apenas uma parte dos dados embora seja improvvel neste aplicativo. Para garantir a leitura de todos os dados, leia os bytes em um loop at que o mtodo read retorne -1 para indicar que no existem mais bytes. Cada iterao converteria os bytes em uma String e concatenaria os caracteres no final do que foi lido anteriormente.]

    Mtodo utilitrio displayToastViaHandlerO mtodo displayToastViaHandler (Fig. 17.15) chamado a partir de outras threads nessa Activity para exibir objetos Toast na thread da interface grfica do usurio usando um Handler.

    349 // usa handler para exibir um Toast na thread da interface grfica // do usurio com a mensagem especificada

    350 public static void displayToastViaHandler(final Context context, 351 Handler handler, final int stringID)352 {353 handler.post( 354 new Runnable()355 {356 public void run()357 {358 Toast.makeText(context, stringID,359 Toast.LENGTH_SHORT).show();360 } // fim do mtodo run361 } // fim de Runnable362 ); // fim da chamada do mtodo post do handler363 } // fim do mtodo displayToastViaHandler

    Fig. 17.15 | Mtodo utilitrio displayToastViaHandler.

  • 18 Android para Programadores

    17.5.2 Activity ViewContact atualizada

    A classe ViewContact (Figs. 17.1617.20) contm as atualizaes que permitem ao usu-rio do aplicativo enviar um contato para outro aparelho.

    Instruo package, instrues import e camposA Figura 17.16 contm a instruo package, as instrues import e os campos da classe. Discutiremos as novas classes e interfaces medida que as encontrarmos ao longo da clas-se. A constante na linha 34 passada para startActivityForResult ao se ativar a Activity DeviceChooser para que o usurio possa escolher o aparelho para o qual vai enviar um contato. BluetoothAdapter (linha 36) usado para determinar se o Bluetooth est habi-litado e para obter um objeto BluetoothDevice para o aparelho selecionado pelo usurio na Activity DeviceChooser. O handler (linha 37) usado a partir de threads que no so da interface grfica do usurio nessa Activity, para garantir que os objetos Toast sejam exibidos na thread da interface.

    1 // ViewContact.java2 // Activity para ver um contato.3 package com.deitel.addressbook;45 import java.io.IOException;6 import java.io.OutputStream;7891011 import android.app.Activity;12 import android.app.AlertDialog;13141516 import android.content.DialogInterface;17 import android.content.Intent;18 import android.database.Cursor;19 import android.os.AsyncTask;20 import android.os.Bundle;21 import android.os.Handler;22 import android.util.Log;23 import android.view.Menu;24 import android.view.MenuInflater;25 import android.view.MenuItem;26 import android.widget.TextView;27 import android.widget.Toast;2829 public class ViewContact extends Activity 30 {31 private static final String TAG = ViewContact.class.getName();3233 // cdigo de solicitao do Intent usado para iniciar uma

    // Activity que retorna um resultado34 private static final int REQUEST_CONNECT_DEVICE = 1;35

    import org.json.JSONException;import org.json.JSONObject;

    import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket;

    Fig. 17.16 | Instruo package, instrues import e campos de ViewContact.

  • Captulo 17 Aplicativo Address Book melhorado 19

    Mtodo onCreate atualizado de ActivityOs nicos recursos novos no mtodo onCreate (Fig. 17.17) esto nas linhas 65 e 67, as quais obtm o BluetoothAdapter padro e criam um Handler, respectivamente.

    46 // chamado quando a Activity criada47 @Override48 public void onCreate(Bundle savedInstanceState) 49 {50 super.onCreate(savedInstanceState);51 setContentView(R.layout.view_contact); // infla a interface

    // grfica do usurio5253 // obtm componentes EditText54 nameTextView = (TextView) findViewById(R.id.nameTextView);55 phoneTextView = (TextView) findViewById(R.id.phoneTextView);56 emailTextView = (TextView) findViewById(R.id.emailTextView);57 streetTextView = (TextView) findViewById(R.id.streetTextView);58 cityTextView = (TextView) findViewById(R.id.cityTextView);5960 // obtm o ID da linha do contato selecionado61 Bundle extras = getIntent().getExtras();62 rowID = extras.getLong(AddressBook.ROW_ID); 6364656667 handler = new Handler(); // cria o Handler68 } // fim do mtodo onCreate

    // obtm o adaptador Bluetooth padro bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

    Fig. 17.17 | Mtodo onCreate atualizado de Activity.

    Mtodo onOptionsItemSelected atualizado de ActivityAtualizamos o mtodo onOptionsItemSelected com um novo caso para o item de menu Transfer Contact (Fig. 17.18, linhas 156171). Se BluetoothAdapter estiver ha-bilitado, as linhas 161164 ativam a Activity DeviceChooser para que o usurio possa selecionar o aparelho para o qual o contato deve ser enviado. O resultado dessa Acti-vity o endereo do aparelho selecionado, o qual retornado para o mtodo onActi-vityResult (Fig. 17.19).

    3637 private Handler handler; // para exibir Toasts na thread da interface

    // grfica3839 private long rowID; // ID da linha no banco de dados do contato selecionado40 private TextView nameTextView; // exibe o nome do contato 41 private TextView phoneTextView; // exibe o telefone do contato42 private TextView emailTextView; // exibe o email do contato43 private TextView streetTextView; // exibe o endereo do contato44 private TextView cityTextView; // exibe cidade/estado/CEP do contato45

    private BluetoothAdapter bluetoothAdapter = null; // adaptador Bluetooth

    Fig. 17.16 | Instruo package, instrues import e campos de ViewContact.

  • 20 Android para Programadores

    Sobrescrevendo o mtodo onActivityResult de ActivityO mtodo onActivityResult (Fig. 17.19) chamado quando a Activity DeviceChooser retorna. Se a Activity retorna um aparelho, as linhas 236237 iniciam uma SendCon-tactTask para enviar o contato para outro aparelho. O parmetro data do mtodo onAc-tivityResult contm um extra representando o endereo do aparelho para o qual o con-tato deve ser enviado. Esse endereo passado como o nico elemento de um array de Strings para o mtodo execute de AsyncTask, o qual ativa a AsyncTask e passa o array de Strings para o mtodo doInBackground da tarefa.

    133 // trata a escolha do menu de opes134 @Override135 public boolean onOptionsItemSelected(MenuItem item) 136 {137 switch (item.getItemId()) // switch baseado no ID do

    // MenuItem selecionado138 {139 case R.id.editItem: // item de menu Edit Contact selecionado140 // cria um Intent para ativar a Activity AddEditContact141 Intent addEditContact =142 new Intent(this, AddEditContact.class);143144 // passa os dados do contato selecionado como extras com o Intent145 addEditContact.putExtra(AddressBook.ROW_ID, rowID);146 addEditContact.putExtra("name", nameTextView.getText());147 addEditContact.putExtra("phone", phoneTextView.getText());148 addEditContact.putExtra("email", emailTextView.getText());149 addEditContact.putExtra("street", streetTextView.getText());150 addEditContact.putExtra("city", cityTextView.getText());151 startActivity(addEditContact); // inicia a Activity152 break;153 case R.id.deleteItem: // item de menu Delete Contact selecionado154 deleteContact(); // exclui o contato exibido155 break;156 case R.id.transferItem: // item de menu Transfer Contact selecionado157 // se ainda no estamos conectados158 if )(159 {160 // ativa DeviceChooser para que o usurio possa

    // escolher um aparelho prximo161 Intent serverIntent = 162 new Intent(this, DeviceChooser.class);163 startActivityForResult(164 serverIntent, REQUEST_CONNECT_DEVICE);165 } // fim do if 166 else // indica que o Bluetooth no est habilitado167 {168 Toast.makeText(this, 169 R.string.no_bluetooth, Toast.LENGTH_LONG).show();170 } // fim do else171 break;172 } // fim do switch173174 return super.onOptionsItemSelected(item);175 } // fim do mtodo onOptionsItemSelected

    bluetoothAdapter.isEnabled()

    Fig. 17.18 | Mtodo onOptionsItemSelected atualizado de Activity.

  • Captulo 17 Aplicativo Address Book melhorado 21

    Classe aninhada SendContactTaskA classe SendContactTask (Fig. 17.20) envia um contato para outro aparelho usando AsyncTask. Quando o mtodo doInBackground executado, as linhas 256257 usam o primeiro elemento do array params que contm um objeto String representando o en-dereo de um aparelho no mtodo getRemoteDevice de BluetoothAdapter. Isso retorna um BluetoothDevice representando o aparelho que est nesse endereo. Em seguida, as linhas 268269 chamam o mtodo createRfcommSocketToServiceRecord de BluetoothDe-vice com AddressBook.UUID como argumento. Essa chamada se comunica com o aparelho remoto para criar uma conexo segura, supondo que exista um aplicativo com o mesmo UUID esperando conexes no aparelho remoto. Se assim for, o mtodo retorna um Blue-toothSocket que pode ser usado para se comunicar com o aplicativo no aparelho remoto. Ento, a linha 270 chama o mtodo connect de BluetoothSocket para abrir a conexo. Nesta Activity, enviamos um contato para o aparelho remoto, de modo que obtemos apenas o OutputStream do BluetoothSocket (linha 273). As linhas 276281 criam um objeto JSONObject contendo as informaes do contato como pares chave/valor. A linha 284 obtm a representao de String de JSONObject e, ento, obtm os bytes do String e escreve esses bytes no OutputStream. Isso envia o contato para o aparelho remoto. O bloco finally nas linhas 301313 garante que BluetoothSocket seja fechado depois que a transferncia estiver concluda (ou se ocorrer um problema durante a transferncia).

    226 // chamado quando uma Activity ativada a partir desta usando 227 // startActivityForResult termina228 public void onActivityResult(int requestCode, int resultCode, 229 Intent data) 230 {231 // se a conexo foi estabelecida232 if (resultCode == Activity.RESULT_OK) 233 {234 // obtm o endereo MAC do aparelho remoto e passa-o para 235 // o mtodo execute de SendContactTas236 new SendContactTask().execute(new String[] { 237 data.getExtras().getString(DeviceChooser.DEVICE_ADDRESS)});238 } // fim do if239 else // houve um erro de conexo240 {241 // exibe Toast de erro de conexo242 Toast.makeText(this, 243 R.string.connection_error, Toast.LENGTH_LONG);244 } // fim do else245 } // fim do mtodo onActivityResult246

    Fig. 17.19 | Sobrescrevendo o mtodo onActivityResult de Activity.

    247 // Tarefa para enviar um contato em uma thread de segundo plano248 private class SendContactTask extends AsyncTask249 {

    Fig. 17.20 | A classe aninhada SendContactTask envia um contato para um aparelho remoto usando uma thread de segundo plano.

  • 22 Android para Programadores

    250 // obtm o BluetoothDevice do endereo especificado, 251 // conecta ao aparelho e envia o contato

    252 @Override253 protected Object doInBackground(String... params)254 {255256257258259 // para enviar o contato260261 // estabelece a conexo com o aparelho remoto e envia o contato262 try263 {264 AddressBook.displayToastViaHandler(ViewContact.this, handler, 265 R.string.sending_contact);266267

    268269270271272 // obtm fluxos (streams) para comunicao via BluetoothSocket273 ;=maertStuptuomaertStuptuO274275 // cria JSONObject representando o contato276 final JSONObject contact = new JSONObject();277 contact.put("name", nameTextView.getText().toString());278 contact.put("phone", phoneTextView.getText().toString());279 contact.put("email", emailTextView.getText().toString());280 contact.put("street", streetTextView.getText().toString());281 contact.put("city", cityTextView.getText().toString());282283 // envia um array de bytes contendo as informaes do contato284285286 AddressBook.displayToastViaHandler(ViewContact.this, handler, 287 R.string.contact_sent);288 } // fim do try289 catch (IOException e) // problema ao enviar o contato290 {291 AddressBook.displayToastViaHandler(ViewContact.this, handler, 292 R.string.transfer_failed);293 Log.e(TAG, e.toString());294 } // fim do catch295 catch (JSONException e) // problema na formatao de dados em JSON296 {297 AddressBook.displayToastViaHandler(ViewContact.this, handler, 298 R.string.transfer_failed);299 Log.e(TAG, e.toString());300 } // fim do catch

    // obtm um objeto BluetoothDevice representando o aparelho remotoBluetoothDevice device = bluetoothAdapter.getRemoteDevice(params[0]);

    BluetoothSocket bluetoothSocket = null;

    // obtm BluetoothSocket e, em seguida, conecta-se com o // outro aparelho bluetoothSocket = device.createRfcommSocketToServiceRecord(

    AddressBook.MY_UUID); bluetoothSocket.connect(); // estabelece a conexo

    bluetoothSocket.getOutputStream()

    outputStream.write(contact.toString().getBytes());outputStream.flush();

    Fig. 17.20 | A classe aninhada SendContactTask envia um contato para um aparelho remoto usando uma thread de segundo plano.

  • Captulo 17 Aplicativo Address Book melhorado 23

    17.5.3 Activity DeviceChooser

    A subclasse DeviceChooser de ListActivity (Fig. 17.2117.26) ativada pela Activity ViewContact quando o usurio tenta enviar um contato para um aparelho remoto.

    Instruo package, instrues import e camposA Figura 17.21 contm a instruo package, as instrues import e os campos da clas-se. A linha 30 define uma constante que representa o nmero de caracteres em um endereo MAC (Media Access Control). Um endereo MAC um identificador de rede exclusivo de determinado aparelho. Usamos o endereo MAC de um aparelho remoto para conectar esse aparelho na Activity ViewContact. A linha 33 define uma constante que usada como chave ao armazenarmos o endereo MAC do aparelho selecionado em um Intent que retornado para a Activity ViewContact. O ArrayAdapter (linha 36) ser usado para preencher o componente ListView dessa Activity com uma lista de aparelhos Bluetooth prximos.

    301 finally // garante que BluetoothSocket seja fechado302 {303 try304 {305306 } // fim do try307 catch (IOException e) // problema ao fechar BluetoothSocket308 {309 Log.e(TAG, e.toString());310 } // fim do catch311312 bluetoothSocket = null;313 } // fim do finally314315 return null;316 } // fim do mtodo doInBackground317 } // fim da classe SendContactTask

    bluetoothSocket.close(); // fecha BluetoothSocket

    Fig. 17.20 | A classe aninhada SendContactTask envia um contato para um aparelho remoto usando uma thread de segundo plano.

    1 // DeviceChooser.java2 // Activity para escolher um aparelho para conectar.3 package com.deitel.addressbook;45 import java.util.Set;67 import android.app.Activity;8 import android.app.ListActivity;91011 import android.content.BroadcastReceiver;12 import android.content.Context;13 import android.content.Intent;

    import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;

    Fig. 17.21 | Instruo package, instrues import e campos de DeviceChooser. (continua)

  • 24 Android para Programadores

    Sobrescrevendo o mtodo onCreate de ActivityO mtodo onCreate (Fig. 17.22) configura essa Activity. A linha 46 chama o m-todo requestWindowFeature da Activity (o que deve ocorrer antes da chamada de setContentView) para indicar que a janela dessa Activity deve mostrar um cone de pro-gresso indeterminado o processo de descoberta do aparelho pode levar algum tempo e pode haver um nmero arbitrrio de aparelhos prximos (e provvel que esse nmero aumente medida que mais e mais aparelhos Bluetooth apaream), de modo que no podemos mostrar um status de progresso exato.

    14 import android.content.IntentFilter;15 import android.os.Bundle;16 import android.view.View;17 import android.view.View.OnClickListener;18 import android.view.Window;19 import android.widget.AdapterView;20 import android.widget.ArrayAdapter;21 import android.widget.Button;22 import android.widget.ListView;23 import android.widget.TextView;24 import android.widget.AdapterView.OnItemClickListener;25 import android.widget.Toast;2627 public class DeviceChooser extends ListActivity 28 {29 // comprimento de um endereo MAC em caracteres30 private static final int MAC_ADDRESS_LENGTH = 17;3132 // chave para armazenar o endereo MAC do aparelho

    // selecionado como um extra de Intent33 public static final String DEVICE_ADDRESS = "device_address";3435 // o Bluetooth Adapter36 private ArrayAdapter foundDevicesAdapter; // dados de ListView37 private ListView newDevicesListView; // ListView que mostra os aparelhos38

    private BluetoothAdapter bluetoothAdapter;

    Fig. 17.21 | Instruo package, instrues import e campos de DeviceChooser.

    39 // chamado quando essa Activity criada40 @Override41 protected void onCreate(Bundle savedInstanceState) 42 {43 super.onCreate(savedInstanceState);4445 // mostra uma barra de progresso enquanto a atividade carregada464748 // configura o layout da Activity49 setContentView(R.layout.device_chooser_layout);5051 // configura o cdigo do resultado a retornar para a Activity anterior52 // se o usurio tocar no componente Button Cancel

    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

    Fig. 17.22 | Sobrescrevendo o mtodo onCreate de Activity.

  • Captulo 17 Aplicativo Address Book melhorado 25

    53 setResult(Activity.RESULT_CANCELED);5455 // cria componente Button para iniciar a descoberta56 Button scanButton = (Button) findViewById(R.id.scanButton);57 scanButton.setOnClickListener(58 new OnClickListener() 59 {60 // chamado quando scanButton clicado61 public void onClick(View v) 62 {63 startDiscovery(); // comea a procurar aparelhos64 } // fim do mtodo onClick65 } // fim de OnClickListener66 ); // fim da chamada de setOnClickListener6768 // inicializa o adaptador da lista de aparelhos encontrados69 foundDevicesAdapter = 70 new ArrayAdapter(this, R.layout.device_layout);7172 // inicializa o ListView que exibir os aparelhos

    // recentemente encontrados73 newDevicesListView = getListView();74 newDevicesListView.setAdapter(foundDevicesAdapter);75 newDevicesListView.setOnItemClickListener(76 deviceListItemClickListener);7778 // capta Intents de transmisso alertando que um aparelho Bluetooth 79 // foi encontrado nas proximidades8081828384 // capta Intents de transmisso alertando que a busca por85 // aparelhos prximos est concluda8687888990 // obtm BluetoothAdapter local919293 // obtm um conjunto de todos os aparelhos com que j nos conectamos94959697 // adiciona o nome de cada aparelho conectado em nosso ListView98 for (BluetoothDevice device : pairedDevices) 99 {100 foundDevicesAdapter.add( + "\n" + 101 ;)102 } // fim do for103 } // fim do mtodo onCreate104

    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);

    registerReceiver(deviceChooserReceiver, filter);

    filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);

    registerReceiver(deviceChooserReceiver, filter);

    bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

    Set pairedDevices = bluetoothAdapter.getBondedDevices();

    device.getName()device.getAddress()

    Fig. 17.22 | Sobrescrevendo o mtodo onCreate de Activity.

  • 26 Android para Programadores

    A linha 53 chama o mtodo setResult da Activity usando a constante RESULT_CAN-CELED. Se o usurio sair dessa Activity pressionando o boto Voltar antes de termos uma chance de retornar dados reais, esse resultado permitir que a chamada da Activity saiba que houve um erro. As linhas 5666 obtm scanButton e configuram seu OnClickLis-tener, o qual chama o mtodo startDiscovery (Fig. 17.24) quando o usurio toca no Button. As linhas 6970 criam o ArrayAdapter utilizado para preencher o ListView dessa Activity. As linhas 7376 configuram o ListView para exibir os aparelhos detectados.

    As linhas 8082 criam um IntentFilter usando a constante BluetoothDevice.ACTION_FOUND e, em seguida, chamam o mtodo registerReceiver da Activity com o deviceChooserReceiver BroadcastReceiver (definido na Fig. 17.26) e o novo IntentFil-ter. Sempre que um aparelho Bluetooth for encontrado, um Intent BluetoothDevice.ACTION_FOUND ser transmitido e o mtodo onReceive de nosso deviceChooserReceiver ser chamado para adicionar o novo aparelho na lista. As linhas 8688 criam outro In-tentFilter usando a constante BluetoothDevice. ACTION_DISCOVERY_FINISHED e, ento, registram deviceChooserReceiver para esse IntentFilter. Quando a descoberta de apa-relhos Bluetooth terminar, ser transmitido um Intent BluetoothAdapter.ACTION_DISCO-VERY_FINISHED e o mtodo onReceive de nosso deviceChooserReceiver ser chamado para verificar se foram encontrados aparelhos.

    A linha 91 obtm o BluetoothAdapter padro e, ento, as linhas 9495 utilizam o mtodo getBondedDevices de BluetoothAdapter para obter um conjunto de aparelhos (Set) contendo os aparelhos atualmente conectados. Ento, adicio-namos o nome e o endereo de cada aparelho (se houver) no ArrayAdapter do ListView (linhas 98102).

    Sobrescrevendo o mtodo onDestroy de ActivityQuando a Activity termina ou quando o Android a destri, o mtodo onDestroy (Fig. 17.23) chama o mtodo cancelDiscovery de BluetoothAdapter para parar de procurar aparelhos prximos (linha 114). Tambm desfazemos o registro de device-ChooserReceiver.

    105 // chamado antes que essa Activity seja destruda106 @Override107 protected void onDestroy() 108 {109 super.onDestroy();110111 // fim da descoberta de Bluetooth112 if (bluetoothAdapter != null) 113 {114115 } // fim do if116117 // desfaz o registro do BroadcastReceiver deviceChooserReceiver118 unregisterReceiver(deviceChooserReceiver);119 } // fim do mtodo onDestroy120

    bluetoothAdapter.cancelDiscovery();

    Fig. 17.23 | Sobrescrevendo o mtodo onDestroy de Activity.

  • Captulo 17 Aplicativo Address Book melhorado 27

    Mtodo startDiscoveryO mtodo startDiscovery (Fig. 17.24) procura aparelhos prximos com Bluetooth habi-litado. Chamamos o mtodo isDiscovering de BluetoothAdapter (linha 132) para deter-minar se j estamos procurando aparelhos. Em caso positivo, interrompemos a busca atual chamando o mtodo cancelDiscovery de BluetoothAdapter (linha 134). A linha 138 exibe a barra de progresso indeterminado e, em seguida, a linha 141 chama o mtodo startDis-covery de BluetoothAdapter para comear a descoberta de aparelhos a partir do zero.

    121 // inicia a descoberta122 private void startDiscovery() 123 {124 // verifica se o Bluetooth ainda est habilitado125 if (!bluetoothAdapter.isEnabled()) 126 {127 Toast.makeText(this, R.string.no_bluetooth, Toast.LENGTH_LONG);128 return;129 } // fim do if130131 // fim da descoberta existente, se necessrio132 if )(133 {134135 } // fim do if136137 // mostra a barra de progresso138139140 // comea a procurar outros aparelhos141142 } // fim do mtodo startDiscovery143

    bluetoothAdapter.isDiscovering()

    bluetoothAdapter.cancelDiscovery();

    setProgressBarIndeterminateVisibility(true);

    bluetoothAdapter.startDiscovery();

    Fig. 17.24 | Mtodo startDiscovery.

    deviceListItemClickListener OnItemClickListener

    Quando o usurio toca em um aparelho no componente ListView da Activity, o mtodo onItemClick de deviceListItemClickListener (Fig. 17.25, linhas 148168) chamado. O usurio selecionou um aparelho; portanto, chamamos imediatamente o mtodo cancelDis-covery de BluetoothAdapter (linha 152) para interromper a busca de outros aparelhos. A procura diminui a vida da bateria de um aparelho; portanto, voc deve encerrar o processo quando a Activity no for mais necessria. As linhas 155157 extraem o endereo MAC do aparelho selecionado e, ento, as linhas 160166 criam um novo Intent com o endereo MAC includo como extra e configuram o Intent como resultado da Activity. Chamamos finish para terminar essa Activity e retornamos o Intent para a Activity ViewContact.

    144 // capta eventos gerados quando o usurio clica no item de ListView145 private OnItemClickListener deviceListItemClickListener = 146 new OnItemClickListener() 147 {148 public void onItemClick(AdapterView parent, View view, 149 int position, long id) 150 {

    Fig. 17.25 | deviceListItemClickListener OnItemClickListener. (continua)

  • 28 Android para Programadores

    deviceChooserReceiver BroadcastReceiverA Figura 17.26 define o BroadcastReceiver que responde aos objetos Intent de trans-misso via broadcast indicando quando um aparelho descoberto e quando a descoberta est concluda. O mtodo onReceive chamado sempre que transmitido um Intent que corresponda a qualquer um dos elementos IntentFilter para os quais esse receptor est registrado para responder. Primeiramente, obtemos a ao do Intent recebido usando seu mtodo getAction (linha 180). Se a ao corresponder constante ACTION_FOUND de BluetoothDevice, sabemos que o Intent dado inclui o BluetoothDevice selecionado como extra. As linhas 186187 obtm o BluetoothDevice usando o mtodo getParcelableEx-tra do Intent. As linhas 191195 verificam se o aparelho retornado j est conectado com o aparelho atual (no caso em que ele j aparece na lista de aparelhos). Se no estiver, o adicionamos no ArrayAdapter do ListView. Se a ao corresponder constante ACTION_DISCOVERY_FINISHED de BluetoothAdapter, a busca terminou. A linha 202 oculta a barra de progresso indeterminado. Se nenhum aparelho foi encontrado, adicionamos um item no ArrayAdapter do ListView explicando esse fato.

    151 // cancela a descoberta antes de tentar se conectar152153154 // obtm o endereo MAC do aparelho selecionado155 String info = ((TextView) view).getText().toString();156 String address = info.substring(info.length() - 157 MAC_ADDRESS_LENGTH);158159 // cria um Intent para retornar Activity que fez a chamada160 Intent intent = new Intent();161162 // inclui o endereo MAC do aparelho no Intent de retorno163 intent.putExtra(DEVICE_ADDRESS, address);164165 // configura nosso Intent como valor de retorno de sucesso e termina166 setResult(Activity.RESULT_OK, intent);167 finish();168 } // fim do mtodo onItemClick169 }; // fim de OnItemClickListener170

    bluetoothAdapter.cancelDiscovery();

    Fig. 17.25 | deviceListItemClickListener OnItemClickListener.

    171 // capta Intents de transmisso anunciando quando uma 172 // descoberta termina e quando novos aparelhos so detectados173 private final BroadcastReceiver deviceChooserReceiver = 174 new BroadcastReceiver() 175 {176 // chamado quando uma transmisso recebida177 public void onReceive(Context context, Intent intent) 178 {

    Fig. 17.26 | deviceChooserReceiver BroadcastReceiver capta Intents de transmisso via broadcast que indicam quando um aparelho encontrado e quando a descoberta de aparelhos terminou.

  • Captulo 17 Aplicativo Address Book melhorado 29

    17.6 Para finalizarO aplicativo Enhanced Address Book permite ao usurio transferir contatos entre aparelhos usando conexes de rede Bluetooth. Voc usou vrias classes do pacote android.bluetooth para executar tarefas relacionadas a Bluetooth. Usou o mtodo esttico getDefaultAdapter de BluetoothAdapter para obter um objeto que representa o adaptador Bluetooth do apa-relho. Para procurar aparelhos Bluetooth prximos, voc usou o mtodo startDiscovery de BluetoothAdapter para dizer ao Android que executasse a tarefa de descoberta, a fim de notific-lo quando aparelhos fossem encontrados e quando a descoberta terminasse.

    179 // obtm a ao do Intent que fez a chamada180 String action = intent.getAction(); 181182 // um novo aparelho foi detectado183 if (BluetoothDevice.ACTION_FOUND.equals(action)) 184 {185 // obtm o BluetoothDevice do Intent de transmisso186187188189 // se o aparelho ainda no estiver conectado, adiciona seu nome190 // no componente ListView191 if )(192 {193 foundDevicesAdapter.add( + "\n" + 194 ;)195 } // fim do if196 } // fim do if197 // uma busca por novos aparelhos terminou198 else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(199 action)) 200 {201 // oculta a barra de progresso202203204 // configura o ttulo da Activity205 setTitle(getResources().getString(R.string.choose_device));206207 // se no havia aparelhos ao alcance, exibe uma mensagem208 if (foundDevicesAdapter.getCount() == 0) 209 {210 // desabilita cliques de item da lista211 newDevicesListView.setOnItemClickListener(null);212 foundDevicesAdapter.add(getResources().getString(213 R.string.no_devices));214 } // fim do if215 } // fim do else if216 } // fim do mtodo onReceive217 }; // fim de BroadcastReceiver218 } // fim da classe DeviceChooser

    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

    device.getBondState() != BluetoothDevice.BOND_BONDED

    device.getName()device.getAddress()

    setProgressBarIndeterminateVisibility(false);

    Fig. 17.26 | deviceChooserReceiver BroadcastReceiver capta Intents de transmisso via broadcast que indicam quando um aparelho encontrado e quando a descoberta de aparelhos terminou.

  • 30 Android para Programadores

    Para receber os resultados da descoberta, voc se registrou para receber objetos In-tent de transmisso via broadcast que notificavam o aplicativo quando cada aparelho Bluetooth era descoberto (fornecendo um objeto BluetoothDevice para cada um deles) e quando a busca de aparelhos terminava.

    Voc usou uma thread separada para captar os pedidos de conexo recebidos de ou-tros aparelhos que estavam executando o aplicativo Enhanced Address Book. Nessa thre-ad, voc chamou o mtodo listenUsingRfcommWithServiceRecord de BluetoothAdapter para obter um BluetoothServerSocket e, ento, usou o mtodo accept desse objeto para captar os pedidos de conexo Bluetooth recebidos. Quando uma conexo era recebida, era retornado um BluetoothSocket contendo um InputStream e um OutputStream para comunicao com o outro aparelho.

    Para se conectar com o outro aparelho, voc usou o mtodo createRfcommSocket-ToServiceRecord de BluetoothDevice, a fim de obter um BluetoothSocket para comuni-cao com o aparelho remoto. Ento, voc chamou o mtodo connect desse objeto para abrir uma conexo com o aparelho.

    Por fim, voc transmitiu e recebeu os dados no formato JSON. Para criar os dados formatados em JSON, voc gerou um objeto JSONObject e obteve sua representao de String. Para receber os dados JSON, voc criou um objeto JSONObject e passou a repre-sentao de String formatada em JSON para o construtor do objeto.

    No Captulo 18, apresentaremos o OpenGL ES para criar elementos grficos tridi-mensionais e animaes. Voc vai criar um aplicativo que mostra um cubo, uma pirmide ou um prisma retangular. O usurio poder selecionar a figura a ser exibida, mudar sua escala e selecionar a velocidade de rotao da figura mostrada ao longo dos eixos x, y e z.