Sei sulla pagina 1di 55

POLITECNICO DI MILANO

Facoltà di Ingegneria

Corso di laurea in Ingegneria Informatica


Dipartimento di Elettronica e Informazione
Anno Accademico 2007/2008

Elaborato di tesi

Progettazione e implementazione di un'applicazione per la


navigazione in ambito urbano per la piattaforma Android

Autori: Marcello Maggioni


matricola: 678703
Alberto Magni
matricola: 676355

Relatore: prof. Antonio Capone


Correlatore: ing. Luca Dell'Anna

1
Indice
1Introduzione........................................................................................................................................4
1.1Descrizione del problema...........................................................................................................4
1.2Obiettivi prefissi.........................................................................................................................5
1.3Scelte Tecnologiche....................................................................................................................6
1.4Soluzioni preesistenti..................................................................................................................8
1.5Organizzazione del Documento..................................................................................................9
2Android: il sistema operativo...........................................................................................................10
2.1La struttura del sistema operativo [14].....................................................................................10
2.2Lo sviluppo di un'applicazione per Android.............................................................................13
2.2.1Il plugin per Eclipse e l'emulatore.....................................................................................13
2.2.2Un progetto Android per Eclipse......................................................................................16
2.2.3Programmare in Android [16]...........................................................................................18
2.2.4Altri elementi utilizzati nel progetto.................................................................................23
3L'applicazione...................................................................................................................................26
3.1L'architettura dell'applicazione.................................................................................................26
3.2Il modello della rete dei servizi pubblici..................................................................................27
3.2.1OpenStreetMap [23]..........................................................................................................27
3.2.2Il Database.........................................................................................................................29
3.2.3La struttura del modello....................................................................................................34
3.2.4La comunicazione con il Database....................................................................................36
3.3L'algoritmo di calcolo del percorso consigliato........................................................................40
3.3.1Introduzione......................................................................................................................40
3.3.2La modellizzazione delle stazioni.....................................................................................40
3.3.3La scelta del mezzo e del percorso....................................................................................42
3.3.4L'individuazione dei malfunzionamenti............................................................................45
3.4Interfaccia grafica ed Esempio di utilizzo................................................................................47
3.4.1L'inserimento dei dati........................................................................................................47
3.4.2La presentazione del percorso...........................................................................................50
3.4.3Conclusioni e possibili sviluppi........................................................................................53
4Note..................................................................................................................................................55
4.1Bibliografia...............................................................................................................................55

2
Indice delle Figure
1: Struttura del sistema Operativo Android........................................................................................11
2: La perspective DDMS....................................................................................................................14
3: L'emulatore del sistema operativo Android....................................................................................15
4: La struttura di un progetto Android in Eclipse...............................................................................16
5: Il ciclo di vita di un'Activity...........................................................................................................19
6: La struttura del Modello.................................................................................................................35
7: La comunicazione con il DataBase................................................................................................38
8: Sequence diagram della costruzione del modello .........................................................................39
9: La classe Node e le sue sottoclassi.................................................................................................41
10: Esempio di percorso.....................................................................................................................43
11: La schermata di Input...................................................................................................................47
12: La scelta fra diverse opzioni.........................................................................................................48
13: L'utilizzo del dispositivo GPS......................................................................................................49
14: Esempio di Elenco Scambi...........................................................................................................50
15: Partenza e Destinazione di Esempio............................................................................................50
16: La mappa e le stazioni..................................................................................................................52

3
1 Introduzione
In questo capitolo introduttivo viene esposto l'ambito all'interno del quale il progetto si
inserisce. Si descrivono quindi i problemi che il lavoro svolto intende risolvere o
semplificare. Verranno discusse e motivate le scelte implementative effettuate descrivendo
le possibilità tra le quali ci si è mossi. Si confronteranno quindi gli obiettivi fissati con altri
progetti in sviluppo o già in circolazione mettendone in evidenza limiti e pregi
1.1 Descrizione del problema
I centri ad alta densità abitativa sono particolarmente interessati da problemi legati
all'elevato numero di mezzi di trasporto privati in circolazione. In alcune fasce orarie la
velocità media delle automobili nel traffico cittadino è decisamente bassa. Una tale
situazione comporta costi, non solo economici, e disagi molto elevati per la collettività: alti
valori degli inquinanti, cattiva qualità di vita, sprechi di risorse energetiche, dispendio di
tempo e denaro. I problemi esposti sono così gravi che le molte amministrazioni comunali
delle città più grandi d'Europa (Milano, Londra, Stoccolma) hanno deciso di introdurre una
tassa per accedere al centro cittadino con i mezzi di trasporto privati. Per disincentivare
l'utilizzo dell'automobile il pedaggio è stato stato fissato a valori decisamente elevati (a
Londra si raggiungono £25 per singolo accesso per mezzi particolarmente inquinanti)[1].
Purtroppo soluzioni di questo tipo non sono radicali né definitive. In particolare la città di
Milano non ha risolto i suoi gravi problemi di inquinamento in quanto l'area a traffico
limitato ha una superficie ridotta, il che rende in pratica impossibile conseguire gli obiettivi
prefissati in fase di studio. Una soluzione definitiva e duratura ai problemi del traffico può
invece giungere da un utilizzo più intenso ed esteso dei mezzi pubblici, da incentivare verso
tutti i possibili fruitori. Ai frequentatori saltuari di una grande città spesso risulta difficile
orientarsi nella rete del trasporto urbano, e ciò è un freno a ricorrervi. Ancora più difficoltà
incontra un turista che intende visitare una città del tutto ignota. Può anche presentarsi il
caso di cittadini che devono recarsi in quartieri che conoscono poco. Le mappe cartacee,
quando sono disponibili, non sempre sono efficaci in quanto non riportano la completa e
aggiornata rappresentazione né delle linee né degli orari. Questi ultimi sono difficili da
reperire se non ci si trova già alla stazione o fermata di partenza. Gravi disagi per i
viaggiatori derivano dal blocco totale di una linea dei mezzi pubblici in seguito a scioperi
improvvisi (particolarmente frequenti in Italia) o a malfunzionamenti dei mezzi.

4
Inconvenienti di questo tipo sono decisamente fastidiosi in quanto costringono il viaggiatore
a riconsiderare per intero il proprio itinerario. L'obiettivo è quindi quello di rendere il
ricorso ai mezzi pubblici più amichevole proponendo semplici soluzioni a problemi quali la
determinazione del percorso più veloce fra località tenendo conto degli orari e degli
eventuali scioperi o malfunzionamenti.
1.2 Obiettivi prefissi
Lo scopo è quindi quello di realizzare un software che permetta di rendere più semplice
l'utilizzo dei mezzi pubblici. Si vuole aiutare l'utente che non conosce in modo approfondito
la rete delle linee urbane di una città a raggiungere una determinata destinazione. Verrà
quindi elaborato un percorso da seguire tenendo conto degli orari dei mezzi che si intendono
utilizzare e di eventuali problemi riguardo a guasti o a scioperi.
Alla luce dei problemi descritti, per essere realmente utile e innovativa l'applicazione che si
vuole realizzare deve presentare determinate caratteristiche.
● Deve poter essere consultabile in qualsiasi momento; in particolare quando si è in
viaggio o in movimento, permettendo, in questo modo, di orientarsi in una città che
non si conosce.
● Deve contenere informazioni riguardo la completa struttura delle linee dei diversi
mezzi pubblici di cui una città è dotata. In particolare devono essere note le posizioni
di tutte le fermate. Questo è un problema non semplice da risolvere in quanto spesso
le linee di superficie subiscono modifiche non solo negli orari ma anche nella
posizione delle fermate. L'ideale sarebbe quindi quello di possedere una fonte di
informazioni sempre aggiornata. Questi dati sono di vitale importanza per realizzare
sistema in grado di elaborare un percorso per raggiungere una località prestabilita.
● Per differenziarsi realmente da una semplice guida stradale, devono inoltre essere
disponibili orari e segnalazioni di guasti o scioperi in tempo reale. É necessario anche
tenere conto di quale orario consultare: festivo o feriale, estivo o invernale.
L'affidabilità di questo tipo di informazioni è di fondamentale importanza in quanto
su di esse si basa l'elaborazione del percorso. Ovviamente essi devono essere tenute
costantemente aggiornatei in relazione a eventuali cambiamenti.
● La presentazione di una mappa interattiva è molto utile per poter determinare e
visualizzare in modo preciso e veloce le località di partenza, arrivo e gli eventuali

5
scambi da effettuare tra le differenti linee.
1.3 Scelte Tecnologiche
Dall'esposizione degli obiettivi che il progetto si propone di raggiungere risulta evidente che
il miglior supporto per l'applicazione in sviluppo è uno smart-phone, ovvero un telefono
portatile che possiede un proprio sistema operativo con funzionalità quali la navigazione in
rete e la semplice gestione di file e contatti. Spesso dispositivi di questo tipo sono dotati di
tastiera e di touch-screen che permettono una fruizione davvero immediata delle sue
potenzialità. Grazie all'evoluzione tecnologica dell'hardware sono oggi disponibili modelli
dotati di sistemi operativi con prestazioni tali da far considerare questi dispositivi
assimilabili a computer invece che a semplici telefonini. L'accessibilità di questo tipo di
prodotti è aumentata di molto nel corso degli anni, portando a un grande aumento delle
vendite negli ultimi anni [2],[3] e permettendo una diffusione capillare del prodotto e delle
loro applicazioni. Un dispositivo hardware che ha trovato grande diffusione fra gli smart-
phone è il rilevatore di coordinate geografiche GPS. Esso è stato introdotto per ottenere la
posizione del telefono sulla superficie terreste. Questa integrazione, e la possibilità di
accedere in modo veloce alla rete, ha permesso la nascita di un nuovo tipo di applicazioni
software: i servizi Location-Based [4]. Essi si prefiggono l'obiettivo di fornire servizi
rispondendo a tre semplici domande: Dove mi trovo?, A che cosa sono vicino? e Dove
posso andare da qui?.
Il mercato dei sistemi operativi per dispositivi mobili è molto variegato e scenario di grande
concorrenza. a oggi1 quelli esposti di seguito sono i software più diffusi [5]:
● Il sistema operativo Symbian possiede la maggioranza relativa del mercato con il
46% delle vendite. Esso è controllato per intero dalla multinazionale finlandese
Nokia, la quale ha acquistato la proprietà della Symbian Ltd nel giugno del 2008 con
l'obiettivo di fondare una società di software open-source [6]. Symbian è stato uno
dei primi sistemi operativi per smart-phone e nel corso degli anni sono state rilasciate
numerose versioni, il che ha permesso una larga diffusione su differenti modelli di
dispositivi. Dato il suo grande successo e la sua diffusione Symbian è stato più volte
oggetto di attacco da parte di virus informatici; questo problema può essere risolto
permettendo l'installazione solo di software autenticato e protetto. Il linguaggio di

1 Ci si riferisce al terzo quadrimestre del 2008.

