Monthly Archives: Abril 2013

Ler uma imagem via HTTP

A comunicação HTTP no Android deve ser feita dentro de uma thread para evitar que a aplicação fique “presa” à espera da resposta do servidor, não permitindo, durante esse tempo, que o utilizador interaja com a mesma. No entanto, neste artigo vamos solicitar uma imagem a um servidor Web dentro da thread principal. É conveniente que a imagem seja pequena (tenha apenas alguns kb) para que a resposta do servidor não faça a aplicação terminar por inatividade. No próximo artigo sobre comunicação HTTP falaremos da criação de uma thread com a classe AsyncTask para implementar uma comunicação HTTP num ambiente mais seguro.

Este exemplo destina-se a apresentar uma classe de comunicação HTTP que permite enviar pedidos via GET ou via POST a um servidor. Para o efeito, são usadas duas classes: HttpRequest e HttpData. A primeira implementa os métodos de invocação dos comandos GET e POST. A segunda gere a resposta do servidor que pode ser um bloco de texto ou um ficheiro binário.

Segue-se o código da classe HttpRequest:

package com.se.login;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

public class HttpRequest {
    public HttpClient httpclient;

    public HttpRequest() {
        HttpParams httpParameters = new BasicHttpParams();
        // Set the timeout in milliseconds until a connection is established.
        // The default value is zero, that means the timeout is not used.
        int timeoutConnection = 30000;
        HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
        // Set the default socket timeout (SO_TIMEOUT)
        // in milliseconds which is the timeout for waiting for data.
        int timeoutSocket = 60000;
        HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

        httpclient = new DefaultHttpClient(httpParameters);
        httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
    }

