Top Banner

of 29

Deitel_Android_16.pdf

Jun 02, 2018

Download

Documents

Marlon Janke
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
  • 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 .