Menu Chiudi

Locator: una applicazione Gps per il sistema operativo Android per smartphone.

Costruisci il tuo sistema ideale per le escursioni montane con Android!

 

Costruisci il tuo sistema ideale per le escursioni montane con Android!

 

Questa volta Google ha colto nel segno con il suo progetto Android conquistandosi una nuova fetta di mercato nel mondo della comunicazione digitale grazie al supporto della OHA (Open Handset Alliance), che associa le aziende leader della telefonia, del calibro di LG, HTC, Motorola, Samsung, Intel , Nvidia, Telecom e tante altre.

Android é un sistema operativo quai del tutto Open Source per dispositivi mobili, e di una raccolta di applicazioni middleware sviluppate in Java basate su kernel Linux 2.6.

 

Introduzione: Caratteristiche principali di un sistema Android

 

  • Application Framework fornito nell’ambiente mette a disposizione delle applicazioni una serie di componenti e oggetti per interfacciarsi con il sistema;

    Dalvik Virtual Machine una macchina virtuale basata su Java Virtual Machine che si preoccupa di interpretare le applicazioni e ottimizzarne l’esecuzione sullo smartphone;

  • Browser Integrato basato sul motore open source di WebKit;

  • Grafiche ottimizzate definite da delle librerie 2D personalizzate; grafiche 3D basate su OpenGL ES 1.0(Accelerazione Grafica Opzionale);

  • SQLite per la memorizzazione di dati strutturati;

  • Supporto Multimediale per comuni formati audio, video, e immagini (MPEG4, H.264, MP3, AAC, AMR, JPG, PNG, GIF);

  • Telefonia GSM (dipendente dall’hardware);

  • Bluetooth, EDGE, 3G, e WiFi (dipendente dall’hardware);

  • Camera, GPS, bussola, e accelerometro (dipendente dall’hardware);

  • Ricco ambiente di sviluppo tra cui un emulatore, strumenti per il debugging e un plugin basati sull’IDE Eclipse;

 

Librerie

 

  • Librerie C di Sistema – a BSD-derived implementazioni delle librerie di sistema C standard(libc), ottimizzato per dispositivi basati su Linux embedded;

  • Librerie Multimediali – basate sull’OpenCORE di PacketVideo; le librerie supportano la riproduzione e la registrazione di molti formati audio e video, così come file di immagini, compresi i seguenti formati: MPEG4, H.264, MP3, AAC, AMR, JPG e PNG;

  • Gestione delle Superfici – gestisce l’accesso al sottosistema display e compone layer grafici 2D e 3D da applicazioni multiple;

  • LibWebCore – un moderno motore per browser web su Android;

  • SGL – motore grafico 2D;

  • Librerie 3D – un’implementazione basata su OpenGL ES 1.0; le librerie usano sia accelerazione hardware 3D (quando disponibile) sia quella inclusa, con un software 3D di registrazione altamente ottimizzato;

  • FreeType – rendering di caratteri in bitmap e vettoriale;

  • SQLite – un leggero ma potente motore di database relazionale a disposizione di tutte le applicazioni.

 

 

Bene, dopo aver introdotto le principali caratteristiche di questo splendido sistema inizieremo col descrivere com’è strutturato il framework e quali chicche hanno introdotto i signori di bigG.

 

I principali componenti che costituiscono un’applicazione Android sono 4:

 

  • Activities

  • Services

  • Broadcast receivers

  • Content providers

 

 

  • Activities

 

L’Activity si occupa della rappresentazione dell’interfaccia utente. Ad esempio un’Activity potrebbe mostrare un elenco di contatti di una applicazione di messaggi. Quindi questa è la classe che verrà implementata nei nostri progetti per la visualizzazione di interfacce grafiche.

 

  • Services

 

I Services a differenza della Activity non possiedono interfacce grafiche ma vengono eseguiti in background. Ad esempio l’utente potrebbe ascoltare della musica mentre svolge altre attività, questa funzionalità potrebbe essere gestita da un servizio che lavora in background. Infatti la scelta delle tracce potrebbe essere fatta da classi che implementano il componente Activity e la riproduzione effettiva può essere gestita da un Service.

