quarta-feira, 25 de maio de 2011

Android: Reconhecimento de voz

Olá povo,

Estou corrigindo os trabalhos do pessoal do TECDAM e uma funcionalidade simples do Android que foi utilizada pelo aluno Leonardo Melo me chamou a atenção: o reconhecimento de voz. Essa API foi introduzida na versão 2.1 do Android, e apesar de simples, ela é pouco explorada (por mim inclusive). Para utiliza-la basta é bem simples. Basta chamar a atividade que iniciará o reconhecimento do que será falado, e em seguida obter lista dos textos que foram reconhecidos através do retorno dessa atividade.

Antes de iniciar, precisamos checar se o aparelho suporta essa funcionalidade. Podemos fazer isso através do código abaixo:


PackageManager pm = getPackageManager();
Intent it = new Intent(
RecognizerIntent.ACTION_RECOGNIZE_SPEECH)

List<ResolveInfo> activities =
pm.queryIntentActivities(it, 0);

if (activities.size() != 0) {
// Aparelho suporta Reconhecimento de Voz
} else {
// Aparelho NÃO suporta Reconhecimento de Voz
}

Com o PackageManager podemos obter uma lista de informações sobre Activities baseado em uma Intent. O método queryIntentActivities retorna a lista de atividades que respondem por uma determinada ação. No nosso caso, procuramos pela ação ACTION_RECOGNIZE_SPEECH, se alguma Activity responder por essa ação, é porque o aparelho tem suporte ao reconhecimento de voz.

Para iniciar o reconhecimento de voz, basta usar o código abaixo:


Intent intent = new Intent(
RecognizerIntent.ACTION_RECOGNIZE_SPEECH);

intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);

intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
"Fala alguma coisa!");

startActivityForResult(intent, MEU_REQUEST_CODE);


Isso resultará na imagem abaixo:



Após capturar a voz, ele fará o reconhecimento e enviará os resultados como resultado da Activity. Para tratar o resultado, usamos o método onActivityResult da atividade que chamou o reconhecimento de voz, conforme abaixo:


protected void onActivityResult(
int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == MEU_REQUEST_CODE
&& resultCode == RESULT_OK) {

// Contém a lista com os resultados
ArrayList<String> matches =
data.getStringArrayListExtra(
RecognizerIntent.EXTRA_RESULTS);
}
}


Mais informações aqui.

4br4ç0s,
nglauber

segunda-feira, 23 de maio de 2011

Curso de Android em João Pessoa

Olá povo,

A LinuxFI abriu as inscrições para a segunda turma de Google Android. As aulas acontecerão aos sábados e domingos durante 3 finais de semana.

No curso, estudaremos os principais recursos da plataforma para smartphones e tablets da Google. Conceitos como Activities, Broadcast Receivers, Handlers, ContentProviders e Services serão aplicados na prática. Veremos também como armazenar informações no banco de dados do celular com SQLite, comunicação com WebServices e com o GoogleMaps, envio de SMS e muito mais.

Quem tiver interesse, pode entrar na página do curso para obter mais informações e fazer sua inscrição.



4br4ç05,
nglauber

terça-feira, 10 de maio de 2011

Screenshot de dispositivo Android via app Java

Olá povo,

Todos devem saber que é possível tirar um screenshot da tela de um aparelho Android através da perspectiva DDMS do Eclipse. Uma outra alternativa é executar a aplicação DDMS a partir do diretório tools do Android SDK. Entretanto, hoje no trabalho eu precisei obter um screenshot de um dispositivo Android programaticamente, ou seja, via código, e exibir essa imagem na tela.

Para fazer isso, podemos utilizar as bibliotecas do DDMS que estão no diretório tools/lib do SDK do Android. Para tirar um screenshot da tela do aparelho utilizaremos o arquivo ddmlib.jar. Copie esse arquivo para o seu projeto e adicione-o ao classpath.

A primeira coisa que devemos fazer é criar uma classe que implemente IDeviceChangeListener, e implementar 3 métodos: deviceChanged(IDevice device, int what), deviceConnected(IDevice device) e deviceDisconnected(IDevice device).
No método deviceConnected devemos guardar a referência de IDevice, é com ela que obteremos o screenshot da tela. Mas antes devemos registrar a classe para capturar a imagem da tela que será capturada.

