deitel_android_16.pdf
TRANSCRIPT
-
8/11/2019 Deitel_Android_16.pdf
1/29
ObjetivosNeste captulo, voc vai:
Especificar permisses para gravar udio e escrever noarmazenamento externo de um aparelho.
Gravar arquivos de udio usando MediaRecorder.
Criar uma representao visual da entrada de udio dousurio.
Usar um ArrayAdapterpara exibir os nomes dos ar-quivos de um diretrio em um ListView.
Usar a classe Filepara salvar arquivos no diretrio dearmazenamento externo de um aparelho.
Usar a classe Filepara excluir arquivos do diretrio dearmazenamento externo de um aparelho.
Permitir que o usurio envie uma gravao como anexode email.
Aplicativo Voice
RecorderGravao de udio com MediaRecorder,
reproduo de udio com MediaPlayer, envio deum arquivo como anexo de email
16
-
8/11/2019 Deitel_Android_16.pdf
2/29
2 Android para Programadores
16.1 IntroduoO aplicativo Voice Recorderpermite ao usurio gravar sons usando o microfone do telefo-ne e salvar os arquivos de udio para reproduzir posteriormente. A Activityprincipal doaplicativo (Fig. 16.1) mostra um componente ToggleButtonRecordque permite ao usurioiniciar a gravao de udio, os botes Savee Deleteque se tornam ativos depois que o usurio
termina uma gravao e um boto View Saved Recordings
que permite ver uma lista de gra-vaes salvas. Quando o usurio toca no componente ToggleButton
Record, este se torna umToggleButtonStop
e a parte superior da tela se torna um visualizador que exibe barras verdescujo tamanho varia proporcionalmente intensidade da voz do usurio (Fig. 16.2). Quandoo usurio toca no componente ToggleButton
Stop, os botes Savee Deleteso habilitados
Resumo 16.1 Introduo
16.2 Teste do aplicativo Voice Recorder
16.3 Viso geral das tecnologias 16.4 Construo dos arquivos da interface
grfica do usurio e dos recursos doaplicativo
16.4.1 Criao do projeto 16.4.2 Uso de cones padro do Android
na interface grfica do usurio do
aplicativo
16.4.3 AndroidManifest.xml 16.4.4 main.xml: layout daActivity
VoiceRecorder
16.4.5 name_edittext.xml: layoutdo componenteAlertDialog
personalizado, usado para dar nome
a uma gravao
16.4.6 saved_recordings.xml: layout daListActivity SavedRecordings
16.4.7 saved_recordings_row.xml:
layout do item personalizadode ListViewda ListActivity
SavedRecordings
16.4.8 play_pause_drawable.xml:elemento drawable para o
componenteButton Play/Pause
16.5 Construo do aplicativo
16.5.1 Subclasse VoiceRecorderdaActivity
16.5.2 SubclasseVisualizerView deView
16.5.3 SubclasseSavedRecordings daActivity
16.6 Para finalizar
Toque para ver asgravaes salvas
Boto Record
Os botes Savee Deletedesabilitados s sohabilitados quando h umanova gravao
rea de visualizao
Fig. 16.1 | Aplicativo Voice Recorderpronto para gravar.
-
8/11/2019 Deitel_Android_16.pdf
3/29
-
8/11/2019 Deitel_Android_16.pdf
4/29
4 Android para Programadores
3. direita do campo de texto Select root directory:, clique em Browsee, em seguida,localize e selecione a pasta VoiceRecorder.
4. Clique em Finishpara importar o projeto.
Conecte em seu computador um aparelho Android configurado para depurao e, emseguida, clique com o boto direito do mouse no projeto do aplicativo na janela PackageExplorere, no menu que aparece, selecione Run As > Android Application.
Gravando um novo arquivo de udio
Toque no componente ToggleButtonRecord(Fig. 16.1) para comear a gravar. me-dida que voc fala no microfone de seu aparelho, o visualizador do aplicativo reage intensidade de sua voz. Se voc gravar por um tempo suficientemente longo, as barras devisualizao rolaro para o lado esquerdo da tela, enquanto novas barras de visualizaoaparecero direita. Quando terminar de gravar, pressione o boto Stoppara habilitar os
botes Savee Delete. Para salvar sua gravao, toque em Savee, em seguida, digite umnome na caixa de dilogo Name Your Recordinge toque no boto Save. Para excluir suagravao, toque em Deletee, em seguida, confirme que voc deseja exclu-la.
Reproduzindo uma gravao
Toque no componente ButtonView Saved Recordings
para exibir uma ListActivityperso-nalizada, contendo uma lista rolante de gravaes anteriores. Toque no nome da gravaoque voc deseja reproduzir ela ser carregada e comear a ser reproduzida imediatamen-te. Deslize o cursor da SeekBarpara ajustar a posio de reproduo da gravao. Toque nocomponente ToggleButtonPausepara fazer uma pausa na reproduo. O rtulo e o cone
do boto mudam para indicar que voc pode tocar no boto novamente para reproduzira gravao toque nele para continuar a reproduo. Para voltar Activityprincipal doaplicativo, toque no boto Voltar do aparelho.
ToggleButton
alterna entrePlaye Pause
a) Selecionando uma gravao salvaanteriormente para reproduo
b)Invitation list.3gp em reproduo
Toque no nome deum clipe parareproduzi-lo
Toque em paraexcluir a gravao
Toque em paraenviar a gravaopor email
Fig. 16.4 | Reproduzindo uma gravao salva anteriormente.
-
8/11/2019 Deitel_Android_16.pdf
5/29
Captulo 16 Aplicativo Voice Recorder 5
16.3 Viso geral das tecnologiasEsta seo apresenta as novas tecnologias que usamos no aplicativo Voice Recorder.
Permisses para escrever dados no armazenamentoexterno e para gravar udio
Como sempre, o arquivo AndroidManifest.xmldescreve os componentes do aplicativo.Lembre-se, do Captulo 11, que os servios compartilhados do Android no so aces-sveis a um aplicativo, por padro. Para acessar os servios compartilhados voc precisapedirpermisso para us-los no arquivo de manifesto com elementos aninhados no elemento raiz . O elemento deste aplicativo contmelementos para gravar udio (para usar o microfone) e para escreverno armazenamento externo de um aparelho (para salvar uma gravao).
Componentes ImageViewque podem ser clicados
Em nossos layouts de itens de ListViewpersonalizados para os aplicativos Slideshow(Captulos 12 e 13), usamos componentes Buttonpara representar as tarefas que podiamser executadas para cada item da lista. O uso de componentes de interface grfica dousurio que podem receber o foco (como os componentes Button) em um layout deitens de ListViewpersonalizados impede que os prprios itens do ListViewpossam ser cli-cados. Isso no foi problema nos aplicativos Slideshowe Enhanced Slideshow, porque astarefas de determinado item de ListVieweram todas definidas por rotinas de tratamentode evento (event handlers) dos componentes Button. Neste aplicativo, queremos queo usurio toque em um item de ListViewpara reproduzir a gravao correspondente.Tambm queremos fornecer botes que permitam ao usurio enviar a gravao comoum anexo de email ou excluir a gravao. Por isso, os botes email e delete so defi-nidos como componentes ImageViewque podem ser clicados(Seo 16.4.7). Isso permiteque os prprios itens do ListViewtambm continuem podendo receber cliques.
Usando um drawable de lista de estados para alterar os cones de umcomponente ToggleButtoncom base em seu estado
Os botes do Android podem assumir vrios estados, dependendo de seu tipo. Por exem-plo, um ToggleButtonpode ser marcado ou desmarcado. s vezes desejvel especificar di-ferentes cones para diferentes estados. No Android, isso feito definindo-se um drawable
de lista de estados em XML, com um elemento raiz (Seo 16.4.8) contendoelementos para cada estado. Cada elemento tambm especifica o Drawable(como um cone, por exemplo) para exibir o estado correspondente. Neste aplicativo,especificamos um Drawablede lista de estados para o atributo android:drawableTopdeum ToggleButtone o Android exibe o Drawablecorreto automaticamente, com base noestado do componente ToggleButton.
Usando um MediaRecorderpara gravar udio
O aplicativo Voice Recorderusa um MediaRecorder(pacote android.media) para gravar avoz do usurio. Um MediaRecordergrava udio usando o microfone do aparelho e o salva
em um arquivo de udio nesse aparelho. A Seo 16.5.1 demonstra como configurar eusar um MediaRecorder.
-
8/11/2019 Deitel_Android_16.pdf
6/29
6 Android para Programadores
Usando a classe Filepara criar um arquivo temporrio,mudar o nome de um arquivo e excluir um arquivo
Inicialmente, cada gravao salva em um arquivo temporrio, o qual criamos com omtodo createTempFileda classe File. Quando o usurio opta por salvar esse arquivo,usamos o mtodo renameToda classe Filepara dar ao arquivo um nome permanente.Esses recursos so mostrados na Seo 16.5.1. A Seo 16.5.3 mostra como excluir umarquivo com o mtodo deletede File.
Enviando uma gravao como anexo de email
Usamos um Intente um seletor de atividade para permitir que o usurio envie umagravao como um anexo de email (Seo 16.5.3) por meio de qualquer aplicativo noaparelho que suporte essa capacidade.
16.4 Construo dos arquivos da interface grficado usurio e dos recursos do aplicativoNesta seo, discutiremos os arquivos de recursos e de layout do aplicativo.
16.4.1 Criao do projeto
Comece criando um novo projeto Android chamado VoiceRecorder. Especifique os se-guintes valores na caixa de dilogo New Android Projecte, em seguida, pressione Finish:
Build Target:certifique-se de que Android 2.3.3esteja marcado Application name:Voice Recorder Package name:com.deitel.voicerecorder Create Activity:VoiceRecorder Min SDK Version:10.
16.4.2 Uso de cones padro do Android na interfacegrfica do usurio
No Captulo 10, voc aprendeu que o Android vem com cones padro que voc podeusar em seus prprios aplicativos. Novamente, eles esto localizados na pasta platforms
do SDK, sob a pasta data/res/drawable-hdpide cada verso de plataforma. Copiamos oscones que utilizamos na pasta res/drawable-hdpideste aplicativo. Expanda essa pasta noEclipse para ver os cones especficos que escolhemos.
16.4.3 AndroidManifest.xml
Assim como nos aplicativos anteriores com vrias atividades, o arquivo AndroidManifest.xmldeste aplicativo contm elementos para cada Activity VoiceRecordere Sa-vedRecordings. Ambos usam a orientao de tela retrato (portrait). Alm disso, o elemen-to contm os seguintes elementos :
-
8/11/2019 Deitel_Android_16.pdf
7/29
Captulo 16 Aplicativo Voice Recorder 7
os quais indicam que o aplicativo exige a capacidade de gravar udio e escrever dados noarmazenamento externo, respectivamente.
16.4.4 main.xml:layout da Activity VoiceRecorder
Nenhum recurso novo apresentado no layout main.xmlpara a Activity VoiceRecorder,de modo que no mostramos a listagem de main.xmlaqui. Quando voc vir o arquivono Eclipse, lembre-se de que componentes Viewpersonalizados, como VisualizerView(linhas 57 no arquivo), devem ser declarados com seus nomes de pacote e de classe.
16.4.5 name_edittext.xml:layout do componente AlertDialogpersonalizado, usado para dar nome a uma gravao
Assim como o aplicativo Slideshow, este aplicativo usa um layout personalizado (name_
edittext.xml) que anexado a um componente AlertDialogpara que o usurio possadigitar um nome para a gravao ao salv-la. O layout idntico quele usado na Seo12.4.6, de modo que no o mostramos aqui.
16.4.6 saved_recordings.xml:layout da ListActivitySavedRecordings
A Figura 16.5 mostra o layout da ListActivity SavedRecordings. Lembre-se de que aopersonalizar o layout de uma ListActivity, voc deve fornecer um componente ListViewcom android:idconfigurado como @android:id/list(linhas 2628). Esse layout apre-
1 2
7 /
11
14
21
25 26 29
android:keepScreenOn="true"
android:drawableTop="@drawable/play_pause_drawable"
Fig. 16.5 | Layout da ListActivitySavedRecordings.
-
8/11/2019 Deitel_Android_16.pdf
8/29
8 Android para Programadores
senta um recurso novo o ToggleButtonespecifica para seu atributo android:drawableTop(linha 17) o Drawablepersonalizado play_pause_drawable (Seo 16.4.8). Esse Drawablepermite ao Android alternar o cone entre play e pause quando o usurio muda o estado
do componente ToggleButton. Os itens exibidos no componente ListViewdesse layoututilizam o drawablepersonalizado definido na Seo 16.4.8.
16.4.7 saved_recordings_row.xml:layout do item de ListViewpersonalizado da ListActivity SavedRecordings
A Figura 16.6 mostra o layout dos itens exibidos no componente ListViewda ListActi-vity SavedRecordings. Cada item consiste em um componente LinearLayouthorizontale dois componentes ImageViewque podem ser clicados especificados pela configuraodo atributoandroid:clickablecomo truepara cada ListView(linhas 16 e 22).
1 2
6
11
17 23
android:clickable="true"
android:clickable="true"
Fig. 16.6 | Layout dos itens do componente ListViewda ListActivitySavedRecordings.
16.4.8 play_pause_drawable.xml:elemento drawablepara obotoPlay/Pause
Como voc sabe, os componentes ToggleButton(introduzidos no Captulo 11) fornecematributos android:textOffe android:textOnque permitem especificar o texto que exi-bido para dois estados do ToggleButton. Voc tambm pode estipular cones diferentespara os dois estados, definindo um Drawablepersonalizado que especifique os dois cones.Para fazer isso:
1. Crie um novo arquivo XML Android para um Drawable isso colocar o arquivona pasta /res/drawabledo projeto por padro.
2. Chame o arquivo de play_pause_drawable.xml. 3. Especifique selectorcomo elemento raiz. 4. Defina os dois elementos mostrados nas linhas 36 da Fig. 16.7.
-
8/11/2019 Deitel_Android_16.pdf
9/29
Captulo 16 Aplicativo Voice Recorder 9
Cada elemento especifica um Drawablepara determinado estado. Neste caso, es-pecificamos componentes Drawablepara os dois principais estados de um ToggleButton isto , quando est marcado e quando est desmarcado. Para especificar a qual estado oDrawablese aplica, use o atributo android:state_checkedcom o valor true(marcado) oufalse(desmarcado). Para mais informaes, consulte:
developer.android.com/guide/topics/resources/
drawable-resource.html#StateList
1
2 3 5 7
Fig. 16.7 | Drawablepersonalizado para o componente ToggleButtonRecordda ActivityVoiceRecorder.
16.5 Construo do aplicativoEste aplicativo consiste em trs classes VoiceRecorder(uma subclasse de Activity,Figs. 16.816.14), VisualizerView(uma subclasse de View, Figs. 16.1516.18) e Save-dRecordings(uma subclasse de ListActivity, Figs. 16.1916.27).
16.5.1 Subclasse VoiceRecorderda Activity
VoiceRecorder a classe Activityprincipal do aplicativo e responsvel por criar umagravao e visualiz-la. A classe VoiceRecordertambm permite que o usurio salve ouexclua uma nova gravao e veja uma Activityseparada para reproduzir gravaes salvasanteriormente que foram criadas por este aplicativo.
Instruo package, instrues importe campos
A nica classe nova usada pela classe VoiceRecorder MediaRecorder, que est realada naFig. 16.8. A linha 36 declara uma VisualizerView, que usada para exibir a representa-o visual da entrada de udio durante a gravao. As outras variveis de instncia serodiscutidas medida que forem usadas ao longo da classe.
1 // VoiceRecorder.java
2 // Activity principal da classe VoiceRecorder
3 package com.deitel.voicerecorder;
4
5 import java.io.File;
6 import java.io.IOException;
7
8 import android.app.Activity;
9 import android.app.AlertDialog;
10 import android.content.Context;
11 import android.content.DialogInterface;
12 import android.content.Intent;
1314 import android.os.Bundle;
import android.media.MediaRecorder;
Fig. 16.8 | Instruo package, instrues importe campos. (continua)
-
8/11/2019 Deitel_Android_16.pdf
10/29
10 Android para Programadores
Sobrescrevendo os mtodos onCreate, onResumeeonPausede Activity
Aps inflar main.xml (Fig. 16.9, linha 47), as linhas 5058 do mtodo onCreateob-tm referncias para os componentes ToggleButton, Buttone VisualizerViewdo layoute desabilitam os componentes saveButtone deleteButton. As linhas 6164 registram osreceptores (listeners) dos componentes ToggleButtone Button. A linha 66 cria o Handlerque ser usado para atualizar a VisualizerView.
15 import android.os.Handler;
16 import android.util.Log;
17 import android.view.Gravity;
18 import android.view.LayoutInflater;
19 import android.view.View;
20 import android.view.View.OnClickListener;21 import android.widget.Button;
22 import android.widget.CompoundButton;
23 import android.widget.CompoundButton.OnCheckedChangeListener;
24 import android.widget.EditText;
25 import android.widget.Toast;
26 import android.widget.ToggleButton;27
28 public class VoiceRecorder extends Activity
29 {30 private static final String TAG= VoiceRecorder.class.getName();
31
32 private Handler handler; // Handler para atualizar o visualizador33 private boolean recording; // estamos gravando?34
35 // variveis da interface grfica do usurio
36 private VisualizerView visualizer;
37 private ToggleButton recordButton;
38 private Button saveButton;
39 private Button deleteButton;40 private Button viewSavedRecordingsButton;
41
private MediaRecorder recorder; // usado para gravar udio
Fig. 16.8 | Instruo package, instrues importe campos.
42 // chamado quando a atividade criada
43 @Override
44 public voidonCreate(Bundle savedInstanceState)
45 {46 super.onCreate(savedInstanceState);
47 setContentView(R.layout.main); // configura o layout da Activity
48 49 // obtm os componentes Buttons e VisualizerView da Activity
50 recordButton =
51 (ToggleButton) findViewById(R.id.recordButton);
52 saveButton = (Button) findViewById(R.id.saveButton);53 saveButton.setEnabled(false); // desabilita saveButton inicialmente
54 deleteButton = (Button) findViewById(R.id.deleteButton);55 deleteButton.setEnabled(false); // desabilita deleteButton inicialmente
Fig. 16.9 | Sobrescrevendo os mtodos onCreate, onResumee onPausede Activity.
-
8/11/2019 Deitel_Android_16.pdf
11/29
Captulo 16 Aplicativo Voice Recorder 11
O mtodo onResume(linhas 7077) configura o receptor(listener) do componenterecordButton. O mtodo onPause(linhas 8097) remove o receptorde recordButtone, serecorderno for null, faz a limpeza das tarefas para o caso de o aplicativo no voltar para oprimeiro plano. A linha 88 remove os callbacksdo handlerpara que o visualizador pare deatualizar e a linha 89 o limpa para uma possvel nova gravao futura. As linhas 9091 ga-rantem que os componentes recordButtone viewSavedRecordingsButtonestejam no estadocorreto, para o caso de o aplicativo voltar para o primeiro plano. A linha 92 chama o m-todo releasede MediaRecorderpara liberar os recursos usados pelo objeto MediaRecorder.Se recorder no for null, ento havia uma gravao em andamento quando foi feita umapausa no aplicativo. Por simplicidade, a linha 95 exclui o arquivo da gravao temporria.
56 viewSavedRecordingsButton =
57 (Button) findViewById(R.id.viewSavedRecordingsButton);
58 visualizer = (VisualizerView) findViewById(R.id.visualizerView);
59
60 // registra os receptores (listeners)
61 saveButton.setOnClickListener(saveButtonListener);62 deleteButton.setOnClickListener(deleteButtonListener);
63 viewSavedRecordingsButton.setOnClickListener(
64 viewSavedRecordingsListener);
65
66 handler = newHandler();// cria o Handler para atualizar o visualizador
67 } // fim do mtodo onCreate68
69 // cria o MediaRecorder
70 @Override71 protected voidonResume()
72 {
73 super.onResume();74 75 // registra o receptor de recordButton
76 recordButton.setOnCheckedChangeListener(recordButtonListener);
77 } // fim do mtodo onResume
78
79 // libera o MediaRecorder
80 @Override81 protected voidonPause()
82 {
83 super.onPause();84 recordButton.setOnCheckedChangeListener(null); // remove o receptor
85
86 if(recorder != null)87 {
88 handler.removeCallbacks(updateVisualizer); // para atualizar a// interface grfica do usurio
89 visualizer.clear(); // limpa o visualizador para a prxima gravao
90 recordButton.setChecked(false); // reconfigura recordButton
91 viewSavedRecordingsButton.setEnabled(true); // habilita
92 93 recording = false; // no estamos mais gravando
94 recorder = null;
95 ((File) deleteButton.getTag()).delete();// exclui o arquivo temporrio96 } // fim do if
97
}
// fim do mtodo onPause
98
recorder.release(); // libera recursos do MediaRecorder
Fig. 16.9 | Sobrescrevendo os mtodos onCreate, onResumee onPausede Activity.
-
8/11/2019 Deitel_Android_16.pdf
12/29
12 Android para Programadores
OnCheckedChangedListenerinicia e para uma gravao
O receptor recordButtonListener(Fig. 16.10) responde aos eventos gerados quando ousurio clica no componente ToggleButtonRecord. Se o parmetro isCheckeddo mtodoonCheckedChanged for true, as linhas 109148 configuram o aplicativo para comearuma nova gravao. A linha 109 limpa a VisualizerViewe, ento, desabilitamos os com-ponentes Buttonque no devem estar ativos quando uma gravao est em andamento.
As linhas 115122 criam um novo MediaRecordere, em seguida, o preparam paragravar, como segue:
A linha 117 chama setAudioSourcepara indicar que MediaRecorderdeve obter suaentrada a partir do microfone do aparelho. Vrias fontes de entrada so suportadas.
99 // inicia/para uma gravao
100 OnCheckedChangeListener recordButtonListener =101 newOnCheckedChangeListener()102 {
103 @Override
104 public voidonCheckedChanged(CompoundButton buttonView,
105 booleanisChecked)106 {
107 if(isChecked)
108 {
109 visualizer.clear(); // limpa o visualizador para a prxima// gravao
110 saveButton.setEnabled(false); // desabilita saveButton
111 deleteButton.setEnabled(false); // desabilita deleteButton
112 viewSavedRecordingsButton.setEnabled(false); // desabilita113
114 115
116
117 118
119
120
121
122
123 124 try
125 {126 // cria arquivo temporrio para armazenar gravao
127
128
129 130 // armazena o arquivo como tag para saveButton e
// deleteButton
131 saveButton.setTag(tempFile);
132 deleteButton.setTag(tempFile);
133 134 // configura o arquivo de sada do MediaRecorder
135 136
137
138 recording = true; // estamos gravando
// cria MediaRecorder e configura opes de gravao
if(recorder == null)
recorder = newMediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(
MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
recorder.setAudioEncodingBitRate(16);
recorder.setAudioSamplingRate(44100);
File tempFile = File.createTempFile(
"VoiceRecorder", ".3gp", getExternalFilesDir(null));
recorder.setOutputFile(tempFile.getAbsolutePath());
recorder.prepare(); // prepara para gravar
recorder.start(); // inicia a gravao
Fig. 16.10 | OnCheckedChangedListener inicia e para uma gravao.
-
8/11/2019 Deitel_Android_16.pdf
13/29
Captulo 16 Aplicativo Voice Recorder 13
Para ver uma lista completa, consulte a documentao online da classe MediaRecor-
der.AudioSource. O mtodo setAudioSourceprecisa ser chamado antes da configu-rao de outros parmetros de gravao de udio. As linhas 118119 chamam setOutputFormat para indicar que o udio deve sersalvo no formato3GP, que recomendado por compatibilidade com os reproduto-res de udio de computadores desktop. Outros formatos so especificados na classeMediaRecorder.OutputFormat .
A linha 120 chama setAudioEncoderpara especificar que deve ser usado o codifica-dor de udio AAC. Um codificadorcompacta o udio diferentes codificadoresproduzem resultados de diferentes qualidades. Escolhemos AAC porque proje-tado para uma melhor qualidade de udio (que tambm consome mais armazena-mento). O Android tambm fornece um codificador AMR, destinado a dados devoz transmitidos pelas redes de telefonia celular.
A linha 121 chama setAudioEncodingBitRate para especificar a taxa de bits (bits/s)da gravao. Taxas de bits menores produzem udio de menor qualidade. Se o apa-relho no suporta a taxa de bits especificada, o Android a ajusta automaticamentepara uma menor.
A linha 122 chama setAudioSamplingRatepara especificar a taxa de amostragem, a qualdepende do codificador de udio em uso. O codificador AAC suporta taxas de amos-tragem de 8 a 96 kHz, com as taxas maiores produzindo som de melhor qualidade.
As taxas de bits e de amostragem que usamos neste exemplo normalmente produzem
som de boa qualidade, sem exigir espao de armazenamento significativo.Uma vez configurado o MediaRecorder, as linhas 127139 criam um arquivo tem-porriopara armazenar a gravao e iniciam o processo de gravao. As linhas 127128
139 handler.post(updateVisualizer); // inicia a atualizao// da view
140 } // fim do try
141 catch(IllegalStateException e)142 {
143 Log.e(TAG, e.toString());
144 } // fim do catch
145 catch(IOException e)
146 {
147 Log.e(TAG, e.toString());148 } // fim do catch
149 } // fim do if
150 else151 {
152
153
154 recording = false; // no estamos mais gravando
155 saveButton.setEnabled(true); // habilita saveButton156 deleteButton.setEnabled(true); // habilita deleteButton
157 recordButton.setEnabled(false); // desabilita recordButton
158 } // fim do else
159 } // fim do mtodo onCheckedChanged
160 }; // fim de OnCheckedChangedListener161
recorder.stop(); // para a gravao
recorder.reset(); // reconfigura o MediaRecorder
Fig. 16.10 | OnCheckedChangedListener inicia e para uma gravao.
-
8/11/2019 Deitel_Android_16.pdf
14/29
14 Android para Programadores
criam o arquivo chamando o mtodo estticocreateTempFileda classe File. Os doisprimeiros argumentos so o prefixo e a extenso do nome do arquivo temporrio. Oltimo argumento o local do arquivo. Lembre-se, do Captulo 13, que o mtodo getEx-ternalFilesDirretorna um objeto Filerepresentando um diretrio de armazenamentoexterno especfico do aplicativo, que gerenciado automaticamente pelo sistema sevoc excluir este aplicativo, seus arquivos tambm sero excludos. As linhas 131132configuram o objeto tempFilecomo a tag dos componentes saveButtone deleteButton,para que tempFilepossa ser usado na rotina de tratamento de evento (handler) onClickde cada componente Button. A linha 135 chama o mtodo setOutputFilede MediaRecor-derpara indicar que a gravao deve ser salva em tempFile. As linhas 136 e 137 chamamos mtodos preparee startde MediaRecorder, respectivamente. O mtodo prepareusa asconfiguraes das linhas 117122 para garantir que o aparelho esteja pronto para gravar.Isso deve ser feito antes da chamada do mtodo start, o qual inicia a gravao do udio.
Em seguida, indicamos que o aplicativo est gravando e iniciamos o Runnable updateVi-sualizer(Fig. 16.11), passando-o para o mtodo postdo Handler.
Se o parmetro isCheckeddo mtodo onCheckedChangedfor false, as linhas 152157 configuram a atividade de modo a permitir que o usurio salve ou exclua o arquivode gravao temporrio. As linhas 152153 chamam os mtodos stope resetdo Media-Recorderpara finalizar a gravao e reconfigurar MediaRecorder. Em seguida, indicamosque o aplicativo no est gravando, habilitamos os componentes ButtonSavee Deleteedesabilitamos o componente ToggleButtonRecord.
Runnable updateVisualizeratualiza VisualizerView
O Runnable updateVisualizer(Fig. 16.11) atualiza a VisualizerView(Seo 16.5.2) pararefletir a entrada de udio atual. Se o aplicativo estiver gravando, a linha 171 chama omtodo getMaxAmplitudeda classe MediaRecorderpara obter a mxima amplitude de gra-vao desde que getMaxAmplitudefoi chamado pela ltima vez. Adicionamos esse valor deamplitude em VisualizerView(linha 172) e, ento, chamamos seu mtodo invalidate(linha 173) para indicar que a Viewprecisa ser redesenhada. A linha 174 agenda update-Visualizerpara que seja executado novamente aps um intervalo de 50 milissegundos.
162 // atualiza o visualizador a cada 50 milissegundos163 Runnable updateVisualizer = newRunnable()
164 {165 @Override
166 public voidrun()
167 {
168 if(recording) // se j estamos gravando169 {
170 // obtm a amplitude atual
171 172 visualizer.addAmplitude(x); // atualiza VisualizeView
173 visualizer.invalidate(); // renova VisualizerView
174 handler.postDelayed(this, 50); // atualiza em 50 milissegundos
175 } // fim do if
176 } // fim do mtodo run
177 }; // fim de Runnable
178
int x = recorder.getMaxAmplitude();
Fig. 16.11 | RunnableupdateVisualizeratualiza VisualizerView.
-
8/11/2019 Deitel_Android_16.pdf
15/29
Captulo 16 Aplicativo Voice Recorder 15
OnClickListenersaveButtonListenerpermiteque o usurio salve uma nova gravao
Olistener
saveButtonListener
(Fig. 16.12) exibe um componenteAlertDialog
com layoutpersonalizado (name_edittext.xml, que inflado na linha 190) para confirmar se a gravaodeve ser salva. Se o usurio tocar no boto Save
da caixa de dilogo e o nome especificadopor ele no for uma Stringvazia, as linhas 210215 do ao arquivo um nomepermanente,especificado pelo usurio. A linha 210 obtm o objeto Fileque foi configurado como tag docomponente Buttonna linha 131 da Fig. 16.10. As linhas 211214 criam um objeto Filerepresentando o nome de arquivo especificado pelo usurio. Ento, a linha 215 chama o m-todo renameTode Fileno objeto tempFilea fim de mudar seu nome para o nome de arquivoespecificado no novo objeto newFile. Se o nome especificado pelo usurio permanecer vazio,as linhas 224229 exibem um Toastindicando que um nome de arquivo obrigatrio.
179 // salva uma gravao
180 OnClickListener saveButtonListener = newOnClickListener()
181 {
182 @Override
183 public voidonClick(finalView v)
184 {
185 // obtm uma referncia para o servio LayoutInflater
186 LayoutInflater inflater = (LayoutInflater) getSystemService(
187 Context.LAYOUT_INFLATER_SERVICE);
188
189 // infla name_edittext.xml para criar um componente EditText
190 View view = inflater.inflate(R.layout.name_edittext, null);
191 finalEditText nameEditText =
192 (EditText) view.findViewById(R.id.nameEditText);193
194 // cria uma caixa de dilogo de entrada para obter o nome da// gravao do usurio
195 AlertDialog.Builder inputDialog =
196 new AlertDialog.Builder(VoiceRecorder.this);
197 inputDialog.setView(view); // configura a View personalizada// da caixa de dilogo
198 inputDialog.setTitle(R.string.dialog_set_name_title);
199 inputDialog.setPositiveButton(R.string.button_save,
200 new DialogInterface.OnClickListener()
201 {
202 public voidonClick(DialogInterface dialog, int which)
203 {
204 // cria SlideshowInfo para uma nova exibio de slides205 String name = nameEditText.getText().toString().trim();
206
207 if(name.length() != 0)
208 {
209 // cria Files para arquivo temporrio e novo nome// de arquivo
210
211
212
213
214
215
216 saveButton.setEnabled(false); // desabilita
File tempFile = (File) v.getTag();File newFile = newFile(
getExternalFilesDir(null).getAbsolutePath() + File.separator+
name + ".3gp");tempFile.renameTo(newFile); // muda o nome do arquivo
Fig. 16.12 | OnClickListenersaveButtonListenerpermite que o usurio salve uma nova gravao.(continua)
-
8/11/2019 Deitel_Android_16.pdf
16/29
16 Android para Programadores
OnClickListenerdeleteButtonListenerpermite
que o usurio exclua uma nova gravaoO listenerdeleteButtonListener (Fig. 16.13) exibe um componente AlertDialogparaconfirmar se a gravao deve ser excluda. Se o usurio tocar no boto Deleteda caixa dedilogo, a linha 257 obtm o objeto Fileque foi configurado como tag do componenteButtonna linha 132 da Fig. 16.10 e, ento, chama o mtodo deletede Filepara excluiro arquivo do aparelho.
217 deleteButton.setEnabled(false); // desabilita
218 recordButton.setEnabled(true); // habilita
219 viewSavedRecordingsButton.setEnabled(true); // habilita
220 } // fim do if
221 else
222 {223 // exibe mensagem dizendo que a mostra de slides deve
// ter um nome
224 Toast message = Toast.makeText(VoiceRecorder.this,
225 R.string.message_name, Toast.LENGTH_SHORT);226 message.setGravity(Gravity.CENTER,
227 message.getXOffset() / 2,
228 message.getYOffset() / 2);229 message.show(); // exibe o Toast
230 } // fim do else
231 } // fim do mtodo onClick
232 } // fim da classe interna annima
233 ); // fim da chamada de setPositiveButton234
235 inputDialog.setNegativeButton(R.string.button_cancel, null);
236 inputDialog.show();
237 } // fim do mtodo onClick
238 }; // fim de OnClickListener239
Fig. 16.12 | OnClickListenersaveButtonListenerpermite que o usurio salve uma nova gravao.
240 // exclui a gravao temporria
241 OnClickListener deleteButtonListener = newOnClickListener()
242 {243 @Override
244 public voidonClick(finalView v)
245 {
246 // cria uma caixa de dilogo de entrada para obter o nome// da gravao do usurio
247 AlertDialog.Builder confirmDialog =
248 newAlertDialog.Builder(VoiceRecorder.this);
249 confirmDialog.setTitle(R.string.dialog_confirm_title);
250 confirmDialog.setMessage(R.string.dialog_confirm_message);
251
252 confirmDialog.setPositiveButton(R.string.button_delete,
253 newDialogInterface.OnClickListener()
254 {
Fig. 16.13 | OnClickListenerdeleteButtonListenerpermite que o usurio exclua uma nova gravao.
-
8/11/2019 Deitel_Android_16.pdf
17/29
-
8/11/2019 Deitel_Android_16.pdf
18/29
-
8/11/2019 Deitel_Android_16.pdf
19/29
Captulo 16 Aplicativo Voice Recorder 19
Mtodos cleare addAmplitude
O mtodo clear(Fig. 16.17, linhas 4346) esvazia a lista amplitudespara preparar avisualizao de uma nova gravao. O mtodo addAmplitude(linhas 4958) chamadopor VoiceRecorderpara adicionar uma leitura de amplitude da gravao atual na listaamplitudes(linha 51). Se as linhas de amplitude da gravao preenchem a largura datela (linha 54), removemos o valor mais antigo, o qual representa a linha mais esquerdana tela isso permite que as linhas de visualizao rolem para o lado esquerdo da tela,
medida que novas linhas so adicionadas direita.
42 // limpa todas as amplitudes para preparar uma nova visualizao
43 public voidclear()
44 {
45 amplitudes.clear();
46 } // fim do mtodo clear
47
48 // adiciona a amplitude dada no ArrayList amplitudes
49 public voidaddAmplitude(float amplitude)
50 {
51 amplitudes.add(amplitude); // adiciona a mais recente
// ao ArrayList amplitudes52
53 // se as linhas preenchem completamente a VisualizerView
54 if(amplitudes.size() * LINE_WIDTH>= width)
55 {
56 amplitudes.remove(0); // remove o valor mais antigo
57 } // fim do if
58 } // fim do mtodo addAmplitude
59
Fig. 16.17 | Mtodos cleare addAmplitude.
Sobrescrevendo o mtodo onDrawde ViewO mtodo onDrawde VisualizerView(Fig. 16.18) exibe uma representao visual dagravao no Canvasdado. Esse mtodo chamado quando a View exibida pela pri-meira vez e quando a atividade VoiceRecorderchama o mtodo invalidatede View. Aslinhas 6876 processam a lista amplitudes. Para cada amplitude, calculamos scaledHei-ght(linha 70) que representa o comprimento da linha de amplitude na tela e ento
39 amplitudes = newArrayList(width / LINE_WIDTH);
40 } // fim do mtodo onSizeChanged
41
Fig. 16.16 | Sobrescrevendo o mtodo onSizeChangedde View.
60 // desenha o visualizador com linhas em escala// representando as amplitudes
61 @Override
62 public void onDraw(Canvas canvas)
63 {
Fig. 16.18 | Sobrescrevendo no mtodo onDrawde View.
-
8/11/2019 Deitel_Android_16.pdf
20/29
-
8/11/2019 Deitel_Android_16.pdf
21/29
Captulo 16 Aplicativo Voice Recorder 21
Sobrescrevendo os mtodos onCreate,onResumee onPausede Activity
O mtodo onCreate(Fig. 16.20, linhas 5073) infla o layout personalizado dessa ListAc-tivity(linha 54) e, em seguida, configura o ArrayAdapterdo ListView(linhas 5761). Aclasse SavedRecordingsAdapter(Fig. 16.21) recebe como segundo argumento do constru-tor um objeto Listcontendo a lista de arquivos do diretrio de arquivos externos
do aplicativo. A linha 60 obtm a lista de nomes de arquivo como um array de Stringschamando o mtodo listde File, o qual usamos para inicializar um ArrayList.
A linha 63 cria um Handlerpara atualizar aposio do cursor da SeekBardurante a re-produo. As linhas 6672 obtm referncias para os outros componentes da interfacegrfica do usurio no layout e registram os receptores (listeners) dos componentes pro-gressSeekBare playPauseButton.
17 import android.media.MediaPlayer.OnCompletionListener;
18 import android.net.Uri;
19 import android.os.Bundle;
20 import android.os.Handler;
21 import android.util.Log;22 import android.view.LayoutInflater;
23 import android.view.View;
24 import android.view.View.OnClickListener;
25 import android.view.ViewGroup;
26 import android.widget.ArrayAdapter;
27 import android.widget.CompoundButton;
28 import android.widget.CompoundButton.OnCheckedChangeListener;
29 import android.widget.ImageView;
30 import android.widget.ListView;
31 import android.widget.SeekBar;
32 import android.widget.SeekBar.OnSeekBarChangeListener;
33 import android.widget.TextView;
34 import android.widget.ToggleButton;35
36 public class SavedRecordings extends ListActivity
37 {
38 private static final String TAG= SavedRecordings.class.getName();39
40 // SavedRecordingsAdapter exibe a lista de gravaes salvas em ListView
41 private SavedRecordingsAdapter savedRecordingsAdapter;42
43 private MediaPlayer mediaPlayer; // reproduz as gravaes salvas
44 private SeekBar progressSeekBar; // controla a reproduo de udio45 private Handler handler; // atualiza a posio do cursor da SeekBar
46 private TextView nowPlayingTextView; // exibe o nome do udio
47 private ToggleButton playPauseButton; // controla a reproduo de udio48
Fig. 16.19 | Instruo package, instrues importe campos.
49 // chamado quando a atividade criada
50 @Override
51 public void onCreate(Bundle savedInstanceState)
52 {
53 super.onCreate(savedInstanceState);
Fig. 16.20 | Sobrescrevendo os mtodos onCreate, onResumee onPausede Activity.
-
8/11/2019 Deitel_Android_16.pdf
22/29
-
8/11/2019 Deitel_Android_16.pdf
23/29
Captulo 16 Aplicativo Voice Recorder 23
diaPlayerpara terminar a reproduo de udio e chamamos o mtodo releasede Media-Playerpara liberar os recursos utilizados pelo MediaPlayer.
Subclasse SavedRecordingsAdapterde ArrayAdapterA classe ViewHolder(Fig. 16.21, linhas 100105) e a classe SavedRecordingsAdapter(li-nhas 108159) usam opadroview-holder (apresentado no Captulo 12) para preen-cher o ListViewda ListActivity SavedRecordings, reutilizando itens do ListViewparaum melhor desempenho. A classe ViewHoldercontm variveis que fazem referncia aoTextViewe a dois elementos ImageViewem um item de ListView(definido no layout sa-ved_recordings_row.xml). O construtor SavedRecordingsAdapter(linhas 113120) orde-na a Listde nomes de arquivo e, em seguida, a armazena na varivel de instncia items.Ento, armazenamos uma referncia para o LayoutInflater, para uso posterior.
98 // Classe para implementar o padro view-holder
99 // para melhor desempenho do ListView
100 private static class ViewHolder
101 {
102 TextView nameTextView;
103 ImageView emailButton;
104 ImageView deleteButton;
105 } // fim da classe ViewHolder
106
107 // ArrayAdapter que exibe nomes de gravao e botes delete
108 private classSavedRecordingsAdapter extends ArrayAdapter
109 {
110 private List items; // lista de nomes de arquivo
111 private LayoutInflater inflater;112
113 public SavedRecordingsAdapter(Context context, List items)114 {
115 super(context, -1, items); // -1 indica que estamos// personalizando a view
116
117 this.items = items;
118 inflater = (LayoutInflater)
119 getSystemService(Context.LAYOUT_INFLATER_SERVICE);
120 } // fim do construtor de SavedRecordingsAdapter
121
122 @Override
123 public View getView(int position, View convertView, ViewGroup parent)124 {
125 ViewHolder viewHolder; // contm referncias para a// interface grfica do item atual
126
127 // se convertView for null, infla a interface grfica e// cria ViewHolder;
128 // caso contrrio, obtm o ViewHolder existente
129 if(convertView == null)
130 {
131 convertView =
132 inflater.inflate(R.layout.saved_recordings_row, null);
133
134 // configura ViewHolder para esse item de ListView
135 viewHolder = newViewHolder();
Collections.sort(items, String.CASE_INSENSITIVE_ORDER);
Fig. 16.21 | Subclasse SavedRecordingsAdapterde ArrayAdapter.
-
8/11/2019 Deitel_Android_16.pdf
24/29
24 Android para Programadores
O mtodo sobrescrito getViewde ArrayAdapter(linhas 122158) determina se umitem de ListViewprecisa ser inflado (linha 129). Em caso positivo, as linhas 131142inflam o layout para um item, configuram um novo objeto ViewHoldere o definem comoa tag do item de ListView. Caso contrrio, simplesmente obtemos o objeto ViewHolderexistente a partir da tag do item de ListView(linha 145). As linhas 148149 obtm onome de arquivo correspondente a partir da lista items, o atribui a iteme o utilizapara configurar o texto de TextView. Em seguida, as linhas 152155 configuram itemcomo tag para os botes emailButtone deleteButton, e registram seus receptores deevento (listeners). Lembre-se de que esses botes so na verdade elementos ImageView,de modo que os itens de ListViewtambm podem ser clicados (consulte a Seo 16.4.7).
OnClickListener emailButtonListener
Quando o usurio toca no cone de email ( ) de determinada gravao, o receptoremailButtonListener(Fig. 16.22) permite que ele anexe a gravao a um email. O m-todo onClickobtm um Uria partir de um objeto Filecriado, usando o caminho dagravao selecionada no diretrio de arquivos externos do aplicativo (linhas 168169).
As linhas 172174 criam e configuram um Intentusando seu ACTION_SENDe configuramo tipo MIME do Intentcomo text/plain. Esse formato pode ser manipulado por qual-quer aplicativo capaz de enviar mensagens de texto, como os aplicativos de email. Inclu-mos o Urida gravao como um extra com a constante EXTRA_STREAMdo Intent. A maio-ria dos clientes de email (incluindo o do Android) anexa o arquivo do Uridado em umrascunho de email, em resposta a esse Intent. Passamos o Intente uma Stringde ttulo
para o mtodo createChooserdo Intent(linha 175) a fim de criar um seletor de atividadepara o novo Intent. importante configurar o ttulo do seletor de atividade para lembraro usurio que ele deve selecionar um aplicativo de email para obter o comportamento es-
136 viewHolder.nameTextView =
137 (TextView) convertView.findViewById(R.id.nameTextView);
138 viewHolder.emailButton =
139 (ImageView) convertView.findViewById(R.id.emailButton);
140 viewHolder.deleteButton =141 (ImageView) convertView.findViewById(R.id.deleteButton);
142 convertView.setTag(viewHolder); // armazena como tag da View
143 } // fim do if
144 else // obtm o ViewHolder a partir da tag de convertView
145 viewHolder = (ViewHolder) convertView.getTag();
146
147 // obtm e exibe o nome do arquivo da gravao
148 String item = items.get(position);
149 viewHolder.nameTextView.setText(item);
150
151 // configura receptores para os botes email e delete
152
153 viewHolder.emailButton.setOnClickListener(emailButtonListener);
154
155 viewHolder.deleteButton.setOnClickListener(deleteButtonListener);
156
157 returnconvertView;
158 } // fim do mtodo getView
159 } // fim da classe SavedRecordingsAdapter
160
viewHolder.emailButton.setTag(item);
viewHolder.deleteButton.setTag(item);
Fig. 16.21 | Subclasse SavedRecordingsAdapter de ArrayAdapter.
-
8/11/2019 Deitel_Android_16.pdf
25/29
Captulo 16 Aplicativo Voice Recorder 25
perado voc no pode controlar os aplicativos instalados no telefone de um usurio e osfiltros de Intentcapazes de ativar esses aplicativos, de modo que possvel que apareamatividades incompatveis no seletor. As linhas 175176 ativam o Intent.
161 // envia a gravao especificada como anexo de email
162 OnClickListener emailButtonListener = newOnClickListener()
163 {
164 @Override
165 public voidonClick(finalView v)
166 {
167 // obtm o Uri para o local da gravao no disco
168
169
170
171 // cria Intent para enviar Email
172
173
174
175 startActivity(Intent.createChooser(intent,
176 getResources().getString(R.string.emailPickerTitle)));
177 } // fim do mtodo onClick
178 }; // fim de OnClickListener
179
Uri data = Uri.fromFile(
newFile(getExternalFilesDir(null), (String) v.getTag()));
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");intent.putExtra(Intent.EXTRA_STREAM, data);
Fig. 16.22 | OnClickListeneremailButtonListener.
OnClickListener deleteButtonListener
O receptor deleteButtonListener(Fig. 16.23) exibe um componente AlertDialogparaconfirmar se a gravao deve ser excluda. Se o usurio tocar no componente ButtonDele-teda caixa de dilogo, as linhas 197198 criam um objeto Filerepresentando a gravaoa ser excluda e, ento, a linha 199 chama o mtodo deletede Filepara excluir o arquivodo aparelho. A linha 200 remove o item correspondente de savedRecordingsAdapter.
180 // exclui a gravao especificada
181 OnClickListener deleteButtonListener = newOnClickListener()
182 {
183 @Override
184 public voidonClick(final View v)185 {
186 // cria uma caixa de dilogo de entrada para obter o nome// da gravao do usurio
187 AlertDialog.Builder confirmDialog =
188 newAlertDialog.Builder(SavedRecordings.this);
189 confirmDialog.setTitle(R.string.dialog_confirm_title);
190 confirmDialog.setMessage(R.string.dialog_confirm_message);
191
192 confirmDialog.setPositiveButton(R.string.button_delete,
193 newDialogInterface.OnClickListener()
194 {
195 public voidonClick(DialogInterface dialog, int which)
196 {
Fig. 16.23 | OnClickListenerdeleteButtonListener.
-
8/11/2019 Deitel_Android_16.pdf
26/29
26 Android para Programadores
Sobrescrevendo o mtodo onListItemClickde ListActivity
O mtodo sobrescrito onListItemClickde ListActivity(Fig. 16.24) usa o MediaPlayerpara reproduzir a gravao selecionada quando o usurio toca em um nome de arquivono elemento ListView. A linha 221 obtm o nome de arquivo selecionado. As linhas224225 criam um objeto Stringcontendo o caminho absoluto da gravao. As linhas234236 redefinem o mediaPlayer, configuram sua fonte de dados com o caminho dagravao selecionada e preparam o mediaPlayerpara reproduzir a gravao. A linha 237usa o mtodo getDurationde MediaPlayerpara obter a durao total da gravao e, en-to, configura-a como o valor mximo de progressSeekBar, usando o mtodo setMaxda
SeekBar. Isso permite que aposio do cursor da SeekBarrepresente a posio de reprodu-o da gravao, pois a posio do cursor ter uma correlao de um para um com a du-rao da gravao. As linhas 239249 configuram OnCompletionListenerde MediaPlayerpara redefinir playPauseButtone progressSeekBar. A linha 250 comea a reproduzir agravao e a linha 251 chama o mtodo rundo Runnable updaterpara comear a atualizarprogressSeekBarcom base na posio atual da reproduo.
197
198
199
200 savedRecordingsAdapter.remove((String) v.getTag());
201 } // fim do mtodo onClick
202 } // fim da classe interna annima
203 ); // fim da chamada de setPositiveButton
204
205 confirmDialog.setNegativeButton(R.string.button_cancel, null);
206 confirmDialog.show();
207 } // fim do mtodo onClick
208 }; // fim de OnClickListener
209
File fileToDelete = newFile(getExternalFilesDir(null) +
File.separator+ (String) v.getTag());
fileToDelete.delete();
Fig. 16.23 | OnClickListenerdeleteButtonListener.
210 @Override
211 protected voidonListItemClick(ListView l, View v, int position,212 longid)
213 {214 super.onListItemClick(l, v, position, id);
215 playPauseButton.setChecked(true); // estado marcado
216 handler.removeCallbacks(updater); // para de atualizar progressSeekBar
217
218 // obtm o item que foi clicado
219 TextView nameTextView =220 ((TextView) v.findViewById(R.id.nameTextView));221 String name = nameTextView.getText().toString();
222
223 // obtm o caminho para o arquivo224 String filePath = getExternalFilesDir(null).getAbsolutePath() +
225 File.separator+ name;
226
Fig. 16.24 | Sobrescrevendo o mtodo onListItemClickde ListActivity.
-
8/11/2019 Deitel_Android_16.pdf
27/29
Captulo 16 Aplicativo Voice Recorder 27
OnSeekBarChangeListener progressChangeListener
O receptor OnSeekBarChangeListener(Fig. 16.25) responde aos eventos de progressSeek-Bar. Quando o usurio arrasta o cursor da SeekBar, o mtodo onProgressChanged(linhas263268) chama o mtodo getProgressda SeekBarpara obter a posio atual do cursor e caso o usurio tenha iniciado o evento (isto , se o parmetro fromUserfor true) passa
essa posio para o mtodo seekTodo MediaPlayerpara continuar a reproduo a partirdo ponto correspondente na gravao. Os outros mtodos de OnSeekBarChangeListenerno so usados neste aplicativo, de modo que so definidos com corpos vazios.
227 // configura o texto de nowPlayingTextView
228 nowPlayingTextView.setText(getResources().getString(
229 R.string.now_playing_prefix) + " "+ name);
230 231 try
232 {233 // configura MediaPlayer para reproduzir o arquivo em filePath
234 mediaPlayer.reset(); // reconfigura MediaPlayer
235 mediaPlayer.setDataSource(filePath);
236 mediaPlayer.prepare(); // prepara MediaPlayer
237 progressSeekBar.setMax(mediaPlayer.getDuration());
238 progressSeekBar.setProgress(0);239 mediaPlayer.setOnCompletionListener(
240 newOnCompletionListener()
241 {242 @Override
243 public voidonCompletion(MediaPlayer mp)
244 {245 playPauseButton.setChecked(false); // estado desmarcado246 mp.seekTo(0);
247 } // fim do mtodo onCompletion
248 } // fim de OnCompletionListener
249 ); // fim da chamada de setOnCompletionListener
250 mediaPlayer.start();
251 updater.run(); // comea a atualizar progressSeekBar252 } // fim do try
253 catch(Exception e)
254 {255 Log.e(TAG, e.toString()); // registra excees
256 } // fim do catch
257 } // fim do mtodo onListItemClick258
Fig. 16.24 | Sobrescrevendo o mtodo onListItemClickde ListActivity.
259 // reage aos eventos criados quando o cursor da Seekbar movimentado
260 OnSeekBarChangeListener progressChangeListener =
261 newOnSeekBarChangeListener()
262 {
263 @Override
264 public voidonProgressChanged(SeekBar seekBar, int progress,
265 booleanfromUser)
266 {
Fig. 16.25 | OnSeekBarChangeListener progressChangeListener. (continua)
-
8/11/2019 Deitel_Android_16.pdf
28/29
28 Android para Programadores
Runnable updater
O Runnabledenominado updater(Fig. 16.26) movimenta o cursor da SeekBar medidaque uma gravao reproduzida. Se o MediaPlayerestiver em reproduo, chamamosseu mtodo getCurrentPosition para obter a posio atual da reproduo e usamos essevalor para configurar a posio do cursor da SeekBar, chamando setProgress. A linha291 chama o mtodo postDelayeddo handlerpara postar esse objeto Runnableuma veza cada 100 milissegundos.
282 // atualiza a SeekBar a cada segundo
283 Runnable updater = newRunnable()284 {
285 @Override
286 public voidrun()
287 {288 if(mediaPlayer.isPlaying())
289 {290 // atualiza a posio da SeekBar
291
292 handler.postDelayed(this, 100);
293 } // fim do if
294 } // fim do mtodo run295 }; // fim de Runnable296
progressSeekBar.setProgress(mediaPlayer.getCurrentPosition());
Fig. 16.26 | Runnableupdater.
OnCheckedChangeListener playPauseButtonListener
O mtodo onClickde OnClickListenerplayPauseButtonListener(Fig. 16.27) alterna en-tre a pausa e a reproduo da gravao selecionada quando o usurio toca no componen-te playPauseToggleButton. Se o componente ToggleButtonestiver marcado, iniciamos a
reproduo de udio usando o mtodo startde MediaPlayere, em seguida, chamamos omtodo runde updater; caso contrrio, chamamos o mtodo pausede MediaPlayerparadar uma pausa na reproduo do udio.
267 if(fromUser)
268
269 } // fim do mtodo onProgressChanged
270
271 @Override
272 public voidonStartTrackingTouch(SeekBar seekBar)
273 {
274 } // fim do mtodo onStartTrackingTouch
275
276 @Override
277 public voidonStopTrackingTouch(SeekBar seekBar)
278 {
279 } // fim do mtodo onStopTrackingTouch
280 }; // fim de OnSeekBarChangeListener
281
mediaPlayer.seekTo(seekBar.getProgress());
Fig. 16.25 | OnSeekBarChangeListener progressChangeListener .
-
8/11/2019 Deitel_Android_16.pdf
29/29
Captulo 16 Aplicativo Voice Recorder 29
16.6 Para finalizarO aplicativo Voice Recorderpermitiu ao usurio gravar sons usando o microfone do apa-relho, salvar gravaes para reproduo posterior, excluir gravaes e envi-las como ane-xos de email. Para permitir a gravao e o salvamento de arquivos, o manifesto desteaplicativo especificou permisses para gravar udio e para escrever no armazenamentoexterno de um aparelho.
Para fornecer reas que pudessem ser clicadas no ListViewda ListActivity Saved-
Recordings, usamos elementos ImageViewque podiam ser clicados, em vez de componentesButton. Isso permitiu que os prprios itens do ListViewtambm fossem clicados.
Para exibir diferentes cones com base no estado de um componente ToggleButton,definimos uma lista de estados drawableem XML, com um elemento raiz que continha elementos para cada estado. Cada elemento especificavao drawable(como um cone, por exemplo) para a exibio do estado correspondente.Ento, configuramos a lista de estados drawablecomo o drawabledo boto e o Androidexibiu o drawablecorreto automaticamente, com base no estado do boto.
Usamos MediaRecorder (pacote android.media) para gravar a voz do usurio pormeio do microfone interno do aparelho e salvamos as gravaes em arquivos de udio noprprio aparelho.
Gerenciamos as gravaes salvando inicialmente cada gravao nova em um arqui-vo temporrio, o qual criamos com o mtodo createTempFileda classe File. Quando ousurio optou por salvar um arquivo temporrio, usamos o mtodo renameToda classeFilepara dar um nome permanente ao arquivo. Quando o usurio optou por excluir umarquivo, o removemos chamando o mtodo deletede File.
Por fim, usamos um Intente um seletor de atividade para permitir ao usurioenviar uma gravao como anexo de email por intermdio de qualquer aplicativo do apa-relho que suportasse essa capacidade. No prximo captulo apresentaremos o aplicativoEnhanced Address Book, o qual permite ao usurio transferir contatos entre aparelhos pormeio de uma conexo Bluetooth.
282 // atualiza a SeekBar a cada segundo
283 Runnable updater = newRunnable()284 {
285 @Override
286 public voidrun()287 {288 if(mediaPlayer.isPlaying())
289 {290 // atualiza a posio da SeekBar291
292 handler.postDelayed(this, 100);
293 } // fim do if
294 } // fim do mtodo run295 }; // fim de Runnable296
progressSeekBar.setProgress(mediaPlayer.getCurrentPosition());
Fig. 16.27 | OnCheckedChangeListener playPauseButtonListener .