6
programmazione utilizzato per lo sviluppo di software in Symbian è il C++. Creare
applicazioni su questo sistema operativo è però piuttosto complicato. Sono difficile
realizzazione anche compiti banali. Questo è dovuto all'architettura di vecchia
concezione sulla quale il software si basa.
● IPhone OS è il sistema rilasciato da Apple per supportare prodotti quali IPhone e
Ipod Touch. Esso stato progettato in layer, come un normale sistema operativo, e con
l'obiettivo di essere molto leggero; adatto a essere eseguito su un dispositivo mobile
[7]. La principale limitazione del software riguarda la portabilità, esso infatti è stato
studiato appositamente per l'hardware Apple. L'azienda ha rilasciato nel marzo del
2008 un tool di sviluppo per applicazioni chiamato iPhone SDK2, che permette la
programmazione di software per sfruttare le potenzialità del sistema operativo. La
distribuzione del prodotto sviluppato non può però avvenire in modo libero: è infatti
necessario far approvare il proprio lavoro da Apple e ottenere l'autorizzazione a
distribuirlo.
● L'azienda canadese RIM ha concentrato le proprie ricerche nello sviluppo di un
sistema operativo per il dispositivo BlackBerry. Gli sforzi si sono stati diretti allo
sviluppo di soluzioni wireless (per rendere semplice e funzionale il collegamento alla
rete) e applicazioni per le attività di lavoro.
● Windows Mobile è il sistema operativo per cellulari rilasciato da Microsoft. Esso è
una derivazione del sistema Windows 32 per PC. Una delle caratteristiche
fondamentali del prodotto è la sua portabilità: esso infatti è disponibile per
innumerevoli hardware, sia smart-phone che computer palmari. Anche Microsoft ha
rilasciato un tool di sviluppo che permette la realizzazione da parte di terzi. Questo è
disponibile in abbinamento all'editor di Windows Visual Studio.
● Di recente introduzione è il sistema operativo Android. Esso è sviluppato da una
società chiamata Open Handset Alliance che è guidata dal leader dei motori di ricerca
Google. La distribuzione del software sul mercato non è ancora avvenuta a livello
mondiale ma da tempo è disponibile in rete un SDK (Software Development Kit) che
permette lo sviluppo di applicazioni per l'architettura. Le funzionalità che vengono
messe a disposizione sono davvero notevoli: possibilità di usufruire di mappe;

2 http://developer.apple.com/iphone/

7
sensore GPS, fotocamera e di database integrato. Molto interessante è il fatto che il
progetto ha come obiettivo rendere semplice e intuitiva la scrittura di codice. A
questo si aggiunge la possibilità di accedere al codice sorgente sia del sistema
operativo che di quello di ogni altra applicazione distribuita. Queste premesse fanno
pensare che in futuro Android si assicurerà una fetta considerevole del mercato.
Riteniamo quindi questa la soluzione migliore per lo sviluppo del software cercato.
1.4 Soluzioni preesistenti
I navigatori satellitari per automobili che aiutano gli automobilisti nella guida fornendo
informazioni riguardo la posizione del veicolo e il tragitto da seguire sono molto diffusi.
Questo non vale per dispositivi che facilitano l'utilizzo dei mezzi pubblici indicando le linee
ideali per raggiungere una località.
Lo stato dell'arte in questo campo è rappresentato dal prodotto Discover Cities [8] della
società statunitense NAVTEQ. Si tratta di un'applicazione software che fornisce
informazioni riguardo la struttura urbanistica delle principali città americane ed europee.
Essa si propone come un supporto ai programmatori che intendono sviluppare applicazioni
location-based in ambito cittadino. Discover Cities permette di elaborare percorsi molto
dettagliati accompagnando l'utente curva dopo curva anche sui mezzi pubblici e fornendogli
orari e informazioni. A questo si aggiunge la disponibilità ottenere dati e indicazioni su
come raggiungere i principali luoghi di interesse e le attrazioni di un città, funzionalità
molto utile per i turisti.
All'interno del progetto GoogleMap l'azienda californiana ha promosso, dal dicembre 2005,
il progetto Transit [9]. Esso è un'applicazione web che permette di pianificare i propri
spostamenti in ambito urbano in modo estremamente semplice. Il progetto è stato realizzato
in associazione con le aziende di trasporto pubblico locale, disponendo così di informazioni
dettagliate e sempre aggiornate sulle stazioni e sugli orari. Oltre che nella versione web, è
disponibile anche su smart-phone e molti sono i sistemi operativi supportati.
Anche per la piattaforma Android, quella scelta per lo sviluppo del progetto, è stata
sviluppata un'applicazione simile a quella descritta. Essa prende il nome di Metroid [10] e
ha come obiettivo quello di pianificare viaggi urbani sfruttando le linee pubbliche. Il suoi
sviluppatori hanno anche partecipato al concorso indetto da Google denominato Android
Challenge. A nostro giudizio Metroid, ancora in fase di sviluppo, ha notevoli margini di

8
miglioramento. Infatti nella base di dati utilizzata non sono mantenute informazioni sulla
posizione delle fermate dei mezzi. É quindi reso difficile capire quale fermata è la più
comoda per giungere in una determinata località. Oltre al semplice elenco degli scambi da
effettuare, sarebbe stata molto utile l'integrazione di una mappa della città, in modo da
visualizzare chiaramente destinazione e partenza. D'altro canto la semplicità con la quale
sono mantenuti i dati utilizzati permette una facile estensione del progetto a nuove città.
1.5 Organizzazione del Documento
La presente relazione è stata suddivisa in tre capitoli principali.
2.Android: il sistema operativo
Il capitolo espone in modo dettagliato le caratteristiche principali del sistema operativo sul
quale l'applicazione viene sviluppata. Viene qui messo in luce il carattere fortemente
innovativo di Android, appositamente studiato per lo sviluppo di software in modo semplice
e veloce. Viene poi descritta la modalità con la quale può essere realizzato un progetto
Android utilizzando un apposito plugin per l'editor Eclipse. Infine sono evidenziate le
componenti principali dell'SDK distribuito da Google.
3.L'applicazione
Viene qui presentato il software realizzato nel corso del progetto. La trattazione inizia
descrivendo l'architettura globale dell'applicazione e addentrandosi poi nei particolari. Sono
esposte e giustificare le scelte implementative effettuate considerando i problemi incontrati
nello sviluppo. Una volta descritta la modalità di recupero dei dati necessari all'esecuzione è
presentato l'utilizzo che ne è fatto nella costruzione del modello della rete dei mezzi
pubblici. Segue quindi l'algoritmo per il calcolo del percorso per il raggiungimento della
destinazione prefissata. Sono qui esposte le semplificazioni introdotte e i criteri utilizzati per
elaborare un algoritmo semplice ma che fornisca risultati affidabili e realistici. Infine è
descritta l'interfaccia grafica con cui l'utente viene in contatto. Il capitolo si conclude con un
esempio di utilizzo del software prodotto descrivendo nei particolari ogni fase dell'utilizzo.
4.Conclusioni e possibili sviluppi
In questo capitolo sono esposte considerazioni circa il raggiungimento degli obiettivi
prefissati, la qualità del percorso proposto e la funzionalità del software. Infine sono
presentate eventuali soluzioni per ampliare il progetto rimuovendo alcune semplificazioni
introdotte.

9
2 Android: il sistema operativo
Android è un sistema operativo progettato per dispositivi mobili sviluppato inizialmente da
Google e successivamente da Open Handset Alliance (OHA). Questa è un'alleanza di
aziende composta fra le altre da: Google, Intel, HTC, Motorola, Samsung, LG, Nvidia,
Qualcomm e T-Mobile, che ha il fine di sviluppare applicazioni e hardware per smart-
phone. Il sistema operativo è stata annunciato il 5 novembre 2007 e rilasciato il 12
novembre. La prima versione commerciale di un cellulare fornito del sistema operativo
Android è stata rilasciata il 22 ottobre del 2008 negli Stati Uniti, sotto il nome di T-Mobile
G13. L'hardware del telefono è stato realizzato dalla compagnia di Taiwan High Tech
Computer (HTC). La caratteristica che rende particolarmente interessante Android è il fatto
che è stato rilasciato sotto licenze open-source [11] : Apache 2.0 [12] e GPLv2 [13]. É
quindi disponibile in rete anche il codice sorgente del sistema operativo4, il quale può essere
modificato e redistribuito a piacere.
Questa scelta è stata presa in quanto Android è pensato per rendere facile lo sviluppo libero
di applicazioni che sfruttino appieno le funzionalità.

2.1 La struttura del sistema operativo [14]


Come i sistemi operativi per calcolatori fissi, anche Android è organizzato secondo il
paradigma a pila. Uno schema della sua struttura è rappresentato nella figura seguente.

3 http://t-mobileg1.com/
4 http://source.android.com/download

10
1: Struttura del sistema Operativo Android

● Applications: la versione base di Android non presenta solamente il sistema operativo


ma anche applicazioni base di frequente utilizzo come un browser, un client di posta
elettronica, un'agenda per la gestione dei contatti eccetera. a esse possono essere aggiunti
altri programmi non appartenenti alla distribuzione ufficiale. La filosofia della OHA
riguardo lo sviluppo di nuove applicazioni può essere riassunto con la frase: “All
applications are created equal”. Ovvero: non c'è differenza fra i prodotti ufficiali e
quelli da sviluppare in modo indipendente. Tutti si basano sulle stesse librerie e hanno
pari privilegi nell'accesso alle risorse messe a disposizione dal sistema operativo.
● Application Framework: questo livello dello stack è necessario per rendere disponibili
i servizi del sistema operativo alle applicazioni al livello superiore. Come detto in
precedenza queste API (Application Programming Interface) sono comuni sia alle
applicazioni ufficiali che a quelle sviluppate in modo indipendente. L'obiettivo
fondamentale che si è cercato di raggiungere nella progettazione di questo livello è il
riuso del codice. Ovvero ogni applicazione può rendere disponibile alle altre servizi

11
specifici permettendo così la progettazione in modo semplice di servizi nuovi basati su
quelli preesistenti. Gli elementi più importanti del framework sono:
○ View System: ovvero l'insieme di oggetti grafici che permettono la costruzione
dell'interfaccia con l'utente5.
○ Content Providers: un content provider è un elemento che permette la condivisione di
dati fra applicazioni. La gestione dei dati memorizzati è lasciata all'implementazione
del singolo provider mentre tutti devono implementare interfacce comuni per
permettere l'esecuzione di query e l'inserimento di dati a ogni applicazione.
○ Resource Managers: permettono l'accesso a tutti gli oggetti non costituiti da codice
sorgente, quali immagini, file di configurazione dell'interfaccia, stringhe eccetera.
○ Notification Managers: permettono alle applicazioni di presentare all'utente notifiche
di eventi asincroni che avvengono in background.
○ Activity Managers: gestiscono il life-cycle delle activity, le quali sono oggetti che
rappresentano una singola operazione che l'utente può eseguire. Le activity, essendo
la base di ogni programma sviluppato in Android, verranno descritte in modo
approfondito in seguito.
● Libraries: le funzionalità messe a disposizione dall'application framework sono
implementate da una serie di librerie scritte in C/C++; le più importanti sono:
○ Un'implementazione della libreria standard C (libc) specificatamente implementata
per i sistemi Linux di tipo embedded.
○ Librerie per la gestione di materiale multimediale basate su PacketVideo's
OpenCORE.
○ WebKit: libreria per web browsing.
○ SQLite: libreria di piccole dimensioni per la gestione di un database relazionale.
○ Gestione della grafica 2D e 3D attraverso la libreria OpenGL.
○ Android Runtime: oltre a ulteriori librerie è presente in questo sottoinsieme la Dalvik
Virtual Machine, ovvero una macchina virtuale all'interno della quale sono eseguite
le applicazioni. Essa esegue classi java che sono state compilate in uno specifico
bytecode chiamato dex.
● Linux Kernel: Android è stato sviluppato a partire dalla versione 2.6 del kernel Linux.
5 Per una collezione di esempi di view consultare l'indirizzo: http://code.google.com/android/reference/view-
gallery.html