    // Faz um pedido GET
    public HttpData get(String url){
        HttpData dados = new HttpData();
        HttpGet request = new HttpGet();
        try {
            request.setURI(new URI(url));
            HttpResponse resp = httpclient.execute(request);
            dados.set(resp);
        } catch (URISyntaxException e1) {
            e1.printStackTrace();
        } catch (ClientProtocolException e1) {
            e1.printStackTrace();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return dados;
    }
    public HttpData getImage(String url, List<NameValuePair> vars) {
        HttpData dados = new HttpData();
        HttpPost request = new HttpPost(url);
        try {
            request.setEntity(new UrlEncodedFormEntity(vars));
            HttpResponse resp = httpclient.execute(request);
            dados.setImage(resp);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dados;
    }

    // Faz um pedido via POST, com variáveis
    public HttpData post(String url, List<NameValuePair> vars){
        HttpData dados = new HttpData();
        HttpPost request = new HttpPost(url);
        try {
            request.setEntity(new UrlEncodedFormEntity(vars));
            HttpResponse resp = httpclient.execute(request);
            dados.set(resp);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dados;
    }
}

A classe HttpData tem o seguinte conteúdo:

package com.se.login;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Hashtable;

import org.apache.http.Header;
import org.apache.http.HttpResponse;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

public class HttpData {
    public String content;
    public Hashtable<String,String> cookies;
    public Hashtable<String,String> headers;
    public int statusCode;
    public Bitmap imagem;

    public HttpData() {
        content = "";
        imagem = null;
        cookies = new Hashtable<String,String>();
        headers = new Hashtable<String,String>();
        statusCode = 0;
    }

    public void set(HttpResponse resp) {
        if(resp == null) return;
        BufferedReader in = null;
        try {
            in = new BufferedReader(new InputStreamReader(resp.getEntity().getContent()));
            StringBuffer sb = new StringBuffer("");
            String line = "";
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                if(sb.length() != 0) sb.append(NL);
                sb.append(line);
            }
            in.close();
            content = sb.toString();
            if(content.startsWith("")) content = content.substring(3);
            Log.d("LOG", "HttpData.set(), tamanho de content: " + content.length());
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
        Header[] hds = resp.getAllHeaders();
        for(Header h: hds) {
            headers.put(h.getName(), h.getValue());
            if (h.getName().equals("set-cookie"))
                cookies.put(h.getName(), h.getValue());

        }
        statusCode = resp.getStatusLine().getStatusCode();
        Log.d("NET", "statusCode = " + statusCode);
    }

    public void setImage(HttpResponse resp) {
        if(resp == null) return;
        InputStream in = null;
        try {
            in = resp.getEntity().getContent();
            imagem = BitmapFactory.decodeStream(in);
            Log.d("LOG", "HttpData.setImage(), tamanho de content: " + content.length());
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        Header[] hds = resp.getAllHeaders();
        for(Header h: hds) {
            headers.put(h.getName(), h.getValue());
            if (h.getName().equals("set-cookie"))
                cookies.put(h.getName(), h.getValue());

        }
        statusCode = resp.getStatusLine().getStatusCode();
        Log.d("NET", "statusCode = " + statusCode);
    }
}

Esta aplicação tem um layout gráfico relativamente simples:

  • um campo de texto para se colocar o endereço Web de uma imagem
  • um botão para acionar o pedido
  • um campo do tipo ImageView para apresentar a imagem lida da Net.

Segue-se o layout gráfico :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	tools:context=".MainActivity"
	android:orientation="vertical"
	>
	<TextView
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:text="URL da imagem:"
		/>
	<EditText
		android:id="@+id/url"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:textSize="20sp"
		/>
	<Button
		android:id="@+id/botao"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:text="Ler Imagem"
		android:textSize="20sp"
		/>
	<ImageView
		android:id="@+id/imagem"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		/>
</LinearLayout>

Para que a aplicação possa comunicar via HTTP, é necessário adicionar à aplicação a permissão de acesso à Web. No ficheiro Android Manifest adicionar o código seguinte antes da marca <application…>:

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

O layout fica com o aspeto seguinte:
imagem

Por fim, a aplicação principal tem o código abaixo:

package com.example.imagem;

import android.os.Bundle;
import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;

public class MainActivity extends Activity {ImageView imagem;
	EditText url;
	Button botao;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		ThreadPolicy tp = ThreadPolicy.LAX;
		StrictMode.setThreadPolicy(tp);
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		imagem = (ImageView) findViewById(R.id.imagem);
		url = (EditText) findViewById(R.id.url);
		botao = (Button) findViewById(R.id.botao);

		botao.setOnClickListener( new View.OnClickListener() {
			public void onClick(View v) {
				String sUrl = url.getText().toString();
				HttpRequest req = new HttpRequest();
				HttpData dados = req.getImage(sUrl);
				imagem.setImageBitmap(dados.imagem);
			}
		});
	}
}

As duas primeiras linhas da função onCreate servem para permitir a comunicação HTTP dentro da thread principal. São as seguintes:

ThreadPolicy tp = ThreadPolicy.LAX;
StrictMode.setThreadPolicy(tp);

Nas primeiras versões do sistema operativo Android era possível executar um pedido HTTP dentro da thread principal. Atualmente isso gera uma exceção do tipo android.os.NetworkOnMainThreadException. Estas duas linhas permitem uma política  de utilização de threads mais permissiva e evitam a ocorrência da exceção. Num artigo próximo, esta situação será resolvida invocando o pedido HTTP dentro de uma nova thread com a classe AsyncTask.

SQLite em Android

O SQLite é um sistema de gestão de bases de dados autónomo, que funciona de forma diferente dos sistemas cliente-servidor. Em SQLite não existe um servidor que execute queries a pedido dos clientes. No SQLite, a aplicação cliente é responsável por criar a base de dados (BD) caso ela não exista, atualizá-la se a versão instalada da BD for mais antiga que a atual usada pela aplicação e, também manipular os dados.

Portanto, contrariamente aos sistemas cliente-servidor usuais como o MySQL, o Oracle, o SQL Server, etc., a aplicação Android que use SQLite tem que incluir o código SQL de manipulação da estrutura da BD, assim como o código de manipulação dos dados.

Este artigo apresenta um exemplo de uma BD simples com uma única tabela para armazenar livros (autor e título). Segue-se a classe DBAdapter que é usada pela Activity definida mais adiante.

package se.bd;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBAdapter
{
private static final String DATABASE_NAME = “Livros”;
private static final int DATABASE_VERSION = 1;

private static final String TABELA_LIVRO =
“CREATE TABLE livro (”
+ “_id INTEGER PRIMARY KEY AUTOINCREMENT, ”
+ “liv_titulo VARCHAR(128), ”
+ “liv_autor VARCHAR(128)”
+ “)”;

private final Context context;

private DatabaseHelper DBHelper;
private SQLiteDatabase db;

public DBAdapter(Context ctx)
{
this.context = ctx;
DBHelper = new DatabaseHelper(context);
}

private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(TABELA_LIVRO);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL(“DROP TABLE IF EXISTS livro”);
onCreate(db);
}
}

//—abre a ligação à BD—
public DBAdapter open() throws SQLException
{
db = DBHelper.getWritableDatabase();
return this;
}

//—fecha a ligação à BD—
public void close()
{
DBHelper.close();
}

//—insere um livro na BD—
public long insereLivro(String titulo, String autor)
{
ContentValues registo = new ContentValues();
registo.put(“liv_titulo”, titulo);
registo.put(“liv_autor”, autor);
return db.insert(“livro”, null, registo);
}

//—consulta todos os livros—
public Cursor getAllLivros() throws SQLException
{
return db.query(true,
“livro”,
new String[] {“_id”,”liv_titulo”,”liv_autor”},
null,
null,
null,
null,
null,
null);
}
}

Segue-se o código da Activity que gere a BD e a interface XML criada mais abaixo.

package se.bd;

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class BD extends Activity {
Button inserir, consultar;
EditText titulo, autor;
DBAdapter bd;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

inserir = (Button)findViewById(R.id.inserir);
consultar = (Button)findViewById(R.id.consultar);
titulo = (EditText)findViewById(R.id.titulo);
autor = (EditText)findViewById(R.id.autor);

bd = new DBAdapter(this);
bd.open();

inserir.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String sTitulo = titulo.getText().toString();
String sAutor = autor.getText().toString();
bd.insereLivro(sTitulo, sAutor);
titulo.setText(“”);
autor.setText(“”);
}
});

