Вы находитесь на странице: 1из 30

Objetivos

Neste captulo, voc vai:


O
Usar Bluetooth para estabelecer uma conexo peer-to-
-peer entre dois aparelhos e transferir informaes de
um para outro.
O
Usar a classe BluetoothAdapter para verificar se o
Bluetooth est habilitado em um aparelho.
O
Iniciar um Intent que pede permisso ao usurio para
habilitar o Bluetooth, se ainda no estiver habilitado.
O
Iniciar um Intent que pede permisso ao usurio
para tornar um aparelho detectvel via Bluetooth,
podendo receber uma conexo.
O
Usar a classe BluetoothServerSocket para esperar
uma conexo de outro aparelho.
O
Usar a classe BluetoothDevice para estabelecer uma
conexo com outro aparelho.
O
Usar a classe BluetoothSocket para transmitir dados
entre aparelhos.
O
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 Introduo
O 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 aplicativo
Abra 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.
R
e
s
u
m
o
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 contato
Para 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 contato
Para 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 um
aparelho 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 tecnologias
Esta 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 Bluetooth
Neste 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 Bluetooth
Para 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 descoberta
Para 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.
Contato
recentemente
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 conexes
Voc 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 aparelho
Para 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 contato
Depois 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 dados
Usamos 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 recursos
Nesta 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 <uses-permission>:
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 <activity> para a nova Activity DeviceChooser.
1 <?xml version="1.0" encoding="utf-8"?>
2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.deitel.addressbook" android:versionCode="1"
4 android:versionName="1.0">
5 <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10"/>
6
7
8
9 <application android:icon="@drawable/icon"
10 android:label="@string/app_name">
11 <activity android:name=".AddressBook"
12 android:label="@string/app_name">
13 <intent-filter>
14 <action android:name="android.intent.action.MAIN" />
15 <category android:name="android.intent.category.LAUNCHER" />
16 </intent-filter>
17 </activity>
18 <activity android:name=".AddEditContact"
19 android:label="@string/app_name"></activity>
20 <activity android:name=".ViewContact"
21 android:label="@string/app_name"></activity>
22
23
24 </application>
25 </manifest>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<activity android:name=".DeviceChooser"
android:label="@string/app_name"></activity>
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 <?xml version="1.0" encoding="utf-8"?>
2 <menu xmlns:android="http://schemas.android.com/apk/res/android">
3 <item android:id="@+id/addContactItem"
Fig. 17.6 | Menu da Activity AddressBook.
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 <?xml version="1.0" encoding="utf-8"?>
2 <menu xmlns:android="http://schemas.android.com/apk/res/android">
3 <item android:id="@+id/editItem"
4 android:title="@string/menuitem_edit_contact"
5 android:orderInCategory="1" android:alphabeticShortcut="e"
6 android:titleCondensed="@string/menuitem_edit_contact"
7 android:icon="@android:drawable/ic_menu_edit"></item>
8 <item android:id="@+id/deleteItem"
9 android:title="@string/menuitem_delete_contact"
10 android:orderInCategory="2" android:alphabeticShortcut="d"
11 android:titleCondensed="@string/menuitem_delete_contact"
12 android:icon="@android:drawable/ic_delete"></item>
13 <item android:id="@+id/transferItem"
14 android:title="@string/menuitem_transfer_contact"
15 android:orderInCategory="3" android:alphabeticShortcut="t"
16 android:titleCondensed="@string/menuitem_transfer_contact"
17 android:icon="@android:drawable/stat_sys_data_bluetooth"></item>
18 </menu>
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"></item>
8 <item android:id="@+id/receiveContactItem"
9 android:title="@string/menuitem_receive_contact"
10 android:icon="@drawable/ic_volume_bluetooth_in_call"
11 android:titleCondensed="@string/menuitem_receive_contact"
12 android:alphabeticShortcut="e"></item>
13 </menu>
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 <?xml version="1.0" encoding="utf-8"?>
2 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content" android:textSize="16sp"
5 android:padding="4dp" />
Fig. 17.9 | Layout do item de ListView do ListView da Activity DeviceChooser.
17.5 Construo do aplicativo
Nesta 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 campos
A 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 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical" android:layout_width="match_parent"
4 android:layout_height="match_parent">
5 <TextView android:layout_width="match_parent"
6 android:layout_height="wrap_content"
7 android:text="@string/title_other_devices"
8 android:background="#666666" android:textColor="#FFFFFF"
9 android:paddingLeft="4dp" />
10 <ListView android:id="@android:id/list"
11 android:layout_width="match_parent"
12 android:layout_height="0dp" android:layout_weight="1" />
13 <Button android:id="@+id/scanButton"
14 android:layout_width="match_parent"
15 android:layout_height="wrap_content"
16 android:text="@string/button_scan" />
17 </LinearLayout>
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.java
2 // Atividade principal do aplicativo Address Book.
3 package com.deitel.addressbook;
4
5 import java.io.IOException;
6 import java.io.InputStream;
7
8
9
10
11
12 import android.app.ListActivity;
13
14
15
16 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 Activity
As 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;
33
34 public class AddressBook extends ListActivity
35 {
36 private static String TAG = AddressBook.class.getName();
37
38
39
40
41
42 // nome desse servio para descoberta de servio
43 private static final String NAME = "AddressBookBluetooth";
44
45 // constantes passadas para startActivityForResult
46 private static final int ENABLE_BLUETOOTH = 1;
47 private static final int REQUEST_DISCOVERABILITY = 2;
48
49 // BluetoothAdapter d acesso aos recursos Bluetooth
50
51 private boolean userAllowedBluetooth = true;
52 private Handler handler; // para exibir Toasts de threads que no so
// da interface grfica do usurio
53
54 public static final String ROW_ID = "row_id"; // chave extra do Intent
55 private ListView contactListView; // ListView da ListActivity
56 private CursorAdapter contactAdapter; // adaptador para ListView
57
// 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 criada
59 @Override
60 public void onCreate(Bundle savedInstanceState)
61 {
62 super.onCreate(savedInstanceState); // chama onCreate de super
63 contactListView = getListView(); // obtm o componente ListView interno
64 contactListView.setOnItemClickListener(viewContactListener);
65
66 // mapeia o nome de cada contato em um TextView no layout do ListView
67 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 Activity
Atualizamos 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
// contactView
72
73 // obtm o adaptador Bluetooth padro
74 bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
75
76 handler = new Handler(); // para exibir Toasts na thread da
// interface grfica
77 } // fim do mtodo onCreate
78
79 // chamado quando essa Activity retorna do segundo plano
80 @Override
81 protected void onResume()
82 {
83 super.onResume(); // chama o mtodo onResume de super
84
85 // pede para que o Bluetooth seja habilitado, caso ainda no esteja
86 if (!bluetoothAdapter.isEnabled())
87 {
88 // cria e inicia um Intent para pedir que o usurio habilite
// o Bluetooth
89
90
91
92
93 } // fim do if
94
95 // 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 Activity
Quando 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 opes
148 @Override
149 public boolean onOptionsItemSelected(MenuItem item)
150 {
151 switch (item.getItemId())
152 {
153 case R.id.addContactItem:
154 // cria novo Intent para ativar a Activity AddEditContact
155 Intent addNewContact =
156 new Intent(AddressBook.this, AddEditContact.class);
157 startActivity(addNewContact); // inicia a Activity AddEditContact
158 break;
159 case R.id.receiveContactItem:
160 if ) (
161 {
162
163
164
165
166
167 } // fim do if
168 else // o usurio no permitiu que o adaptador Bluetooth fosse
// habilitado
169 {
170 Toast.makeText(this,
171 R.string.no_bluetooth,
172 Toast.LENGTH_LONG).show();
173 } // fim do else
174 break;
175 } // fim do switch
176
177 return super.onOptionsItemSelected(item); // chama o mtodo de super
178 } // fim do mtodo onOptionsItemSelected
bluetoothAdapter.isEnabled()
// ativa Intent para pedir capacidade de descoberta por 120
// segundos
Intent 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 startActivityForResult
199 @Override
200 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 ReceiveContactTask
O 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.
204
205 switch (requestCode) // processa o resultado com base em requestCode
206 {
207 case ENABLE_BLUETOOTH: // tentou habilitar Bluetooth
208 if (resultCode == RESULT_OK) // Bluetooth foi habilitado
209 {
210 Toast.makeText(this,
211 R.string.bluetooth_enabled,
212 Toast.LENGTH_LONG).show();
213 } // fim do if
214 else // Bluetooth no foi habilitado
215 {
216 userAllowedBluetooth = false;
217 Toast.makeText(this, R.string.no_bluetooth,
218 Toast.LENGTH_LONG).show();
219 } // fim do else
220 break;
221 // tentou tornar o aparelho descobrvel
222 case REQUEST_DISCOVERABILITY:
223 if (resultCode != RESULT_CANCELED) // o usurio deu permisso
224 {
225 listenForContact(); // comea a esperar por uma conexo
226 } // fim do if
227 else // o usurio no permitiu a capacidade de descoberta
228 {
229 Toast.makeText(this,
230 R.string.no_discoverability,
231 Toast.LENGTH_LONG).show();
232 } // fim do else
233 break;
234 } // fim do switch
235 } // fim do mtodo onActivityResult
236
Fig. 17.13 | Sobrescrevendo o mtodo onActivityResult de Activity.
237 // comea a esperar por um contato enviado de outro aparelho
238 private void listenForContact()
239 {
240 // inicia tarefa de segundo plano para esperar uma conexo
241 // e receber um contato
242 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 recebidos
247 private class ReceiveContactTask
248 extends AsyncTask<Object, Object, Object>
249 {
250
251
252
253 // espera conexo, recebe contato e atualiza lista de contatos
254 @Override
255 protected Object doInBackground(Object... params)
256 {
257 try
258 {
259
260
261
262
263
264 displayToastViaHandler(AddressBook.this, handler,
265 R.string.waiting_for_contact);
266
267
268
269
270
271
272
273 // cria um array de bytes para conter as informaes de
// contato recebidas
274 byte[] buffer = new byte[1024];
275 int bytes; // nmero de bytes lidos
276
277
278
279
280 if (bytes != -1) // um contato foi recebido
281 {
282 DatabaseConnector databaseConnector = null;
283
284 // converte readMessage em JSONObject
285 try
286 {
287
288
289
290
291 // cria novo DatabaseConnector
292 databaseConnector =
293 new DatabaseConnector(getBaseContext());
294
295 // abre o banco de dados e adiciona o contato nele
296 databaseConnector.open(); // conecta ao banco de dados
297
private BluetoothServerSocket serverSocket; // espera conexo
private 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 buffer
bytes = inputStream.read(buffer);
// cria JSONObject a partir dos bytes lidos
JSONObject 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 contato
299
300
301
302
303
304
305 // atualiza a lista de contatos
306 new GetContactsTask().execute((Object[]) null);
307 displayToastViaHandler(AddressBook.this, handler,
308 R.string.contact_received);
309 } // fim do try
310 catch (JSONException e) // problema na formatao JSON
311 {
312 displayToastViaHandler(AddressBook.this, handler,
313 R.string.contact_not_received);
314 Log.e(TAG, e.toString());
315 } // fim do catch
316 finally // garante que a conexo com o banco de dados
// seja fechada 317
{
318 if (databaseConnector != null)
319 databaseConnector.close(); // fecha a conexo
320 } // fim do finally
321 } // fim do if
322 } // fim do try
323 catch (IOException e)
324 {
325 Log.e(TAG, e.toString());
326 } // fim do catch
327 finally // garante que BluetoothServerSocket e BluetoothSocket
// sejam fechados
328 {
329 try
330 {
331 // se BluetoothServerSocket no for null, fecha-o
332 if (serverSocket != null)
333
334
335 // se BluetoothSocket no for null, fecha-o
336 if (socket != null)
337
338 } // fim do try
339 catch (IOException e) // problema ao fechar um socket
340 {
341 Log.e(TAG, e.toString());
342 } // fim do catch
343 } // fim do finally
344
345 return null;
346 } // fim do mtodo doInBackround
347 } // 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 displayToastViaHandler
O 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 run
361 } // fim de Runnable
362 ); // fim da chamada do mtodo post do handler
363 } // 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 campos
A 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.java
2 // Activity para ver um contato.
3 package com.deitel.addressbook;
4
5 import java.io.IOException;
6 import java.io.OutputStream;
7
8
9
10
11 import android.app.Activity;
12 import android.app.AlertDialog;
13
14
15
16 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;
28
29 public class ViewContact extends Activity
30 {
31 private static final String TAG = ViewContact.class.getName();
32
33 // cdigo de solicitao do Intent usado para iniciar uma
// Activity que retorna um resultado
34 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 Activity
Os 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 criada
47 @Override
48 public void onCreate(Bundle savedInstanceState)
49 {
50 super.onCreate(savedInstanceState);
51 setContentView(R.layout.view_contact); // infla a interface
// grfica do usurio
52
53 // obtm componentes EditText
54 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);
59
60 // obtm o ID da linha do contato selecionado
61 Bundle extras = getIntent().getExtras();
62 rowID = extras.getLong(AddressBook.ROW_ID);
63
64
65
66
67 handler = new Handler(); // cria o Handler
68 } // fim do mtodo onCreate
// obtm o adaptador Bluetooth padro
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Fig. 17.17 | Mtodo onCreate atualizado de Activity.
Mtodo onOptionsItemSelected atualizado de Activity
Atualizamos 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).
36
37 private Handler handler; // para exibir Toasts na thread da interface
// grfica
38
39 private long rowID; // ID da linha no banco de dados do contato selecionado
40 private TextView nameTextView; // exibe o nome do contato
41 private TextView phoneTextView; // exibe o telefone do contato
42 private TextView emailTextView; // exibe o email do contato
43 private TextView streetTextView; // exibe o endereo do contato
44 private TextView cityTextView; // exibe cidade/estado/CEP do contato
45
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 Activity
O 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 opes
134 @Override
135 public boolean onOptionsItemSelected(MenuItem item)
136 {
137 switch (item.getItemId()) // switch baseado no ID do
// MenuItem selecionado
138 {
139 case R.id.editItem: // item de menu Edit Contact selecionado
140 // cria um Intent para ativar a Activity AddEditContact
141 Intent addEditContact =
142 new Intent(this, AddEditContact.class);
143
144 // passa os dados do contato selecionado como extras com o Intent
145 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 Activity
152 break;
153 case R.id.deleteItem: // item de menu Delete Contact selecionado
154 deleteContact(); // exclui o contato exibido
155 break;
156 case R.id.transferItem: // item de menu Transfer Contact selecionado
157 // se ainda no estamos conectados
158 if ) (
159 {
160 // ativa DeviceChooser para que o usurio possa
// escolher um aparelho prximo
161 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 habilitado
167 {
168 Toast.makeText(this,
169 R.string.no_bluetooth, Toast.LENGTH_LONG).show();
170 } // fim do else
171 break;
172 } // fim do switch
173
174 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 SendContactTask
A 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 termina
228 public void onActivityResult(int requestCode, int resultCode,
229 Intent data)
230 {
231 // se a conexo foi estabelecida
232 if (resultCode == Activity.RESULT_OK)
233 {
234 // obtm o endereo MAC do aparelho remoto e passa-o para
235 // o mtodo execute de SendContactTas
236 new SendContactTask().execute(new String[] {
237 data.getExtras().getString(DeviceChooser.DEVICE_ADDRESS)});
238 } // fim do if
239 else // houve um erro de conexo
240 {
241 // exibe Toast de erro de conexo
242 Toast.makeText(this,
243 R.string.connection_error, Toast.LENGTH_LONG);
244 } // fim do else
245 } // fim do mtodo onActivityResult
246
Fig. 17.19 | Sobrescrevendo o mtodo onActivityResult de Activity.
247 // Tarefa para enviar um contato em uma thread de segundo plano
248 private class SendContactTask extends AsyncTask<String, Object, Object>
249 {
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 @Override
253 protected Object doInBackground(String... params)
254 {
255
256
257
258
259 // para enviar o contato
260
261 // estabelece a conexo com o aparelho remoto e envia o contato
262 try
263 {
264 AddressBook.displayToastViaHandler(ViewContact.this, handler,
265 R.string.sending_contact);
266
267
268
269
270
271
272 // obtm fluxos (streams) para comunicao via BluetoothSocket
273 ; = m a e r t S t u p t u o m a e r t S t u p t u O
274
275 // cria JSONObject representando o contato
276 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());
282
283 // envia um array de bytes contendo as informaes do contato
284
285
286 AddressBook.displayToastViaHandler(ViewContact.this, handler,
287 R.string.contact_sent);
288 } // fim do try
289 catch (IOException e) // problema ao enviar o contato
290 {
291 AddressBook.displayToastViaHandler(ViewContact.this, handler,
292 R.string.transfer_failed);
293 Log.e(TAG, e.toString());
294 } // fim do catch
295 catch (JSONException e) // problema na formatao de dados em JSON
296 {
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 remoto
BluetoothDevice 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 campos
A 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 fechado
302 {
303 try
304 {
305
306 } // fim do try
307 catch (IOException e) // problema ao fechar BluetoothSocket
308 {
309 Log.e(TAG, e.toString());
310 } // fim do catch
311
312 bluetoothSocket = null;
313 } // fim do finally
314
315 return null;
316 } // fim do mtodo doInBackground
317 } // 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.java
2 // Activity para escolher um aparelho para conectar.
3 package com.deitel.addressbook;
4
5 import java.util.Set;
6
7 import android.app.Activity;
8 import android.app.ListActivity;
9
10
11 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 Activity
O 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;
26
27 public class DeviceChooser extends ListActivity
28 {
29 // comprimento de um endereo MAC em caracteres
30 private static final int MAC_ADDRESS_LENGTH = 17;
31
32 // chave para armazenar o endereo MAC do aparelho
// selecionado como um extra de Intent
33 public static final String DEVICE_ADDRESS = "device_address";
34
35 // o Bluetooth Adapter
36 private ArrayAdapter<String> foundDevicesAdapter; // dados de ListView
37 private ListView newDevicesListView; // ListView que mostra os aparelhos
38
private BluetoothAdapter bluetoothAdapter;
Fig. 17.21 | Instruo package, instrues import e campos de DeviceChooser.
39 // chamado quando essa Activity criada
40 @Override
41 protected void onCreate(Bundle savedInstanceState)
42 {
43 super.onCreate(savedInstanceState);
44
45 // mostra uma barra de progresso enquanto a atividade carregada
46
47
48 // configura o layout da Activity
49 setContentView(R.layout.device_chooser_layout);
50
51 // configura o cdigo do resultado a retornar para a Activity anterior
52 // 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);
54
55 // cria componente Button para iniciar a descoberta
56 Button scanButton = (Button) findViewById(R.id.scanButton);
57 scanButton.setOnClickListener(
58 new OnClickListener()
59 {
60 // chamado quando scanButton clicado
61 public void onClick(View v)
62 {
63 startDiscovery(); // comea a procurar aparelhos
64 } // fim do mtodo onClick
65 } // fim de OnClickListener
66 ); // fim da chamada de setOnClickListener
67
68 // inicializa o adaptador da lista de aparelhos encontrados
69 foundDevicesAdapter =
70 new ArrayAdapter<String>(this, R.layout.device_layout);
71
72 // inicializa o ListView que exibir os aparelhos
// recentemente encontrados
73 newDevicesListView = getListView();
74 newDevicesListView.setAdapter(foundDevicesAdapter);
75 newDevicesListView.setOnItemClickListener(
76 deviceListItemClickListener);
77
78 // capta Intents de transmisso alertando que um aparelho Bluetooth
79 // foi encontrado nas proximidades
80
81
82
83
84 // capta Intents de transmisso alertando que a busca por
85 // aparelhos prximos est concluda
86
87
88
89
90 // obtm BluetoothAdapter local
91
92
93 // obtm um conjunto de todos os aparelhos com que j nos conectamos
94
95
96
97 // adiciona o nome de cada aparelho conectado em nosso ListView
98 for (BluetoothDevice device : pairedDevices)
99 {
100 foundDevicesAdapter.add( + "\n" +
101 ; )
102 } // fim do for
103 } // fim do mtodo onCreate
104
IntentFilter filter =
new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(deviceChooserReceiver, filter);
filter =
new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(deviceChooserReceiver, filter);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> 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<BluetoothDevice>) 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 Activity
Quando 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 destruda
106 @Override
107 protected void onDestroy()
108 {
109 super.onDestroy();
110
111 // fim da descoberta de Bluetooth
112 if (bluetoothAdapter != null)
113 {
114
115 } // fim do if
116
117 // desfaz o registro do BroadcastReceiver deviceChooserReceiver
118 unregisterReceiver(deviceChooserReceiver);
119 } // fim do mtodo onDestroy
120
bluetoothAdapter.cancelDiscovery();
Fig. 17.23 | Sobrescrevendo o mtodo onDestroy de Activity.
Captulo 17 Aplicativo Address Book melhorado 27
Mtodo startDiscovery
O 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 descoberta
122 private void startDiscovery()
123 {
124 // verifica se o Bluetooth ainda est habilitado
125 if (!bluetoothAdapter.isEnabled())
126 {
127 Toast.makeText(this, R.string.no_bluetooth, Toast.LENGTH_LONG);
128 return;
129 } // fim do if
130
131 // fim da descoberta existente, se necessrio
132 if ) (
133 {
134
135 } // fim do if
136
137 // mostra a barra de progresso
138
139
140 // comea a procurar outros aparelhos
141
142 } // fim do mtodo startDiscovery
143
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 ListView
145 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 BroadcastReceiver
A 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 conectar
152
153
154 // obtm o endereo MAC do aparelho selecionado
155 String info = ((TextView) view).getText().toString();
156 String address = info.substring(info.length() -
157 MAC_ADDRESS_LENGTH);
158
159 // cria um Intent para retornar Activity que fez a chamada
160 Intent intent = new Intent();
161
162 // inclui o endereo MAC do aparelho no Intent de retorno
163 intent.putExtra(DEVICE_ADDRESS, address);
164
165 // configura nosso Intent como valor de retorno de sucesso e termina
166 setResult(Activity.RESULT_OK, intent);
167 finish();
168 } // fim do mtodo onItemClick
169 }; // fim de OnItemClickListener
170
bluetoothAdapter.cancelDiscovery();
Fig. 17.25 | deviceListItemClickListener OnItemClickListener.
171 // capta Intents de transmisso anunciando quando uma
172 // descoberta termina e quando novos aparelhos so detectados
173 private final BroadcastReceiver deviceChooserReceiver =
174 new BroadcastReceiver()
175 {
176 // chamado quando uma transmisso recebida
177 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 finalizar
O 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 chamada
180 String action = intent.getAction();
181
182 // um novo aparelho foi detectado
183 if (BluetoothDevice.ACTION_FOUND.equals(action))
184 {
185 // obtm o BluetoothDevice do Intent de transmisso
186
187
188
189 // se o aparelho ainda no estiver conectado, adiciona seu nome
190 // no componente ListView
191 if ) (
192 {
193 foundDevicesAdapter.add( + "\n" +
194 ; )
195 } // fim do if
196 } // fim do if
197 // uma busca por novos aparelhos terminou
198 else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(
199 action))
200 {
201 // oculta a barra de progresso
202
203
204 // configura o ttulo da Activity
205 setTitle(getResources().getString(R.string.choose_device));
206
207 // se no havia aparelhos ao alcance, exibe uma mensagem
208 if (foundDevicesAdapter.getCount() == 0)
209 {
210 // desabilita cliques de item da lista
211 newDevicesListView.setOnItemClickListener(null);
212 foundDevicesAdapter.add(getResources().getString(
213 R.string.no_devices));
214 } // fim do if
215 } // fim do else if
216 } // fim do mtodo onReceive
217 }; // fim de BroadcastReceiver
218 } // 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.

Вам также может понравиться