12
Esso ha la funzione di astrarre dal livello hardware e fornire i servizi base di qualsiasi
calcolatore, ovvero gestione della memoria, dei processi e del collegamento alla rete.
2.2 Lo sviluppo di un'applicazione per Android
Il linguaggio di programmazione scelto dagli sviluppatori della OHA per la realizzazione di
applicazioni in Android è Java. Questa scelta è particolarmente significativa in quanto Java
è il linguaggio più diffuso al mondo [15]. L'obiettivo della Open Handset Alliance è quindi
quello di rendere accessibile al maggior numero di programmatori la possibilità di realizzare
software per Android. È da leggere in quest'ottica la scelta di Google di indire nel maggio
del 2008 un concorso (Android Developer Challenge) volto a premiare le applicazioni più
innovative. Le semplificazioni introdotte permettono al programmatore di concentrarsi sulla
sua applicazione tralasciando le problematiche riguardanti l'interazione con l'hardware,
gestite dal sistema operativo.

2.2.1 Il plugin per Eclipse e l'emulatore


La realizzazione di applicazioni per Android è possibile attraverso il Software Development
Kit (SDK), ovvero l'insieme di tutte le classi Java necessarie allo sviluppo. La ricerca da
parte della OHA della massima semplicità nella realizzazione di nuove applicazioni ha
portato alla realizzazione di una IDE (Integrated Development Environment) apposita per
Android. Essa consiste in un'estensione della IDE preesistente Eclipse attraverso un plugin.
Anche la scelta di Eclipse non è casuale in quanto esso è uno degli ambienti di sviluppo
gratuiti più diffusi per la programmazione in java. Il plugin ADT (Android Developement
Tools) non è parte integrante dell'SDK ma è estremamente utile in fase di sviluppo. Esso,
ad esempio, aggiunge a Eclipse la perspective chiamata DDMS (Dalvik Debug Monitor
Service) che permette di lanciare l'emulatore in modalità di debug e avere una visione di
insieme sui processi attivi, l'occupazione della memoria e le prestazioni della CPU. Vi sono
anche view per il controllo dei dati sul file-system dell'emulatore, dello heap e dei singoli
thread di ogni processo. Di grande importanza per la rilevazione degli errori è la view
chiamata LogCat la quale presenta allo sviluppatore messaggi di log inviati dall'emulatore.
Attraverso la classe Log è possibile programmare l'invio di messaggi con il fine di verificare
lo stato dell'applicazione e quindi determinare eventuali errori.

13
2: La perspective DDMS
Le applicazioni sviluppate con il plugin possono essere testate in modo realistico attraverso
un emulatore: un telefonino virtuale eseguito sul computer. L'emulatore, come si vede nella
figura nella pagina seguente, presenta la riproduzione di un telefonino a fianco di una di una
tastiera con la quale è possibile interagire con l'emulatore. Tutti i bottoni visibili sono
funzionanti e hanno un effetto sull'emulatore. L'unico limite dell'emulatore consiste nel fatto
che non può effettuare vere telefonate. Si possono anche simulare eventi esterni come
l'arrivo di un SMS, di una chiamata o il cambiamento della posizione nel mondo del
telefono. La presenza del dispositivo GPS è molto importante per applicazioni di tipo
location-based. Se non si usa il plugin di Eclipse è possibile comandare l'emulatore
attraverso comandi telnet inviati alla porta sulla quale è in esecuzione l'emulatore Nel caso
in figura il comando per connettersi è il seguente: telnet localhost 5554.

14
3: L'emulatore del sistema operativo Android

15
2.2.2 Un progetto Android per Eclipse

La struttura di un progetto Android sviluppato con il plugin di


Eclipse è qui riportata nell'immagine a fianco. Nella cartella
“src” sono contenute tutte le classi java utilizzate per lo
sviluppo del progetto. Molto interessante è la cartella chiamata
“res”. In essa sono contenute tutte le risorse non costituite da
codice sorgente utilizzate dall'applicazione. Esse sono
suddivise in cartelle:
4: La struttura di un ● Drawable raccoglie tutti gli elementi che possono essere
progetto Android in
Eclipse utilizzati come icone o in generale disegnati sullo schermo.
Sono accettati tre tipi di oggetti: immagini (di solito in formato png o jpg), definizioni di
colori attraverso file xml e immagini di tipo NinePatch (file png a cui è associato un xml
che ne definisce proprietà riguardanti la deformazione che può subire).
● Layout contiene tutti i file per la definizione delle interfacce utente delle differenti
activity specificate in formato xml. Ogni file contiene la definizione di una schermata o
di una parte di essa. Essi sono associati alla corrispondente activity attraverso
l'invocazione del metodo Activity.setContentView() il quale prende come
parametro un riferimento all'xml desiderato. Attraverso l'utilizzo dei tag propri di xml è
possibile creare una struttura ad albero che rappresenta l'interfaccia grafica. a ogni
elemento proprio di un'interfaccia corrisponde un tag. Ad esempio esistono i tag
<TextView> e <Button> ma anche elementi che ne raggruppano di altri al loro
interno come <LinearLayout>, ordinandoli secondo un criterio prestabilito. Per
l'elenco completo degli elementi che possono essere utilizzati nella definizione di un
layout e dei corrispondenti tag xml consultare l'indirizzo:
http://code.google.com/android/devel/ui/layout.html.
● Values raccoglie valori semplici che sono utilizzati da molti elementi all'interno
dell'applicazione. Si possono inserire tre tipi di oggetti: stringhe definizioni di colori e di
misure di lunghezza.
Se si usa il plugin di Eclipse tutte le classi sviluppate e tutte le risorse saranno

16
automaticamente raccolte in un singolo file di estensione .apk (Android PacKage). Esso
sarà l'unico file necessario per l'installazione dell'applicazione su un emulatore come
quello descritto in precedenza. Questa soluzione rende estremamente semplice la
condivisione di programmi. Prima di essere inseriti nel file .apk tutte le risorse utilizzate
dall'utente e inserite nella cartella “rsc” verranno prima compilate dal compilatore aapt
(Android Asset Packaging Tool) in file binari. Ancora una volta ADT si rivela
estremamente comodo in quanto invoca in modo automatico il tool in fase di deploy
dell'applicazione. L'ultimo file rimasto da descrivere è quello chiamato
AndroidManifest.xml. Esso deve essere specificato in ogni programma e fornisce
informazioni di carattere generale. Per esempio devono qui essere dichiarati le Activity e
i Service utilizzati, i permessi che devono essere garantiti all'applicazione per
l'esecuzione dei suoi compiti, oppure riferimenti a librerie necessarie per specifiche
funzionalità. Sono qui definiti anche gli IntentFilter spiegati nello specifico nei paragrafi
successivi.

17
2.2.3 Programmare in Android [16]
Si presentano ora i concetti e i tipi di dato astratto fondamentali per lo sviluppo di
un'applicazione Android.
● Activity [17]
Ogni singola operazione che l'utente può svolgere è rappresentata da una Activity. La
creazione di una nuova azione prevede la definizione di una nuova classe, la quale
estende la classe Activity che si trova nel package android.app dell'SDK. La
maggior parte delle Activity prevede un'interazione con l'utente. Si rende quindi
necessaria la creazione di una interfaccia grafica e la sua associazione alla
corrispondente Activity. La definizione della struttura dell'interfaccia è stata spiegata
nel capitolo precedente. La Dalvik Virtual Machine mantiene in memoria una pila
delle attività invocate dall'utente durante l'utilizzo dell'applicazione. Ogni volta che
l'utente invoca una nuova schermata (ovvero un'attività) essa viene inserita sulla cima
della pila. Sul fondo si troveranno invece le attività meno recenti, che non sono
visualizzate attualmente sullo schermo. Questo meccanismo rende molto facile e
veloce il browsing fra le differenti schermate. È quindi molto importante
comprendere a fondo il cosiddetto life-cycle delle activity, ovvero la gestione degli
stati nei quali esse si possono trovare. Tre sono le modalità principali nelle quali
un'Activity si può trovare:
○ Running: l'activity è visualizzata sullo schermo e l'utente interagisce con essa.
○ Paused: l'utente non può più interagire con l'attività ma il suo layout è ancora
visibile (ad esempio sopra di esso appare una finestra di dialogo). Le activity in
questo stato mantengono tutte le informazioni riguardanti il loro stato e possono
essere terminate dalla DVM nel caso di scarsità di risorse.
○ Stopped: quando l'utente passa da un'Activity a un'altra, la prima è posta in stato
di stop. Ciò significa che una nuova activity verrà posta sulla cima della pila. Le
attività in stop sono le prime a essere terminate in caso di necessità di ulteriori
risorse.
La figura seguente mostra i passaggi di stato di activity. I rettangoli rappresentano le
chiamate ai metodi di callback, ognuno dei quali svolge una funzione specifica
nell'ambito del ciclo di vita dell'applicazione.

18
5: Il ciclo di vita di un'Activity

19
Tutti i seguenti metodi possono essere oggetto di override da parte del programmatore, che
può quindi adattarli alle proprie esigenze.
○ onCreate(Bundle): questo metodo è invocato dalla DVM quando l'Activity
viene creata per la prima volta ed è necessario alla sua inizializzazione. Le
operazioni fondamentali che vengono svolte in questo metodo riguardano la
definizione dell'interfaccia grafica attraverso un file .xml, l'associazione di ogni
elemento dell'interfaccia alla corrispondente azione desiderata e l'inizializzazione
delle strutture dati utilizzate quali liste e basi di dati. L'oggetto di tipo Bundle
passato come parametro è necessario al passaggio di informazioni riguardanti lo
stato dell'applicazione.
○ onPause(): ogni volta che l'utente lascia un'Activity la DVM invoca questo
metodo nel quale il programmatore dovrà aver specificato operazioni riguardanti
il salvataggio dello stato raggiunto dall'applicazione.
○ onStart(): quando l'activity è visualizzata sullo schermo del telefono viene
invocato questo metodo.
○ onRestart(): metodo chiamato ogni volta che l'activity diventa visibile
all'utente dopo che è stata posta nello stato paused. Subito dopo la terminazione
del metodo viene invocato onStart().
○ onResume(): il metodo è chiamato subito prima che l'activity sia posta sulla
cima della pila e che quindi si possibile per l'utente un'interazione.
○ onStop(): quando un'Activity viene oscurata da un'altra viene invocato questo
metodo.
○ onDestroy(): il metodo è lanciato subito prima della distruzione finale
dell'Activity.
Nello schema si possono qui individuare 3 cicli:
○ ciclo di vita: ricadono in questo insieme tutte le operazioni comprese fra le
chiamate ai metodi onCreate(), nel quale si allocano tutte le risorse
necessarie, e onDestroy(), nel quale le risorse sono rilasciate.
○ ciclo di visibilità: compreso fra i metodi onStart() e onStop(). In questo
periodo di tempo l'interfaccia dell'actitvity è sì visibile all'utente ma può non
essere possibile l'interazione con essa a causa della presenza di altre activity in