E’ possibile connettersi a (agganciarsi a) un servizio in corso (e avviare il servizio, se non è già in esecuzione) durante il collegamento, è possibile comunicare con il servizio attraverso un’interfaccia fornita dal servizio. Ad esempio per il servizio di gestione della musica, questa interfaccia potrebbe consentire agli utenti di mettere in pausa, riavvolgere, arrestare e riavviare la riproduzione.

 

  • Broadcast receivers

 

Il Broadcast receiver è un componente il cui scopo è esclusivamente quello di ricevitore globale di messaggi. Ad esempio messaggi di tipo “il fuso orario è cambiato”, o “la batteria è a un livello basso”, oppure “l’utente ha cambiato la preferenza della lingua”.

 

  • Content providers

 

Il Content provider è un componente atto a dare servizi per la gestione dei dati alle applicazioni che ne richiedono l’utilizzo. Ad esempio da la possibilità di memorizzare dati nel file system o in un database SQLite.

 

Ma adesso basta con la teoria facciamo un pò di pratica. Vediamo dove prendere l’SDK e come settarlo per il nostro progetto:

 

Procurarsi gli strumenti:

 

  1. Scaricare l’SDK da https://developer.android.com/ (scaricare la versione Android 1.5 SDK r3 in uso alla pubblicazione di questo articolo) e scompattarlo in una directory di nome android-sdk-linux_x86-1.5_r3;

  2. Scaricare un IDE, nel nostro caso Eclipse visto che è supportato ufficialmente da Android, da qui http://www.eclipse.org/downloads/ e scompattarlo in una directory;

  3. Adesso avviamo Eclipse e installiamo il plugin per android ADT:

  • Avviare eclipse, e selezionare help → Software Updates….

  • Nella finestra di dialogo, selezionare il tab Available Software..

  • Cliccare su Add Site…

  • Nella finestra di dialogo di Add Site immettere la seguente stringa http://dl-ssl.google.com/android/eclipse/ e cliccare OK.

  • Ok adesso ritornando nel tab di Available Software spuntare la checkbox del plugin appena inserito e cliccare su Install…

  • Nella finestra di dialogo spuntare Android Developer Tools e Android Editors e cliccare su Next.

  • Accettare la licenza e cliccare su Finish.

  • Riavviare eclipse.

 

Locator, un semplice sistema di localizzazione GPS

 

Progetto:

 

Ora che abbiamo gli strumenti adatti spendiamo due righe per capire appieno le funzionalità che avrà l’applicazione che andremo a sviluppare. Essa consiste in un sistema di localizzazione costante tramite GPS, che visualizza la propria posizione sulla mappa aggiornandola costantemente e fornendo altre informazioni come Latitudine, Longitudine, Altitudine e Velocità.

 


 

 

Creare il progetto:

 

Adesso creiamo il nostro progetto: File → New → Project selezioniamo l’etichetta “Android” ed infine selezioniamo “Adroid Project” e clicchiamo su Next.

 

 

Nella schermata successiva impostiamo il nome del progetto, pakage, il nome dell’Activity e quello dell’applicazione(fare riferimento all’immagine).

 

 

 

 

Finita la fase di creazione del progetto, possiamo catapultarci nello sviluppo dell’interfaccia grafica(UI).

In android l’interfaccia grafica di un’Activity viene in genere definita da una o piu’ View con l’ausilio di vari tipi di layout (se ne possono creare anche di personalizzati).

Le varie View possono essere definite da codice oppure tramite un file xml.

In genere il file xml è quello più utilizzato oltre che consigliato in quanto meno complicato e velocemente modificabile. All’interno della directory /res/layout troviamo il seguente file main.xml:

 

<?xml version=”1.0″ encoding=”utf-8″?>

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”

android:id=”@+id/mainlayout”  

android:orientation=”vertical”  