consultar.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mostraLivros();
}
});
}

public void mostraLivros() {
Cursor c = bd.getAllLivros();
if(c.moveToFirst()) {
do {
int id = c.getInt(0);
String sTitulo = c.getString(1);
String sAutor = c.getString(2);
String msg = String.format(“%d, %s, %s”, id, sTitulo, sAutor);
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}while(c.moveToNext());
}
c.close();
}

public void onDestroy() {
super.onDestroy();
bd.close();
}
}

O layout gráfico da aplicação é dados pelo ficheiro XML seguinte:

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:orientation=”vertical” ><TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Título”
android:textSize=”20sp”
/>
<EditText
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:id=”@+id/titulo”
android:inputType=”text”
android:textSize=”20sp”
/>
<TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Autor”
android:textSize=”20sp”
/>
<EditText
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:id=”@+id/autor”
android:inputType=”text”
android:textSize=”20sp”
/>
<Button
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:id=”@+id/inserir”
android:text=”Inserir”
android:textSize=”20sp”
/>
<Button
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:id=”@+id/consultar”
android:text=”Consultar”
android:textSize=”20sp”
/></LinearLayout>

A aplicação tem duas caixas de texto (EditText) para o utilizador colocar o título do livro e nome do autor. Tem também dois botões: um para inserir um novo livro e o outro para consultar os livros já armazenados.

Segue-se uma imagem do layout da aplicação.

device-2013-04-03-030339

Mapas e geolocalização com MapFragment

Ficheiros da aplicação

  • No menu, abrir a vista de Navigator: Window – Show View – Navigator
  • Em Navigator (janela do lado esquerdo), premir o botão direito do rato e escolher New – Project. Depois selecionar Android e Android Application Project. Premir Next. Surge uma janela de diálogo.
    • Em Application Name, colocar “Mapas”
    • Em Project Name, colocar “Mapas”
    • Em package name, colocar “com.lingweb.mapa”
    • Em Minimum Required SDK selecionar Google APIs 3.0
    • Em Target SDK selecionar Google APIs 4.2 (ou versão mais recente)
    • Premir Next três vezes
    • Em Create Activity, selecionar BlankActivity. Premir Next
    • Em Activity Name, colocar “Mapas”
    • Em Layout Name, colocar “mapas_layout”
    • Premir Finish
  • Em Navigator, premir o botão direito do rato sobre o projeto Mapas e criar uma diretoria com o nome “deploy”
  • Em Navigator, abrir o ficheiro AndroidManifest.xml e colocar dentro da marca application, as seguinte linhas (antes de <application>):

<permission
android:name=”com.example.mapdemo.permission.MAPS_RECEIVE”
android:protectionLevel=”signature” />