20
primo piano.
○ ciclo di vita in primo piano: in questo insieme sono comprese tutte le operazioni
fra i metodi onResume() ed onPause(). L'Activity è qui completamente
disponibile all'utente il quale può interagire con essa, ad esempio riempiendo dei
form di input.
Esistono due modi per lanciare un'Activity. Essi si identificano nei due metodi
startActivity(Intent) e startActivityOnResult(Intent,int). Il primo
permette il semplice lancio di un'Activity identificata dall'oggetto di tipo Intent (spiegato nel
paragrafo successivo). Il secondo metodo invece prevede che la classe invocata ritorni un
risultato; esso sarà disponibile facendo override, nel chiamante, del metodo
onActivityResult(int,int,Result) che verrà invocato alla terminazione
dell'attività chiamata.
● Intent [18]
Questo tipo di dato rappresenta la descrizione astratta di un'operazione che può
essere compiuta. Esso può essere utilizzato per lanciare nuove Activity o nuovi
Service. In ogni istanza di un Intent è necessario specificare almeno due parametri:
○ l'azione che si intende compiere ad esempio: ACTION_VIEW o ACTION_EDIT.
○ I dati necessari all'esecuzione dell'azione identificati da un URI (Uniform
Resource Identifier). La definizione di un Intent può avvenire quindi nel seguente
modo:
Intent   intent   =   new   Intent   (Intent.ACTION_VIEW, 
content://contacts/1);
Questo intent permetterà di visualizzare le informazioni caratteristiche del
contatto identificato dal numero 1. Una volta creato l'oggetto è necessario avviare
l'Activity che possa effettivamente visualizzare queste informazioni. Questa
operazione è possibile attraverso:
startActivity(intent);
L'associazione fra intent e activity avviene grazie alla definizione di un
IntentFilter. Esso consiste in una dichiarazione di essere in grado di gestire
una determinata richiesta e deve essere specificato nel file
AndroidManifest.xml associato a ogni applicazione. L'utilizzo degli

21
IntentFilters è particolarmente utile in quanto permette di riutilizzare codice già
scritto in precedenza per assolvere dei compiti semplici come ottenere
informazioni riguardo un contatto dalla rubrica. È importante anche notare che il
chiamante ignora completamente come il compito sia assolto, in quanto conosce
solo l'interfaccia pubblicata dall'IntentFilter.
● Service [19]
Un Service è un componente dell'applicazione che viene eseguito in background per
un periodo di tempo indefinito, e che non ha quindi interazione diretta con l'utente. É
importante notare che il codice contenuto in una classe che estende Service è
eseguito nel thread principale dell'applicazione. Nel caso in cui siano eseguite
operazioni che utilizzano molto la CPU o la connessione a una rete è quindi
consigliabile la creazione di un nuovo thread. Come per le activity anche nei Service
sono presenti metodi di callback eseguiti in momenti specifici dell'esecuzione. Essi
sono ad esempio onCreate(), onDestroy(), dal significato affine a quello
specificato per la classe Activity. Vi sono due modi per avviare un service:
○ All'invocazione del metodo Context.startService() una nuova istanza di
un service è creata (con il metodo onCreate()) e lanciata ( con il metodo
onStart(Intent,int)). L'esecuzione prosegue fino alla chiamata del
metodo Context.stopService().
○ Se il metodo Context.onBind() è invocato viene instaurata una connessione
persistente a un o specifico servizio il quale, se non esiste già, può venir creato. In
questo caso il metodo onStart() non è chiamato. Il chiamante otterrà così un
identificativo del Service, cosa che gli permetterà di effettuare richieste.
Un Service può essere al tempo stesso avviato con il metodo onStart() e
oggetto di connessioni. Esso potrà essere terminato solo quando non ci saranno
più connessioni attive e il metodo Context.stopService() non verrà
chiamato.
● Content Provider [20]
Gli oggetti di tipo ContentProvider hanno la funzione di garantire l'accesso a dati
condivisi da più applicazioni. L'effettiva implementazione del salvataggio dei dati in
memoria di massa non è specificato ed è lasciata al programmatore. Tutti i content

22
provider però devono implementare interfacce predefinite che specificano il modo
col quale le query possono essere effettuate e la modalità di presentazione del
risultato. I tipi di dati salvati possono essere di vario tipo6: contatti telefonici, file
audio e video. Ogni ContentProvider fornisce un URI ai client che vogliono
utilizzare i suoi dati; è attraverso questa stringa che è possibile effettuare richieste o
inserire dati. Esempio:
L'URI content://contacts/people/ permette di ottenere tutti gli elementi
della tabella people; invece l'URL content://contacts/people/10 ritorna
la singola persona identificata dal codice 10.
L'inserimento di dati invece avviene specificando oltre a un URI anche una mappa
che fa corrispondere alle colonne della tabella relazionale i campi della riga da
inserire.

2.2.4 Altri elementi utilizzati nel progetto


● Le Mappe
Nel tipo di applicazione sviluppata in questo progetto è di fondamentale importanza
la visualizzazione di una mappa per permettere all'utente di orientarsi all'interno della
città. L'SDK di Android rende possibile l'integrazione di una mappa all'interno
dell'applicazione. Per questo scopo è fornita una particolare sottoclasse di Activity
chiamata MapActivity. Come per la sua superclasse sarà necessario specificarne il
layout attraverso un file xml. Esso, oltre ai normali elementi grafici, conterrà un tag
di nome <com.google.android.maps.MapView> che corrisponde a un
oggetto della classe MapView, la quale rappresenta la mappa vera e propria.
MapView fornisce accesso ai dati di Google Maps, per questo per utilizzarla è
necessario possedere una chiave chiamata Maps API Key7 propria per ogni
sviluppatore, che la può usare in tutte le sue applicazioni. Attraverso il metodo
ereditato dalla classe Activity findViewById() il programmatore può istanziare
un oggetto MapView e lavorare su di esso. Molto utile è un classe di supporto
chiamata MapController che permette di impostare alcuni parametri della mappa

6 Per consultare l'elenco dei tipi di dato astratti che rappresentano i dati memorizzati in un ContentProvider si veda:
http://code.google.com/android/reference/android/provider/package-summary.html
7 http://code.google.com/android/toolbox/apis/mapkey.html

23
quali le coordinate del centro e il livello di ingrandimento. Un oggetto di questo tipo
si può ottenere a partire da MapView attraverso il metodo getController().
● Il GPS
L'SDK di Android mette a disposizione alcune classi per permettere al
programmatore di ottenere informazioni riguardanti la posizione attuale del telefono
(e quindi del suo proprietario) nel mondo. Lo strumento a disposizione è il rilevatore
GPS (Global Positioning System). Esso permette di ottenere le coordinate
geografiche del luogo dove si trova il telefono sotto forma di latitudine e longitudine.
Realizzare programmi che sfruttino questa potente funzionalità è molto facile
nell'ambiente Android. La classe che permette di ottenere le due coordinate è
chiamata LocationManager8 ed è istanziabile nel seguente modo:
LocationManager lm = 
(LocationManager)getSystemService(Context.LOCATION_SERVIC
E);
Per poter utilizzare questa funzionalità è necessario garantire un permesso particolare
all'applicazione specificando nel file AndroidManifest.xml il seguente tag.
<uses­permission 
android:name="android.permission.ACCESS_FINE_LOCATION" />
Una volta ottenuto l'oggetto lm da esso è possibile ottenere un'istanza della classe
Location.
Location loc=lm.getLastKnownLocation 
(LocationManager.GPS_PROVIDER);
Location rappresenta un preciso luogo geografico in un determinato momento.
Attraverso i due metodi getLatitude() e getLongitude() è possibile
ottenere le coordinate del luogo rappresentato. Questa funzionalità può essere testata
sull'emulatore anche se non possiede una connessione alla rete GPS. Sarà necessario
simulare il funzionamento di un LocationProvier. Ciò è possibile in molti modi:
○ Sotto la voce Location Controls nella finestra Emulator Control della perspective
DDMS fornita dal plugin ADT di Eclipse si specificano direttamente le
coordinate del luogo desiderato, oppure si fa l'upload di file di formato KML o

8 http://code.google.com/android/toolbox/apis/mapkey.html

24
GPX contenenti anche molte coordinate.
○ Inviando attraverso un comando telenet direttamente le coordinate
all'emulatore. Una volta stabilita la connessione eseguire il seguente comando:
geo fix longitude latitude
● Il DataBase SQLite [21], [22]
Un database SQLite è un DBMS relazionale di piccole dimensioni perfetto per essere
utilizzato da un'applicazione per smart-phone. Esso non è un processo indipendente
che si basa sul paradigma client-server come i normali DBMS quali MySQL
(utilizzato in un altro ambito del progetto), ma una libreria parte integrante del
programma realizzato. È quindi possibile accedere ai dati memorizzati attraverso
semplici chiamate a metodi, molto più veloci rispetto alla comunicazione fra
processi. Il database vero e proprio è memorizzato in un file il quale viene messo in
lock ogni qualvolta una query viene eseguita. La classe dell'SDK che rappresenta un
database SQLite si chiama: SQLiteDatabase. Essa mette a disposizione metodi
quali query, delete e update che permettono una completa gestione del database. Di
grande utilità è il tipo di dato astratto SQLiteOpenHelper. Esso gestisce le
operazioni elementari da eseguire sul database. La classe si occupa ad esempio di
aprire il database, o di crearlo se esso non esiste, e di organizzare le transizioni a
seguito di upgrade (ad esempio un'aggiunta o una rimozione di una tabella). Due
database SQLite sono utilizzati nell'applicazione sviluppata per gestire la
memorizzazione delle località frequentate e per permettere il passaggio di parametri
riguardanti il percorso generato da un'Activity a un'altra.

25
3 L'applicazione
Questo capitolo ha il fine di descrivere in modo approfondito le caratteristiche fondamentali
dell'applicazione sviluppata in questo progetto. Verranno quindi presi in considerazione
elementi quali la costruzione del modello della rete dei mezzi pubblici cittadini;
l'elaborazione dell'algoritmo di calcolo del percorso più veloce e la presentazione del
risultato all'utente. Insieme alle soluzioni implementate verranno presentati anche le
problematiche affrontate durante lo sviluppo e come queste sono state superate giungendo
alla soluzione realizzata.
3.1 L'architettura dell'applicazione
L'applicazione è stata strutturata a livelli. Ognuno di essi raggruppa tipi di dato astratto che
hanno funzionalità e scopi simili. Una classe appartenente a un dato livello può comunicare
solamente con quelle appartenenti ai livelli contigui. Questa architettura ha diversi vantaggi,
apprezzabili soprattutto in fase di sviluppo e testing. Infatti è possibile cambiare l'effettiva
implementazione delle classi di un dato livello se si mantiene l'interfaccia che esse
presentano agli altri. Questo è evidente per la comunicazione con il database remoto.
L'applicazione non è infatti legata al particolare tipo di database usato ma può essere estesa
in modo semplice come descritto nel capitolo dedicato. Per quanto riguarda il debugging
esso può essere condotto in modo più semplice analizzando un livello per volta. La seguente
tabella presenta la struttura dell'architettura.
Livello Classi Principali
LocationsInsertion, StopList, Map, Error,
Presentazione RowEntry, EntryView, PlacesOverlays, StopsOverlays,
LocalDataBase
Modello della rete dei mezzi MetroLines,TramLines,Station,Node,MetroNode,
pubblici e Algoritmo TramNode, Problem, Path, PathCreator
Rappresentazione del database DBInterface; RemoteDB
Elaborazione delle query e
SQLQueryUtil, ToSql
Connessione con il Database

Le classi in corsivo nel livello “Presentazione” estendono un'Activity.

26
3.2 Il modello della rete dei servizi pubblici
Per realizzare un algoritmo che computa un percorso fra due luoghi di una città è necessario
possedere una struttura completa della rete dei mezzi pubblici. Dovranno quindi essere note
le posizioni geografiche di tutte le fermate e il loro numero d'ordine nelle linee che le
utilizzano. Uno dei problemi maggiori incontrati durante la progettazione e lo sviluppo è
stato proprio ottenere queste informazioni. Con riferimento a Milano, la città utilizzata come
esempio, parte di questi dati sono disponibili sul sito dell'azienda locale dei trasporti
pubblici: http://www.atm-mi.it/ATM/. Nel sito è contenuto l'intero elenco delle linee dei
mezzi pubblici, le corrispondenti fermate e gli orari. É stato però deciso di non utilizzare
questa fonte per molti motivi:
● L'ATM non mette a disposizione le coordinate geografiche in latitudine e longitudine
delle stazioni. Questi dati sono però fondamentali per la determinazione delle
distanze.
● Ovviamente l'accesso al database di back-end dell'applicazione web è precluso ai
normali utenti. Recuperare le informazioni di cui si ha bisogno da un sito internet
attraverso il parsing di una risposta HTML non è un modo corretto di procedere. La
controindicazione più grave riguarda eventuali modifiche che il sito può subire in
fase di manutenzione. Queste comporterebbero a una completa riprogettazione del
parser.
L'ipotesi di utilizzare il sito ATM è stata per questi motivi scartata.
Si è quindi cercata un'altra fonte per recuperare i dati necessari, in particolare le coordinate
delle stazioni e delle fermate. Si è quindi rivolta l'attenzione a un progetto open-source:
OpenStreetMap.

3.2.1 OpenStreetMap [23]


Il progetto OpenStreetMap ha lo scopo di realizzare mappe del mondo attraverso la libera
collaborazione di volontari. Per quanto riguarda il recupero di informazioni sulle fermate dei
mezzi, quello che interessa non sono le mappe in sé ma piuttosto gli elementi topologici che
le compongono. Tutte le cartine di OpenStreetMap sono costruite a partire dai dati contenuti
in un database chiamato “OSM Database”. È possibile interrogare la base di dati effettuando
una richiesta HTTP e ottenendo una risposta in formato testuale. I parametri della query da

27
inoltrare al database devono essere tutti inseriti nell'URL. Un esempio di indirizzo che
permette di ottenere informazioni riguardo le stazioni della metropolitana in una zona
centrale di Milano è il seguente:
http://www.informationfreeway.org/api/0.5/node[railway=subway]
[bbox=9.19064,45.478228,9.22201,45.4957]
Nell'URL si possono individuare due elementi fondamentali:
● node: questa parola chiave permette di specificare l'elemento topologico che si
intende ricercare nel database. In questo caso vengo cercate stazioni della
metropolitana: verrà quindi inserita la parola chiave subway. L'elenco completo
degli elementi che possono essere recuperati dal database è consultabile all'indirizzo:
http://wiki.openstreetmap.org/wiki/Mapfeatures.
● bbox: questo predicato è necessario a definire un rettangolo di superficie terrestre nel
quale effettuare la ricerca. Esso dovrà essere specificato nella forma:
[bbox=left,bottom,right,top], dove i left e right sono gli estremi
della latitudine, mentre bottom e top sono gli estremi della longitudine.
La risposta dal server è in formato xml; in cui il tag <node> identifica un singolo elemento
topografico. Quello riportato di seguito è un passaggio della risposta fornita alla richiesta
descritta in precedenza.
<node   id='260094077'   lat='45.4923424'   lon='9.1927303' 
user='ilrobi'   osmxapi:users='bh3u4m,EdoM,ilrobi' 
timestamp='2008­11­28T13:58:30Z' >
<tag k='name' v='MM3 Zara'/>
<tag k='railway' v='station'/>
</node>
Come si nota <node> contiene molte informazioni riguardo la stazione come le coordinate,
il nome, la linea e l'identificativo dell'utente di OpenStreetMap che ha inserito il dato.
Questa struttura del file xml presenta però molti problemi a essere analizzata da un parser.
● Non è specificata la linea alla quale la stazione appartiene. Nel caso di esempio essa
è stata inserita nel nome, ma questa non è una convenzione: è stata semplicemente la
scelta dell'utente. Non esiste infatti un tag xml che identifica la linea.
● Pur avendo specificato nell'URL la variabile subway vengono incluse nella risposta

28
stazioni diverse da quelle della metropolitana.
● Non è possibile stabilire un ordinamento delle stazioni; non vi è presente infatti
nessuna informazione riguardo la posizione della fermata all'interno della linea.
In definitiva l'insieme dei tag messi a disposizione per la specifica dei luoghi rilevanti è a
nostro giudizio insufficiente per effettuare un'analisi programmatica dei file xml forniti. Per
questa ragione è stata scartata l'ipotesi di utilizzare OpenStreetMap come database.
Per risolvere il problema del reperimento di informazioni è stato deciso di creare un
database costruito appositamente per le nostre esigenze. Esso non conterrà l'insieme di tutte
le linee di tram o metropolitana ma solo una piccola parte. Le tratte coperte saranno però
complete, ovvero da esso sarà possibile costruire il modello. Oltre alle informazioni
topologiche su fermate e stazioni esso conterrà dati riguardo gli orari dei mezzi e eventuali
interruzioni sulle linee.

3.2.2 Il Database
Il database è di tipo relazionale ed è stato realizzato utilizzando la tecnologia MySql. La
base di dati è composta di molte tabelle, ognuna delle quali rappresenta un particolare
insieme elementi per la costruzione del modello. Qui di seguito è riportato il codice SQL
che definisce la strutture delle tabelle.
● Metro Stops e Tram Stops
Queste due tabelle sono simili fra loro in quanto rappresentano e mantengono in
memoria le informazioni riguardanti rispettivamente le stazioni della metropolitana e le
fermate del tram.

create table metro_stops (
stop_name varchar(28) not null,
line tinyint not null,
stop_number smallint not null,
latitude real not null,
longitude real not null,
terminal boolean not null,
branch boolean not null,
primary key (stop_name,line));

29
create table tram_stops (
stop_name varchar(28) not null,
line tinyint not null,
stop_number smallint not null,
latitude real not null,
longitude real not null,
terminal boolean not null,
primary key (stop_name,line));

Oltre al nome e alla linea a cui appartiene la fermata sono memorizzati il numero della
fermata all'interno della linea, le coordinate geografiche in latitudine longitudine, un flag
per segnalare se la fermata è un capolinea e uno per indicare la presenza in quella
stazione di diramazioni della linea. La chiave è composta dai due campi stop_name e
line.
Due aspetti sono da evidenziare riguardo questa scelta di salvataggio dei dati. Il primo
riguarda le stazioni comuni a più linee. Per ognuna di essa saranno presenti nel database
tante entry quante sono le linee che usano quella fermata. Ognuna di queste si
distinguerà dalle altre solo per il campo line. Il secondo aspetto riguarda la
numerazione delle fermate in corrispondenza di biforcazioni di una linea (cosa che a
Milano avviene per due tratte della metropolitana). In questi casi la numerazione
continua in modo progressivo aggiungendo al numero computato nella maniera normale
una cifra in più. Essa sarà 0 per la prima biforcazione (la quale è scelta in modo
arbitrario), 1 per la seconda, 2 per la terza e così via. Questa scelta permette di
mantenere un ordine crescente nella numerazione delle fermate.

30
● Time Table
La tabella Time Table memorizza per ogni fermata del tram gli orari dei passaggi. Il
database non rispecchia il reale orario dei tram in quanto esso è stato realizzato a puro
scopo dimostrativo.
create table time_table(
stop_name varchar(28) not null,
line tinyint not null,
summer boolean not null,
working_day boolean not null,
hour_of_day tinyint not null,
minutes varchar(50) not null,
primary key (stop_name, line,summer,working_day),
foreign   key   (stop_name,line)   references 
tram_stops(stop_name,line)  on   update   cascade   on   delete 
cascade);

I due campi stop_name e line sono necessari per individuare in modo univoco la
fermata alla quale ci si riferisce. I due flag summer e working_day servono a
discriminare fra orario estivo ed invernale e fra giorno festivo e feriale. hour_of_day 
identifica l'ora all'interno della quale si intende prendere il tram. In corrispondenza di
ogni ora è salvata una stringa al cui interno sono salvati i minuti dei passaggi sotto forma
di interi separati da virgole.
Effettuando una query a questa tabella si otterranno quindi i minuti dei passaggi del tram
per l'ora desiderata.

31
● Metro Problem e Tram Problem
Queste due tabelle della base di dati memorizzano le informazioni riguardanti eventuali
problemi sulle linee di tram e metro.
create table metro_problem(
first_stop_name varchar(28) not null,
last_stop_name varchar(28) not null,
line tinyint not null,
start_date date not null,
end_date date not null,
start_time time not null,
end_time time not null,
description varchar(100),
primary key 
(line,start_date,first_stop_name,last_stop_name),
foreign key (first_stop_name, line) references 
metro_stops(stop_name,line) on update cascade on delete 
cascade,
foreign key (last_stop_name, line) references 
metro_stops(stop_name,line) on update cascade on delete 
cascade)
Per poter individuare in modo preciso i differenti problemi che possono verificarsi sono
qui memorizzate la prima e l'ultima stazione in cui l'inconveniente si verifica (in caso di
uno sciopero saranno i due capolinea). Vi sono poi i riferimenti alle date e agli orari di
inizio di fine presunta del malfunzionamento o dello sciopero.

32
Per simulare in modo realistico la presenza di un sito remoto dal quale tutte le informazioni
sopra riportate sono recuperate è stata creata un'applicazione web che funge da interfaccia al
database. Non è quindi possibile effettuare delle query direttamente alla base di dati; esse
verranno inoltrate dall'applicazione sullo smart-phone alla web-application la quale le
interpreterà e le inoltrerà al server MySql fornendo poi il risultato.
Questo è stato realizzato utilizzando la tecnologia Servlet di Java [24]. Una servlet è un
oggetto eseguibile da un application-server che svolge una specifica funzione a seguito di
una richiesta. Nell'applicazione server qui sviluppata la classe QuerySrv, estendendo
HTTPServlet, avrà il compito di interpretare le richieste del client e interrogare il
database. La richiesta HTTP proveniente dal client dovrà contente i parametri per poter
effettuare la richiesta SQL. Essi sono 4 e corrispondono ai campi di una query SQL:
select, from, where e order by.
La classe di supporto DBUtil avrà il compito di effettuare la richiesta vera e propria.
Il collegamento fra la business-logic e i dati è permesso dalle classi dell'API JDBC (Java
DataBase Connectivity) [25]. Viene ora presentata la procedura utilizzata per accedere e
interrogare il server MySql. La classe JDBC che permette l'accesso al database è chiamata
Connection. Per ottenerne un'istanza è necessario possedere un account sul server MySql
(ovvero un username ed una password) e conoscere la porta sulla quale esso è in ascolto. Il
tipo di dato astratto Statement rappresenta un'istruzione in codice Sql che viene inoltrata
al database a cui si è connessi. É possibile ottenere un oggetto di questo tipo invocando il
metodo connection.createStatement() una volta avvenuto il collegamento con il
server. L'istruzione da eseguire verrà specificata attraverso il metodo
statement.execute() o statement.executeQuery() sotto forma di String a
partire dai dati forniti in input dall'utente attraverso l'oggetto request. Il risultato delle
query effettuate sarà del tipo ResultSet. Esso verrà quindi scansionato per ottenerne una
String. Per identificare i campi delle differenti colonne in fase di lettura essi sono divisi fra
di loro da un simbolo separatore convenzionale. La stringa testuale così elaborata sarà
quindi la risposta alla richiesta effettuata. La risposta arriverà quindi al client in formato
testuale in modo che se ne possa effettuare il parsing in modo semplice.

33
3.2.3 La struttura del modello
La classe fondamentale per la costruzione del modello si chiama Station. Essa eredita
dalla classe dell'SDK Location contenuta nel package android.location descritta
in precedenza. Questo permette di riutilizzare attributi e metodi della superclasse senza re
implementarne di nuovi. In particolare verranno utilizzati i metodi set e get degli attributi
double latitude e longitude; e il metodo float   distanceTo(Location 
dest). Esso ritorna la distanza in metri fra la località che lo implementa e quella passata
come parametro. Si rivelerà molto utile nella elaborazione del percorso più breve. La classe
Station aggiunge quindi a questi attributi variabili per la memorizzazione dei dati ricavati
dalla lettura del database. Essi sono:
private String name;
private int line;
private int number;
private boolean terminal;
private boolean branch;
Una volta rappresentate le stazioni è necessario costruire un modello per le linee dei diversi
tipi di mezzi pubblici. A questo scopo sono state introdotte le due classi MetroLines e
TramLines. Esse possiedono gli attributi tram_stops e metro_stops i quali sono
del tipo ArrayList<Station>. Queste due liste conterranno quindi tutte le istanze della
classe Station utili per la determinazione del percorso da compiere. È da notare che le
due liste contengono tutte le stazioni (o della metropolitana o dei tram), non vi è quindi
distinzione fra le differenti linee. Inoltre l'ordine con il quale le stazioni sono raccolte non
rispecchia la successione delle fermate su una linea; ma l'ordinamento alfabetico.
La struttura sopra descritta è riassunta nel seguente schema UML.

34
6: La struttura del Modello

35
3.2.4 La comunicazione con il Database
La classe che mette a disposizione i metodi per la comunicazione con il database è chiamata
ToSql. Essa implementa l'interfaccia DBInterface la quale contiene tutti i metodi
pubblici indispensabili per il recupero delle informazioni necessarie. I metodi della classe
ToSql non possono essere chiamati direttamente dalle classi di livello più alto. Al loro
posto devono essere invocati quelli di RemoteDB, che implementa anch'esso l'interfaccia
DBInterface. Questo è stato fatto in quanto non si è voluto legare il funzionamento dei
livelli superiori dell'applicazione a una specifica implementazione del collegamento con il
database. Infatti se si decidesse di sostituire la classe ToSql si dovrebbe cambiare solo una
riga di codice nella classe RemoteDB mentre le classi ai livelli superiori rimarrebbero
invariate. Nel costruttore delle classi che compongono il modello quali TramLines e
MetroLines vi sarà quindi un'invocazione di un metodo di RemoteDB che chiamerà a
sua volta ToSql per ottenere le informazioni richieste. In ogni metodo di RemoteDB è
presente un'invocazione del corrispondente in ToSql. Per evitare la creazione di oggetti di
tipo RemoteDB che risulterebbero inutili ai fini pratici questa classe implementa il pattern
architetturale chiamato “Singleton” [26]. Il quale prevede di nascondere il costruttore di una
classe e rendere pubblico solo il metodo getInstance() che ritorna un nuovo oggetto o
fornire un riferimento a quello già esistente.
Viene qui di seguito descritta la procedura, implementata dalla classe ToSql, con la quale è
possibile effettuare richieste a un server attraverso il protocollo HTTP. Ciò è garantito dalle
classi del package dell'SDK org.apache.http.
La classe DefaultHttpClient identifica un generico client HTTP. È attraverso di essa
che possono quindi essere inoltrate le richieste ed ottenere le risposte. Il tipo HttpPost 
identifica una request inoltrata al metodo POST del protocollo, mentre HttpResponse 
rappresenta ovviamente la risposta ritornata. Una volta inizializzati gli oggetti di tipo
DefaultHttpClient e HttpPost è necessario inserire nella richiesta i dati di input,
ovvero i parametri della query. A questo scopo si utilizza la classe NameValuePair, una
mappa che fa corrispondere due stringhe fra loro: ovvero il nome ed il valore di un
parametro. É possibile ora inoltrare la richiesta che verrà elaborata dalla servlet descritta in
precedenza. Il metodo per fare ciò è: http_client.execute(request). L'oggetto

36
HttpResponse ritornato è quindi trasformato in una String ed è pronto per essere
analizzato.

37
7: La comunicazione con il DataBase

38
Per meglio visualizzare il procedimento di costruzione del modello della rete dei mezzi pubblici e mettere in evidenza la suddivisione in
livelli viene presentato il seguente sequence diagam.

8: Sequence diagram della costruzione del modello

39
3.3 L'algoritmo di calcolo del percorso consigliato

3.3.1 Introduzione
L'algoritmo di calcolo del percorso è la parte del programma che genera l'itinerario
attraverso le linee di metro e tram per raggiungere punto prestabilito dall'utente.
L'algoritmo è contenuto nella classe PathCreator e il percorso viene generato attraverso
il metodo:
PathCreator.generatePath(double   from_x,   double   from_y,   double 
to_x, double to_y).
generatePath() prende in input le coordinate x (longitudine) e y (latitudine)
rispettivamente di origine e destinazione e ritorna una lista delle stazioni di snodo che
l'utente deve attraversare per raggiungere una destinazione. Vengono qui definite stazioni
snodo quelle in cui si incrociano più linee di mezzi pubblici. Esse permettono quindi di
cambiare linea in modo da utilizzare la migliore per raggiungere il punto desiderato.

3.3.2 La modellizzazione delle stazioni


Per rappresentare nel modo migliore una stazione di snodo l'algoritmo utilizza la classe
Node. Essa permette di gestire la relazione tra le differenti linee che attraversano una
stazione di scambio. In particolare sono mantenuti riferimenti, sotto forma di array, ai
numeri delle linee che si incrociano e al numero d'ordine della stazione all'interno della
linea. La classe Node è estesa da MetroNode e TramNode; le quali identificano
rispettivamente uno snodo per la metropolitana e per il tram.
Questa struttura introdotta semplifica il calcolo dei percorsi racchiudendo l'interconnessione
tra le varie linee dei mezzi in un'unica classe. Si rende così semplice ottenere informazioni
riguardanti la presenza o meno di una linea in una determinata stazione, il fatto che che ci
sia una deviazione e il numero d'ordine.

40
9: La classe Node e le sue sottoclassi

Ecco una generale spiegazione su ogni metodo delle classi:


● getStations() ritorna un ArrayList<Station> contenente una Station 
per ogni linea presente in quel nodo.
● getStation(int line) ritorna l'oggetto Station relativo alla linea passata
come parametro.
● getStationNumber(int line) ritorna il numero della stazione rappresentata
dall'oggetto Node sulla linea line.
● addStation(Station   st) aggiunge una linea a un nodo. Come parametro
viene fornito un oggetto di tipo Station che rappresenta la stazione sulla linea. Questo
metodo è oggetto di override nella classe MetroNode in quando le linee della
metropolitana possiedono delle biforcazioni e si deve quindi gestire in modo corretto
il numero d'ordine.
● hasLine(int line) ritorna un boolean che identifica la presenza o meno di una
linea sul nodo sulla quale è chiamato.
La classe MetroNode inoltre ha due metodi in più:
● isDeviation(int line) ritorna un boolean indicante se il MetroNode è o
meno una biforcazione di linea sulla linea passata come parametro. Per esempio, con

41
riferimento a Milano, la città presa in considerazione, “Cascina Gobba” è una
biforcazione sulla linea della metro 2 e una chiamata a
gobba_node.isDeviation(2) ritornerebbe true.
● getBranch(int line) ritorna un intero: il numero del ramo in cui la stazione si
trova sulla linea passata come parametro. Se la stazione non si trova su alcun ramo
verrà ritornato il valore 0. Come esempio la stazione di “Cologno Nord” si trova sul
ramo 1 della linea 2, quindi una ipotetica chiamata a
cologno_node.getBranch(2) ritornerebbe “1”.
Entrambe le sottoclassi MetroNode e TramNode hanno poi un attributo public, chiamato
LINES_NUMBER di tipo int, che specifica il numero di linee totali rispettivamente sul
sistema delle metro e sul sistema dei tram considerato.

3.3.3 La scelta del mezzo e del percorso


I mezzi a disposizione dell'utente sono due: Metropolitana e Tram. L'algoritmo tende
sempre e comunque di preferire il mezzo che riduce al minimo il percorso a piedi
dell'utente. Esso è calcolato in base alla distanza che separa il viaggiatore dalla fermata più
vicina l'ultima fermata dalla destinazione.
L'algoritmo supporta anche la generazione di percorsi misti, ossia con cambio di mezzo da
tram a metro o viceversa. Si introduce qui una semplificazione che prevede che sia possibile
effettuare un solo cambio di mezzo, in quanto cambiare più volte può essere oneroso per
l'utente. Il criterio che l'algoritmo segue per la generazione dei percorsi misti è il medesimo
seguito per i percorsi semplici, ossia la riduzione al minimo del percorso a piedi dell'utente.
Per esempio, se la destinazione si trova vicino a una stazione della metropolitana e l'utente è
vicino a una fermata del tram allora verrà generato un percorso misto che prevederà il tram
come primo mezzo e terminerà con la metro. Questo sempre che la differenza di distanza tra
la stazione terminale di tram e metro sia sufficientemente ampia, altrimenti viene scelto un
percorso semplice.
Come già indicato, il percorso viene calcolato dal metodo generatePath(double 
from_x,   double   from_y,   double   to_x,   double   to_y), che ritorna al
chiamante un ArrayList<Station>  contenente tutti i punti di scambio da effettuare
sulla rete di trasporto.

42
Ad esempio, se il percorso comporta la partenza dalla stazione di San Babila linea 1 e
l'arrivo a Centrale FS linea 3 sulla rete metropolitana l'ArrayList ritornato conterrà gli
oggetti Station rappresentanti le stazioni di partenza e arrivo (San Babila L1 e Centrale FS
L3) rispettivamente come primo e ultimo elemento della lista, e poi tutte le stazioni di
scambio tra una linea e l'altra che, nel caso descritto sarebbe semplicemente Duomo.

10: Esempio di percorso


Nell'ArrayList vengono anche specificati i passaggi attraverso determinate diramazioni
(come ad esempio Cascina Gobba) che, anche se non sono stazioni di partenza, arrivo o di
scambio, vengono comunque inserite all'interno del percorso per rendere chiari eventuali
scambi da effettuare.
La metodo generatePath() non è il principale attore del calcolo del percorso. Esso si
occupa principalmente di trovare le stazioni più vicine e di decidere quale mezzo adottare
per raggiungere la destinazione in base al criterio del “percorso a piedi più breve”. Il calcolo
vero e proprio viene delegato a due metodi privati: getNearestMetro(Location l) 
e getNearestTram(Location l). Essi prendono in input la posizione di partenza o
destinazione dell'utente e ritornano un oggetto di tipo Node che rappresenta la fermata del
tram o della metropolitana più vicina. In mancanza di informazioni riguardanti il tragitto che
è possibile effettuare a piedi per determinare la distanza viene utilizzato il metodo di
Location distanceTo(Location   l) ereditato dalle classi Metro e
TramStation e descritto in precedenza (3.2.3).
Il lavoro di generazione del percorso vero e proprio è lasciato quindi a due metodi privati :

43
metroPathCalculation(MetroNode   metro_start,   MetroNode 
metro_end) e
tramPathCalculation(TramNode   tram_start,   TramNode   tram_end) i
quali ritornano un oggetto del tipo Path. Esso è semplicemente un contenitore per il
percorso generato da PathCreator e viene usato solo internamente alla classe stessa.
La classe Path contiene al suo interno tre attributi di tipo public:
● ArrayList<Station> path: una lista contenente le stazioni del percorso. E'
ciò che, a fine computazione, viene ritornato al chiamante di generatePath();
● int cost: il costo del percorso in numero di stazioni;
● int   original_line: questo valore indica, nel caso di percorso ancora
incompleto, la linea da cui viene raggiunta la prima stazione del percorso. Se il
percorso è completo allora questo valore è “0”.
I metodi metroPathCalculation() e tramPathCalculation() generano il
percorso in maniera ricorsiva richiamandosi continuamente fino al raggiungimento della
destinazione. A ogni chiamata il metodo controlla se la stazione di destinazione sta sulla
stessa linea di quella di partenza. Questo è il caso base e il percorso generato comprende,
banalmente, la stazione di partenza ed arrivo.
Quando ciò non avviene vengono raccolte tutte le stazioni di snodo (stazioni in cui sono
presenti più di una linea di metro, come Centrale FS o Duomo) e, per ognuna di esse viene
richiamato il metodo di calcolo del percorso, impostando come punto di arrivo sempre la
destinazione e come punto di partenza la stazione di snodo che si sta considerando. A questo
punto il metodo si ripete fino a che non viene trovata una stazione di snodo che ha la stessa
linea della stazione di arrivo.
Visto che il metodo viene chiamato più volte (una volta per ogni stazione di snodo nel caso
in cui il percorso non sia banale) i percorsi generati saranno più d'uno. In base al costo (il
criterio adottato è il più semplice, ovvero il numero di stazioni percorse) viene selezionato il
percorso più breve e ritornato.
Per quanto riguarda i percorsi misti vengono di fatto calcolati due percorsi differenti
chiamando quindi una volta la metroPathCalculation() e una volta
tramPathCalculation().
Le due funzioni vengono chiamate per creare due percorsi, uno di metro e uno di tram, per