android:layout_width=”fill_parent”  

android:layout_height=”fill_parent” >  

<TableLayout  

android:orientation=”vertical”  

android:layout_width=”fill_parent”  

android:layout_height=”wrap_content”  

android:stretchColumns=”1″ >  

<TableRow>  

<TextView

android:id=”@+id/lat”  

android:layout_width=”wrap_content”  

android:layout_height=”wrap_content”  

android:text=”Latitude:”  

android:padding=”3dip” />  

 

<TextView  

android:id=”@+id/log”  

android:layout_width=”wrap_content”  

android:layout_height=”wrap_content”  

android:gravity=”right”  

android:text=”Longitude:”  

android:padding=”3dip” />  

</TableRow>  

 

<TableRow>  

<TextView

android:id=”@+id/alt”  

android:layout_width=”wrap_content”  

android:layout_height=”wrap_content”  

android:text=”Altitude:”  

android:padding=”3dip” />  

 

<TextView  

android:id=”@+id/speed”  

android:layout_width=”wrap_content”  

android:layout_height=”wrap_content”  

android:gravity=”right”  

android:text=”Speed:”  

android:padding=”3dip” />  

</TableRow>  

</TableLayout>  

<RelativeLayout

android:orientation=”vertical”

android:layout_width=”fill_parent”

android:layout_height=”wrap_content” >  

<com.google.android.maps.MapView  

android:id=”@+id/mapview”  

android:layout_width=”fill_parent”  

android:layout_height=”fill_parent”  

android:clickable=”true”  

android:apiKey=” Your Maps API Key” />

<LinearLayout  

android:id=”@+id/zoomview”  

android:layout_width=”wrap_content”  

android:layout_height=”wrap_content”  

android:layout_alignBottom=”@id/mapview”  

android:layout_centerHorizontal=”true” />  

</RelativeLayout>  

</LinearLayout> 

 

Abbiamo appena scritto una UI con l’ausilio dei layout standard di android. Dal momento che non è obiettivo di questo articolo spiegare in modo approfondito cosa siano le View, si darà giusto qualche accenno sui layout utilizzati per il progetto:

 

  • LineaLayout, dispone i componenti figli in singole righe o singole colonne.

  • RelativeLayout, un layout in cui le posizioni dei componenti figli sono relazionate le une alle altre.

  • TableLayout, dispone i componenti figli in righe e colonne.

     

Si ha la possibilità di definire anche i vari attributi delle View utilizzando sempre la medesima struttura XML:

 

android:id

Fornisce un nome identificativo per questo tipo di component, per poi recuperare con View.findViewById () o Activity.findViewById (). Rappresenta una risorsa di riferimento; in genere si usa questa sintassi @+ per creare un nuovo ID. Ad esempio: android: id =”+id@/my_id” che ti permette di recuperare il component View in seguito con findViewById (R.id.my_id).

android:layout_width

Questo attributo definisce le dimensioni in larghezza sullo schermo. Se si desidera espandersi sull’intera dimensione dello schermo basta impostare il valore su “fill_parent”.

android:layout_height

Questo attributo definisce le dimensioni in altezza sullo schermo. Se si desidera espandersi sull’intera dimensione dello schermo basta impostare il valore su “fill_parent”.

android:orientation

Definisce l’orientamento del View che può essere settato in “vertical” o “horizontal

 

E’ importante soffermarsi sul componente com.google.android.maps.MapView che si occupa della visualizzazione delle cartografie all’interno della View, ma per poter accedere alle carte geografiche di google maps si ha bisogno di una key che è ottenibile tramite la procedura spiegata a questo link: https://developers.google.com/maps/documentation/android-sdk/v1/?hl=it-IT&csw=1 .

Dopo aver ottenuto la key si deve integrare nell’attributo android:apiKey al posto della stringa Your Maps API Key.

Perfetto ora che abbiamo sviluppato l’interfaccia grafica, possiamo iniziare con lo scrivere l’applicazione vera e propria. In src/hlcs/gps troviamo la nostra classe Locator.java:

 

