domingo, 25 de outubro de 2009

Intents nativas do Android

Olá povo,

Um grande benefício que a plataforma Android trouxe para nós desenvolvedores foi a capacidade de nos comunicar com aplicações "nativas" através de intenções (Intents).
Sendo assim, resolvi publicar algumas das intents nativas mais comuns do Android. Segue abaixo o código-fonte.


public class ExemploIntents extends ListActivity {

private static final String[] OPCOES = {
"Browser",
"Realizando uma chamada",
"Visualizar contato",
"Todos os contatos",
"Mapa",
"Tocar música",
"SMS",
"Sair"
};

@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
ArrayAdapter<String> adapter =
new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
OPCOES);

setListAdapter(adapter);
}

@Override
protected void onListItemClick(ListView l, View v,
int position, long id) {

super.onListItemClick(l, v, position, id);
Uri uri = null;
Intent intent = null;

switch (position) {
// Abrindo uma URL
case 0:
uri = Uri.parse("http://nglauber.blogspot.com");
intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
break;

// Realiza uma chamada
case 1:
uri = Uri.parse("tel:99887766");
intent = new Intent(Intent.ACTION_DIAL, uri);
startActivity(intent);
break;

// Visualiza um contato específico
// da lista de contatos
case 2:
uri = Uri.parse(
"content://contacts/people/5");
intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
break;

// Visualiza todos os contatos e permite
// selecionar um através do resultado
// da Activity
case 3:
uri = Uri.parse(
"content://contacts/people/");
intent = new Intent(Intent.ACTION_PICK, uri);
startActivityForResult(intent, 0);
break;

// Pesquisa uma posição do mapa
// !Seu AVD deve estar usando Google APIs!
case 4:
uri = Uri.parse(
"geo:0,0?q=Rua+Amelia,Recife");
intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
break;

// Executa uma música do SDcard
case 5:
uri = Uri.parse(
"file:///sdcard/musica.mp3");
intent = new Intent();
intent.setDataAndType(uri,"audio/mp3");
startActivity(intent);
break;

// Abrindo o editor de SMS
case 6:
uri = Uri.parse("sms:12345");
intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra("sms_body", "Corpo do SMS");
startActivity(intent);
break;

default:
finish();
}
}

@Override
protected void onActivityResult(int requestCode,
int resultCode, Intent data) {

super.onActivityResult(requestCode,
resultCode, data);

// Mostra um contato selecionado (case 3)
// em um Toast
if (data == null){
Toast.makeText(this, "Nenhum contato",
Toast.LENGTH_SHORT).show();
} else {
Uri uri = data.getData();
Toast.makeText(this, "Contato: "+ uri,
Toast.LENGTH_SHORT).show();
}
}
}


Vamos explicar o que foi feito acima. Criamos uma lista com várias opções de intents nativas. E quando o usuário clicar em qualquer uma dessas opções, a respectiva Intent será disparada.
Em todos os casos, utilizamos o objeto Uri para criar a Intent. Esse objeto indica um recurso do aparelho queremos acessar, e baseado no protocolo informado, ele irá disparar a atividade desejada.
Em conjunto com a Uri, associamos uma ação que queremos realizar sobre o recurso. Vamos exemplificar como o Android entende a solicitação, usando o caso do Browser: "O usuário está com a intenção (Intent) de visualizar (ACTION_VIEW) o recurso (Uri) http://nglauber.blogspot.com". Nesse momento o Android faz uma busca interna pra saber quem pode tratar essa intenção.

No exemplo de discar um número, utilizamos a ação ACTION_DIAL e o protocolo "tel:" seguido do número do telefone a ser discado. Notem que aqui há uma diferença entre "discar" (ACTION_DIAL) e "chamar" (ACTION_CALL). A primeira opção apenas disca o número não chama. Se quiséssemos chamar o número ao invés de apenas discá-lo, deveríamos utilizar a ACTION_CALL e adicionar a permissão abaixo no manifest:

<uses-permission name="android.permission.CALL_PHONE"/>

Na lista de contatos temos dois casos. O primeiro visualiza um contato utilizando o protocolo "content://" - que identifica um ContentProvider - passando o caminho do provider de contatos. Já o segundo caso está usando a ação ACTION_PICK para recuperar a Uri de um contato específico. Para tal, é utilizado o método startActivityForResult que iniciará a tela de contatos permitindo que selecionemos um da lista. Para tratar o retorno da atividade, utilizamos o método onActivityResult.
Para abrir a aplicação de Mapas em um local específico utilizamos o protocolo "geo:" seguido do do endereço do local desejado. É possível passar também a longitude e latitude (geo:lat,long).
Para executarmos o MP3 Player padrão do aparelho passando uma música, utilizamos o método setDataAndType e passamos a Uri com o protocolo "file://" e informando o MIME type do arquivo.
Mais informações aqui.

4br4ç05,
nglauber

terça-feira, 13 de outubro de 2009

Hospedagem grátis: Java + MySql

Olá povo,

Aqui vai uma boa dica para quem precisa hospedar, para testes, sites em Java . O site EATJ permite que você hospede sua aplicação de graça com as seguintes configurações:
  • Java 1.5 ou 1.6;
  • Servidor Tomcat 5.5 ou 6.0 (permitindo o acesso ao Manager e o Administrator);
  • Banco de dados MySql 4.1 ou 5.0 com acesso através do PHPMyAdmin.