44
raggiungere prima, dalla stazione di partenza, un “punto di raccordo” e poi, dal punto di
raccordo, la destinazione . Il punto di raccordo tra le due tipologie di mezzi differenti viene
calcolato attraverso la ricerca di due nodi vicini dai quali è possibile passare facilmente da
un mezzo all'altro. Ovviamente viene considerato che la distanza in più che il passaggio da
un mezzo all'altro può comportare può rendere sconveniente l'utilizzo di un percorso misto,
per questa ragione viene considerato un percorso misto solo se ci sono due nodi di passaggio
tra tram e metro sufficientemente vicini.
Nel calcolo del punto di raccordo viene usato il metodo privato
findNearest(Collection<MetroNode>,   Collection<TramNode>)  che
prende in input due liste di nodi, rispettivamente di tram e metro e ritorna la coppia di nodi
più vicini nelle due liste. Le liste passate alla funzione sono rispettivamente la lista
composta da tutte le stazioni della metro e delle stazioni del tram presenti sulle linee della
stazione dalla quale il tram parte o arriva (a seconda che il percorso misto preveda la
partenza o l'arrivo col tram).

3.3.4 L'individuazione dei malfunzionamenti


Le reti pubbliche possono essere soggette a malfunzionamenti di varia natura.
L'applicazione si assume il compito di individuare eventuali problemi sulle linee. Essi sono
recuperati dalla base di dati remota come e sono organizzati nel modo descritto nel capitolo
3.2.2. Nel caso in cui il percorso migliore non si disponibile il software si fa carico di
elaborare un percorso alternativo.
L'individuazione di guasti o scioperi è delegata al metodo private hasProblem(Path 
path). La funzione viene chiamato ogni volta che è generato un percorso dai metodi di
generazione precedentemente presentati. Il percorso elaborato ricevuto in ingresso è quindi
suddiviso in tratti in relazione al mezzo e alla linea utilizzati. Su ognuno di essi è invocato il
metodo del livello sottostante di comunicazione con il database getProblem(). Esso
riceve in ingresso la prima e l'ultima fermata del tratto che si intende percorrere su una
determinata linea e l'ora attuale. La query effettuata al database tiene conto di questi
elementi per valutare la presenza o meno di inconvenienti. In particolare si verifica che non
ci siano problemi su tutte le stazioni del percorso nell'orario indicato. Nel caso si riscontrino
malfunzionamenti o scioperi viene ritornato un oggetto del tipo Problem. Esso conterrà il

