Tesi Android Maggioni Magni

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

Transcript of Tesi Android Maggioni Magni

Page 1: Tesi Android Maggioni Magni

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

Page 2: Tesi Android Maggioni Magni

Indice1Introduzione........................................................................................................................................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

Page 3: Tesi Android Maggioni Magni

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

Page 4: Tesi Android Maggioni Magni

1 IntroduzioneIn 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

Page 5: Tesi Android Maggioni Magni

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

Page 6: Tesi Android Maggioni Magni

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

Page 7: Tesi Android Maggioni Magni

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

Page 8: Tesi Android Maggioni Magni

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

Page 9: Tesi Android Maggioni Magni

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

Page 10: Tesi Android Maggioni Magni

2 Android: il sistema operativoAndroid è 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

Page 11: Tesi Android Maggioni Magni

● 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

1: Struttura del sistema Operativo Android

Page 12: Tesi Android Maggioni Magni

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

Page 13: Tesi Android Maggioni Magni

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

Page 14: Tesi Android Maggioni Magni

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

2: La perspective DDMS

Page 15: Tesi Android Maggioni Magni

15

3: L'emulatore del sistema operativo Android

Page 16: Tesi Android Maggioni Magni

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:

● Drawable raccoglie tutti gli elementi che possono essere

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

4: La struttura di un progetto Android in Eclipse

Page 17: Tesi Android Maggioni Magni

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

Page 18: Tesi Android Maggioni Magni

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

Page 19: Tesi Android Maggioni Magni

19

5: Il ciclo di vita di un'Activity

Page 20: Tesi Android Maggioni Magni

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

Page 21: Tesi Android Maggioni Magni

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

Page 22: Tesi Android Maggioni Magni

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

Page 23: Tesi Android Maggioni Magni

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

Page 24: Tesi Android Maggioni Magni

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

Page 25: Tesi Android Maggioni Magni

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

Page 26: Tesi Android Maggioni Magni

3 L'applicazioneQuesto 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

Presentazione

LocationsInsertion, StopList, Map, Error,

RowEntry, EntryView, PlacesOverlays, StopsOverlays,

LocalDataBase

Modello della rete dei mezzi

pubblici e Algoritmo

MetroLines,TramLines,Station,Node,MetroNode,

TramNode, Problem, Path, PathCreator

Rappresentazione del database DBInterface; RemoteDB

Elaborazione delle query e

Connessione con il DatabaseSQLQueryUtil, ToSql

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

26

Page 27: Tesi Android Maggioni Magni

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

Page 28: Tesi Android Maggioni Magni

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

Page 29: Tesi Android Maggioni Magni

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

Page 30: Tesi Android Maggioni Magni

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

Page 31: Tesi Android Maggioni Magni

● 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

Page 32: Tesi Android Maggioni Magni

● 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

Page 33: Tesi Android Maggioni Magni

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

Page 34: Tesi Android Maggioni Magni

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

Page 35: Tesi Android Maggioni Magni

35

6: La struttura del Modello

Page 36: Tesi Android Maggioni Magni

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

Page 37: Tesi Android Maggioni Magni

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

analizzato.

37

Page 38: Tesi Android Maggioni Magni

38

7: La comunicazione con il DataBase

Page 39: Tesi Android Maggioni Magni

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.

39

8: Sequence diagram della costruzione del modello

Page 40: Tesi Android Maggioni Magni

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

Page 41: Tesi Android Maggioni Magni

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

9: La classe Node e le sue sottoclassi

Page 42: Tesi Android Maggioni Magni

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

Page 43: Tesi Android Maggioni Magni

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.

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

10: Esempio di percorso

Page 44: Tesi Android Maggioni Magni

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

Page 45: Tesi Android Maggioni Magni

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

Page 46: Tesi Android Maggioni Magni

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

Page 47: Tesi Android Maggioni Magni

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.

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

11: La schermata di Input

Page 48: Tesi Android Maggioni Magni

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:

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

12: La scelta fra diverse opzioni

Page 49: Tesi Android Maggioni Magni

(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.

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

13: L'utilizzo del dispositivo GPS

Page 50: Tesi Android Maggioni Magni

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.

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

15: Partenza e Destinazione di Esempio

14: Esempio di Elenco Scambi

Page 51: Tesi Android Maggioni Magni

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

Page 52: Tesi Android Maggioni Magni

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.

52

16: La mappa e le stazioni

Page 53: Tesi Android Maggioni Magni

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

Page 54: Tesi Android Maggioni Magni

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

Page 55: Tesi Android Maggioni Magni

4 Note4.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