<uses-feature
android:glEsVersion=”0x00020000″
android:required=”true” />

<uses-permission
android:name=”com.example.mapdemo.permission.MAPS_RECEIVE” />
<uses-permission
android:name=”android.permission.INTERNET” />
<uses-permission
android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />
<uses-permission android:name=
“com.google.android.providers.gsf.permission.READ_GSERVICES” />
<uses-permission
android:name=”android.permission.ACCESS_COARSE_LOCATION” />
<uses-permission
android:name=”android.permission.ACCESS_FINE_LOCATION” />

e no fim (antes de </application>):

<meta-data
android:name=”com.google.android.maps.v2.API_KEY”
android:value=”XXX…XXX” />

Na linha anterior deve ser colocada a chave fornecida pelo Google.

  • Em Navigator, abrir o ficheiro /res/layout/mapas_layout.xml e substituir o seu conteúdo pelo código seguinte. No parâmetro android:apiKey deve colocar a chave que obteve no Google. O código abaixo contém três objetos que constituem o esquema gráfico da aplicação: o primeiro é um objeto do tipo MapView, onde é colocado o mapa, os outros dois são textos onde é escrita a posição (latitude e longitude) do telemóvel.

<RelativeLayout       xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:tools=”http://schemas.android.com/tools”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:context=”.Mapas” >

<fragment
android:id=”@+id/map”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
/>

</RelativeLayout>

É necessário importar a biblioteca do Google Play services descarregada anteriormente através do SDK Manager e incluí-la no projeto.

  • No Eclipse, selecionar:
  • File – Import – Android – Existing Android Code into Workspace
  • Premir Next. Em Browse, selecionar o caminho para a biblioteca:
    C:\adt-bundle-windows-x86_64\sdk\extras\google\google_play_services\ \libproject\google-play-services_lib
  • Marcar a opção Copy projects into workspace e premir Finish
  • Em Navigator, premir o botão direito do rato sobre o projeto e selecionar Properties
  • Selecionar Android. Em Library, não marcar a caixa Is Library e adicionar a biblioteca google-play-services_lib
  • Por fim, colocar o código da aplicação:
  • Em Navigator, dentro das diretorias do projeto, abrir o ficheiro /src/com/ /lingweb/mapa/Mapas.java e colocar o código:
package com.lingweb.mapa;import android.app.Activity;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.Toast;import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class Mapas extends Activity implements LocationListener {
static final LatLng LISBOA = new LatLng(38.725, -9.151);
private GoogleMap mapa;
LocationManager lm;
Marker lisboa, aqui;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mapas_layout);
lm = (LocationManager) getSystemService(LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 3, this);
mapa = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
.getMap();
lisboa = mapa.addMarker(new MarkerOptions().position(LISBOA)
.title(“Lisboa”));
aqui = mapa.addMarker(new MarkerOptions()
.position(LISBOA)
.title(“Bom dia”)
.snippet(“Você está aqui”)
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.ic_launcher)));

// Move a câmara instanteneamente para lisboa com um zoom de 15.
mapa.moveCamera(CameraUpdateFactory.newLatLngZoom(LISBOA, 10));
if ( !lm.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
Toast.makeText(getApplicationContext(), “Por favor, ative o GPS”, Toast.LENGTH_LONG).show();
}

}

@Override
public void onLocationChanged(Location loc) {
double lat = loc.getLatitude();
double lng = loc.getLongitude();
LatLng sitio = new LatLng(lat, lng);
// Zoom in, com animação da câmara.
mapa.animateCamera(CameraUpdateFactory.newLatLngZoom(sitio, 15), 2000, null);
aqui.setPosition(sitio);
}

@Override
public void onProviderDisabled(String a) {}
@Override
public void onProviderEnabled(String a) {}
@Override
public void onStatusChanged(String a, int b, Bundle c) {}

}

No caso do Eclipse produzir um erro devido à falta de tradução de cadeias de carateres, o problema pode ser contornado da seguinte forma:

  • No Eclipse, em Window – Preferences, selecionar Android e na caixa procurar CorrectnessMessages
  • Premir ExtraTranslation e alterar a Severity para Warning. Fazer o mesmo com a opção MissingTranslation

As aplicações que usam a biblioteca google-play-services_lib não podem ser executadas no emulador. É necessário criar uma aplicação assinada e executá-la num dispositivo físico.
Para executar esta aplicação tem que instalar o Google Play Services no dispositivo, a partir da loja do Android: Google Play.