AndroidDebugBridge.init(false);
AndroidDebugBridge.createBridge();
AndroidDebugBridge.addDeviceChangeListener(
instancia_de_IDeviceChangeListener);

No meu caso, estou usando uma tela SWT. Para tirar um screenshot e carregar na tela, utilizei o código abaixo:

RawImage raw;
try {
raw = device.getScreenshot();
PaletteData pal = new PaletteData(
0xFF00, 0xFF0000, 0xFF000000);
ImageData image = new ImageData(
raw.width, raw.height, raw.bpp,
pal, 1, raw.data);

ImageLoader loader = new ImageLoader();
loader.data = new ImageData[] { image };
loader.save("imagem.png", SWT.IMAGE_PNG);

lblImagem.setImage(new Image(
Display.getCurrent(), "imagem.png"));

} catch (TimeoutException e) {
e.printStackTrace();
} catch (AdbCommandRejectedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}


O resultado pode ser observado abaixo:


Referência:
http://blog.codetastrophe.com/2008/12/using-androiddebugbridge-api-to-get.html

4br4ç05,
nglauber

domingo, 1 de maio de 2011

Conexão 3G no Android

Olá povo,

Meu aluno Rafael Cavalcanti me perguntou como saber o tipo de conexão (Wi-Fi ou 3G) que o aparelho Android está utilizando. O código é bem simples, basta utilizar a classe ConnectivityManager que é um serviço do sistema que provê informações sobre as conexões do aparelho.


ConnectivityManager connec = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);

android.net.NetworkInfo wifi =
connec.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
android.net.NetworkInfo mobile =
connec.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

String s = "Conexão: ";
if (wifi.isConnected()) {
s += "Wi-Fi";
} else if (mobile.isConnected()) {
s += "3G";
} else {
s += "Nenhuma";
}
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
Adicione a permissão android.permission.ACCESS_NETWORK_STATE no seu arquivo AndroidManifest.xml conforme abaixo.

<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE"/>

Outra pergunta de Rafael foi como desabilitar, via código, a conexão 3G. Para conseguir isso, dei uma investigada no código fonte do projeto ApnDroid. E fiz um pequeno exemplo QUE USA O CÓDIGO DESSA FERRAMENTA. Para baixa-lo, clique aqui.

4br4ç05,
nglauber

domingo, 24 de abril de 2011

Curso de Android no Ceará

Olá povo,

Em parceria com a Cassic ministrarei os cursos intermediário e avançado de Android. O curso com duração de 40 horas/aula acontecerá nos dias 21 e 22 de maio, e 04 e 05 de junho em Juazeiro do Norte, região do Cariri no Ceará.
Os interessados podem garantir sua vaga aqui com um ótimo desconto.






4br4ç05,
nglauber

domingo, 17 de abril de 2011

Background gradiente no Android

Olá povo,

Post rápido do domingo: como colocar um background gradiente no Android. No diretório res/drawable de um projeto Android podemos colocar arquivos XML também. Esses arquivos devem fazer referências a imagens ou definir formas geométricas como círculos e retângulos. Vejam abaixo como definir um "quadrado" com bordas arredondadas e com cor gradiente.

<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#0000FF"
android:endColor="#000000"
android:angle="90"
android:type="linear" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
<corners
android:radius="30dp" />
</shape>