package hlcs.gps;

import java.util.List;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ZoomControls;

public class Locator extends MapActivity implements LocationListener{
private LinearLayout linearLayout;
private MapView mapView;

private MapController mapController;
private ZoomControls mZoom;

private MyLocationOverlay myLocationOverlay;
private LocationManager locationManager;

private TextView lat;
private TextView log;
private TextView alt;
private TextView speed;

 

Dato che il nostro progetto si basa sulla rappresentazione GPS della propria posizione sulla mappa

si avrà l’esigenza di utilizzare le sotto strutture google per la gestione delle cartografie.

Per visualizzare e gestire una mappa di google maps su android le classi interessate dovranno estendere la classe MapActivity; invece per gestire la propria posizione si ha la necessità d’implementazione dell’interfaccia LocationListener con cui si ricevono le notifiche dal GPS ogni qual volta cambia la posizione.

 

/** Viene richiamato quando l’Activity viene avviata la prima volta. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

//Init MapView, LinerLayout, i TextView, MapController e lo Zoom
mapView = (MapView) findViewById(R.id.mapview);
linearLayout = (LinearLayout) findViewById(R.id.zoomview);

lat = (TextView) findViewById(R.id.lat);
log = (TextView) findViewById(R.id.log);
alt = (TextView) findViewById(R.id.alt);
speed = (TextView) findViewById(R.id.speed);

mapController = mapView.getController();
mZoom = (ZoomControls) mapView.getZoomControls();

//Imposta la distanza dello Zoom e aggiunge i tasti Zoom in fondo alla mappa
mapController.setZoom(10);
linearLayout.addView(mZoom);

// Aggiunge l’overlay sulla mappa della propria posizione
myLocationOverlay = new MyLocationOverlay(this, mapView);
List<Overlay> overlays = mapView.getOverlays();
overlays.add(myLocationOverlay);
myLocationOverlay.enableMyLocation();

//Setta il LocationManager
locationManager = (LocationManager) getSystemService (Context.LOCATION_SERVICE);
}

 

Il primo metodo che viene richiamato quando viene lanciata un’applicazione android, e in particolare un’Activity, è onCreate() il cui scopo è inizializzare tutti i componenti compresa la UI. SetContentView() setta la View precedentemente creata tramite codice XML in alto alla gerarchia dei ViewGrup così che l’utente possa vedere tutti i componenti settati tramite findViewById().

 

L’oggetto MyLocationOverlay() si occupa di rappresentare la posizione corrente dell’utente e grazie all’ausilio della classe Overlay si riesce a raffigurare la propria posizione sulla mappa.

 

LocationManager questa classe fornisce l’accesso al sistema di localizzazione, fornendo aggiornamenti periodici del dispositivo di GPS; getSystemService() ritorna il gestore del sistema richiesto, nel nostro caso è appunto il GPS.

 

@Override
public void onStart() {
super.onStart();

// Aggiorna la UI
Location location = locationManager.getLastKnownLocation(Context.LOCATION_SERVICE);
updateWithNewLocation(location);

// Avvia il Listener per gli aggiornamenti della posizione
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
0, // 0sec
0, // 0m
this);

//Verifica se il GPS è abilitato altrimenti avvisa l’utente
if(!locationManager.isProviderEnabled(“gps”)){
Toast.makeText(this, “GPS è attualmente disabilitato. E’ possibile abilitarlo dal menu impostazioni.”, Toast.LENGTH_LONG).show();
}
}

@Override
public void onStop() {
// Stoppa Listener delle posizioni
locationManager.removeUpdates(this);

super.onStop();
}

@Override
protected boolean isRouteDisplayed() {
return false;
}

 

L’immagine seguente rappresenta il ciclo di vita di un’applicazione android, nel nostro caso è interessante studiare onStart() che indica quando l’Activity sta per essere visualizzata e onStop() che viene richiamata quando l’Activity sta per andare in background, normalmente perchè è stata avviata un’altra Activity che si prepara a prendere il foreground.

 

Tramite getLastKnownLocation() si individua l’ultima posizione ottenuta dal sistema di localizzazione e con requestLocationUpdates() si registrano tutte le notifiche ogni qual volta il LocationListener cambia stato.

 

@Override
public void onLocationChanged(Location location) {
updateWithNewLocation(location);
}

@Override
public void onProviderDisabled(String provider) {
updateWithNewLocation(null);
}

@Override
public void onProviderEnabled(String provider) { }

@Override
public void onStatusChanged(String provider, int status, Bundle extras) { }

 

I metodi qui sopra elencati sono definiti dall’interfaccia LocationListener. Quello che più ci interessa è onLocationChanged() che viene richiamato quando cambia la posizione dell’utente, così da poter aggiornare la rappresentazione grafica sulla mappa con le annesse informazioni.

 

/** Update the map with a new location */
private void updateWithNewLocation(Location location) {

// Aggiorna la posizione della mappa e l’overlay
if (location != null) {

// Aggiorna il marker della mappa
mapView.invalidate();

// Aggiorna la location
Double geoLat = location.getLatitude()*1E6;
Double geoLng = location.getLongitude()*1E6;
GeoPoint point = new GeoPoint(geoLat.intValue(), geoLng.intValue());

mapController.animateTo(point);

//Setta le info sui TexView
lat.setText(“Latitude: “+normalize(location.getLatitude()));
log.setText(“Longitude: “+normalize(location.getLongitude()));
alt.setText(“Altitude: “+Math.floor(location.getAltitude())+” m”);
speed.setText(“Speed: “+Math.floor((location.getSpeed()*3.6))+” km/h”);
}

}

//Riduce a 6 il numero di cifre decimali dopo la virgola
private String normalize(Double x){
x *= 1000000;
x = Math.floor(x);
x /= 1000000;
return x.toString();
}

}

 