Tudo isso através de uma interface bem simples. Para fazer o deploy basta fazer o upload do seu arquivo WAR (de até 50MB para conta gratuita) e pronto! Sua aplicação já está no ar.

A URL fica no seguinte formato: http://seuusuario.s156.eatj.com/
Um ponto negativo que eu verifiquei, é que as contas gratuitas tem seus servidores reiniciados a cada 6 horas. Mas como utilizei para testes, é uma boa opção.

4br4ç05,
nglauber

terça-feira, 6 de outubro de 2009

Android Widgets

Olá povo,

Todo mundo vem reparando a grande quantidade de inovação trazida pelo Android para as aplicações mobile. Entre essas inovações, temos a possibilidade de criar pequenas aplicações que podem ser adicionadas na tela principal do aparelho. A essas aplicações chamamos de widgets.

Procurando um pouco na internet você acha esse exemplo no site do próprio Android.

Porém, ele não é muito trivial nem didático para quem tá querendo aprender os conceitos sobre o assunto. Sendo assim, vou apresentar um exemplo bem simples de widget baseado no tutorial em inglês de Norbert Möhring)

Vamos lá! Crie um novo projeto Android no Eclipse. Dê um nome ao seu projeto; na opção "Build target" coloque a versão 1.5 (os widgets surgiram a partir dessa versão); o pacote que coloquei foi ngvl.android.widget; desmarque a caixa para criar uma atividade, pois não precisamos.

Altere o arquivo res/layout/main.xml, para que fique da seguinte forma:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:orientation="vertical"
android:background="@drawable/widget_bg_normal"
android:layout_gravity="center"
android:layout_height="wrap_content">

<TextView android:id="@+id/widget_textview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal|center"
android:layout_marginTop="5dip"
android:padding="10dip"
android:textColor="@android:color/black"/>
</LinearLayout>


Notem que eu utilizei uma imagem como background do LinearLayout. Clique aqui para baixá-la, e depois coloque na pasta res/drawable do seu projeto. Essa imagem está no formato Nine Patch. O Android dá suporte a esse padrão de imagem que estabelece como uma imagem deve ser redimensionada. Mais informações sobre esse formato clique aqui.

O nosso widget não será uma Activity, mas sim um BroadcastReceiver que será notificado quando nosso widget receber atualizações (que serão configuradas mais na frente).


package ngvl.android.widget;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.os.Handler;
import android.widget.RemoteViews;

public class MeuWidget extends AppWidgetProvider {

private Handler handler;
private MyTime time;

@Override
public void onUpdate(Context ctx,
AppWidgetManager appWidgetManager,
int[] appWidgetIds) {

time = new MyTime(ctx, appWidgetManager)
handler = new Handler();
handler.post(time);
}

private class MyTime implements Runnable {
RemoteViews remoteViews;
AppWidgetManager appWidgetManager;
ComponentName thisWidget;
DateFormat dateFormat;

public MyTime(Context context,
AppWidgetManager appWidgetManager) {

this.appWidgetManager = appWidgetManager;
this.remoteViews = new RemoteViews(
context.getPackageName(),
R.layout.main);

this.thisWidget = new ComponentName(
context, MeuWidget.class);

this.dateFormat = SimpleDateFormat.
getTimeInstance(
SimpleDateFormat.MEDIUM,
Locale.getDefault());
}

@Override
public void run() {
remoteViews.setTextViewText(
R.id.widget_textview,
"Time "+ dateFormat.format(
new Date()));
appWidgetManager.updateAppWidget(
thisWidget, remoteViews);
handler.postDelayed(this, 1000);
}
}
}


Como podemos ver, nossa classe herda de android.appwidget.AppWidgetProvider que por sua vez, herda de android.content.BroadcastReceiver e devemos implementar o método onUpdate. Esse método é chamado toda vez o o widget precisar ser atualizado. Nesse método estou utilizando um Handler para atualizar o o conteúdo com a data/hora atual.
A classe MyTime recebe uma referência para o contexto da aplicação e um objeto do tipo AppWidgetManager. É a partir dele que obtemos as refências para as views utilizadas no layout. No método run dessa classe atualizamos o TextView com a data/hora atuais.

Agora vamos criar uma pasta chamada xml dentro da pasta res e criar o arquivo meuwidget_provider.xml com o seguinte conteúdo:


<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="146dip"
android:minHeight="72dip"
android:initialLayout="@layout/main"
android:updatePeriodMillis="1000"/>


Nesse arquivo, definimos o tamanho mínimo do nosso componente, bem como o layout e o intervalo de atualizações do mesmo.

Agora, vamos atualizar o nosso AndroidManifest.xml:


<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="ngvl.android.widget"
android:versionCode="1"
android:versionName="1.0">

<application
android:icon="@drawable/icon"
android:label="@string/app_name">

<receiver
android:label="@string/app_name"
android:name=".MeuWidget">

<intent-filter>
<action
android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/meuwidget_provider"
/>
</receiver>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>


Pronto! Agora mande rodar a aplicação. Depois que a aplicaçao for instalada (olhe no Console view ou no Logcat), vá até a Home Screen (a tela onde fica o relógio) e pressione Menu / Add / Widget e voilà! Nosso widget apareceu na lista. Selecione-o na lista e ele ficará na sua tela principal. Para removê-lo, basta pressioná-lo e arrasta-lo para lixeira (na parte inferior).



Espero que tenha sido útil. Qualquer dúvida, entrem em contato.

4br4ç05,
nglauber