O arquivo acima, como já dissemos, deve ser criado dentro da pasta res/drawable do seu projeto. Nós o nomeamos como meubg.xml, e nele estamos definindo um retângulo de cor gradiente, começando de azul para preto. O angulo do gradiente é de 90 graus do tipo linear. Determinamos um espaçamento das borda para o componente que utilizar esse arquivo como background. Por fim, determinamos uma borda arredeondada com raio de 30dp.
Se colocarmos esse drawable como background (android:background="@drawable/meubg) de um LinearLayout por exemplo, o resultado ficará como abaixo:



Dúvidas? Consultem a documentação do Android aqui.

4br4ç05,
nglauber

segunda-feira, 11 de abril de 2011

Android: Dicas 2

Olá povo,

Estar à frente de uma sala de aula me propicia o benefício da "ensinagem" (ensino + apredizagem) onde ao mesmo tempo em que ensino, aprendo bastante com meu alunos. Esse post foi totalmente formado por dúvidas dos meu alunos do TECDAM, e que foram resolvidos por eles próprios. Bom para todos, que aprendemos juntos.

Dica 1 (crédito para Gustavo - olha ele aí - Coutinho)
O Android tem um sistema de i18n (internacionalização) muito bacana, onde basta prover recursos através de notações pré-definidas pelo próprio Android em pastas do projeto. Inclusive falei disso nesse post. Os recursos são selecionados automaticamente de acordo com configurações do aparelho. Mas, e se eu quiser determinar o idioma da aplicação? Segue abaixo o código que força um idioma para nossa aplicação.


String languageToLoad = "es"; // espanhol
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
Resources res = getBaseContext().getResources();
res.updateConfiguration(config, res.getDisplayMetrics());
setContentView(R.layout.main);


Dica 2 (crédito para Rogério Casal, aluno do Unibratec)
Nesse post, mostrei como limitar os caracteres utilizando expressões regulares. Porém, podemos fazer a mesma coisa utilizando a propriedade digits do componente EditText, basta colocar os caracteres que você quer permitir.

Dica 3 (crédito para Augusta "Nariquinha")
É comum colocarmos os identificadores dos componentes adicionados nos arquivos de layout utilizando @+id/idDoComponente. Entretanto, quando ficamos com muitas telas ou quando começamos a importar layouts pode haver uma confusão ou até um conflito com esses identificadores. Uma abordagem legal, seria substituir o "id" por algo mais inteligível como "cadpessoa". Por exemplo a definição do EditText abaixo seria perfeitamente válida:
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+cadpessoa/edtNome"/>

E no código Java, poderíamos acessar esse id usando:
EditText edt = 
(EditText)findViewById(R.cadpessoa.edtNome);


Dica 4 (crédito para Leonardo Santos)
Essa eu não arrumei uma justificativa plausível. Quando fui executar um arquivo MP3 no emulador o código abaixo funcionou perfeitamente.
MediaPlayer player = new MediaPlayer();
player.setDataSource("file:///mnt/sdcard/musica.mp3");
player.prepare();
player.start();

Porém, quando coloquei no telefone não funcionou. O erro "Playing Audio - error: PVMFErrNotSupported (Prepare failed.: status=0x1)" era exibido. Após uma busca rápida no Google, a solução foi simples. Ao invés de passar a String diretamente, é passado um objeto FileDescriptor obtido através de um FileInputStream como abaixo.
MediaPlayer player = new MediaPlayer();
FileInputStream fis =
new FileInputStream("/sdcard/musica.mp3");
player.setDataSource(fis.getFD());
player.prepare();
player.start();

Como disse acima, não sei o porquê do erro.

Dica 5 (crédito para Pedro CC)
Para gerar a chave para utilizar a API do Google Maps no Android é preciso usar a ferramenta keytool que vem no JDK (Java Development Kit). Porém, um problema que acontecia constantemente quando ia gerar essa chave era a mensagem "erro de keytool: java.lang.IllegalArgumentException: unknown format type at". Ou seja, erro sem explicação... Esse problema ocorre aparentemente por conta das configurações regionais. Quando elas estão em português, esse erro acontece, em inglês não.
No Windows, vá até o Painel de Controle, e em Configurações Regionais altere o formato das informações para inglês. No Mac vá até System Preferences, em seguida selecione Language e Text, na aba Formats selecione Inglês. [Editado com o comment de Eric Braga] No Linux, basta setar a variável de ambiente LC_ALL usando (export LC_ALL="en_US").

Dica 6 (crédito para Ricardo Gilson)
Se quiser fazer com que cada atributo de cada tag de um arquivo XML fique em uma linha separada no Eclipse, acesse o menu
Windows>Preferences>XML>XML Files>Editor e marque a opção "Split multiple attributes each on a new line". Depois é só abrir seus arquivos de Layout e pressionar Ctrl+Shift+F para que o arquivo fique bem mais agradável.

Agradeço a todos pelas dicas e se dei os créditos errado ou faltou alguém é só avisar :)

4br4ç05,
nglauber