Android Debug Bridge

Neste artigo, apresenta-se um exemplo de execução remota da aplicação OlaAndroid através do Android Debug Bridge

  • Em consola, iniciar o emulador. Para isso, descer à diretoria de ferramentas do Android
    cd ” C:adt-bundle-windows-x86_64sdk ools>”
  • e depois executar o comando
    emulator -avd avd_01
  • Mudar, depois, para a diretoria platform-tools
    cd ” C:adt-bundle-windows-x86_64sdkplatform-tools>”
  • O comando seguinte instala a aplicação Ola.apk no emulador:
    adb install Ola.apk
    (é necessário que o ficheiro Ola.apk esteja na mesma diretoria, caso contrário deve fornecer-se o caminho completo para o APK)
  • O comando seguinte mostra a lista de ficheiros da diretoria raiz no cartão de memória do emulador
    adb shell ls /

Se tiver mais do que um dispositivo Android ativo, é necessário indicar qual o dispositivo a que pretende aceder. Nesse caso, o comando acima pode ser substituído por:
adb -s emulator-5554 shell ls /

  • Para listar todos os dispositivos ativos, executar o comando:
    adb devices
  • O comando seguinte cria uma diretoria no cartão de memória do emulador (no caso de ter permissões de escrita):
    adb shell mkdir /sdcard/imagens
  • O comando seguinte copia um ficheiro do disco do computador para o emulador (no caso de ter permissões de escrita):
    adb push foto23.jpg /sdcard/imagens/f1.jpg

O comando seguinte apaga o ficheiro /sdcard/imagens/f1.jpg que se encontra no cartão de memória do emulador do Android:

adb shell rm /sdcard/imagens/f1.jpg

É possível aceder remotamente, via telnet, ao emulador para executar alguns comandos de controlo do mesmo. O primeiro emulador está disponível no porto 5554. Se houver um segundo emulador ativo, este é afeto ao porto 5555, e assim sucessivamente. Os comandos que é possível executar com acesso via telnet são os seguintes:

help|h|? print a list of commands
event simulate hardware events
geo Geo-location commands
gsm GSM related commands
kill kill the emulator instance
network manage network settings
power power related commands
quit|exit quit control session
redir manage port redirections
sms SMS related commands
avd manager virtual device state
window manage emulator window

Seguem-se alguns exemplos de utilização do acesso via telnet.

Acesso remoto ao emulador via telnet

  • Em consola, e com o emulador ativo, executar o seguinte comando:
    telnet localhost 5554
  • Depois, na sessão de telnet enviar os comandos que se seguem
    • Enviar dados de localização (GPS) para o emulador, onde a longitude é o primeiro parâmetro e a latitude o segundo:
      geo fix -9.145174 38.733660
    • Para conhecer os parâmetros do comando network
      help network
    • Para saber o estado da rede
      network status
    • Para saber o estado da bateria
      power display
    • Abandonar a sessão de telnet
      exit

Compilar e testar uma aplicação

Neste artigo vai compilar-se e testar-se a aplicação OlaAndroid criada anteriormente.

Compilar a aplicação

  • Em Navigator, premir o botão direito do rato sobre o projeto OlaAndroid e selecionar Android Tools – Export Signed Application Package, para criar uma aplicação assinada
  • Premir Next. Em Location selecionar a keystore criada anteriormente LWEB.ks que está na diretoria C:\Users\root\workspace (em Windows). Inserir a password e premir Next
  • Em Alias, selecionar web e inserir a password. Premir Next
  • Em Destination APK file, selecionar a diretoria deploy criada anteriormente: C:\Users\root\workspace\OlaAndroid\deploy
    onde “root” é o nome do utilizador
  • Premir Finish. A aplicação fica em: C:\Users\root\workspace\OlaAndroid\deploy

A aplicação assinada pode ser instalada num telemóvel ou tablet com o sistema operativo Android. Para isso, deve ser copiada para o SD Card do dispositivo e depois instalada a partir desse local. Também pode ser instalada no emulador segundo o processo abaixo indicado.