45
tratto bloccato e una descrizione del problema. Se, al contrario, tutto è funzionante
getProblem() ritorna null. L'informazione sul problema così ottenuta viene poi usata per
scegliere il percorso alternativo fra quelli disponibili.
Al verificarsi di un inconveniente molto grave, e su più linee, che impedisce il
raggiungimento della destinazione viene generata una
ProblemOnEveryPathException. In questo caso l'utente viene informato
dell'impossibilità di utilizzare i mezzi attraverso una finestra di pop-up.

46
3.4 Interfaccia grafica ed Esempio di utilizzo

3.4.1 L'inserimento dei dati


La prima parte schermata dell'interfaccia grafica, implementata dall'Activity
LocationsInsertion, è necessaria all'inserimento dei dati utili per il calcolo del
percorso: ovvero la località di partenza e di destinazione. L'interfaccia è riportata nella
figura seguente.

11: La schermata di Input


Per l'inserimento della partenza sono a disposizione dell'utente due modalità di input: la
specifica delle via dalla quale intende partire oppure l'utilizzo del dispositivo GSP. Con la
prima possibilità l'utente deve inserire il nome della via e della città dalla quale intende
partire. L'SDK di Android mette a disposizione nel package android.location la
classe GeoCoder [27] che possiede metodi utili per la gestione degli indirizzi. In questo
conteso con il verbo GeoCoding si intende il processo di ottenere le coordinare geografiche
latitudine e longitudine a partire da un identificativo di una località. Mentre Reverse
Goecoding è il procedimento opposto il quale parte dalle coordinate per ottenere un
indirizzo. In questa Activity sono utilizzati entrambi. Ecco come: l'indirizzo fornito in input