updateWithNewLocation Questo metodo non fa altro che aggiornare la posizione sulla mappa e settare le informazioni di latitudine, longitudine, altitudine e velocità.

 

Per poter avviare l’applicazione in modo corretto è necessario impostare i seguenti permessi nel file AndroidManifest.xml , il cui scopo è dichiarare i componenti intrinsechi, le librerie di cui l’applicazione ha bisogno, il nome e gli eventuali permessi che garantiscono il funzionamento dell’applicazione stessa.

 

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”hlcs.gps”
android:versionCode=”1″
android:versionName=”1.0″>
<application android:icon=”@drawable/icon” android:label=”@string/app_name”>
<activity android:name=”.Locator”
android:label=”@string/app_name”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
<uses-library android:name=”com.google.android.maps” />
</application>
<uses-sdk android:minSdkVersion=”3″ />

 

Qui di seguito sono rappresentati i permessi che daranno l’accesso a internet e all’utilizzo dei sistemi di localizzazione come il GPS.

 

<uses-permission android:name=”android.permission.INTERNET” />
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_GPS” />

</manifest>

 

Ok! Adesso possiamo finalmente testare l’applicazione utilizzando l’emulatore messo a disposizione da android, quindi si manda in esecuzione l’applicazione e tramite l’utilizzo di una shell si avvia una sessione telnet con l’emulatore per simulare il sistema di GPS:

 

$telnet localhost 5554

 

La porta 5554 è quella messa a disposizione dall’emulatore per le comunicazioni esterne, la porta potrebbe anche cambiare in presenza di più emulatori in esecuzione ma i numeri di porta sono recuperabili dal titolo in finestra dell’emulatore.

 

Per inviare i dati GPS basta digitare i seguenti comandi nella shell e notare gli effetti sull’applicazione:

 

geo fix 16.13 39.68

 

La sintassi è la seguente geo fix <longitudine> <latitudine> <altitudine>.

 

Autore:

Marco Rizzo

HALT Hacklab Altomonte (CS)

WordPress Appliance - Powered by TurnKey Linux