Instalar a aplicação assinada no Emulador (exemplo para Windows)

  • No explorador do Windows, descer até à diretoria do Android:
    C:adt-bundle-windows-x86_64
  • Executar o programa SDK Manager.exe
  • Premir Tools – Manage AVDs…
  • Selecionar o AVD pretendido e premir Start e depois Launch
  • Por fim, numa janela de consola descer à diretoria de ferramentas do Android
    cd adt-bundle-windows-x86_64sdkplatform-tools
  • e executar o comando
    adb -s emulator-5554 install –r
    “C:\Users\root\workspace\OlaAndroid\deploy\OlaAndroid.apk”
  • Aparece um ícone da aplicação na lista de aplicações do emulador do Android. Premir para executar.

Alternativamente também pode lançar uma aplicação não assinada (assinada com a chave de depuração) no emulador. Os passos necessários são explicados abaixo.

Instalar uma aplicação não assinada (assinada com a chave de depuração) no Emulador

  • No Eclipse, em Navigator, premir o botão direito do rato sobre o projeto OlaAndroid e selecionar Run As – Android Application
  • Selecionar o emulador pretendido e premir OK

De notar que não é possível instalar uma versão assinada num emulador que já tem uma versão não assinada da mesma aplicação, ou vice-versa. Nesse caso deve, previamente desistalar-se a versão existente. Isso pode ser feito de uma das duas formas seguintes:

  • No Windows, em consola descer à diretoria de ferramentas do Android
    cd adt-bundle-windows-x86_64sdkplatform-tools
  • e executar o comando
    adb -s emulator-5554 uninstall com.lingweb.ola

ou, alternativamente, no emulador, premir o ícone Settings, selecionar Applications e Manage applications. Depois selecionar a aplicação e premir Uninstall

A aplicação “Android Debug Bridge” (ADB) pode ser utilizada para comunicar com um emulador ou com um dispositivo móvel que esteja ligado através de um cabo USB ao computador. O ADB pode ser utilizado para executar comandos remotamente tanto num emulador como num dispositivo móvel. Seguem-se alguns exemplos de comandos executados em consola, em Windows, sobre um emulador de Android.

Aplicação “Olá Mundo”

Criar a aplicação

  • No menu do Eclipse, selecionar Window – Show View – Navigator
  • Em Navigator (janela do lado esquerdo), premir o botão direito do rato e escolher New – Project. Depois selecionar Android e Android Application Project. Premir Next. Surge uma janela de diálogo.
    • Em Application Name, colocar “OlaAndroid”
    • Em Project Name, colocar “OlaAndroid”
    • Em package name, colocar “com.lingweb.ola”
    • Em Minimum Required SDK selecionar Android 2.2
    • Em Target SDK selecionar Android 4.2 (ou versão mais recente)
    • Premir Next três vezes
    • Em Create Activity, selecionar BlankActivity. Premir Next
    • Em Activity Name, colocar “OlaAndroid”
      (Nota: Activity é a classe de base das aplicações gráficas do Android)
    • Premir Finish
  • Em Navigator, premir o botão direito do rato sobre o projeto OlaAndroid e criar uma diretoria com o nome “deploy”
  • Em Navigator, dentro das diretorias do projeto, abrir o ficheiro /src/com/lingweb/ola/OlaAndroid.java e colocar o código seguinte dentro do método onCreate:
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText(“Olá Mundo”);
setContentView(tv);

 

Criar um certificado para assinar aplicações Android

Para usar o Google Maps ou para publicar uma aplicação na loja de aplicações do Android, é necessário proceder à assinatura da aplicação. O processo de criação da chave para assinar uma aplicação e da assinatura de aplicações é explicado de seguida.

Criar uma keystore

  • Em consola, descer à diretoria dos projetos do Eclipse
  • Em Windows, para o utilizador root:
    cd “C:\Users\root\workspace”
  • Depois executar a linha seguinte (Windows):
    “C:\Program Files\Java\jdk1.7.0_11\bin\keytool” -genkey -v -keyalg RSA -validity 10000 -alias WEB -keystore LWEB.ks
    considerando que o JDK da Sun está instalado na diretoria
    C:\Program Files\Java\jdk1.7.0_11
  • Responder interativamente ao programa, dando origem a uma saída como a que se  segue:
Enter keystore password: passe
Re-enter new password: passe
What is your first and last name?
[Unknown]: WEB, SA
What is the name of your organizational unit?
[Unknown]: Java Dev
What is the name of your organization?
[Unknown]: Pro Bono
What is the name of your City or Locality?
[Unknown]: Lisbon
What is the name of your State or Province?
[Unknown]: Lisbon VT
What is the two-letter country code for this unit?
[Unknown]: PT
Is CN=”WEB, SA”, OU=Java Dev, O=Pro Bono, L=Lisbon, ST=Lisbon VT, C=PT correct?
[no]: yesGenerating 2.048 bit RSA key pair and self-signed certificate (SHA256withRSA) with
a validity of 10.000 days
for: CN=”WEB, SA”, OU=Java Dev, O=Pro Bono, L=Lisbon, ST=Lisbon VT, C=PTEnter key password for
(RETURN if same as keystore password):
[Storing LWEB.ks]

Verificar e obter a assinatura SHA1 do certificado
(necessário para obter a chave do Google API)

  • Na mesma diretoria (em Windows) “C:\Users\root\workspace” executar
    “C:\Program Files\Java\jdk1.7.0_11\bin\keytool” -v -list -keystore LWEB.ks
  • Responder interativamente ao programa, dando origem a um resultado como o que se segue:
Enter keystore password: passeKeystore type: JKS
Keystore provider: SUNYour keystore contains 1 entry

Alias name: web

Certificate fingerprints:
SHA1: F1:3E:7F:47:07:6A:34:B1:19:…:A5:06:12:E2:B9

No sítio do Google, pedir uma chave para desenvolver aplicações com o Google Maps

  • No browser, colocar o endereço seguinte:
    https://code.google.com/apis/console/
  • Em Services, ative a opção “Google Maps Android API v2”
  • Em API Access, premir Create New Android key…
  • Inserir a chave SHA1, seguida de “;” e do nome do pacote da aplicação. Deve criar-se uma chave por cada projeto
  • Guardar a chave gerada pelo Google, para a utilizar na criação da aplicação.

Guia para o desenvolvimento Android – Instalação

Lista de pacotes a instalar

Instalar o ADT Plugin

  • No Eclipse, escolher Help – Install New Software…
  • Em Work with, premir o botão Add. Surge uma caixa de diálogo
    • Em Name, escrever Android
    • Em Location, colocar https://dl-ssl.google.com/android/eclipse/
    • Premir OK
  • Selecionar “Developer Tools na caixa. Todas as opções, nomeadamente “Android DDMS” e “Android Development Tools”, devem estar selecionadas. Premir Next.
  • Na janela de Install Details, premir Next outra vez.
  • Ler a licença, aceitar e premir Finish.

Configurar o ADT Plugin

  • No Eclipse, escolher Window – Preferences
  • Selecionar Android no painel esquerdo
  • Em SDK Location colocar a diretoria do SDK do Android. Em Windows, num sistema a 64 bits, deverá ser o seguinte: C:\adt-bundle-windows-x86_64\sdk
  • Premir Apply
  • Premir OK

Instalar os componentes para o SDK do Android

  • Verifique se tem a diretoria de ficheiros binários do Java colocada na variável PATH do sistema operativo. Em Windows, nas propriedades do computador, selecione Advanced System Settings – Environment Variables e em System variables, selecione PATH e coloque, como primeira variável, o caminho para os binários do Java: “C:\Program Files\Java\jdk1.7.0_11\bin;”
  • Em Windows, no explorador do Windows, descer até à diretoria do Android:
  • C:\adt-bundle-windows-x86_64\
  • Executar o programa SDK Manager.exe
  • Em Availables Packages, selecionar os pacotes pretendidos e premir Install Selected. É aconselhável selecionar pelo menos um de cada versão maior do SDK Platform e do Google APIs: por exemplo o 2.2, o 3.0, o 3.2 e o 4.2. Se selecionar todos, o processo de instalação pode ser muito moroso. Instalar também o Google Play services que está na pasta Extras
  • Criar um telemóvel virtual (Android Virtual Device, AVD) para usar em debug. No Android SDK Manager, premir :
    • Tools – Manage AVDs…
    • Selecionar um AVD predefinido em Device Definitions. Alternativamente, pode criar um AVD novo. Para isso:
      • Em Android Virtual Devices:
      • Premir o botão “New”
      • Dar um nome ao telemóvel virtual, p. ex.: avd_01
      • Configurar as opções pretendidas
      • Premir “OK”