47
dall'utente è convertito attraverso il metodo getFromLocationName(String,int).
Esso, dati in input il nome della strada e il numero massimo di risultati che si intende
ottenere, fornisce un ArrayList di Address. Questa classe identifica un indirizzo e
contiene, oltre alle coordinate geografiche, il nome della via, città, provincia e nazione. Il
metodo descritto può lavorare anche se riceve in ingresso una parte di un indirizzo;
ovviamente non potrà ritornare un'unica località ma fornirà l'insieme che più si avvicina alla
descrizione fornita. In questi casi, quando vi è un'incertezza sull'effettiva località, è mostrata
all'utente una lista delle possibili scelte. Starà quindi a lui il compito di selezionare la
desiderata. Se l'indirizzo dal quale si intende partire non è presente nemmeno nell'elenco
sarà necessario aumentare la precisione della descrizione fornita. Un esempio dell'elenco
fornito all'utente è riportato nella figura seguente:

12: La scelta fra diverse opzioni

Per rendere più semplice e veloce l'input da parte dell'utente vengono mantenute in memoria
e presentate in fase di inserimento le località richieste in precedenza. Questo è stato fatto
utilizzando il database SQLite messo a disposizione dall'SDK di Android9.
Se invece ci si trova già nel luogo dal quale si vuole partire è possibile utilizzare il GPS

9 Esso è descritto nel capitolo: 2.2.4.Altri elementi utilizzati nel progetto

48
(2.2.4). Il rilevatore calcolerà la posizione geografica fornendo le coordinate latitudine e
longitudine. Con il processo di Reverse GeoCoding messo a disposizione dal metodo
getFromLocation(double,double,int) è possibile ottenere un'istanza della
classe Address che rappresenta il luogo nel quale ci si trova. Per notificare all'utente il
successo dell'operazione è mostrato in output una finestra di pop-up con l'indirizzo ottenuto.

13: L'utilizzo del dispositivo GPS

