O Usar o mecanismo de converso de texto em voz do Android para passar instrues em udio para o usurio. O Usar o mecanismo de reconhecimento de fala do An- droid para interpretar entradas de voz do usurio. O Usar o SMSManager para enviar mensagens de texto. O Enviar objetos Message para um Handler a fim de ga- rantir que as modificaes feitas na interface grfica do usurio ocorram na thread da interface. Aplicativo PHAB`S Pizza Converso de texto em voz, reconhecimento de fala e telefonia 15 2 Android para Programadores 15.1 Introduo O aplicativo PHAB`S Pizza (Fig. 15.1), para pedir pizza, usa os mecanismos de converso de texto em voz e de reconhecimento de fala do Android para se comunicar com o usurio falando textos e recebendo a entrada falada do usurio. O aplicativo cria um pedido de pizza solici- tando ao usurio que responda perguntas sobre o tamanho da pizza e a cobertura. O usurio responde falando ao telefone quando solicitado. Se o aplicativo no conseguir entender o usurio ou receber uma resposta inesperada, ele pede para que repita a resposta. Aps pro- cessar as respostas do usurio, o aplicativo resume o pedido, pergunta ao usurio se est tudo certo e se o pedido deve ser enviado. Em caso positivo, o aplicativo envia o pedido para um nmero de telefone mvel (especificado no arquivo strings.xml do aplicativo) na forma de uma mensagem de SMS, usando as APIs de telefonia do Android. Se o usurio quiser mudar o pedido, o aplicativo reinicia e faz as perguntas novamente. Depois de feito o pedido, o usurio tem a opo de sair do aplicativo ou de recomear com um novo pedido. 15.2 Testando o aplicativo para pedir Pizza Abrindo e executando o aplicativo Abra o Eclipse e importe o projeto do aplicativo Pizza. Para importar o projeto: 1. Selecione File > Import para exibir a caixa de dilogo Import. 2. Expanda o n General, selecione Existing Projects into Workspace e, em seguida, cli- que em Next >. R e s u m o 15.1 Introduo 15.2 Teste do aplicativo para pedir Pizza 15.3 Viso geral das tecnologias 15.4 Arquivos da interface grfica do usurio e de recursos 15.4.1 Criao do projeto 15.4.2 AndroidManifest.xml 15.4.3 main.xml, strings.xml e arrays.xml 15.5 Construo do aplicativo 15.6 Para finalizar Fig. 15.1 | Aplicativo para pedir Pizza. Captulo 15 Aplicativo PHAB`S Pizza 3 3. direita do campo de texto Select root directory:, clique em Browse e, em seguida, localize e selecione a pasta Pizza. 4. Clique em Finish para importar o projeto. Quando este livro estava sendo produzido, os recursos de sntese e reconhecimento de fala e o recurso de envio de mensagens SMS s funcionavam em aparelhos reais e no no emulador do Android. Alm disso, necessria uma conexo de rede (via plano de dados ou WiFi) para que o reconhecimento de voz funcione. Para usar a funcionalidade de en- vio de mensagens SMS, digite o nmero de seu telefone mvel no recurso phone_number <string> em strings.xml. Certifique-se de ter conectado em seu computador um apare- lho Android com a depurao de USB habilitada (USB debugging), clique com o boto direito do mouse na pasta do projeto e selecione Run As > Android Application para instalar e executar o aplicativo em seu aparelho. Escolhendo sua pizza Oua cada pergunta falada pelo aplicativo para sua comodidade, as perguntas tambm aparecem na tela. Responda cada pergunta somente depois que o aplicativo pedir para voc falar. Certifique-se de falar claramente no microfone de seu aparelho. Se houver muito rudo de fundo, o aplicativo poder pedir para que voc repita certas respostas. Enviando um pedido O aplicativo repetir o pedido completo e depois perguntar se voc deseja realmente fazer o pedido. Diga yes para fazer o pedido, o que envia uma mensagem SMS para o nmero de telefone especificado em seu arquivo strings.xml. Se o nmero de telefone especificado representar um telefone mvel real, esse telefone receber uma mensagem de texto SMS detalhando seu pedido; caso contrrio, a mensagem SMS no ser enviada corretamente. 15.3 Viso geral das tecnologias Sntese de fala O aplicativo fala com o usurio utilizando uma instncia da classe TextToSpeech. O me- canismo de converso de texto em voz exige inicializao assncrona. Por isso, o elemento TextToSpeech.OnInitListener do aplicativo notificado quando essa inicializao termi- na. O mtodo speak de TextToSpeech converte objetos String em mensagens de udio. Um elemento TextToSpeech.OnUtteranceCompletedListener notificado quando o sinte- tizador de fala acaba de pronunciar uma mensagem de udio. Reconhecimento de fala O aplicativo ouve a entrada do usurio lanando um objeto Intent para o elemento RecognizerIntent, usando a constante RecognizerIntent.ACTION_RECOGNIZE_SPEECH. Usa- mos startActivityForResult para receber os resultados de reconhecimento de fala no mtodo onActivityResult da Activity. Um ArrayList de correspondncias possveis da fala do usurio includo como um extra no objeto Intent retornado pelo elemen- to RecognizerIntent e passado para onActivityResult. Comparando os elementos desse ArrayList com as opes existentes no menu de pedidos, podemos determinar a opo escolhida pelo usurio e montar o pedido de forma correspondente. 4 Android para Programadores Enviando mensagens SMS Quando um pedido concludo, o aplicativo envia uma mensagem de texto via progra- mao usando a classe SMSManager. O mtodo esttico getDefault de SMSManager retorna o objeto SMSManager que seu aplicativo pode usar para enviar uma mensagem. O mtodo sendTextMessage de SMSManager envia uma mensagem SMS para um nmero de telefone especificado. Um dos argumentos do mtodo sendTextMessage um PendingIntent que transmitido quando a mensagem SMS enviada. Isso nos permite usar BroadcastReceiver para receber a transmisso a fim de determinar se a mensagem SMS foi enviada com xito. Usando um Handler para passar Messages entre threads Como voc sabe, todas as modificaes feitas na interface grfica do usurio devem ser realizadas por meio da thread de execuo da interface no Android. Neste aplicativo, outras threads que no so da interface grfica do usurio precisam notificar a thread da interface para exibir texto. Por exemplo, a sntese de fala ocorre em uma thread de execu- o separada. Quando a sntese de fala termina e precisamos exibir um texto, notificamos a thread da interface grfica do usurio passando um objeto Message para um Handler que criado a partir da thread da interface. O mtodo handleMessage de Handler chamado na thread que criou o Handler. 15.4 Arquivos da interface grfica do usurio e de recursos Nesta seo, criamos o aplicativo para pedir Pizza e discutimos seus arquivos XML. 15.4.1 Criao do projeto Comece criando um novo projeto Android chamado Pizza. Especifique os seguintes va- lores na caixa de dilogo New Android Project e, em seguida, pressione Finish: Build Target: certifique-se de que Android 2.3.3 esteja marcado Application name: Pizza Package name: com.deitel.pizza Create Activity: Pizza Min SDK Version: 8 15.4.2 AndroidManifest.xml A Figura 15.2 mostra o arquivo AndroidManifest.xml deste aplicativo. O nico recurso novo a permisso android.permission.SEND_SMS para enviar mensagens SMS (linha 16). 1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.deitel.pizza" android:versionCode="1" 4 android:versionName="1.0"> 5 <application android:icon="@drawable/icon" 6 android:label="@string/app_name" android:debuggable="true"> 7 <activity android:name=".Pizza" android:screenOrientation="portrait" 8 android:label="@string/app_name"> 9 <intent-filter> 10 <action android:name="android.intent.action.MAIN" /> Fig. 15.2 | AndroidManifest.xml. Captulo 15 Aplicativo PHAB`S Pizza 5 15.4.3 main.xml, strings.xml e arrays.xml O layout main.xml desse aplicativo composto por um LinearLayout vertical, contendo um componente TextView e um componente ImageView. Exibimos as Strings faladas no componente TextView para que o usurio tambm possa l-las. As Strings do aplicativo so definidas como recursos <string> em strings.xml e como recursos <string-array> em arrays.xml. Voc pode examinar o contedo desses arquivos XML abrindo-os no Eclipse. 15.5 Construo do aplicativo A classe Pizza (Figs. 15.315.17) a nica Activity do aplicativo. O aplicativo faz per- guntas para determinar o pedido de pizza desejado pelo usurio e, em seguida, envia o pedido como uma mensagem SMS para um nmero de telefone especificado como um recurso <string> em strings.xml. Instruo package, instrues import e campos da classe Pizza Activity A Figura 15.3 contm a instruo package, as instrues import e os campos da classe Pizza. Realamos as instrues import das novas classes e interfaces que foram apresen- tadas na Seo 15.3. Discutiremos os campos da classe medida que forem usados. O mtodo loadResources (Fig. 15.7) inicializa a maioria das variveis de instncia da classe usando recursos XML que carregamos a partir de strings.xml e arrays.xml. 1 // Pizza.java 2 // Atividade principal do aplicativo Pizza. 3 package com.deitel.pizza; 4 5 import java.util.ArrayList; 6 import java.util.HashMap; 7 import java.util.Locale; 8 9 import android.app.Activity; 10 import android.app.PendingIntent; 11 import android.content.ActivityNotFoundException; 12 13 import android.content.Context; 14 import android.content.Intent; 15 16 import android.content.res.Resources; 17 import android.os.Bundle; 18 import android.os.Handler; import android.content.BroadcastReceiver; import android.content.IntentFilter; Fig. 15.3 | Instruo package, instrues import e campos da classe Pizza Activity. (continua) 11 <category android:name="android.intent.category.LAUNCHER" /> 12 </intent-filter> 13 </activity> 14 </application> 15 <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10"/> 16 17 </manifest> <uses-permission android:name="android.permission.SEND_SMS"/> Fig. 15.2 | AndroidManifest.xml. 6 Android para Programadores 19 import android.os.Message; 20 21 22 23 24 25 import android.widget.TextView; 26 import android.widget.Toast; 27 28 public class Pizza extends Activity 29 { 30 private String phoneNumber; // nmero de telefone para o qual o // pedido enviado 31
32 // String identificador da Intent de transmisso da mensagem SMS enviada 33 private static final String BROADCAST_STRING = 34 "com.deitel.pizza.sent_sms"; 35 36 // Intent de transmisso (broadcast) da mensagem SMS 37 38 39 // ndice baseado em 0 de cada pergunta sobre a pizza 40 private static final int PIZZA_SIZE_INDEX = 1; 41 private static final int PEPPERONI_INDEX = 2; 42 private static final int MUSHROOM_INDEX = 3; 43 private static final int ORDER_SUMMARY_INDEX = 4; 44 45 // IDs de mensagem para diferenciar entre uma 46 // mensagem normal e a ltima mensagem 47 private final static int UPDATE_TEXT_ID = 15; 48 private final static int FINAL_UPDATE_TEXT_ID = 16; 49 private final static int DISPLAY_TOAST_ID = 17; 50 51 // identificadores de String para restaurar o estado da instncia 52 private final static String INDEX_ID = "index"; 53 private final static String ORDER_ID = "order"; 54 private final static String LISTENING_ID = "listening"; 55 56 57 private int currentMessageIndex; // ndice da mensagem atual 58 59 private boolean waitingForResponse; // esperando resposta do usurio? 60 private boolean listening; // esperando resultado da Activity? 61 private TextView messageText; // usado para exibir a mensagem atual 62 private String order; // o pedido de pizza 63 64 private String[] audioMessages; // mensagens faladas pelo aplicativo 65 private String[] displayMessages; // mensagens exibidas pelo aplicativo 66 67 private String errorMessageString; // mensagem para resposta inesperada 68 private String finalMessageString; // mensagem quando o aplicativo // finaliza o pedido 69 import android.speech.RecognizerIntent; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.OnInitListener; import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener; import android.telephony.SmsManager; private BroadcastReceiver textMessageStatusBroadcastReceiver; private TextToSpeech textToSpeech; // converte texto em fala Fig. 15.3 | Instruo package, instrues import e campos da classe Pizza Activity. Captulo 15 Aplicativo PHAB`S Pizza 7 Sobrescrevendo o mtodo onCreate de Activity O mtodo onCreate (Fig. 15.4) configura a Activity Pizza. As linhas 89115 criam um novo objeto TextToSpeech e configuram seus receptores (listeners). Usaremos esse objeto para pronunciar comandos e perguntas para o usurio durante o processo de pedido de pizza. O primeiro argumento do construtor de TextToSpeech o elemento Context no qual o objeto ser usado. O segundo argumento o TextToSpeech.OnInitListener (linhas 90114) que ser notificado quando a inicializao do mecanismo TextToSpeech terminar. 70 // escolhas possveis para cada uma das cinco opes de pedido 71 private String[][] choices = new String[6][]; 72 73 private String positiveResponseString; // "Yes" 74 private String negativeResponseString; // "No" 75 76 private Resources resources; // usado para acessar os recursos do aplicativo 77 private boolean quitInProgress; 78 79 private HashMap<String, String> ttsParams; // parmetros de TextToSpeech 80 Fig. 15.3 | Instruo package, instrues import e campos da classe Pizza Activity. 81 // Chamado quando a Activity criada 82 @Override 83 public void onCreate(Bundle savedInstanceState) 84 { 85 super.onCreate(savedInstanceState); 86 setContentView(R.layout.main); // configura o layout da Activity 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 // inicializa o mecanismo TextToSpeech e registra o seu OnInitListener textToSpeech = new TextToSpeech(this, new OnInitListener() { // chamado quando TextToSpeech inicializado @Override public void onInit(int status) { // fala em ingls dos EUA textToSpeech.setLanguage(Locale.US); // configura o listener que responde aos eventos gerados // quando as mensagens so concludas textToSpeech.setOnUtteranceCompletedListener( new OnUtteranceCompletedListener() { @Override public void onUtteranceCompleted(String id) { utteranceCompleted(); } // fim do mtodo onUtteranceCompleted } // fim da classe annima interna ); // fim da chamada de setOnUtteranceCompletedListener Fig. 15.4 | Sobrescrevendo o mtodo onCreate de Activity. (continua) 8 Android para Programadores O mtodo onInit de TextToSpeech.OnInitListener chamado quando a iniciali- zao do objeto TextToSpeech termina. A linha 97 usa o mtodo setLanguage de Text- ToSpeech para especificar que o aplicativo falar em ingls dos Estados Unidos (Locale. US). A classe Locale fornece constantes para muitas localidades, mas no garantido que todas sejam suportadas em cada aparelho. Voc pode usar o mtodo isLanguageAvailable para verificar se um Locale especfico est disponvel, antes de us-lo. As linhas 101110 definem OnUtteranceCompletedListener do objeto TextToSpeech, que notificado quando o objeto TextToSpeech acaba de pronunciar uma mensagem. Quando isso ocorre, o mto- do onUtteranceCompleted da rotina de tratamento de eventos (handler) (linhas 104108) chama nosso mtodo utteranceCompleted (Fig. 15.9) para processar esse evento. As linhas 119120 criam e configuram o HashMap ttsParams que ser usado como ltimo argumento em cada chamada do mtodo speak do objeto TextToSpeech. Para garantir que OnUtteranceCompletedListener seja notificado quando a fala terminar, o HashMap deve conter a chave TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID com um valor que no seja uma string vazia. O valor associado a essa chave passado para o mtodo onUtteranceCompleted de OnUtteranceCompletedListener e pode ser usado no mtodo para determinar o texto que o mecanismo TTS acabou de falar, para que voc possa executar tarefas especficas com base nessa informao. No usamos o argumento do mtodo onUtteranceCompleted neste aplicativo. A varivel de instncia currentMessageIndex (linha 122) mantm o ndice de um array de Strings das mensagens e perguntas que o aplicativo fala para o usurio. O valor boolean waitingForResponse indica se o aplicativo est ou no esperando que o usurio responda antes de continuar com o pedido o aplicativo ainda no falou nenhum texto, de modo que o valor inicializado como false (linha 123). A linha 128 chama nosso m- todo loadResources (Fig. 15.7) para carregar os valores String dos arquivos strings.xml e arrays.xml do aplicativo. 111 112 113 114 115 116 117 118 119 120 121 122 currentMessageIndex = 1; // comea na primeira mensagem 123 waitingForResponse = false; // no est esperando pela resposta // do usurio 124 125 // obtm o elemento TextView da Activity 126 messageText = (TextView) findViewById(R.id.mainText); 127 128 loadResources(); // carrega recursos String de xml 129 } // fim do mtodo onCreate 130 playFirstMessage(); } // fim do mtodo onInit } // fim da classe interna annima que implementa OnInitListener ); // fim da chamada do construtor de TextToSpeech // usado nas chamadas do mtodo speak de TextToSpeech para garantir que // OnUtteranceCompletedListener seja notificado quando a fala terminar ttsParams = new HashMap<String, String>(); ttsParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "speak"); Fig. 15.4 | Sobrescrevendo o mtodo onCreate de Activity. Captulo 15 Aplicativo PHAB`S Pizza 9 Sobrescrevendo o mtodo onResume de Activity Quando o usurio conclui o pedido, o aplicativo pergunta se o pedido deve ser enviado como uma mensagem SMS. Para garantir que a mensagem SMS seja enviada, podemos re- gistrar um BroadcastReceiver para verificar o resultado do Intent que enviou a mensagem. O mtodo onResume (Fig. 15.5) cria e registra o textMessageStatusBroadcastReceiver. Quando o mtodo onReceive de BroadcastReceiver chamado, verificamos se o cdigo do resultado no Activity.RESULT_OK (linha 144), no caso em que exibimos uma mensagem de erro no aplicativo. O BroadcastReceiver notificado de forma assncrona, de modo que precisamos exibir o erro a partir da thread da interface grfica do usurio, o que fazemos passando um objeto Message para o mtodo sendMessage de um Handler (linhas 146148). O viewUpdateHandler est definido na Fig. 15.15 e usado por toda a Activity Pizza. 131 // chamado quando essa Activity retomada 132 @Override 133 public void onResume() 134 { 135 super.onResume(); 136 137 // cria um BroadcastReceiver para receber transmisso de // status de mensagem SMS 138 textMessageStatusBroadcastReceiver = 139 { 140 @Override 141 142 { 143 // se a mensagem no foi enviada 144 if (getResultCode() != Activity.RESULT_OK) 145 { 146 147 148 149 } // fim do if 150 } // fim do mtodo onReceive 151 }; // fim da classe interna annima BroadcastReceiver 152 153 // registra o listener 154 155 156 } // fim do mtodo onResume 157 new BroadcastReceiver() public void onReceive(Context context, Intent intent) viewUpdateHandler.sendMessage( viewUpdateHandler.obtainMessage(Pizza.DISPLAY_TOAST_ID, R.string.text_error_message, 0, null)); registerReceiver(textMessageStatusBroadcastReceiver, new IntentFilter(Pizza.BROADCAST_STRING)); Fig. 15.5 | Sobrescrevendo o mtodo onResume de Activity. O mtodo handleMessage de um Handler executado na thread a partir da qual o Handler foi criado e recebe o objeto Message enviado pelo mtodo sendMessage do Handler. Como viewUpdateHandler uma varivel de instncia da classe Pizza da Activi- ty, viewUpdateHandler criada na thread de execuo da interface grfica do usurio. Isso nos ajuda a garantir que as modificaes feitas na interface grfica do usurio aconteam na thread da interface. O Android mantm um pool global de objetos Message reutilizveis, de modo que, em vez de criar objetos Message com o construtor padro, as linhas 147148 criam o objeto Message passado para viewUpdateHandler chamando o mtodo obtainMessage de Handler. A verso de obtainMessage usada aqui exige quatro argumentos um identificador inteiro 10 Android para Programadores que indica o objetivo do objeto Message (usado para decidir como vai process-lo), dois valores inteiros arbitrrios e um Object arbitrrio que pode ser usado no tratamento da mensagem. Em nosso caso, o segundo argumento um ID de recurso do tipo String para a mensagem de erro que exibiremos. Passamos 0 e null para os dois ltimos argumentos, pois no os utilizamos neste aplicativo. As linhas 154155 passam o BroadcastReceiver e um novo IntentFilter para o mtodo registerReceiver da Activity para permitir que o aplicativo receba objetos In- tent de transmisso (broadcast). O argumento String do construtor IntentFilter uma String especfica do aplicativo que permite a ele receber as transmisses destinadas ao aplicativo. Quando enviamos a mensagem SMS (Fig. 15.14), nos preparamos para rece- ber um objeto Intent via broadcast com uma String de ao que usa a mesma constante Pizza.BROADCAST_STRING. Sobrescrevendo o mtodo onPause de Activity Quando a Activity est em pausa, no h necessidade de receber objetos Intent via broadcast, de modo que sobrescrevemos onPause (Fig. 15.6) para desfazer o registro de nosso BroadcastReceiver, passando-o para o mtodo unregisterReceiver da Activity. 158 // chamado quando essa Activity entra em pausa 159 @Override 160 public void onPause() 161 { 162 super.onPause(); 163 164 // se o BroadcastReceiver no for null, desfaz seu registro 165 if (textMessageStatusBroadcastReceiver != null) 166 167 168 textMessageStatusBroadcastReceiver = null; 169 } // fim do mtodo onPause 170 unregisterReceiver(textMessageStatusBroadcastReceiver); Fig. 15.6 | Sobrescrevendo o mtodo onPause de Activity. Mtodo loadResources de Pizza O mtodo loadResources (Fig. 15.7) chamado a partir de onCreate (linha 128 da Fig. 15.4) e carrega os recursos de String do aplicativo usando os mtodos getString e getStringAr- ray do objeto Resource da Activity. O array de Strings bidimensional choices contm as respostas possveis para cada pergunta feita pelo aplicativo. Por exemplo, o array de Strings no ndice PEPPERONI_INDEX contm todas as respostas aceitveis para a pergunta: Do you want pepperoni? neste caso, Yes e No. Esses objetos String so carregados no array bina- ryChoices (linhas 194195) e reutilizados em vrias perguntas. 171 // carrega recursos de String a partir do XML 172 private void loadResources() 173 { 174 resources = getResources(); // obtm os recursos do aplicativo 175 phoneNumber = resources.getString( 176 R.string.phone_number); // carrega o nmero do telefone Fig. 15.7 | Mtodo loadResources de Pizza. Captulo 15 Aplicativo PHAB`S Pizza 11 Mtodo playFirstMessage de Pizza O mtodo playFirstMessage (Fig. 15.8) chamado (Fig. 15.4, linha 112) aps o mecanismo TextToSpeech ser inicializado. O mtodo fala a mensagem de boas-vin- das do aplicativo (armazenada em audioMessages[0]), chamando o mtodo speak de TextToSpeech com trs argumentos o objeto String a ser falado, o modo de enfi- leiramento e um HashMap de parmetros para o mecanismo TextToSpeech. O modo de enfileiramento pode ser TextToSpeech.QUEUE_FLUSH ou TextToSpeech.QUEUE_ADD. O modo QUEUE_FLUSH esvazia a fila de fala (a lista de objetos String que esto esperando para serem falados) para que o novo objeto String possa ser falado imediatamente. O modo QUEUE_ADD adiciona o novo texto a ser falado no final da fila de fala. Mtodo utteranceCompleted de Pizza O mtodo utteranceCompleted (Fig. 15.9) chamado pela rotina de tratamento de even- to (handler) onUtteranceCompleted do objeto TextToSpeech (Fig. 15.4, linhas 104108) e 177 audioMessages = resources.getStringArray( 178 R.array.audio_messages); // carrega mensagens de udio 179 displayMessages = resources.getStringArray( 180 R.array.display_messages); // carrega as mensagens de exibio 181 errorMessageString = resources.getString( 182 R.string.error_message); // mensagem de erro 183 finalMessageString = resources.getString( 184 R.string.final_message); // mensagem final 185 positiveResponseString = resources.getString( 186 R.string.positive_response); // "Yes" 187 negativeResponseString = resources.getString( 188 R.string.negative_response); // "No" 189 190 // inicializa o pedido de pizza 191 order = resources.getString(R.string.initial_order); 192 193 // carrega as respostas vlidas do usurio 194 String[] binaryChoices = 195 resources.getStringArray(R.array.binary_choices); 196 choices[PIZZA_SIZE_INDEX] = 197 resources.getStringArray(R.array.size_choices); 198 choices[PEPPERONI_INDEX] = binaryChoices; 199 choices[MUSHROOM_INDEX] = binaryChoices; 200 choices[ORDER_SUMMARY_INDEX] = binaryChoices; 201 } // fim do mtodo loadResources 202 Fig. 15.7 | Mtodo loadResources de Pizza. 203 // fala a primeira mensagem 204 private void playFirstMessage() 205 { 206 // fala a primeira mensagem 207 208 209 } // fim do mtodo playFirstMessage 210 textToSpeech.speak( audioMessages[0], TextToSpeech.QUEUE_FLUSH, ttsParams); Fig. 15.8 | Mtodo playFirstMessage de Pizza. 12 Android para Programadores quando o aplicativo precisa passar para a prxima mensagem a ser falada. Primeiramen- te, obtemos do objeto ttsParams o valor da chave TextToSpeech.Engine.KEY_PARAM_UT- TERANCE_ID para podermos determinar se o usurio resolveu fechar o aplicativo (linhas 220225). Se isso aconteceu, encerramos (com shutDown) o mecanismo TextToSpeech para liberar seus recursos e encerrar o aplicativo chamando o mtodo finish da Activity. Em seguida, determinamos se o pedido foi concludo (linhas 228229). Em caso positivo, chamamos o mtodo allowUserToQuit para permitir que o usurio encerre o aplicativo ou inicie um novo pedido. Se no estivermos esperando uma resposta do 211 // mtodo utilitrio chamado quando a fala termina e 212 // quando hora de passar para a prxima mensagem 213 private void utteranceCompleted() 214 { 215 // se TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID 216 // contm quit, termina o aplicativo 217 String quit = 218 ttsParams.get(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID); 219 220 if (quit.equals("quit")) // verifica se o usurio deseja encerrar 221 { 222 223 finish(); 224 return; 225 } // fim do if 226 227 // permite que o usurio encerre 228 if (currentMessageIndex >= displayMessages.length && 229 !quitInProgress) 230 { 231 allowUserToQuit(); 232 } // fim do if 233 else if (!waitingForResponse) // se no estamos esperando uma resposta 234 { 235 // atualiza TextView 236 237 238 239 String words = ""; 240 241 // resume o pedido 242 if (currentMessageIndex == ORDER_SUMMARY_INDEX) 243 { 244 words = resources.getString(R.string.order_summary_prefix); 245 words += order.substring(order.indexOf(':') + 1); 246 } // fim do if 247 248 words += audioMessages[currentMessageIndex]; // prxima mensagem 249 words = words.replace(resources.getString(R.string.pepperoni), 250 resources.getString(R.string.pepperoni_speech)); 251 words = words.replace(resources.getString(R.string.pizza), 252 resources.getString(R.string.pizza_speech)); 253 textToSpeech.shutdown(); // encerra TextToSpeech viewUpdateHandler.sendMessage( viewUpdateHandler.obtainMessage(UPDATE_TEXT_ID)); Fig. 15.9 | Mtodo utteranceCompleted de Pizza. Captulo 15 Aplicativo PHAB`S Pizza 13 usurio (linha 233), passamos um objeto Message para viewUpdateHandler a fim de que ele possa atualizar o texto de TextView. As linhas 239252 configuram a String words, que conter a representao de String das palavras a serem faladas para o usurio. Se estivermos na ltima das mensagens que o aplicativo fala para o usurio (linha 242), as linhas 244245 resumem o pedido. A linha 248 anexa o objeto String atual do ar- ray audioMessages em words. As linhas 249250 substituem as palavras pepperoni e pizza por strings que permitem ao mecanismo TextToSpeech falar essas palavras com uma pronncia melhor como pehperohnee para pepperoni. Em seguida, a linha 255 fala a mensagem atravs do mtodo speak de TextToSpeech. Tambm configuramos waitingForResponse como true. Se estivermos esperando uma resposta do usurio (linha 258), chamamos o mtodo listen (Fig. 15.10) para iniciar um Intent para a Activity de reconhecimento de fala. Mtodo listen de Pizza O mtodo listen (Fig. 15.10) usa um objeto Intent (270271) para iniciar uma Acti- vity que recebe entrada de udio do usurio. A constante RecognizerIntent.ACTION_RE- COGNIZE_SPEECH representa a Activity de reconhecimento de fala. Ativamos o objeto In- tent usando startActivityForResult (linha 276) para que possamos receber resultados no mtodo sobrescrito onActivityResult da Activity Pizza. Capturamos uma exceo ActivityNotFoundException que ser lanada por um AVD ou por qualquer equipamento que no tenha recursos de reconhecimento de fala. Se isso acontecer, enviamos uma mensagem para viewUpdateHandler a fim de exibir um Toast explicando por que esse apli- cativo no funcionar. 254 // fala a prxima mensagem 255 256 waitingForResponse = true; // estamos esperando uma resposta 257 } // fim do if 258 else if (!listening && currentMessageIndex > 0) 259 { 260 listen(); // captura a resposta do usurio 261 } // fim do else if 262 } // fim do mtodo utteranceCompleted 263 textToSpeech.speak(words, TextToSpeech.QUEUE_FLUSH, ttsParams); Fig. 15.9 | Mtodo utteranceCompleted de Pizza. 264 // recebe a resposta do usurio 265 private void listen() 266 { 267 listening = true; // agora estamos escutando 268 269 // cria um Intent para Activity de reconhecimento de fala 270 271 272 273 // tenta ativar a Activity de reconhecimento de fala 274 try 275 { Intent speechRecognitionIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); Fig. 15.10 | Mtodo listen de Pizza. (continua) 14 Android para Programadores Sobrescrevendo o mtodo onActivityResult de Activity A Activity Pizza sobrescreve o mtodo onActivityResult (Fig. 15.11) para processar os resultados da Activity de reconhecimento de fala. Passamos RecognizerIntent.EXTRA_RE- SULTS para o mtodo getStringArrayListExtra do Intent recebido (linhas 296298) a fim de obter um ArrayList contendo representaes de String das interpretaes da Activity de reconhecimento de fala da entrada falada pelo usurio. O reconhecimento de fala no exato; portanto, se qualquer um desses objetos String coincidir com uma resposta esperada pelo aplicativo, assumiremos que o usurio falou essa resposta e agir de forma correspon- dente. As linhas 316327 iteram pelas escolhas vlidas, comparando-as com cada uma das correspondncias possveis para a entrada de fala do usurio. Salvamos a primeira corres- pondncia em result (linha 323). Se no houver correspondncia alguma, chamamos o mtodo playError para pedir ao usurio que repita a resposta (linha 330). Caso contrrio, as linhas 331418 processam a resposta do usurio. As linhas 331371 encerram ou conti- nuam o aplicativo. As linhas 373387 enviam o pedido de pizza ou comeam de novo. As linhas 388412 continuam o processo de pedido chamamos o mtodo utteranceComple- ted (linha 411) com o objeto String vazio para falar a prxima mensagem para o usurio. As linhas 414418 processam o caso no qual o usurio cancela a entrada de fala. 276 277 } // fim do try 278 catch (ActivityNotFoundException exception) 279 { 280 281 282 } // fim do catch 283 } // fim do mtodo listen 284 startActivityForResult(speechRecognitionIntent, 0); viewUpdateHandler.sendMessage(viewUpdateHandler.obtainMessage( Pizza.DISPLAY_TOAST_ID, R.string.no_speech_message, 0, null)); Fig. 15.10 | Mtodo listen de Pizza. 285 // chamado quando a Activity de reconhecimento de fala retorna 286 @Override 287 protected void onActivityResult(int requestCode, int resultCode, 288 Intent dataIntent) 289 { 290 listening = false; 291 292 // se no houve erro algum 293 if (requestCode == 0 && resultCode == RESULT_OK) 294 { 295 // obtm a lista das correspondncias possveis para a // fala do usurio 296 297 298 299 300 // obtm a lista atual de escolhas vlidas possveis 301 String[] validResponses; 302 303 if (!quitInProgress) 304 validResponses = choices[currentMessageIndex]; ArrayList<String> possibleMatches = dataIntent.getStringArrayListExtra( RecognizerIntent.EXTRA_RESULTS); Fig. 15.11 | Sobrescrevendo o mtodo onActivityResult de Activity. Captulo 15 Aplicativo PHAB`S Pizza 15 305 else 306 validResponses = 307 resources.getStringArray(R.array.binary_choices); 308 309 if (validResponses == null) 310 return; 311 312 String result = null; 313 314 // para cada escolha vlida possvel, compara com a fala do usurio 315 // para determinar se ele pronunciou uma dessas escolhas 316 checkForMatch: 317 for (String validResponse : validResponses) 318 { 319 for (String match : possibleMatches) 320 { 321 if (validResponse.compareToIgnoreCase(match) == 0) 322 { 323 result = validResponse; // armazena a resposta do usurio 324 break checkForMatch; // para de verificar as respostas possveis 325 } // fim do if 326 } // fim do for 327 } // fim do for 328 329 if (result == null) // no houve correspondncia alguma 330 playError(); // pede para o usurio repetir a resposta 331 else if (quitInProgress) 332 { 333 quitInProgress = false; 334 335 // o usurio disse para encerrar 336 if (result.equalsIgnoreCase(positiveResponseString)) 337 { 338 if (currentMessageIndex >= displayMessages.length) 339 { 340 reset(); // redefine o pedido 341 return; // retorna 342 } // fim do if 343 else 344 { 345 346 347 348 // fala a mensagem final 349 350 351 352 } // fim do else 353 } // fim do if 354 else // o usurio quer retornar 355 { 356 if (currentMessageIndex >= displayMessages.length) 357 { ttsParams.put( TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "quit"); textToSpeech.speak( resources.getString(R.string.quit_message), TextToSpeech.QUEUE_FLUSH, ttsParams); Fig. 15.11 | Sobrescrevendo o mtodo onActivityResult de Activity. (continua) 16 Android para Programadores 358 359 360 361 // fala a mensagem final 362 363 364 365 } // fim do if 366 else 367 { 368 listen(); 369 } // fim do else 370 } // fim do else 371 } // fim do else if 372 // no houve correspondncia e essa a ltima mensagem 373 else if (currentMessageIndex == displayMessages.length - 1) 374 { 375 // o usurio disse para enviar o pedido 376 if (result.equalsIgnoreCase(positiveResponseString)) 377 { 378 waitingForResponse = false; 379 ++currentMessageIndex; 380 sendMessage(); // envia o pedido como uma mensagem de texto 381 } // fim do if 382 else // o usurio cancelou o pedido 383 { 384 reset(); // redefine o pedido 385 return; // retorna 386 } // fim do else 387 } // fim do else if 388 else // no houve correspondncia e essa no a ltima mensagem 389 { 390 // o usurio respondeu positivamente 391 if (result.equalsIgnoreCase(positiveResponseString)) 392 { 393 // se a pergunta anterior quis saber se o usurio deseja pepperoni 394 if (currentMessageIndex == PEPPERONI_INDEX ) 395 { 396 // acrescenta pepperoni no pedido de pizza 397 order += resources.getString(R.string.pepperoni ); 398 } // fim do if 399 else if (currentMessageIndex == MUSHROOM_INDEX ) 400 { 401 // acrescenta cogumelos (mushrooms) no pedido de pizza 402 order += resources.getString(R.string.mushrooms ); 403 } // else if 404 } // fim do if 405 else if (!result.equalsIgnoreCase(negativeResponseString)) 406 order += ", " + result; // atualiza o pedido 407 408 waitingForResponse = false; 409 ++currentMessageIndex; // vai para a prxima pergunta 410 ttsParams.put( TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "quit"); textToSpeech.speak( resources.getString(R.string.leave_message), TextToSpeech.QUEUE_FLUSH, ttsParams); Fig. 15.11 | Sobrescrevendo o mtodo onActivityResult de Activity. Captulo 15 Aplicativo PHAB`S Pizza 17 Mtodo playError de Pizza O mtodo playError (Fig. 15.12, linhas 425429) chamado por onActivityResult quando o mecanismo de reconhecimento de fala do Android no consegue reconhecer a resposta falada pelo usurio. As linhas 427428 usam o mtodo speak do objeto text- ToSpeech para pedir que o usurio tente novamente. O mtodo reset (linhas 432441) chamado por onActivityResult quando o usurio decide reiniciar o processo de pedido. 424 // chamado quando o usurio pronuncia uma resposta inesperada 425 private void playError() 426 { 427 428 429 } // fim do mtodo playError 430 431 // inicia um novo pedido 432 private void reset() 433 { 434 // reconfigura as variveis de instncia associadas a um pedido 435 currentMessageIndex = 1; 436 order = resources.getString(R.string.initial_order); 437 waitingForResponse = false; 438 listening = false; 439 440 playFirstMessage(); 441 } // fim do mtodo reset 442 textToSpeech.speak(errorMessageString, // reproduz a mensagem de erro TextToSpeech.QUEUE_FLUSH, ttsParams); Fig. 15.12 | Mtodos playError e reset de Pizza. Sobrescrevendo os mtodos onSaveInstanceState e onRestoreInstanceState de Activity Os mtodos onSaveInstanceState e onRestoreInstanceState da Activity (Fig. 15.13) salvam e restauram os valores das variveis de instncia currentMessageIndex, order e listening da Activity Pizza para o caso da atividade ser colocada em segundo plano e trazida de volta para o primeiro plano. 411 utteranceCompleted(); // passa para a prxima mensagem 412 } // fim do else 413 } // fim do if 414 else if ((currentMessageIndex > 0 && !listening) || 415 resultCode == Activity.RESULT_CANCELED) 416 { 417 allowUserToQuit(); // ouve a entrada do usurio 418 } // fim do else 419 420 // chama o mtodo super 421 super.onActivityResult(requestCode, resultCode, dataIntent); 422 } // fim do mtodo onActivityResult 423 Fig. 15.11 | Sobrescrevendo o mtodo onActivityResult de Activity. 18 Android para Programadores Mtodo sendMessage de Pizza O mtodo sendMessage (Fig. 15.14) chamado por onActivityResult para enviar o ob- jeto String de pedido final como uma mensagem de texto SMS. Para fazer isso, criamos um novo Intent (linha 469) com um objeto String de ao correspondente ao que usa- mos para registrar o textMessageStatusBroadcastReceiver. Ento, usamos esse Intent para criar um PendingIntent (linhas 470471), chamando o mtodo esttico getBro- adcast de PendingIntent. Lembre-se, do Captulo 14, que PendingIntent representa um Intent e uma ao a ser executada com esse Intent. Quando PendingIntent termina, ele transmite o Intent especificado como o terceiro argumento de getBroadcast esse o Intent que BroadcastReceiver (Fig. 15.5) recebe, indicando se a mensagem SMS foi enviada com sucesso. A linha 474 obtm o SMSManager chamando o mtodo static getDefault de SMS- Manager. O mtodo sendTextMessage de SMSManager (linhas 477478) envia a mensagem 443 // salva o estado do pedido 444 @Override 445 public void onSaveInstanceState(Bundle savedStateBundle) 446 { 447 // armazena os valores de currentMessageIndex, order e listening 448 savedStateBundle.putInt(INDEX_ID, currentMessageIndex); 449 savedStateBundle.putString(ORDER_ID, order); 450 savedStateBundle.putBoolean(LISTENING_ID, listening); 451 452 super.onSaveInstanceState(savedStateBundle); 453 } // fim do mtodo onSaveInstanceState 454 455 // restaura o estado do pedido 456 @Override 457 public void onRestoreInstanceState(Bundle savedStateBundle) 458 { 459 // recupera os valores de currentMessageIndex, order e listening 460 currentMessageIndex = savedStateBundle.getInt(INDEX_ID); 461 order = savedStateBundle.getString(ORDER_ID); 462 listening = savedStateBundle.getBoolean(LISTENING_ID); 463 super.onRestoreInstanceState(savedStateBundle); 464 } // fim do mtodo onRestoreInstanceState 465 Fig. 15.13 | Sobrescrevendo os mtodos onSaveInstanceState e onRestoreInstanceState de Activity. 466 // envia o pedido como uma mensagem de texto 467 private void sendMessage() 468 { 469 470 471 472 473 // obtm o SMSManager padro 474 475 Intent broadcastIntent = new Intent(Pizza.BROADCAST_STRING); PendingIntent messageSentPendingIntent = PendingIntent.getBroadcast(this, 0, broadcastIntent, 0); SmsManager smsManager = SmsManager.getDefault(); Fig. 15.14 | Mtodo sendMessage de Pizza. Captulo 15 Aplicativo PHAB`S Pizza 19 SMS. O primeiro argumento o nmero de telefone para o qual a mensagem ser en- viada. O segundo argumento, null, indica que a central de SMS padro (SMSC) deve ser usada para encaminhar a mensagem SMS ao seu destino. O terceiro argumento a mensagem a ser enviada. O PendingIntent no quarto argumento transmitido quando a mensagem enviada o cdigo resultante de PendingIntent indicar se o envio da mensagem SMS foi bem-sucedido ou falhou. O ltimo argumento (se no for null) outro PendingIntent, que transmitido quando a mensagem SMS entregue para o destinatrio. As linhas 481482 enviam um objeto Message para viewUpdateHandler a fim de exibir uma mensagem de pedido concludo para o usurio e para falar essa mensagem. viewUpdateHandler para atualizar a interface grfica do usurio O viewUpdateHandler (Fig. 15.15) chamado em toda a Activity Pizza para atualizar a interface grfica do usurio de acordo com o estado atual do pedido e para exibir mensa- gens de erro. As linhas 489519 sobrescrevem o mtodo handleMessage de Handler, o qual recebe um objeto Message como argumento e atualiza a interface grfica do usurio com base no contedo desse objeto Message. As linhas 492518 processam o objeto Message com base no identificador contido em receivedMessage.what. Para Pizza.UPDATE_TEXT_ ID, exibimos a prxima mensagem em displayMessages, para que o usurio possa ver o mesmo texto que o aplicativo est falando. Para Pizza.FINAL_UPDATE_TEXT_ID, exibimos e falamos finalMessageString. Para Pizza.DISPLAY_TOAST_ID, exibimos um Toast contendo o valor que foi armazenado na varivel de instncia arg1 de Message quando o objeto Mes- sage foi enviado essa varivel de instncia contm o texto a ser exibido no Toast. 476 // envia o pedido para PHONE_NUMBER 477 478 479 480 // exibe a mensagem final 481 viewUpdateHandler.sendMessage( 482 viewUpdateHandler.obtainMessage(FINAL_UPDATE_TEXT_ID)); 483 } // fim do mtodo sendMessage 484 smsManager.sendTextMessage(phoneNumber, null, order, messageSentPendingIntent, null); Fig. 15.14 | Mtodo sendMessage de Pizza. 485 // atualiza a interface do usurio 486 private Handler viewUpdateHandler = new Handler() 487 { 488 // exibe a prxima mensagem dada 489 490 { 491 // processa a Message com base no identificador armazenado // em receivedMessage.what 492 switch ) ( 493 { 494 case Pizza.UPDATE_TEXT_ID: // se no for a ltima mensagem 495 // exibe a mensagem 496 String text = ""; 497 public void handleMessage(Message receivedMessage) receivedMessage.what Fig. 15.15 | viewUpdateHandler para atualizar a interface grfica do usurio. (continua) 20 Android para Programadores Mtodo allowUserToQuit de Pizza O mtodo allowUserToQuit (Fig. 15.16) chamado pelos mtodos utteranceCompleted e onActivityResult para perguntar se o usurio deseja sair do aplicativo Pizza. Se j con- clumos um pedido (linha 529), perguntamos ao usurio se deseja sair do aplicativo ou comear outro pedido (linhas 531533); caso contrrio, perguntamos se ele deseja sair ou continuar o pedido atual. 522 // permite ao usurio sair do aplicativo 523 private void allowUserToQuit() 524 { 525 quitInProgress = true; 526 waitingForResponse = true; 527 528 // se o pedido estiver concludo, pergunta se vai sair // ou iniciar um novo pedido 529 if (currentMessageIndex >= displayMessages.length) 530 { 531 532 533 534 } // fim do if 535 else // pergunta se vai sair ou continuar o pedido 536 { textToSpeech.speak( resources.getString(R.string.leave_question), TextToSpeech.QUEUE_FLUSH, ttsParams); Fig. 15.16 | Mtodo allowUserToQuit de Pizza. 498 // se a prxima mensagem a ltima 499 if (currentMessageIndex == displayMessages.length - 1) 500 text = order; 501 502 text += displayMessages[currentMessageIndex]; 503 messageText.setText(text); 504 break; 505 case Pizza.FINAL_UPDATE_TEXT_ID: // se o pedido estiver concludo 506 // exibe e reproduz a mensagem final 507 messageText.setText(finalMessageString); 508 509 // fala a mensagem final 510 511 512 break; 513 case DISPLAY_TOAST_ID: 514 // se o reconhecimento de fala no est disponvel nesse aparelho 515 // informa o usurio utilizando um Toast 516 Toast.makeText(Pizza.this , , 517 Toast.LENGTH_LONG).show(); 518 } // fim da instruo switch 519 } // fim do mtodo handleMessage 520 }; // fim do Handler 521 textToSpeech.speak(finalMessageString, TextToSpeech.QUEUE_FLUSH, ttsParams); receivedMessage.arg1 Fig. 15.15 | viewUpdateHandler para atualizar a interface grfica do usurio. Captulo 15 Aplicativo PHAB`S Pizza 21 Sobrescrevendo o mtodo onDestroy de Activity O mtodo onDestroy (Fig. 15.17) chamado quando essa Activity destruda. Cha- mamos o mtodo shutdown de TextToSpeech para liberar os recursos nativos do Android usados pelo mecanismo TextToSpeech. 543 // quando o aplicativo encerrado 544 @Override 545 public void onDestroy() 546 { 547 super.onDestroy(); // chama o mtodo super 548 549 } // fim do mtodo onDestroy 550 } // fim da classe Pizza textToSpeech.shutdown(); // encerra o TextToSpeech Fig. 15.17 | Sobrescrevendo o mtodo onDestroy de Activity. 15.6 Para finalizar O aplicativo PHAB`S Pizza usou os mecanismos de converso de texto em voz e de reconhe- cimento de fala do Android para se comunicar com o usurio falando texto e recebendo a entrada falada pelo usurio. Quando um pedido era concludo, o aplicativo o enviava para um nmero de telefone celular como uma mensagem SMS, usando as APIs de tele- fonia do Android. O aplicativo usou um objeto TextToSpeech para falar texto. Como o mecanismo de converso de texto em voz inicializado de forma assncrona, voc usou TextToSpe- ech.OnInitListener para que o aplicativo pudesse ser notificado quando a inicializao terminava. Voc converteu texto em mensagens faladas chamando o mtodo speak de TextToSpeech e determinou como proceder no aplicativo quando a fala era concluda implementando TextToSpeech.OnUtteranceCompletedListener. Voc recebeu entrada do usurio ativando um RecognizerIntent com a constante ACTION_RECOGNIZE_SPEECH e, en- to, respondeu aos resultados do reconhecimento de fala no mtodo onActivityResult da Activity Pizza. O RecognizerIntent retornava um ArrayList de possveis correspondn- cias para a fala do usurio. Comparando os elementos desse ArrayList com as opes de pedido do aplicativo, voc determinou qual opo foi escolhida pelo usurio e processou o pedido de forma correspondente. Quando um pedido foi concludo, voc enviou uma mensagem SMS via progra- mao, com o SMSManager que voc obteve com o mtodo esttico getDefault de SMS- Manager. Voc enviou a mensagem SMS chamando o mtodo sendTextMessage de SMS- Manager. Usou um PendingIntent para receber uma notificao indicando se a mensagem SMS foi enviada com sucesso e tratou a notificao com um BroadcastReceiver. 537 538 539 540 } // fim do else 541 } // fim do mtodo allowUserToQuit 542 textToSpeech.speak( resources.getString(R.string.quit_question), TextToSpeech.QUEUE_FLUSH, ttsParams); Fig. 15.16 | Mtodo allowUserToQuit de Pizza. 22 Android para Programadores Para garantir que todas as modificaes feitas na interface grfica do usurio fossem realizadas a partir da thread de execuo da interface, voc passou um objeto Message para um Handler criado a partir da thread da interface. O mtodo handleMessage do Han- dler foi chamado na thread que criou o Handler neste aplicativo, a thread da interface grfica do usurio. No Captulo 16, apresentaremos o aplicativo Voice Recorder, que permite ao usu- rio gravar sons usando o microfone do telefone e salvar os arquivos de udio para repro- duo posterior.