Una volta terminata con successo la fase di inserimento dell'indirizzo della partenza è ora
necessario specificare la destinazione. Questo è possibile nella parte inferiore della
schermata; dove è necessario inserire l'indirizzo. Nel caso di incertezza il comportamento è
identico a quello del primo inserimento.
Solo una volta completata la fase di input è possibile proseguire con l'utilizzo
dell'applicazione.

49
3.4.2 La presentazione del percorso
La pressione sul bottone “Ok” provoca la l'avvio del processo di elaborazione del percorso
attraverso l'invocazione del metodo generatePath. Esso richiede una quantità di tempo
significativa in quanto è necessario il recupero di tutte le informazioni dal database
attraverso una connessione HTTP. Una volta ultimato il calcolo viene presentato all'utente
un elenco con tutte le informazioni riguardanti gli scambi che deve effettuare per giungere a
destinazione. Le figure seguenti illustrano un esempio di inserimento di dati e il risultato
ottenuto.

15: Partenza e Destinazione di 14: Esempio di Elenco Scambi


Esempio

Come si nota, nella lista sono riportati i differenti tratti del tragitto consigliato. Per poter
visualizzare gli scambi da effettuare è necessario condividere l'oggetto ritornato
dall'algoritmo fra le differenti Activity che compongono l'interfaccia. Questo però non è di
semplice soluzione. La condivisione di oggetti fra activity è permessa principalmente in due
modi:
● con l'aggiunta di parametri alla creazione dell'oggetto di tipo Intent utilizzato per
l'invocazione dell'Activity. Ciò è permesso dal metodo putExtra(), che prende in

50
ingresso la variabile da inviare e una String identificativa del parametro passato.
● attraverso la creazione di oggetti del tipo SharedPreferences. Essi sono infatti
recuperabili da differenti Activity all'interno della stessa applicazione. L'aggiunta di
parametri avviene attraverso l'utilizzo della classe Editor che possiede metodi quali
putString() o putInt().
I due metodi sono però insufficienti in questo caso. Infatti essi non permettono la
condivisione di oggetti di tipo complesso come ArrayList<Station>. É stato quindi
necessario elaborare un altra modalità. Essa prevede l'utilizzo della base di dati locale
SQLite. Sono qui utilizzate due tabelle distinte. Una, chiamata locations_table,
mantiene informazioni riguardo le stazioni di partenza, scambio e destinazione. Essa sarà
utilizzata nella MapActivity Map per la visualizzazione delle icone sulle mappe. La
seconda, di nome stops_table, invece permette di costruire l'insieme dei tratti di
percorso visualizzati nell'elenco. Ognuno di essi è rappresentato da una classe apposita
chiamata RowEntry. Nella tabella, e anche nella classe che la rappresenta, sono quindi
mantenute informazioni quali: la prima e l'ultima fermata per ogni linea, il tipo di mezzo e,
nel caso dei tram, anche gli orari dei prossimi passaggi. L'elenco in figura è stato realizzato,
nella classe StopList, attraverso un'implementazione specifica di un particolare tipo di
Activity: ListActivity [28]. La classe BaseAdapter è stata utilizzata per
personalizzare la lista presentata. A ogni elemento visualizzato è associato quindi un oggetto
del tipo RowEntry ottenuto dalla lettura del database.
In una ListActivity è anche possibile attribuire un'azione a un click dell'utente su un
elemento della lista. Il metodo onListItemClick di ListActivity è stato pensato a
questo scopo. Come parametro esso riceve il numero d'ordine della riga selezionata
permettendo così al programmatore di definire il comportamento desiderato. In questo caso
selezionando un elemento è possibile visualizzare una mappa di Milano che mette in
evidenza i luoghi più importanti ai fini del viaggio. Essi, come detto, sono ottenuti da
un'interrogazione alla tabella locations_table del database SQLite. Un segnalino
verde evidenzia la partenza, uno giallo l'arrivo e i simboli dei diversi mezzi le fermate di
scambio. Questi elementi sono stati realizzati attraverso Overlay, ovvero oggetti che
vengono disegnati sopra una mappa. In particolare è stata ridefinita la classe

51
ItemizedOverlay<OverlayItem>. Essa rappresenta un insieme di overlay
accomunati dalla stessa icona. Al suo interno è definito un oggetto del tipo
ArrayList<OverlayItem> che mantiene l'elenco completo degli oggetti. a ogni
OverlayItem è associata una breve descrizione ed un oggetto GeoPoint che salva la
posizione dell'overlay sulla superficie terrestre permettendone la visualizzazione in un punto
preciso di una mappa. Una volta costruiti gli oggetti del tipo PlacesOverlays e
StopsOverlays essi possono essere aggiunti alla mappa e presentati attraverso il metodo
getOverlays().add della classe MapView. Per poter visualizzare in modo più chiaro
le vie da percorrere è possibile effettuare zoom sulla mappa.

16: La mappa e le stazioni

52
3.4.3 Conclusioni e possibili sviluppi
Lo sviluppo del progetto qui presentato è stato fortemente influenzato dall'evoluzione della
piattaforma stessa sulla quale esso è stato elaborato. L'SDK di Android infatti durante il
periodo di elaborazione dell'applicazione ha subito molte modifiche. In particolare è stata
rimossa la libreria chiamata googlenav. Essa conteneva classi particolarmente utili per un
progetto come quello realizzato in quanto queste fornivano il supporto per elaborare e
visualizzare su mappe percorsi pedonali o automobilistici per il raggiungimento di una
destinazione prefissa. Caduta l'opzione googlenav, si è tentato di recuperare informazioni di
routing spostando l'attenzione su un progetto dell'università di Bonn: OpenRouteService
[29]. Esso si appoggia sui dati di OpenStreetMap (3.2.1) per elaborare percorsi dati la
partenza e la destinazione. Il progetto è molto interessante soprattutto se si tiene in
considerazione che tutti i dati sono open-source e possono essere ottenuti gratuitamente.
OpenRouteService è però a oggi ancora in fase di sviluppo. Esso presenta infatti
un'interfaccia grafica per poter effettuare richieste e visualizzare i risultati via web. Dal web
è anche possibile ottenere un file in formato xml che contiene tutte le informazioni riguardo
al viaggio pianificato curva per curva. Al momento è possibile ottenere questo file solo
attraverso l'interfaccia e non con una connessione HTTP in modo programmatico. In una
nota sul sito gli sviluppatori affermano di voler introdurre questa funzionalità nelle versioni
future10.
La possibilità di ottenere informazioni di routing avrebbe permesso di offrire un miglior
supporto all'utente permettendogli di orientarsi in modo ancora più semplice e
accompagnandolo a ogni svolta. OpenRouteService sarebbe stato anche utile nel rimuovere
una semplificazione introdotta nel calcolo del percorso. Avremmo potuto tenere in
considerazione l'effettiva lunghezza dei tratti da percorrere a piedi e non la distanza in linea
d'aria.
Come ampiamente spiegato nel capitolo 3.2 difficoltà si sono incontrare nel reperimento dei
dati necessari alla costruzione di un modello completo per la rete dei mezzi pubblici. La
soluzione adottata, la costruzione di un database apposito, può sembrare semplicistica ma se
opportunamente mantenuto e aggiornato, questo rappresenta di sicuro la soluzione più
efficiente per il recupero di tutte le informazioni desiderate.
10 http://data.giub.uni-bonn.de/openrouteservice/contact.php#Intro

53
Un'estensione molto interessante è quella di fornire indicazioni sul tempo richiesto dal
tragitto. Sarebbe stato possibile quindi aggiungere un metro di giudizio nell'elaborazione del
percorso. Non si sarebbe tenuto conto solo del numero di fermate ma anche del tempo
impiegato; considerando anche l'attesa per un mezzo quale il tram. Questa funzionalità
richiede però una base di dati molto più fornita e completa rispetto a quella da noi costruita.
Informazioni di questo tipo sono disponibili solo accedendo alle basi di dati dei gestori dei
mezzi pubblici di una città.
Vengono di seguito presentate considerazioni sulla qualità dell'algoritmo elaborato.
Il metodo costruito è particolarmente efficace nel trovare percorsi fra due fermate dei tram o
della metropolitana; in questi casi esso ritorna il percorso più veloce in termini di fermate
effettuate. Problemi nascono quando l'utente indica come partenza un luogo vicino a più
fermate di mezzi differenti. Mantenendo il criterio prescelto, ovvero quello di minimizzare
il percorso effettuato a piedi, l'algoritmo opta per la fermata più vicina. Questa non è sempre
la scelta migliore in quanto costringe l'utente a tragitti spesso più complicati pur di
risparmiare pochi metri a piedi. Riteniamo però che elaborare innumerevoli percorsi
considerando le possibili fermate dei mezzi in un certo raggio dalla partenza dell'utente sia
estremamente oneroso dal punto di vista computazionale, in particolare per un'applicazione
sviluppata per un dispositivo mobile. Sarebbero necessarie infatti molte richieste al server
dati per l'individuazione di eventuali problematiche sul percorso.
Infine, a nostro giudizio l'introduzione della funzionalità di rilevamento di
malfunzionamenti è di grande importanza e decisamente innovativa: permette infatti di
conoscere in anticipo la disponibilità di un mezzo e eventualmente ricalcolare il percorso,
offrendo un notevole risparmio di tempo.

54
4 Note
4.1 Bibliografia
1: http://www.quattroruote.it/News/articolo.cfm?codice=124145,
2: http://www.gartner.com/it/page.jsp?id=688116,
3: http://blog.wired.com/business/2007/11/smartphone-sale.html,
4: geo.unizh.ch/publications/cartouche/lbs_lecturenotes_steinigeretal2006.pdf,
5: http://www.canalys.com/pr/2008/r2008112.htm,
6: http://www.nokia.com/A4136001?newsid=1230415,
7: http://www.macworld.co.uk/ipod-itunes/news/index.cfm?newsid=16927,
8: http://www.navteq.com/about/advanced_discover_cities.html,
9: http://googleblog.blogspot.com/2005/12/public-transit-via-google.html,
10: http://metroid.ycsoft.org/index.php?id=3,
11: http://source.android.com/license,
12: http://www.apache.org/licenses/LICENSE-2.0,
13: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html,
14: http://code.google.com/android/what-is-android.html,
15: http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html,
16: Frank Ableson, Charlie Collins, Robi Sen, Unlocking Android, a developer's guide,
17: http://code.google.com/android/reference/android/app/Activity.html,
18: http://code.google.com/android/reference/android/content/Intent.html,
19: http://code.google.com/android/reference/android/app/Service.html,
20: http://code.google.com/android/devel/data/contentproviders.html,
21: http://code.google.com/android/devel/data/databases.html,
22: http://www.sqlite.org/,
23: http://www.openstreetmap.org/,
24: http://java.sun.com/products/servlet/,
25: http://java.sun.com/products/jdbc/overview.html,
26: http://www.patterndepot.com/put/8/Singleton.PDF,
27: http://code.google.com/android/reference/android/location/Geocoder.html,
28: http://code.google.com/android/reference/android/app/ListActivity.html,
29: http://data.giub.uni-bonn.de/openrouteservice/,

55