UNIVERSITÀ POLITECNICA DELLE MARCHE
FACOLTÀ DI INGEGNERIA
Corso di Laurea triennale in Ingegneria Informatica e dell’Automazione
TESI DI LAUREA
PROGETTO E SVILUPPO DI APPLICAZIONI
MHP PER PRENOTAZIONE DI SERVIZI
TRAMITE IL CANALE DI RITORNO
Relatore:
Candidato:
Prof. Aldo Franco Dragoni
Fabio Talamonti
Correlatore:
Prof. Paolo Puliti
Anno Accademico 2005/2006
INDICE
INTRODUZIONE
5
CAPITOLO 1
INTRODUZIONE ALLA TV DIGITALE TERRESTRE
7
1.1 Televisione Digitale Terrestre: DVB-T
7
1.2 Vantaggi e svantaggi del digitale terrestre
8
1.3 La piattaforma per i servizi della TV digitale
10
CAPITOLO 2
LO STANDARD MHP
12
2.1 La piattaforma MHP
12
2.2 Architettura della piattaforma MHP
13
2.2.1 Applicazioni
14
2.2.2 Software di sistema
16
2.2.3 Risorse e periferiche
17
2.3 Profili MHP
17
2.4 Protocollo di trasporto
21
2.4.1 Il protocollo DSM-CC Object Carousel
21
2.5 Fruizione di un servizio interattivo MHP
24
2.6 Il Set-Top Box (STB)
26
CAPITOLO 3
APPLICAZIONI MHP: LE XLET
28
3.1 L’ambiente Java delle Xlet
28
3.2 Ciclo di vita di una Xlet
29
3.3 Contesto di una Xlet
32
-2-
3.4 Interfaccia grafica delle Xlet
34
CAPITOLO 4
SVILUPPO DI UN’APPLICAZIONE MHP
4.1 Presentazione del progetto
37
37
4.1.1 Registrati
38
4.1.2 Prenota
39
4.1.3 Info
40
4.2 Realizzazione della Xlet
41
4.2.1 Il JDBC
41
4.2.2 Le socket
43
4.3 Il Server
45
4.3.1 SimpleServer.java
46
4.3.2 ServerRegistration.java
49
4.3.3 ServerFilm.java
51
4.3.4 ServerPrenotation.java
54
4.3.5 ServerPrenotaSingolo.java
57
4.3.6 PrenotaSingolo.java
58
4.3.7 ObjectRegistration
59
4.3.8 ObjectPrenotation.java
61
4.3.9 ObjectFilm.java
62
4.3.10 ObjectPosti.java
63
4.3.11 ObjectPrenFilm.java
64
4.4 La Xlet
65
4.4.1 Main.java
65
4.4.2 BackgroundController.java
70
4.4.3 GestoreSfondi.java
80
4.4.4 InterfacciaGrafica.java
81
-3-
4.4.5 Keypad.java
90
4.4.6 KeypadButton.java
97
4.4.7 Comunica.java
98
4.4.8 Strumenti.java
100
4.4.9 Registra.java
101
4.4.10 Prenota.java
116
4.4.11 Film.java
125
4.4.12 PlateaPrenota.java
131
4.4.13 Platea.java
132
4.4.14 Info.java
141
CONCLUSIONI
145
BIBLIOGRAFIA
147
-4-
INTRODUZIONE
Questo lavoro si prefigge l’obiettivo di illustrare il procedimento per
sviluppare un’applicazione MHP per la televisione digitale terrestre,
mostrando il risultato finale ed i vari passi per arrivarci.
Prima di fare ciò, è necessaria un’introduzione alla TV digitale terrestre, e in
particolare allo standard MHP, sul quale si basano le applicazioni per la
televisione.
Si inizierà con un po’ di storia del digitale terrestre, in particolare il progetto
DVB; verranno poi illustrati vantaggi e svantaggi di questa nuova tecnologia,
seguiti da una doverosa spiegazione del funzionamento della piattaforma per i
servizi della TV digitale.
Si passerà, poi, ad introdurre lo standard MHP, illustrando l’architettura della
piattaforma e i profili MHP, senza tralasciare il protocollo di trasporto e
l’apparecchio con il quale è possibile vedere la TV digitale: il Set-Top Box
(STB).
Ci sarà, inoltre, una doverosa spiegazione del funzionamento delle Xlet, cioè
le applicazioni vere e proprie, tramite la descrizione dell’ambiente java, del
ciclo di vita, del contesto e dell’interfaccia grafica delle Xlet, ed anche per
mezzo di alcuni esempi.
Infine, si presenterà il progetto sviluppato, che ha come scopo principale di
mostrare un esempio di applicazione MHP che preveda l’utilizzo del canale di
ritorno. Si inizierà con una descrizione dell’applicazione, seguita da
un’illustrazione dei vari passi che sono stati necessari alla realizzazione del
progetto. Si passerà, in seguito, a mostrare il codice Java, partendo dal server
e proseguendo con la Xlet.
Questo progetto evidenzia come la televisione digitale terrestre abbia ampi
margini di ampliamento e di sviluppo orientati, ad esempio, verso l’utilizzo di
-5-
Internet anche senza avere un computer, oppure verso servizi di prenotazione
(come nel caso del progetto qui considerato) relativi a cinema, ristoranti, ecc.
Inoltre, l’applicazione sviluppata, consente di notare come lo standard MHP
possa essere facilmente integrato con altre tecnologie, come i database
residenti su server.
La televisione digitale terrestre, dunque, rappresenta una tecnologia destinata
a svilupparsi nel futuro, e che potrebbe diventare di uso quotidiano in tutte le
case, ma anche negli uffici, aziende, ecc. Per questo motivo è importante
avere delle nozioni di base su questo importante scenario del futuro.
-6-
CAPITOLO 1
INTRODUZIONE ALLA TV DIGITALE TERRESTRE
1.1 TELEVISIONE DIGITALE TERRESTRE: DVB-T
La trasmissione digitale costituisce una tappa importantissima nello sviluppo
tecnologico dei sistemi televisivi. Essa consente di trasformare l’apparecchio
televisivo in una piattaforma per lo sviluppo dei servizi interattivi, che si
aggiungono così alla funzione tradizionale di diffusione circolare dei segnali.
In Europa, all’inizio delle attività in questo campo, c’è il progetto Digital
Video Broadcasting (DVB) promosso dalla Commissione Europea per
definire standard comuni. Il progetto, cui hanno partecipato 170 società
coinvolte nei diversi settori dell'industria televisiva, ha raggiunto l'obiettivo di
stabilire un unico standard condiviso su scala europea per le trasmissioni
televisive digitali via satellite (DVB-S), via cavo (DVB-C) e via terra (DVBT). Questi standard sono stati ora adottati anche dal Giappone e da altri paesi
non europei.
-7-
Capitolo 1
Introduzione alla TV digitale terrestre
Figura 1: Stato della televisione digitale terrestre nel mondo
1.2 VANTAGGI E SVANTAGGI DEL DIGITALE TERRESTRE
I vantaggi del digitale terrestre possono essere individuati in questi punti:
 potenziamento del servizio televisivo in termini di quantità e di qualità:
ciò riguarda una migliore qualità dell’immagine e del suono permettendo,
inoltre, l’utilizzo di televisori di grande formato. Si ha, inoltre, un notevole
aumento del numero di canali disponibili: su ogni canale televisivo viene
trasmesso un flusso di dati che trasporta nello stesso momento con la tecnica
del multiplex un certo numero di programmi televisivi diversi. Non esiste un
numero fisso di programmi televisivi che si possono trasmettere perché questo
è funzione della larghezza di banda occupata da ciascun programma, tenendo
presente che la larghezza di banda massima a disposizione per singolo canale
è circa 24 Mbit/sec. In un canale si possono così trasmettere quattro
programmi da 6 Mbit/sec l'uno, oppure dodici programmi da 2 Mbit/sec
ciascuno, ovviamente con una minore qualità delle immagini. È ovviamente
possibile trasmettere anche un solo programma da 24 Mbit/sec ad alta qualità,
per esempio con una definizione maggiore. Attualmente l'ipotesi è solamente
teorica, perché la trasmissione, per essere realmente fruibile, avrebbe bisogno
anche di un ricevitore in grado di fornire in uscita un segnale ad alta
definizione, e anche il display (televisore o monitor) dovrebbe essere ad alta
definizione.
 Interattività: la trasmissione digitale consentirà di interagire con la
televisione; ciò consiste nella possibilità di dialogare attraverso il decoder,
munito di modem, con l'emittente. Mentre con le trasmissioni analogiche gli
impianti funzionano da semplici ricevitori, con le trasmissioni digitali è
possibile interagire con l'emittente attraverso un decoder che adotta lo
standard compatibile con il digitale terrestre, detto MHP. Si potrà partecipare
a programmi televisivi a quiz, rispondere a domande e sondaggi, interrogare il
-8-
Capitolo 1
Introduzione alla TV digitale terrestre
portale su alcuni servizi come quelli del proprio comune, eseguire operazioni
bancarie, eccetera.
 Meno stazioni di trasmissione: per trasmettere il segnale serve molta
meno potenza, circa un decimo di quella necessaria per l'analogico ed è
prevista una riduzione del numero di stazioni trasmittenti sul territorio, una
per provincia. Nonostante il rischio legato all’elettrosmog non sia stato
dimostrato essere effettivamente pericoloso si tratta comunque di una positiva
novità del sistema digitale. Va inoltre evidenziata la possibilità di trasmettere
in isofrequenza, tecnica che non era possibile implementare nelle trasmissioni
televisive analogiche. Questa evoluzione tecnologica permette di inviare lo
stesso segnale sulla medesima frequenza contemporaneamente da più siti
trasmittenti.
Vi sono, però, anche alcuni significativi svantaggi:
 Costi aggiuntivi: Gli svantaggi del digitale terrestre sono legati soprattutto
al passaggio dal sistema analogico. Anche se in futuro il decoder potrà essere
integrato nei televisori oggi è necessario comprarne uno a parte per ogni
televisore. Inoltre, serve un canale di comunicazione aggiuntivo (via modem o
cellulare) per interagire con i servizi trasmessi (anche questo potrebbe in
futuro essere integrato con il televisore). Inoltre, gli apparecchi ad alta
definizione per cui il digitale è pensato sono ancora costosi.
 Ricezione: Attualmente il sistema italiano è in fase sperimentale e molte
zone non sono ancora coperte dal segnale digitale oppure sono soggette a
temporanei blackout.
A differenza del segnale analogico che ha una degradazione graduale (vale a
dire, c'è una transizione continua tra la ricezione perfetta e l'impossibilità di
vedere una qualunque immagine), il segnale digitale è un sistema quasi "onoff". Questo significa che sopra una certa soglia di rapporto segnale/rumore il
segnale viene visualizzato perfettamente, con il software che riesce a
-9-
Capitolo 1
Introduzione alla TV digitale terrestre
ricostruirlo grazie alla ridondanza dei dati inviati via etere. Al ridursi del
rapporto segnale/rumore il numero di errori di decodifica (detto BER) cresce
fino al punto in cui la correzione dell'errore diviene impossibile, con un
passaggio repentino a una non fruibilità assoluta del segnale. In questa
situazione, appaiono spesso disturbi tipici della codifica MPEG, quali
"quadrettoni colorati" in luogo dell'immagine video e fischi e altri rumori
anomali in luogo del normale audio.
La disposizione ministeriale che prevede solamente una stazione di
trasmissione per provincia potrebbe creare problemi nelle zone montuose. I
ripetitori installati sono attualmente una piccola frazione della copertura
necessaria.
1.3 LA PIATTAFORMA PER I SERVIZI DELLA TV DIGITALE
Figura 2: Schema di trasmissione per i servizi della TV digitale
La piattaforma dei servizi per la TV digitale terrestre è mostrata in figura 2.
- 10 -
Capitolo 1
Introduzione alla TV digitale terrestre
Un ruolo fondamentale è ricoperto dal Centro Servizi, direttamente collegato
con un fornitore di Servizi. Questo può essere interpretato come più unita
distinte che svolgono ruoli separati, che possono consistere in fornitori di dati,
fornitori di applicativi MHP o enti esterni con cui le applicazioni necessitano
di interagire. Solitamente il fornitore di servizi è colui che si occupa di
rilasciare le informazioni (foto, file A/V, testi,ecc…) che verranno puoi
incluse nelle applicazioni MHP.
Il fornitore di servizi potrebbe essere in certi casi anche colui che progetta
direttamente l’applicativo MHP ma che necessita di un’unità in grado di
comunicare con il broadcaster e che lo appoggi nella gestione dell’interattività
con canale di ritorno. E’ infatti con le applicazioni che fanno uso del canale di
ritorno che il ruolo del Centro Servizi si fa fondamentale.
Il Centro Servizi appoggiandosi alla rete IP mette a disposizione un numero
telefonico a cui le applicazioni effettuano la chiamata con il modem PSTN
integrato.
Offre anche un sistema di autenticazione a livello di collegamento tramite un
nome utente e una password, che pero solitamente è comune a tutti gli utenti.
Sarà compito del programmatore creare un metodo di autenticazione
dell’utente a livello più alto magari tramite l’uso di una Smart Card per
applicazioni che richiedono accesso con autenticazione.
E’ comunque il Centro Servizi a fornire l’IP che verrà poi utilizzato dal
ricevitore per lo scambio di informazioni, e quindi dovrà essere in grado di
sostenere più connessioni contemporanee mettendo a disposizione un
adeguato pool di indirizzi IP pubblici e tramite un sistema di primari ISDN di
capacità adeguata alle possibili chiamate telefoniche contemporanee.
- 11 -
CAPITOLO 2
LO STANDARD MHP
2.1 LA PIATTAFORMA MHP
I due concetti fondamentali della TV digitale sono la multimedialità e
l’interattività.
Il DVB si è, dunque, preso il compito di definire le specifiche per un servizio
televisivo multimediale che consenta l’interattività con l’utente tramite il
canale di ritorno. Il consorzio, ha perciò definito uno standard denominato
MHP (Multimedia Home Platform), al quale devono conformarsi sia i centri
di emissione sia i decoder degli utenti.
MHP definisce una generica interfaccia tra le applicazioni digitali interattive
ed i terminali sui quali le applicazioni vengono eseguite. Un decoder
compatibile MHP è una macchina capace di eseguire le primitive previste
nelle API (Application Programming Interface) specificate nello standard,
nascondendo alle applicazioni i dettagli sulle specifiche risorse hardware e
software dello stesso decoder. Così, è possibile realizzare e modificare con
molta flessibilità programmi televisivi digitali che diventano eseguibili su tutti
i decoder compatibili MHP.
Esistono diverse tipologie di API (librerie nelle quali sono raccolte un insieme
di primitive informatiche) per MHP:
- generiche: Java 1.1, che sono le seguenti:
 javax.tv.service e javax.service.navigation per l’interazione con il
servizio;
 javax.service.guide per la gestione dell’EPG (Electronic Program
Guide);
- 12 -
Capitolo 2
Lo standard MHP
 javax.service.transport per la gestione dello strema MPEG-2;
 javax.tv.xlet che fornisce le interfacce usate dalle applicazioni (Xlet) e
permette loro la comunicazione con l’application manager (vedi par.
2.2.2);
 javax.media, javax.tv per il media control;
- per l’accesso a MPEG a basso livello: org.davic.mpeg;
- per la gestione delle risorse: org.davic.resources;
- per l’application lifecycle: org.dvb.application;
- per le comunicazioni: org.dvb.dsmcc, java.io;
- per la grafica: org.havi.ui;
- per la sicurezza: dvb.signature, dvb.certificate;
Per le sue peculiarità, MHP si prefigura come un elemento in grado di
consentire la convergenza delle tecnologie di radiodiffusione con quelle
Internet.
2.2 ARCHITETTURA DELLA PIATTAFORMA MHP
- 13 -
Capitolo 2
Lo standard MHP
Figura 3: Architettura della piattaforma MHP
L’architettura della piattaforma MHP, come mostrato in Figura 3, è definita in
tre livelli:
- Risorse o periferiche
- Software di sistema
- Applicazioni
2.2.1 Applicazioni
Un’applicazione è la realizzazione di un servizio interattivo formato da
moduli programmabili che richiedono funzionalità specifiche residenti
nell’hardware o nel software del terminale. Esse sono la parte fondamentale
nella filosofia MHP.
Lo standard MHP supporta diverse tipologie di applicazioni, come:
- EPG (Electronic Program Guide) che si presenta come una pagina Web
interattiva dedicata alla guida multimediale, alla sintonia dei programmi ed
all’illustrazione del loro contenuto;
- servizi di teletext avanzato, che consiste in un aumento di contenuti
anche sotto forma di immagini, grafici, ipertesti, clip audio e video, giochi,
- 14 -
Capitolo 2
Lo standard MHP
rendendo questo servizio informativo del tutto analogo a pagine di siti
web;
- applicazioni collegate al contenuto dei programmi o sincronizzate con
il contenuto televisivo, come banner pubblicitari, giochi interattivi ed
altro;
- servizi di e-commerce, servizi bancari, che permettono di effettuare e
controllare gli acquisti da remoto, o gestire ordinarie operazioni su conti
correnti, compravendita di azioni ed altro;
- servizi transattivi, quali quelli forniti già su Internet da vari enti, come
Poste Italiane, INPS, Ferrovie dello Stato, ASL, ecc. Questi servizi non
riguardano quelli propriamente televisivi, dato che utilizzano il terminale
solo come alternativa al computer; essi, però, costituiscono un esempio di
convergenza tecnologica che potrà avere importanti sviluppi in futuro,
specie se si potesse allacciare il decoder televisivo a canali a larga banda
(ADSL e simili);
- giochi.
Le applicazioni possono essere di tre tipi:
 Residenti: forniscono servizi diversi a seconda del decoder considerato;
 Installabili: contengono funzionalità aggiuntive che possono integrare il
funzionamento delle applicazioni residenti;
 Scaricabili: vengono, di solito, offerte dagli operatori di servizi televisivi
per arricchire l’offerta al cliente. Devono essere conformi allo standard.
- 15 -
Capitolo 2
Lo standard MHP
Figura 4: Esempi di applicazioni MHP
2.2.2 Software di sistema
Il software di sistema comprende diversi moduli che devono essere costruiti
sulle risorse informatiche del singolo decoder:
- insieme di programmi (sistema operativo, programmi di gestione delle
periferiche, ecc.) che usano le risorse disponibili per nasconderle alle
applicazioni, fornendo ad esse una rappresentazione logica in termini di
primitive software;
-
piattaforma nota come DVB-Java (DVB-J) che si interfaccia con le
applicazioni attraverso le API MHP; essa include, a sua volta:
 una macchina virtuale Java JVM (Java Virtual Machine),
secondo le specifiche della Sun Microsystem;
 pacchetti software con funzionalità generali (API Java della Sun)
e specifiche (API Java per la TV, per DAVIC e per HAVI).
- gestore di applicazioni (application manager), noto anche come navigatore,
che gestisce la piattaforma MHP e le applicazioni che girano su di essa.
- 16 -
Capitolo 2
Lo standard MHP
2.2.3 Risorse e periferiche
Le risorse e le periferiche del terminale MHP sono standardizzate solo in
parte. La dotazione standard prevede le seguenti risorse:
- demodulatore hardware MPEG;
- moduli di accesso condizionato;
- processore;
- memorie Ram e Flash, hard disk.
Le interfacce, invece, sono le seguenti:
- modem;
- lettore smart-card;
- lettore DVD.
2.3 PROFILI MHP
Il sistema MHP ha fornito il concetto di profilo per dare una mano
nell’implementazione dello standard. Ogni profilo si riferisce ad una specifica
area di applicazioni e conseguentemente definisce i requisiti dei Set Top Box
necessari a supportarlo. Attualmente esistono tre profili MHP, definiti in due
set di specifiche. Infatti dato che i primi due sono molto simili tra loro, il
consorzio ha deciso di includerli nella stessa release di specifiche. I tre profili
(vedi figura 5) attorno ai quali ruota tutta la piattaforma sono:
 Enhanced Broadcast Profile: definito nelle specifiche MHP 1.0,è
designato a rispecchiare i vari modi e le funzionalità dei sistemi
middleware esistenti e le applicazioni che girano su di essi. Questo profilo
richiede un Set Top Box con nessuna o limitate capacità di gestione del
canale di ritorno; è il profilo base e permette solamente l’arricchimento del
contenuto audio-video con informazioni e immagini visualizzabili e
- 17 -
Capitolo 2
Lo standard MHP
navigabili sullo schermo. Per questo motivo non sono richieste
performance particolari da parte dei Set Top Box.
 Interactive TV Profile: definito nelle specifiche MHP 1.0, è il profilo
intermedio che permette di utilizzare il canale di ritorno (di tipo PSTN,
ADSL, GPRS, Ethernet, ecc.) per fornire servizi con interattività superiore
rispetto al profilo base. Questo profilo, infatti, supporta anche il
caricamento di applicazioni MHP tramite il canale di ritorno (ma solo dalla
versione 1.1), caratteristica che nel profile Enhanced è possibile solo
attraverso il canale broadcast;
 Internet Access Profile: definito nelle specifiche MHP 1.1, richiede un Set
Top Box molto più sofisticato, con potenza di calcolo e memoria interni
maggiori che nei primi due profili; permette, tramite il canale di ritorno,
un’interattività totale e un completo accesso ai contenuti di Internet. Il
profilo Internet Access contiene un elemento HTML opzionale chiamato
DVB-HTML, permettendo il supporto di HTML, CSS, DOM, EMCA
Script. Questo profilo necessita di performance di alto livello
essendo
obbligatoria l’adozione di un browser internet e di un cliente e-mail
embedded nel Set Top Box.
- 18 -
Capitolo 2
Lo standard MHP
Figura 5: MHP - Profili implementativi
Lo standard di base è costituito dalla specifica MHP 1.0.
La specifica 1.0.X contiene:
- l'architettura base di MHP;
- informazioni dettagliate sui profili “Enhanced Broadcasting” ed “Interactive
TV”;
- diversi formati contenuti in MHP, che includono JPEG, MPEG-2 video e
audio;
- protocolli di trasporto, che includono DSM-CC per la trasmissione broadcast
e IP per il canale di ritorno;
- modelli di applicazione DVB-J;
- modelli di applicazione DVB-HTML;
- allegati al profilo DSM-CC, una presentazione testuale e varie API;
MHP 1.0.X specifica l'ambiente dove si possono eseguire le applicazioni per
la tv interattiva digitale, indipendentemente dall'hardware e dal software
sottostante, che sono specifici del produttore di STB.
- 19 -
Capitolo 2
Lo standard MHP
La specifica MHP 1.0 fornisce un insieme di caratteristiche e funzioni
richieste dai profili ‘enhanced broadcasting' ed ‘interactive broadcasting'.
In seguito è stata emanata la specifica MHP 1.1 per implementare il profilo
“Internet Access”. MHP 1.1.X contiene:
- informazioni dettagliate sui profili “Interactive TV” ed “Internet Access”;
- la disponibilità per l'immagazzinamento delle applicazioni nella memoria
persistente;
- download delle applicazioni mediante i canali broadcast o di interazione;
- estensioni al DVB-J per supportare meglio le applicazioni e l'accesso a
lettori di smart card non certificati;
- specifiche di DVB-HTML;
- supporta la gestione di plug-in interoperabili (per il supporto di formati di
applicazioni non conformi);
- supporto per i riferimenti bidirezionali tra il contenuto di MHP ed il
contenuto internet;
MHP 1.1 è stata sviluppata basandosi sulla specifica MHP 1.0 con lo scopo di
supportare meglio l'uso del canale di interazione e per specificare gli elementi
che promuovono l'interoperabilità con il contenuto internet. Infatti MHP 1.1 è
semplicemente un'altra versione della specifica MHP 1.0, basata sugli stessi
file sorgente. Perciò in gran parte il contenuto di MHP 1.0 è ripetuto in MHP
1.1.
Con MHP 1.1, grazie al profilo Internet Access, le applicazioni possono
controllare le operazioni basilari dei client residenti su internet (web browser,
e-mail).
Per aggiungere queste funzionalità ed integrare il formato applicativo DVB-J,
MHP 1.1 ha definito un nuovo tipo di applicazione opzionale: DVB-HTML,
che è un linguaggio di mark-up basato su HTML; permette ad un ricevitore di
presentare le applicazioni della tv interattiva digitale in HTML. Le specifiche
- 20 -
Capitolo 2
Lo standard MHP
DVB-HTML presentano le stesse estensioni e restrizioni delle specifiche del
linguaggio W3C esistente.
2.4 PROTOCOLLO DI TRASPORTO
Affinché sia in grado di comunicare con il mondo esterno, è necessario che il
terminale supporti vari tipi di rete; per questo le specifiche MHP introducono
il supporto di diversi protocolli, così come definiti nelle specifiche DVB, a cui
la piattaforma fa riferimento. I protocolli definiti in questo standard
forniscono il supporto generico a una varietà di servizi sia di tipo broadcast
che interactive; le specifiche infatti supportano i protocolli DSM-CC data
carousel e object carousel e tutti i protocolli basati su IP. Risulta interessante
che i protocolli IP, intrinsecamente usabili sul canale interactive, possono
essere usati anche sul canale broadcast grazie al supporto dalla Multiprotocol
Encapsulation (MPE). Le varie configurazioni di rete supportate sono
raggruppate in due classi:
- i servizi broadcast sono implementati su sistemi che consistono di un
canale di downstream dal Service Provider all’utente finale;
- i servizi interattivi invece si riferiscono a sistemi che consistono di un
canale di downstream associato ad un canale di ritorno.
I file dati sono trasmessi utilizzando i protocolli DSM-CC o IP incapsulato in
MPEG-2 così come definito nelle specifiche DVB relativamente alla MPE. Le
applicazioni MHP vengono trasportate all’utente finale attraverso il protocollo
DVB Object Carousel.
2.4.1 Il protocollo DSM-CC Object Carousel
Il protocollo DSM-CC è stato originariamente progettato per l’uso con
macchine di rete VTR (Video Tape Recorder – Registrazione video in rete).
- 21 -
Capitolo 2
Lo standard MHP
Da allora si è sviluppato molto e adesso include il controllo di server video
MPEG in rete (con funzioni di play, stop, pausa del video e dell’audio), il
supporto per la trasmissione di dati utilizzando MPEG-2, timecode per il
video MPEG, il broadcasting di dati semplici e interi file system. I sistemi
broadcast sono per loro natura unidirezionali. I dati vengono inviati da un
trasmettitore e il ricevitore non può richiedere dati specifici. Questo significa
che un ricevitore non può accedere ad uno specifico file su un server come
avviene nei normali PC. Per questo è necessaria un’altra soluzione che
permetta al ricevitore MHP di accedere ai dati sul flusso broadcast.
L’approccio è quello di trasmettere periodicamente ogni file del file-system e
il ricevitore non deve fare altro che attendere il file di cui ha bisogno. Il
miglior esempio di questa soluzione è il sistema teletext digitale: ad ogni
pagina è associato un numero univoco e le pagine vengono trasmesse una
dopo l’altra ciclicamente. Quando l’utente digita il numero della pagina da
ricevere, il ricevitore deve attendere che la pagina venga trasmessa prima di
poterla decodificare e presentare al display. Questo tipo di soluzione va sotto
il nome di carosello (ogni pagina viene trasmessa a turno periodicamente e il
ricevitore deve attendere il ritorno di quella pagina nel flusso broadcast per
poterla prelevare e usarla). Certamente questa soluzione non è molto
efficiente, ed infatti si sono nel tempo sviluppate tecniche per migliorarne le
prestazioni. Nel DSM-CC, i dati vengono trasmessi in blocchi chiamati
“moduli” invece che in pagine, ma il principio è lo stesso del sistema di
teletext. I dati da trasmettere vengono suddivisi in moduli, vengono aggiunte
informazioni a ciascun modulo, quindi ogni modulo viene trasmesso a turno.
Il DSM-CC supporta due tipi di carosello. Il più semplice dei due è il data
carousel, che fornisce al broadcaster un modo per trasmettere blocchi di dati
al ricevitore. Non sono però presenti dati aggiuntivi che informano sul tipo di
dati e su cosa si stia trasmettendo ed è quindi compito del ricevitore
- 22 -
Capitolo 2
Lo standard MHP
rielaborare i dati in una forma sensata. In situazioni più complesse il data
carousel non risulta molto utile e in questi casi è l’object carousel costituisce
una soluzione migliore.
L’object carousel è costruito come protocollo direttamente sopra il data
carousel e fornisce funzionalità vicine a quelle di un file-system standard.
Ogni object carousel consiste di un albero di directory suddiviso in una serie
di moduli, che possono contenere uno o più file o directory. Ogni modulo può
contenere molteplici file con una dimensione totale minore di 64Kb
(l’inserimento di più file in un modulo di dimensione maggiore di 64Kb non è
permesso, così come suddividere un unico file su più moduli), quindi un file
più grande di 64Kb andrà a riempire il suo proprio modulo che conterrà
solamente quel file. Questi moduli vengono trasmessi in broadcast l’uno dopo
l’altro fino alla fine. A questo punto la trasmissione comincia da capo con il
primo modulo. Per l’accesso ad un preciso file, il ricevitore deve attendere
fino a che non riceve il modulo contenente quel file; a questo punto può
elaborare il modulo ed avere accesso al file desiderato. Questo metodo può
non essere molto efficiente quando le dimensioni totali dei dati da trasmettere
sono considerevoli, ma la maggior parte dei ricevitori è in grado di mantenere
memorizzati nella cache parte dei dati e questo velocizza notevolmente le
operazioni.
Alcuni moduli possono essere trasmessi più di una volta all’interno
dell’object carousel. Infatti, trasmettendo alcuni moduli più spesso di altri, il
tempo di accesso ai file più comunemente usati viene ridotto notevolmente.
D’altro canto, però, agendo in questo modo, cresce la dimensione totale del
carosello, causando un aumento del tempo di accesso ai dati meno usati. Nel
progetto di layout di un carosello si deve considerare
attentamente questo
compromesso che, se ottimizzato, può portare ad una riduzione notevole del
tempo di caricamento di un’applicazione.
- 23 -
Capitolo 2
Lo standard MHP
Nello stesso carosello è possibile inserire più applicazioni che verranno così
trasmesse contemporaneamente dando all’utente la possibilità di scegliere, ad
esempio, se sfogliare la guida EPG piuttosto che misurarsi in un gioco
interattivo. Ovviamente spetta all’object carousel generator il compito di
condividere tra le varie applicazioni la banda destinata al carosello.
All’interno di un transport stream DVB possono essere trasportati uno o più
Object Carousel, nello stesso modo in cui vengono gestiti gli stream del
video, dell’audio e della service information. Ad ogni stream Object Carousel
viene allocato un PID univoco che viene referenziato nelle tabelle DVB-SI.
Uno stream Object Carousel occupa tipicamente una banda di payload di circa
1Mbps, ma nelle applicazioni reali questo valore può essere limitato
dall’abilità del ricevitore di decodificare e elaborare le applicazioni.
2.5 FRUIZIONE DI UN SERVIZIO INTERATTIVO MHP
Nella figura 6, viene illustrato in maniera molto schematica l’ambiente
coinvolto nell’esecuzione di un’applicazione MHP.
Nel momento in cui si fruisce dalla TV digitale entrano in gioco due gestori di
contenuti: il primo è quello che fornisce i contenuti sotto forma di programmi
televisivi, il broadcaster, il secondo è quello che fornisce i contenuti sotto
forma di dati (estratti conto, informazioni pubblicitarie, ecc.). Il primo
distribuisce i propri servizi broadcast, sfruttando un canale dedicato
(unidirezionale) che dipende dallo standard utilizzato, mentre il secondo
distribuisce i propri servizi utilizzando Internet come luogo di scambio.
- 24 -
Capitolo 2
Lo standard MHP
Figura 6: Architettura di fruizione di un servizio interattivo MHP
Durante un programma televisivo è possibile, attraverso la pressione di un
apposito tasto del telecomando, richiedere l’esecuzione di un’applicazione,
ove essa sia disponibile. Di solito il fornitore informa l’utente della presenza
di un’applicazione nel carosello per mezzo di un segnale visivo, un’etichetta
lampeggiante o un’icona corrispondente ad un tasto colorato del telecomando.
Nel momento in cui l’applicazione si trova nella fase di Active, l’utente può
iniziare ad usufruire del servizio che, a seconda del tipo, è dotato di un
maggiore o minore grado di interattività.
L’utente effettua delle richieste interagendo con l’applicazione che le inoltra,
per mezzo del canale di ritorno, al centro servizi, il quale restituisce i
contenuti voluti al lato client che li ripropone all’interno dello schermo
televisivo.
- 25 -
Capitolo 2
Lo standard MHP
2.6 IL SET-TOP BOX (STB)
Il decoder interattivo (Set-Top Box) è l'apparecchio indispensabile per
ricevere i canali digitali e utilizzare i software interattivi. Questo dispositivo
permette innanzitutto la decodifica del segnale da digitale ad analogico per gli
apparecchi televisivi analogici che attualmente nel nostro paese rappresentano
la totalità del mercato. Infine consente di eseguire applicazioni Java grazie
alla presenza di una Personal JVM embedded.
Come mostra la Figura 7 un decoder è formato da una parte hardware (CPU,
memoria, modem, ecc.), da un sistema operativo real time e da un middleware
MHP.
Figura 7: Schema hardware/software di un STB
Un attore importante che troviamo all'interno del decoder è il cosiddetto
navigatore (o application manager). Il suo compito è fondamentale, infatti
esso si occupa di segnalare all'utente la lista delle applicazioni MHP
disponibili sul canale televisivo. Inoltre se l'utente effettua una selezione da
tale lista, il navigatore inizia la fase di download in memoria dei moduli
relativi all'applicazione scelta. Importante sottolineare che non tutti i moduli
che compongono l'applicazione verranno scaricati, infatti il download sarà
- 26 -
Capitolo 2
Lo standard MHP
relativo solo a quelli necessari alla partenza della Xlet. Successivamente e
solo se realmente necessari verranno scaricati anche quelli rimanenti. Tale
meccanismo ricorda il modello di caricamento delle pagine del televideo ed è
pensato allo scopo di ridurre i tempi di attesa del telespettatore.
Un dispositivo tecnologico presente sul decoder che rende operativo il
concetto di canale di ritorno definito nello standard è il modem nei decoder di
fascia bassa e l'ADSL, Gprs, Ethernet, etc. sui decoder di fascia alta. Il canale
di ritorno permette di interagire con servizi esterni, su server dedicati o
internet e scaricare contenuti su richiesta del telespettatore. Nel caso di
modem V90 i tempi di connessione e recupero dati sono abbastanza
lunghi(30-40 sec solo per la chiamata telefonica e l'autenticazione presso un
ISP), ma nel caso di connessioni "always on" come con ADSL allora gli
scenari possibili sono molto più interessanti, come la possibilità di scaricare
musica e video su richiesta dell'utente.
- 27 -
CAPITOLO 3
APPLICAZIONI MHP: LE XLET
3.1 L’AMBIENTE JAVA DELLE XLET
Le applicazioni sviluppate per MHP vengono chiamate applicazioni DVB-J.
Sono scritte in Java e consistono in un insieme di classi trasmesse in
broadcast. Spesso si fa riferimento a tali applicazioni con il nome di Xlet.
In pratica, un’applicazione Java convenzionale non si adatta bene
all’ambiente televisivo digitale. Questo modello presuppone l’esecuzione di
una sola applicazione in una data macchina virtuale, e che l’applicazione
stessa abbia il controllo completo del proprio ciclo di vita. In un ricevitore
televisivo digitale, invece, è frequente che più applicazioni vengano eseguite
nello stesso momento. A tal proposito viene considerato il funzionamento
delle applet che, a differenza delle normali applicazioni, possono essere
avviate da una sorgente esterna, il web browser, ed alcune di esse possono
essere eseguite sulla stessa pagina web nello stesso momento. Ovviamente il
sistema televisivo digitale è diverso dal Web, perciò devono essere adottati
alcuni cambiamenti affinché questi concetti si adattino al ricevitore digitale.
Una Xlet quindi non è un’applicazione Java standard: è una particolare
applicazione concepita per essere scaricata ed eseguita sui decoder interattivi;
esse sono state introdotte da Sun nella specifica JavaTV, ed adottate come
formato applicativo Java per MHP.
Sono molto simili ad applet: come nelle applet, l’interfaccia Xlet permette ad
un software specifico esterno, l’application manager nel caso del ricevitore
MHP, di controllarne il ciclo di vita, avviando o fermando l’applicazione.
L’interfaccia Xlet si trova nel package javax.tv.xlet.
- 28 -
Capitolo 3
Applicazioni MHP: le Xlet
Come le classi applet, l’interfaccia Xlet contiene i metodi che permettono
all’application manager di inizializzare, avviare, mettere in pausa e
distruggere una applicazione.
Poiché potrebbero esserci più Xlet che vengono eseguite nello stesso
momento, esse non possono effettuare alcuni compiti che potrebbero
influenzare la Java Virtual Machine; in particolare, una Xlet non deve mai
richiamare il metodo ‘System.exit()’ per terminare l’applicazione .
La differenza più importante tra applet e Xlet è che una Xlet può essere messa
in pausa ed essere riavviata in un secondo momento. La ragione è semplice:
nel caso di un ricevitore digitale, diverse applicazioni potrebbero essere
eseguite nello stesso momento, mentre le capacità dell’hardware permettono
ad una sola applicazione di essere visibile; quelle non visibili perciò devono
essere messe in pausa con lo scopo di mantenere le risorse libere per l’unica
applicazione mostrata.
3.2 CICLO DI VITA DI UNA XLET
Le interfacce javax.tv.xlet.Xlet e javax.tv.xlet.XletContext servono per
interagire con l’application manager in merito al ciclo di vita e al contesto in
cui la Xlet viene eseguita.
Una Xlet di fatto implementa i quattro metodi presenti
nell’interfaccia
javax.tv.xlet.Xlet:
 initXlet: questo metodo viene invocato dall’application manager per
inizializzare l’Xlet;
 startXlet: è la funzione che serve per eseguire l’Xlet;
 pauseXlet: usata per mettere in pausa l’Xlet;
 destroyXlet: invocata quando l’application manager termina l’Xlet.
- 29 -
Capitolo 3
Applicazioni MHP: le Xlet
Il ciclo di vita di una Xlet è dunque caratterizzato da quattro stati:
 Loaded: la Xlet viene creata ma non ancora inizializzata. Se durante
questa fase viene rilevata un’eccezione, si passa direttamente allo stato
Destroyed. Una Xlet può trovarsi in questo stato solo una volta durante
tutto il suo ciclo di vita.
 Paused: la Xlet viene inizializzata, e può trovarsi in questo stato sia dopo
che il metodo initXlet ritorna con successo dallo stato Loaded, oppure
dopo che il metodo pauseXlet ritorna con successo dallo stato Active. In
questo stato, la Xlet deve limitare al massimo l'utilizzo delle risorse
condivise e soprattutto non impegnare la GUI televisiva.
 Active: in questo stato la Xlet è attiva e utilizza le risorse necessarie per
fornire i suoi servizi; se è dotata di GUI, allora dovrebbe essere l'unica
applicazione abilitata a ricevere gli eventi dal telecomando.
 Destroyed: in questo stato la Xlet deve rilasciare tutte le risorse in uso per
predisporsi alla terminazione.
Figura 8: Ciclo di vita di una Xlet
Una sequenza tipica del ciclo di vita può essere la seguente:
- 30 -
Capitolo 3
Applicazioni MHP: le Xlet
1. L’application manager carica la classe principale della Xlet, su
segnalazione del broadcaster, e ne crea un’istanza: l’applicazione si trova
nello stato Loaded.
2. Quando l’utente sceglie di avviare l’Xlet, o un’altra applicazione segnala
che l’Xlet deve partire automaticamente, l’application manager invoca il
metodo
initXlet. L’Xlet
usa il
‘context’
per inizializzarsi, ed
eventualmente per richiedere alcune risorse, come le immagini. Quando
l’inizializzazione è completata, l’Xlet si trova nello stato Paused, ed è
pronta per essere avviata.
3. Una volta che il metodo initXlet ritorna con successo, l’application
manager richiama il metodo startXlet. Questo comporta il passaggio dallo
stato Paused allo stato Active, così l’Xlet sarà capace di interagire con
l’utente ed utilizzare le risorse necessarie per fornire i servizi per cui è
stata creata.
4. Durante l’esecuzione, l’application manager può invocare il metodo
pauseXlet; questo comporta il passaggio dell’applicazione dallo stato
Active allo stato Paused. L’applicazione potrà tornare nello stato Active
richiamando il metodo startXlet: questa situazione può accadere svariate
volte in tutta la vita di una Xlet.
5. Alla fine del ciclo di vita, l’application manager invoca il metodo
destroyXlet, che comporta il passaggio allo stato Destroyed, liberando
tutte le risorse. A seguito di questa operazione, l’istanza di questa Xlet non
può essere più richiamata.
Il costruttore della classe principale di ogni Xlet deve essere lasciato vuoto:
quando il middleware avvia un’applicazione, all’inizio crea un’istanza della
classe principale. In questo modo invoca il costruttore di default, se esiste, ed
esegue il codice contenuto.
- 31 -
Capitolo 3
Applicazioni MHP: le Xlet
In realtà una Xlet possiede un altro metodo che deve essere usato per questo
tipo di setup: il metodo initXlet(), che permette un controllo migliore delle
operazioni. Tutte le inizializzazioni devono essere fatte nell’implementazione
di questo metodo. Durante l’inizializzazione, se qualcosa fallisse verrebbe
lanciata un’eccezione, passando direttamente allo stato Destroyed.
3.3 CONTESTO DI UNA XLET
Ogni Xlet ha a disposizione un “contesto di applicazione”, l’XletContext, che
è un’istanza della classe javax.tv.xlet.XletContext.
Questo context è simile alla classe AppletContext associata ad una applet: in
entrambi i casi il contesto viene usato dall’applicazione per accedere alle
proprietà dell’ambiente circostante e per comunicare i cambiamenti di stato
all’application manager.
L’interfaccia javax.tv.xlet.XletContext prevede i seguenti metodi:
- notifyDestroyed;
- notifyPaused;
- getXletProperty;
- resumeRequest.
I metodi notifyDestroyed e notifyPaused permettono ad una Xlet di notificare
al decoder che l’applicazione sta per terminare o per mettersi in pausa; in
questo modo, il ricevitore conosce lo stato di ogni applicazione e può
effettuare le azioni appropriate. Questi metodi devono essere richiamati
immediatamente prima che l’Xlet entri negli stati Paused o Destroyed, a causa
del fatto che il ricevitore potrebbe effettuare alcune operazioni per le quali
l’applicazione non è detto che sia pronta.
Una Xlet può richiedere di passare dallo stato Paused allo stato Active usando
il metodo resumeRequest. Questo può accadere quando si verifica un certo
- 32 -
Capitolo 3
Applicazioni MHP: le Xlet
evento, rilevato ad esempio nello stream MPEG. Questo metodo richiede che
un’applicazione venga fatta partire nuovamente, anche se il software del
ricevitore potrebbe scegliere di ignorare questa richiesta a causa di limiti nelle
risorse.
Il metodo getXletProperty permette alla Xlet di accedere alle proprietà
segnalate dal broadcaster. Attualmente è stata definita una sola proprietà da
JavaTV e da MHP, XletContext.ARGS, che permette ad un’applicazione di
accedere agli argomenti che le vengono segnalati tramite AIT.
Di seguito viene mostrato cosa succede quando una Xlet chiede di cambiare il
proprio stato tramite l’Xlet context. Si consideri una Xlet che vuole mettersi
in pausa e successivamente richiede di riavviarsi.
1. Per prima cosa, l’Xlet notifica al suo Xlet context che si è messa in pausa,
invocando il metodo XletContext.notifyPaused().
2. L’Xlet context inoltra questa informazione all’application manager
presente nel middleware.
3. L’application manager aggiorna il suo stato interno per notificare che
l’applicazione si è messa in pausa, quindi l’Xlet si ferma.
4. Quando un’applicazione vuole riavviare le operazioni, ad esempio perché
è passato un certo tempo prefissato oppure perché l’utente ha premuto un
tasto, viene richiamato dalla Xlet il metodo XletContext.requestResume().
5. Come prima, l’Xlet context passa tale richiesta all’application manager.
6. L’application manager può quindi decidere se riavviare l’applicazione
oppure no. Se la riavvia, aggiorna il proprio stato interno per notificare il
cambiamento, quindi chiama il metodo startXlet() sulla Xlet: come tutte le
altre operazioni che controllano il ciclo di vita della Xlet, questo metodo
viene richiamato direttamente dall’application manager e non attraverso
l’Xlet context.
7. Infine l’Xlet riavvierà le proprie operazioni.
- 33 -
Capitolo 3
Applicazioni MHP: le Xlet
3.4 INTERFACCIA GRAFICA DELLE XLET
Ogni Xlet deve implementare l’interfaccia Xlet, presente nel package
javax.tv.xlet delle API JavaTV di Sun.
Per costruire l’interfaccia grafica devono essere importati altri package:
- java.awt.*;
- java.awt.event.*;
- org.havi.ui.*;
- org.havi.ui.event.*;
- org.dvb.ui.*;
- org.dvb.event;
Questi package servono per fornire le necessarie funzionalità grafiche ed i
rispettivi eventi per implementare l’interfaccia utente.
In pratica, il modello grafico definito dallo standard MHP viene supportato
dai package sopra citati, tra i quali spicca quello Havi.
La classe fondamentale per gestire il layout su schermo è la HScene, presente
nei pacchetti forniti da Havi. HSceneFactory è la classe che permette di
richiamare l’unica istanza HScene.
Il modello grafico definito dallo standard MHP è basato su tre differenti layer.
Al livello più basso si trova il Background layer, che può contenere un colore
o una immagine statica (rappresentata da un particolare frame MPEG-2). Nel
secondo livello è situato il Video layer, rappresentato dal flusso A/V del
canale TV o da una qualsiasi altra fonte in formato MPEG-2. Al livello più
alto infine si trova il Graphic layer, che contiene la grafica creata nella Xlet, e
può essere strutturato su più livelli sovrapposti.
- 34 -
Capitolo 3
Applicazioni MHP: le Xlet
Figura 9: I layer grafici dell'MHP
Questo modello grafico è supportato dai package messi a disposizione dallo
standard, tra i quali quello più importante viene fornito da Havi.
In tale package, il container di più alto livello nella Xlet è rappresentato dalla
classe org.havi.ui.HScene, che possiede caratteristiche specifiche per i
decoder digitali.
La classe che ci permette di richiedere l'unica istanza della HScene è fornita
dallo stesso package e si chiama org.havi.ui.HSceneFactory.
Oltre ad Havi e AWT è possibile utilizzare un package specifico DVB,
org.dvb.ui, dove è possibile trovare classi di utilità come la DvbColor, che
permette di gestire anche le trasparenze tramite il parametro alpha, non
presente nella classe java.awt.Color.
Il font di sistema supportato in MHP è il Tiresias.
I formati grafici supportati sono: png, jpg, gif e mpg(I-Frame).
Gli eventi associati al telecomando definiti in MHP sono i tasti numerici, le
frecce di navigazione, il tasto OK ed i 4 tasti colorati: rosso, verde, giallo e
blu.
- 35 -
Capitolo 3
Applicazioni MHP: le Xlet
Lo standard non definisce l’evento per il tasto EXIT, anche se è presente sulla
quasi totalità dei decoder, quindi genera degli eventi non-standard e non
sempre coerenti sui vari decoder.
MHP fornisce due possibilità per la gestione degli eventi nelle Xlet:
 il classico meccanismo java, fornito in AWT, che si realizza
implementando l'interfaccia java.awt.event.KeyListener.;
 le classi del package org.dvb.event.
Le classi principali del package org.dvb.event sono la EventManager e la
UserEventRepository, che gestiscono rispettivamente la registrazione degli
eventi ed il repository degli eventi a cui si è realmente interessati. Questo
approccio ha il vantaggio di non imporre ad una Xlet di richiedere il focus
tramite la HScene, come invece prevede il modello AWT.
- 36 -
CAPITOLO 4
SVILUPPO DI UN’APPLICAZIONE MHP
4.1 PRESENTAZIONE DEL PROGETTO
Lo scopo del progetto è quello di realizzare un’applicazione MHP eseguibile
su un decoder per la televisione digitale terrestre, sfruttando il canale di
ritorno del decoder stesso.
Si è pertanto pensato di creare un’applicazione che permetta la prenotazione
di posti in un cinema.
L’applicazione è stata sviluppata tramite un programma per scrivere il codice
Java (Eclipse 3.1.2). Parallelamente la xlet appena scritta veniva verificata su
un emulatore del sistema televisivo digitale terrestre: XleTView. Si è, inoltre,
utilizzato un database MySQL per la memorizzazione degli utenti e dei posti
nelle varie sale.
Per la verifica su Set-Top Box si è utilizzato il X75-DEV di ADB, un
particolare decoder per lo sviluppo, dotato di una presa seriale per il
caricamento delle applicazioni da computer, e di canale di ritorno PSTN ed
ETHERNET.
Il progetto è stato realizzato utilizzando quest’ultimo.
L’applicazione si presenta con un menù di scelta a sinistra, e con lo schermo
televisivo al centro in basso.
- 37 -
Sviluppo di un’applicazione MHP
Capitolo 4
Figura 10: Schermata iniziale
Con le frecce UP e DOWN del telecomando si scorre il menù, e con il tasto
OK si sceglie l’operazione da effettuare.
4.1.1 Registrati
Premendo OK sul pulsante REGISTRATI si accede alla seguente schermata.
Figura 11: Registrazione
- 38 -
Sviluppo di un’applicazione MHP
Capitolo 4
Con le freccie UP e DOWN si scorrono i campi Username, password, ecc.
L’utente può compilare i campi premendo i tasti numerici del telecomando,
più volte a seconda della lettera da inserire. La tastiera, infatti, è stata
implementata come quella di un cellulare, cioè premendo più volte lo stesso
tasto si sceglie una lettera differente.
Premendo il pulsante ROSSO, si procede all’inserimento del nuovo utente nel
database. E’ necessario, però, compilare tutti i campi. Se ciò non è accaduto e
l’utente preme il pulsante ROSSO, verrà visualizzato un messaggio di errore
che specifica il campo da compilare.
Premendo il tasto VERDE, invece, si torna alla schermata iniziale.
4.1.2 Prenota
Premuto OK sul pulsante PRENOTA, si accede ad una schermata di
inserimento di username e password, con lo stesso metodo della registrazione.
Premendo il tasto ROSSO si verifica che nel database sia presente l’utente
inserito. Se ciò non è verificato viene visualizzato un messaggio di errore,
altrimenti viene presentata la seguente schermata.
Figura 12: Scegli il film
- 39 -
Sviluppo di un’applicazione MHP
Capitolo 4
Con i tasti UP e DOWN è possibile posizionarsi sul film per il quale
prenotare il posto, e premendo OK si accede alla schermata che visualizza la
mappa della platea, con i posti verdi (liberi) e rossi (occupati).
Con le frecce UP, DOWN, RIGHT, LEFT si scorrono i posti, e con il tasto
OK si prenota. Verrà poi visualizzato un messaggio per confermare la riuscita
o l’errore nella prenotazione. Premendo il tasto BLU, invece, viene aggiornata
la mappa dei posti, e con il tasto VERDE si torna alla schermata di partenza.
Figura 13: Scegli il posto
4.1.3 Info
Premendo OK sul pulsante INFO, si accede ad una schermata che visualizza
semplicemente alcune informazioni utili sul cinema.
- 40 -
Sviluppo di un’applicazione MHP
Capitolo 4
Figura 14: Info
4.2 REALIZZAZIONE DELLA XLET
4.2.1 Il JDBC
Il cuore del progetto sta nella connessione della Xlet al database MySQL. Con
il java, ciò è possibile, tramite il JDBC (Java DataBase Connectivity), che è
un middleware per database che consente l'accesso alle basi di dati da
qualsiasi programma scritto con il linguaggio di programmazione Java,
indipendentemente dal tipo di DBMS utilizzato. È costituita da una API,
raggruppata nel package java.sql, che serve ai client per connettersi a un
database. Fornisce metodi per interrogare e modificare i dati. È orientata ai
database relazionali ed è Object Oriented. La piattaforma Java 2 Standard
Edition contiene le API JDBC, insieme all'implementazione di un bridge
JDBC-ODBC, che permette di connettersi a database relazionali che
supportino ODBC.
Il funzionamento è il seguente:
- 41 -
Sviluppo di un’applicazione MHP
Capitolo 4
Il metodo Class.forName() carica la classe del driver JDBC. La linea seguente
carica il driver per mioDbms nell'applicazione.
Class.forName( "com.mioDbms.mioDriver" );
Poi, il metodo DriverMangager.getConnection() crea una connessione.
Connection conn = DriverManager.getConnection(
"jdbc:mioDbms:altri dati utili per il driver",
"mioLogin",
"miaPassword" );
La stringa da utilizzare dipende dal driver JDBC che useremo. Inizia sempre
con "jdbc:", il resto varia a seconda del prodotto scelto. Una volta stabilita la
connessione, occorre passare una istruzione.
Statement stmt = conn.createStatement();
stmt.executeUpdate( "INSERT INTO miaTabella( nome )
VALUES ( 'roberto' ) " );
I dati vengono prelevati dal database col classico meccanismo delle query.
L'esempio sottostante mostra come creare ed eseguire un'interrogazione:
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery( "SELECT * FROM miaTabella" );
while ( rs.next() ) {
int numeroColonne = rs.getMetaData().getColumnCount();
for ( int i = 1 ; i <= numeroColonne ; i++ ) {
// I numeri di colonna iniziano da 1.
// Vi sono diversi metodi che convertono il valore di una colonna
//in un certo tipo.
// Vedi la documentazione per una lista delle conversioni valide.
System.out.println( "COLONNA " + i + " = " + rs.getObject(i) );
}
- 42 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
rs.close();
stmt.close();
E’ stato però riscontrato e verificato un grande problema: lo standard MHP
non supporta il JDBC.
4.2.2 Le socket
Per ovviare al problema sopra citato si è deciso di ricorrere alla seguente
soluzione: nello stesso PC in cui c’è il database MySQL viene fatto girare un
server (sempre scritto in Java), che fa da tramite tra l’applicazione MHP e il
database. Il server accede al database tramite il JDBC, e la Xlet accede al
server per mezzo delle socket.
Per realizzare un canale di comunicazione Client/Server occorre la creazione
di un programma Server che funge da ascolto su una determinata porta, e di
un programma Client che, remotamente, lo invochi.
Per la creazione del programma Server in Java è necessario seguire i seguenti
passaggi:
 Importare i package java.io e java.net per poter utilizzare le classi Socket e
ServerSocket
 Intercettare l'eccezione IOException che deve essere gestita (tramite try e
catch) o propagata (tramite throws), dato che vengono richiamati metodi
delle classi che appartengono ai package java.io e java.net.
 Creare un oggetto ServerSocket, utilizzando il costruttore ServerSocket(int
port) che si aspetta come parametro la porta del Server in ascolto per il
servizio da attivare. Ad esempio:
ServerSocket server = new ServerSocket(9999);
- 43 -
Sviluppo di un’applicazione MHP
Capitolo 4
Da notare che il numero corrispondente alla porta di ascolto non è una
stringa.

Utilizzare il metodo accept() dell'oggetto ServerSocket per poter accettare
le chiamate Client su un oggetto Socket:
Socket client = server.accept();
Il metodo che viene invocato ritorna un'oggetto
utilizzato
Socket
che potrà essere
per le comunicazioni con il client.
 Creare due oggetti DataInputStream e DataOutputStream per attivare uno
stream di comunicazione con il cliente (ovviamente il DataInputStream
servirà per leggere le richieste del client, e il DataOutputStream per
inviare risposte al client):
DataInputStream is = new DataInputStream(server.getInputStream());
DataOutputStream os = new DataOutputStream(
server.getOutputStream());
 Richiamare il metodo close() sugli oggetti dello stream e sull'oggetto
ServerSocket per chiudere i canali di comunicazione:
os.close();
is.close();
server.close();
A livello client i passaggi sono i seguenti:
 Importare i package java.io, java.net per utilizzare le classi Stream (per i
canali di comunicazione) e Socket (per il nostro scopo) .
 Intercettare l'eccezione IOException che deve essere gestita (tramite try e
catch) o propagata (tramite throws), dato che vengono richiamati metodi
delle classi che appartengono ai package java.io e java.net.
 Creare un oggetto Socket e specificare l'indirizzo IP ed il numero di porta
in ascolto sul server, caratteristiche imposte dal TCP per la comunicazione
- 44 -
Sviluppo di un’applicazione MHP
Capitolo 4
server/client. Ad esempio, per connettersi al server descritto negli esempi
sopra, si deve effettuare un'inizializzazione nel seguente modo:
Socket client = new Socket("localhost",9999);
A livello client l'indirizzo IP viene ricavato mentre la porta viene assegnata
in modo dinamico in base alla disponibilità.
 Creare il canale di comunicazione con il server per inviare e ricevere
messaggi tramite gli Stream di Byte in input ed output tramite le classi
DataInputStream
e
DataOutputStream,
associandole
ai
metodi
getInputStream e getOutputStream della classe Socket.
DataInputStream is = new DataInputStream(client.getInputStream());
DataOutputStream os = new DataOutputStream(
client.getOutputStream());
 Chiudere gli stream di comunicazione e l'oggetto socket.
is.close();
os.close();
client.close();
4.3 IL SERVER
Il server è composto dai seguenti file:
SimpleServer.java,
ServerRegistration.java,
ServerPrenotaSingolo.java,
ObjectRegistration,
ServerFilm.java,
ObjectPrenotation,
ServerPrenotation.java,
PrenotaSingolo.java,
ObjectPrenFilm,
ObjectPosti,
ObjectFilm.
Il server funziona nel seguente modo: SimpleServer è la classe che va in
esecuzione.
Il server si mette in ascolto, attendendo che la Xlet gli mandi un oggetto, che
viene poi letto. A seconda del tipo di oggetto ricevuto, il server chiama la
classe relativa.
- 45 -
Sviluppo di un’applicazione MHP
Capitolo 4
4.3.1 SimpleServer.java
import java.net.*;
import java.io.*;
public class SimpleServer {
private int port;
private ServerSocket server;
private Object obj;
private String ris;
private Object film;
private Object posti;
private Object prenotaS;
public SimpleServer (int port){
ris="";
this.port = port;
if(!startServer()) System.err.println("Errore durante la creazione
del Server");
}
private boolean startServer(){
try{
server = new ServerSocket(port);
}catch (IOException ex){
ex.printStackTrace();
return false;
}
System.out.println("Server creato con successo!");
- 46 -
Sviluppo di un’applicazione MHP
Capitolo 4
return true;
}
//metodo che viene chiamato quando va in esecuzione il server
public void runServer(){
while (true){
try{
// Il server resta in attesa di una richiesta
System.out.println("Server in attesa di richieste...");
Socket s1 = server.accept();
System.out.println("Un client si e' connesso...");
InputStream is = s1.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
try{
//viene letto l’oggetto ricevuto
obj=(Object)(ois.readObject());
System.out.println("oggetto letto");
}
catch (ClassNotFoundException e) {
System.out.println("Error: "+e.getMessage());
}
// a seconda del tipo di oggetto letto, viene chiamata la
// classe relativa
if (obj instanceof ObjectRegistration) {
ris=(new ServerRegistration((ObjectRegistration)obj)).start();
OutputStream s1out = s1.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(s1out);
// Il server invia la risposta al client
oos.writeObject(ris);
// Chiude lo stream di output e la connessione
- 47 -
Sviluppo di un’applicazione MHP
Capitolo 4
oos.close();
}
if(obj instanceof ObjectPrenotation) {
film=(new ServerFilm((ObjectPrenotation)obj)).start();
OutputStream s1out = s1.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(s1out);
oos.writeObject(film);
oos.close();
}
if (obj instanceof PrenotaSingolo) {
prenotaS=(new ServerPrenotaSingolo((
PrenotaSingolo)obj)).start();
OutputStream s1out = s1.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(s1out);
oos.writeObject(prenotaS);
oos.close();
}
if (obj instanceof ObjectPrenFilm) {
posti=(new ServerPrenotation((ObjectPrenFilm)obj)).start();
OutputStream s1out = s1.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(s1out);
oos.writeObject(posti);
oos.close();
}
s1.close();
System.out.println("Chiusura connessione effettuata\n");
}catch (IOException ex){
ex.printStackTrace();
}
- 48 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
}
public static void main(String[] args) {
SimpleServer ss = new SimpleServer(8000);
ss.runServer();
}
}
4.3.2 ServerRegistration.java
Questo file si occupa della fase di registrazione: legge dall’oggetto
ObjectRegistration i dati necessari, si connette al database MySQL e inserisce
nella tabella Cliente i dati del nuovo utente (a meno che non sia già presente
nel database).
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class ServerRegistration {
private ObjectRegistration obj;
private String ris;
public ServerRegistration(ObjectRegistration object) {
this.obj=object;
ris="";
}
- 49 -
Sviluppo di un’applicazione MHP
Capitolo 4
public String start() {
//Crea la connessione con il database MySQL
try {
Class.forName("com.mysql.jdbc.Driver");
System.out.println("eseguito class.forname");
}
catch (ClassNotFoundException e1){}
try{
String user="talax";
String pass="gufo";
String url="jdbc:mysql://localhost/cinema";
Connection con =
DriverManager.getConnection(url,user,pass);
Statement stmt=con.createStatement();
System.out.println(((ObjectRegistration)obj).getUser());
//Controlla che l’utente da inserire non sia già presente.
String query= "SELECT user FROM cliente WHERE
(user='"+((ObjectRegistration)obj).getUser()+"');";
ResultSet rm=stmt.executeQuery(query);
while (rm.next()) {
ris=rm.getString(1);
}
//Se l’utente non è presente, si procede all’inserimento.
if (ris=="") {
String query2= "INSERT INTO cliente
(user,password,nome,cognome,data_n,
citta,indirizzo) VALUES ('"+((
ObjectRegistration)obj).getUser()+
- 50 -
Sviluppo di un’applicazione MHP
Capitolo 4
"','"+((ObjectRegistration)obj).getPassword()
+"','"+((ObjectRegistration)obj).getNome()
+"','"+((ObjectRegistration)obj).getCognome
()+"','"+((ObjectRegistration)obj).getData()+
"','"+((ObjectRegistration)obj).getCitta()+
"','"+((ObjectRegistration)obj).getIndirizzo()
+"');";
stmt.executeUpdate(query2);
ris="Registrazione effettuata con successo!";
System.out.println("query effettuata");
}
else {
ris="Username esistente.";
}
rm.close();
stmt.close();
con.close();
}
catch(Exception exc) {
ris="Errore!";
}
return ris;
}
}
4.3.3 ServerFilm.java
Questo file si occupa della prima parte della prenotazione. Ha il compito di
controllare se username e password inseriti dall’utente sono corretti.
- 51 -
Sviluppo di un’applicazione MHP
Capitolo 4
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ServerFilm {
private ObjectPrenotation obj;
private Object film;
public ServerFilm(ObjectPrenotation obj) {
this.obj=obj;
}
public Object start() {
try {
Class.forName("com.mysql.jdbc.Driver");
System.out.println("eseguito class.forname");
}
catch (ClassNotFoundException e1)
{film="Errore nella connessione\nal database";}
try{
String user="talax";
String pass="gufo";
String url="jdbc:mysql://localhost/cinema";
Connection con =
DriverManager.getConnection(url,user,pass);
Statement stmt=con.createStatement();
- 52 -
Sviluppo di un’applicazione MHP
Capitolo 4
//Controlla che user e password siano corretti.
String query="SELECT user FROM cliente WHERE user=
'"+obj.getUser()+"' AND password='"+
obj.getPassword()+"';";
ResultSet rm=stmt.executeQuery(query);
String ris1="";
while(rm.next()) {
ris1=ris1+rm.getString(1);
}
rm.close();
if (ris1=="") {
System.out.println("user pwd errati");
film="Username o password errati.";
}
else {
/* Se user e password sono corretti, viene creato
l’oggetto ObjectFilm contenente la lista dei film
del cinema
*/
System.out.println("user pwd esatti");
String query2= "SELECT nome FROM film;";
ResultSet rm2=stmt.executeQuery(query2);
System.out.println("eseguita query2");
String[] nome=new String[4];
int i=0;
while (rm2.next()) {
nome[i]=rm2.getString(1);
System.out.println("nome film: "+nome[i]);
- 53 -
Sviluppo di un’applicazione MHP
Capitolo 4
i++;
}
rm2.close();
film=new ObjectFilm(nome);
}
}
catch (SQLException exc) {
film="Errore nella prenotazione";
System.out.println("SQLException: "+exc.getMessage());
}
return film;
}
}
4.3.4 ServerPrenotation.java
Questa classe si occupa della seconda parte della prenotazione. Viene
recuperata dal database la mappa dei posti relativi al film scelto.
import java.sql.*;
public class ServerPrenotation {
private ObjectPrenFilm obj;
private Object posti;
private int codice;
public ServerPrenotation(ObjectPrenFilm obj) {
this.obj=obj;
}
public Object start() {
try {
- 54 -
Sviluppo di un’applicazione MHP
Capitolo 4
Class.forName("com.mysql.jdbc.Driver");
System.out.println("eseguito class.forname");
}
catch (ClassNotFoundException e1)
{posti="Errore nella connessione\nal database";}
try{
String user="talax";
String pass="gufo";
String url="jdbc:mysql://localhost/cinema";
Connection con =
DriverManager.getConnection(url,user,pass);
Statement stmt=con.createStatement();
System.out.println("user pwd esatti");
codice=this.obj.getCodice();
String query2= "SELECT count(*) FROM
posti_"+codice+";";
ResultSet rm2=stmt.executeQuery(query2);
System.out.println("eseguita query2");
int length=0;
while (rm2.next()) {
length=Integer.parseInt(rm2.getString(1));
System.out.println("length: "+length);
}
rm2.close();
String query3= "SELECT * FROM posti_"+codice+";";
ResultSet rm3=stmt.executeQuery(query3);
int[] num=new int[length];
String[] utente=new String[length];
- 55 -
Sviluppo di un’applicazione MHP
Capitolo 4
int[] libero=new int[length];
int j=0;
while (rm3.next()) {
utente[j]=rm3.getString(1);
System.out.println(utente[j]);
num[j]=Integer.parseInt(rm3.getString(2));
System.out.println(num[j]);
libero[j]=Integer.parseInt(rm3.getString(3));
System.out.println(libero[j]);
j++;
}
posti=new ObjectPosti(utente,num,libero,codice);
rm3.close();
stmt.close();
con.close();
}
catch(SQLException exc) {
posti="Errore nella prenotazione";
System.out.println("SQLException: "+exc.getMessage());
}
return posti;
}
}
- 56 -
Sviluppo di un’applicazione MHP
Capitolo 4
4.3.5 ServerPrenotaSingolo.java
Questo file consente di prenotare un singolo posto in platea, aggiornando il
database relativo.
import java.sql.*;
public class ServerPrenotaSingolo {
private PrenotaSingolo obj;
private String ris;
public ServerPrenotaSingolo(PrenotaSingolo obj) {
this.obj=obj;
}
public Object start() {
ris="";
try {
Class.forName("com.mysql.jdbc.Driver");
System.out.println("eseguito class.forname");
}
catch (ClassNotFoundException e1){}
try{
String user="talax";
String pass="gufo";
String url="jdbc:mysql://localhost/cinema";
Connection con =
DriverManager.getConnection(url,user,pass);
Statement stmt=con.createStatement();
// Aggiorna il database dei posti in platea
// (0=occupato, 1=libero)
- 57 -
Sviluppo di un’applicazione MHP
Capitolo 4
String query= "UPDATE posti_"+obj.getCodice()+
" SET libero=0 ,utente='"+obj.getUser()+"'
WHERE num_posto="+obj.getNumero()+";";
stmt.executeUpdate(query);
ris="Prenotazione eseguita con successo!";
stmt.close();
con.close();
}
catch (SQLException e) {
System.out.println("Eccezione: "+e.getMessage());
ris="Errore prenotazione";
}
return ris;
}
}
4.3.6 PrenotaSingolo.java
Questo file rappresenta l’oggetto che viene passato a ServerPrenotaSingolo, e
contiene il nome dell’utente, il numero del posto e il codice della platea.
import java.io.*;
public class PrenotaSingolo implements Serializable {
private String user;
private int numero;
private int codice;
public PrenotaSingolo (String user, int numero, int codice) {
this.user=user;
- 58 -
Sviluppo di un’applicazione MHP
Capitolo 4
this.numero=numero;
this.codice=codice;
}
public String getUser() {
return user;
}
public int getNumero() {
return numero;
}
public int getCodice() {
return codice;
}
}
4.3.7 ObjectRegistration
Questo oggetto viene passato a ServerRegistration.java, e contiene tutti i dati
dell’utente da inserire nel database.
import java.io.*;
public class ObjectRegistration implements Serializable{
private String user;
private String password;
private String nome;
private String cognome;
- 59 -
Sviluppo di un’applicazione MHP
Capitolo 4
private String data;
private String citta;
private String indirizzo;
public ObjectRegistration(String u, String pwd, String nom, String cog,
String data, String citta, String ind) {
this.user=u;
this.password=pwd;
this.nome=nom;
this.cognome=cog;
this.data=data;
this.citta=citta;
this.indirizzo=ind;
System.out.println("creato objectRegistration");
}
public String getUser() {
return this.user;
}
public String getPassword() {
return this.password;
}
public String getNome() {
return this.nome;
- 60 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
public String getCognome() {
return this.cognome;
}
public String getData() {
return this.data;
}
public String getCitta() {
return this.citta;
}
public String getIndirizzo() {
return this.indirizzo;
}
}
4.3.8 ObjectPrenotation.java
Questo oggetto viene passato a ServerFilm.java. Contiene semplicemente user
e password per fare il login.
import java.io.*;
public class ObjectPrenotation implements Serializable {
private String user;
private String password;
- 61 -
Sviluppo di un’applicazione MHP
Capitolo 4
public ObjectPrenotation (String user, String password){
this.user=user;
this.password=password;
}
public String getUser() {
return this.user;
}
public String getPassword() {
return this.password;
}
}
4.3.9 ObjectFilm.java
Questo oggetto viene creato in ServerFilm.java. Contiene la lista di film
disponibili.
import java.io.*;
public class ObjectFilm implements Serializable{
private String[] nome;
public ObjectFilm(String[] nome) {
this.nome=nome;
}
public String getNome(int i) {
return nome[i];
}
- 62 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
4.3.10 ObjectPosti.java
Questo oggetto viene creato in ServerPrenotation.java, e contiene la mappa
dei posti in platea, con nome utente, numero del posto, flag per sapere se il
posto è libero o occupato, e codice della platea.
import java.io.*;
public class ObjectPosti implements Serializable{
private String[] utente;
private int[] num_posto;
private int[] libero;
private int codice;
public ObjectPosti(String[] utente, int[] num, int[] libero,int codice) {
this.num_posto=num;
this.libero=libero;
this.utente=utente;
this.codice=codice;
}
public String getUtente(int i) {
return utente[i];
}
public int getNumero(int i) {
return num_posto[i];
}
public int getLibero(int i) {
return libero[i];
- 63 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
public int getLength() {
return utente.length;
}
public int getCodice() {
return codice;
}
}
4.3.11 ObjectPrenFilm.java
Questo oggetto viene passato a ServerPrenotation.java, e contiene il codice
della platea.
import java.io.*;
public class ObjectPrenFilm implements Serializable{
private int codice;
public ObjectPrenFilm(int codice) {
this.codice=codice;
}
public int getCodice() {
return codice;
}
}
- 64 -
Sviluppo di un’applicazione MHP
Capitolo 4
4.4 LA XLET
La Xlet contiene i seguenti file sorgenti: BackgroundController.java,
Comunica.java,
Film.java,
InterfacciaGrafica.java,
GestoreSfondi.java,
Keypad.java,
KeypadButton.java,
Info.java,
Main.java
Platea.java, PlateaPrenota.java, Prenota.java, Registra.java, Strumenti.java,
ObjectFilm.java,
ObjectPosti.java,
ObjectPrenFilm.java,
ObjectPrenotation.java, ObjectRegistration.java, PrenotaSingolo.java (dove
questi ultimi sei file sono gli stessi presenti nel server).
Il file principale, cioè quello che implementa Xlet, è Main.java.
4.4.1 Main.java
import java.awt.event.*;
import javax.tv.xlet.Xlet;
import javax.tv.xlet.XletContext;
import javax.tv.xlet.XletStateChangeException;
import org.havi.ui.*;
import org.havi.ui.event.*;
//Classe iniziale è questa che implementa l'interfaccia Xlet e KeyListener e
//che quindi sarà utilizzata dall'application manager per gestire il
//ciclo di vita della xlet. Si occupa di inizializzare i vari componenti,
//ascoltare gli eventi dal telecomando, creare l'oggetto scene fondamentale
//per la parte grafica.
public class Main implements Xlet, KeyListener {
- 65 -
Sviluppo di un’applicazione MHP
Capitolo 4
private XletContext context;
public static GestoreSfondi gestoreSfondi;
private HScene scene;
public int tastoPremuto = 0;
private InterfacciaGrafica interfaccia;
public static String user;
public static String password;
public static String numero;
public static String ip;
//Costruttore vuoto.
public Main() {
}
// Definisco un metodo che inizializza la Xlet, e i suoi componenti.
public void initXlet(XletContext xletContext)
throws XletStateChangeException {
//xletContext utilizzato per la gestione del ciclo di vita della xlet
context = xletContext;
HSceneFactory hsceneFactory = HSceneFactory.getInstance();
//estraggo l'oggetto scene su cui si appoggiano i componenti grafici.
scene = hsceneFactory.getFullScreenScene(
HScreen.getDefaultHScreen().getDefaultHGraphicsDevice());
//le dimensioni sono quelle standard di risoluzione di un televisore
// analogico.
scene.setSize(720, 576);
- 66 -
Sviluppo di un’applicazione MHP
Capitolo 4
scene.setLayout(null);
//aggiungo l'ascoltatore degli eventi in questo caso la classe stessa.
scene.addKeyListener((KeyListener)this);
gestoreSfondi = new GestoreSfondi(context);
interfaccia = new InterfacciaGrafica(scene);
user="user";
password="password";
numero="000000000";
ip="localhost"; //indirizzo del computer in cui è in esecuzione il server
}
// Definisco il metodo che permette di mandare in esecuzione la Xlet
public void startXlet() throws XletStateChangeException {
System.out.println("Eseguo startXlet");
scene.setVisible(true);
scene.requestFocus();
interfaccia.disegnaInit();
gestoreSfondi.displayBackgroundInitImage();
}
// Definisco il metodo per mettere in pausa la Xlet
public void pauseXlet() {
System.out.println("Xlet in pausa");
context.notifyPaused();
}
// Definisco il metodo che distrugge la Xlet e rilascia le risorse.
- 67 -
Sviluppo di un’applicazione MHP
Capitolo 4
public void destroyXlet(boolean flag) throws XletStateChangeException {
if(flag){
System.out.println("Distruggi Xlet");
interfaccia.distruggi();
//rimuovo l'ascoltatore degli eventi.
scene.removeKeyListener(this);
scene.removeKeyListener((KeyListener)this);
scene.setVisible(false);
HSceneFactory.getInstance().dispose(scene);
scene = null;
gestoreSfondi.displayBackgroundExit();
context.notifyDestroyed();
}
}
// Ascoltatore degli eventi legati al telecomando. Gli eventi vengono
//passati alla classe InterfacciaGrafica che poi li passerà alle
//funzioni attive.
public void keyPressed (KeyEvent key) {
int pulsantePremuto = key.getKeyCode();
switch(pulsantePremuto){
//Tastierino numerico
case KeyEvent.VK_0:
case KeyEvent.VK_1:
case KeyEvent.VK_2:
case KeyEvent.VK_3:
case KeyEvent.VK_4:
- 68 -
Sviluppo di un’applicazione MHP
Capitolo 4
case KeyEvent.VK_5:
case KeyEvent.VK_6:
case KeyEvent.VK_7:
case KeyEvent.VK_8:
case KeyEvent.VK_9:
case 520:
//Tasti colorati
case HRcEvent.VK_COLORED_KEY_0:
//rosso
case HRcEvent.VK_COLORED_KEY_1:
//verde
case HRcEvent.VK_COLORED_KEY_2:
//giallo
case HRcEvent.VK_COLORED_KEY_3:
//blu
//Tasti direzionali
case HRcEvent.VK_UP:
case HRcEvent.VK_DOWN:
case HRcEvent.VK_RIGHT:
case HRcEvent.VK_LEFT:
case HRcEvent.VK_ENTER:
//OK
//Vengono passati gli eventi.
interfaccia.keyPressed(key);
break;
//Alla pressione del tasto EXIT del telecomando si
//richiama il metodo destroyXlet, per fermare la xlet.
case HRcEvent.VK_ESCAPE:
try{
destroyXlet(true);
}
catch (XletStateChangeException xsce){
System.out.println(xsce.toString());
- 69 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
break;
default:
break;
}
}
public void keyTyped(KeyEvent ignored) { }
public void keyReleased(KeyEvent ignored) { }
}
4.4.2 BackgroundController.java
// Importo le classi HAVi UI necessarie
import org.havi.ui.*;
// Poiché alcune configurazioni grafiche richiedono risorse scarse,
// abbiamo bisogno di usare le DAVIC resource notification API
import org.davic.resources.*;
import javax.tv.service.selection.*;
import javax.tv.media.AWTVideoSizeControl;
import javax.tv.media.AWTVideoSize;
import java.awt.Rectangle;
import javax.tv.xlet.XletContext;
- 70 -
Sviluppo di un’applicazione MHP
Capitolo 4
/**
* Questa classe gestisce la visualizzazione di immagini di sfondo in un
* semplice modo d’uso.
*/
class BackgroundController implements org.davic.resources.ResourceClient{
// Il background device che useremo per visualizzare l’immagine
private HBackgroundDevice backdevice;
// La configurazione per il background device
private HStillImageBackgroundConfiguration backconfig;
/**
* Questo metodo inizializzerà i dispositivi video e grafici per
* permettere loro di visualizzare l’immagine di sfondo.
*/
public boolean init()
{
// Per prima cosa abbiamo bisogno di prendere il background
// device che useremo per visualizzare l’immagine.
// Per fare questo, abbiamo bisogno di decidere prima quale
// HScreen utilizzeremo. In questo caso, useremo quello di
// default.
HScreen screen = HScreen.getDefaultHScreen();
// Una volta che l’abbiamo, prendiamo il background device di
// default per quello HScreen.
HBackgroundDevice backdevice =
screen.getDefaultHBackgroundDevice();
- 71 -
Sviluppo di un’applicazione MHP
Capitolo 4
// Una volta che abbiamo una referenza al dispositivo, possiamo
// ottenere una configurazione per esso.
HBackgroundConfigTemplate
backgroundConfigurationTemplate =
new HBackgroundConfigTemplate();
backgroundConfigurationTemplate.setPreference(
HBackgroundConfigTemplate.FLICKER_FILTERING,
HBackgroundConfigTemplate.REQUIRED);
HBackgroundConfiguration backconfig;
backconfig = backdevice.getBestConfiguration(
backgroundConfigurationTemplate);
// Possiamo riservare il dispositivo così che possiamo cambiare i
// settaggi su di esso?
if (backdevice.reserveDevice(this))
{
// Se possiamo, settiamo la configurazione del background
// device al primo che abbiamo preso sopra – questà è la
// configurazione di default per questo dispositivo.
try
{
backdevice.setBackgroundConfiguration(
backconfig);
}
catch (Exception ex)
{
System.out.println("Can't initialise the background
device");
- 72 -
Sviluppo di un’applicazione MHP
Capitolo 4
//Rilascia il dispositivo così che altre applicazioni
// possano usarlo, se necessario.
backdevice.releaseDevice();
return false;
}
// Dobbiamo verificare se possiamo mettere un’immagine
// di sfondo, in questa configurazione, dato che non
// possiamo farlo in qualsiasi configurazione.
if(backconfig instanceof
HStillImageBackgroundConfiguration)
{
// Possiamo usare questo.
this.backconfig =
(HStillImageBackgroundConfiguration)backconfig;
this.backdevice = backdevice;
return true;
}
else
{
// Se non possiamo, rilasciamo ancora il dispositivo
// finché non lo usiamo.
backdevice.releaseDevice();
}
}
return false;
}
- 73 -
Sviluppo di un’applicazione MHP
Capitolo 4
/**
* Libera le risorse di cui abbiamo bisogno per visualizzare immagini
* di sfondo. Alcune implementazioni lasciano l’immagine lì, ma c’è un
* pericolo esplicito nelle specifiche MHP che questo non sia possibile
* in tutte le implementazioni. Se vogliamo essere sicuri che la nostra
* immagine sia ancora visibile, non facciamo questo.
*/
public void dispose(XletContext context)
{
// Controlla che abbiamo qualcosa da disporre
if (backdevice != null)
{
this.hideVideo(context,0,0,720,576);
// Rilascia il dispositivo e cancella ogni referenza.
backdevice.releaseDevice();
backdevice = null;
backconfig = null;
}
}
/**
* Visualizza un’immagine di sfondo.
*/
public void display(String filename)
{
- 74 -
Sviluppo di un’applicazione MHP
Capitolo 4
// Controlla che abbiamo le risorse di cui necessitiamo per
// visualizzare l’immagine di sfondo.
if(backconfig != null) {
// Crea una nuova immagine di sfondo. L’immagine è
// caricata dal filename che abbiamo passato.
HBackgroundImage backimage =
new HBackgroundImage(filename);
// Ora visualizza l’immagine. Ciò può generare parecchie
// eccezioni, così dobbiamo mettere il codice in un blocco
//‘try’.
try {
backconfig.displayImage(backimage);
}
catch (java.io.IOException ioe) {
System.out.println("Can't display background image
– IO exception");
ioe.printStackTrace();
}
catch (HPermissionDeniedException hpde) {
System.out.println("Can't display background image
– permission denied");
}
catch (HConfigurationException hce) {
System.out.println("Can't display background image
– configuration exception");
hce.printStackTrace();
}
- 75 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
}
/**
* Nasconde il video che potrebbe oscurare il nostro sfondo
*/
public void hideVideo(XletContext context,int x, int y, int larg, int alt) {
// Lo sfondo potrebbe essere nascosto dal video quando parte la
// Xlet. Per risolvere questo problema, dobbiamo fare due cose:
// 1) fermare il video
// 2) ridimensionare il video così che possiamo vedere
// l’applicazione sotto ad esso. Questo non è sempre
// necessario, ma alcuni emulatori non nascondo il video
// quando lo fermiamo.
// Prende una referenza al JavaTV ServiceContextFactory
ServiceContextFactory factory;
factory = ServiceContextFactory.getInstance();
// Da ciò, possiamo ottenere una referenza al service context
// genitore della nostra Xlet. Per fare questo, abbiamo bisogno di
// una referenza al context della nostra Xlet.
ServiceContext myContext = null;
try {
myContext = factory.getServiceContext(context);
}
catch (Exception e) {
e.printStackTrace();
- 76 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
if (myContext != null) {
// Gli oggetti ServiceContentHandler sono responsabili per
// presentare le diverse parti del servizio. Ciò include i
// component multimediali.
ServiceContentHandler[] handlers;
handlers = myContext.getServiceContentHandlers();
for(int i=0; i < handlers.length ; i++) {
if (handlers[i] instanceof ServiceMediaHandler) {
// Questa è la parte Player del servizio, visto che gli
// oggetti ServiceMediaHandler sono istanze degli
// oggetti JMF Player.
javax.media.Player p = (javax.media.Player)
handlers[i];
// potremmo aver bisogno di tutto questo per veder il
// nostro sfondo…
//
p.stop();
//
p.deallocate();
// ...ma alcuni emulatori richiedono di più
AWTVideoSizeControl awtVideoSizeControl;
awtVideoSizeControl = (AWTVideoSizeControl)
p.getControl("
javax.tv.media.AWTVideoSizeControl");
// in questo caso, impostiamo la dimensione del
// video a 0, ma potremo settarla per visualizzare
- 77 -
Sviluppo di un’applicazione MHP
Capitolo 4
// una parte dello schermo.
awtVideoSizeControl.setSize(new AWTVideoSize
(new Rectangle(0, 0, 720, 576),
new Rectangle(x,y,larg,alt)));
}
}
}
else {
System.out.println("Can't get our service context. May not
be able to " + "resize the video, so our background
may not be visible");
}
}
/*********************************************************
*
* Questi metodi sono ereditati dall’interfaccia ResourceClient e sono
* usati per dire all’applicazione quando ha perso l’accesso alle sue
* risorse.
*/
/**
* Questo metodo viene chiamato quando il gestore di risorse richiede
* che concedere la risorsa. Possiamo rifiutare di fare così, ed è quello
* che facciamo in questo caso.
*/
- 78 -
Sviluppo di un’applicazione MHP
Capitolo 4
public boolean requestRelease(ResourceProxy proxy,
Object requestData) {
return false;
}
/**
* Questo metodo viene chiamato quando il gestore di risorse ci
* informa che dobbiamo rilasciare una risorsa.
*/
public void release(ResourceProxy proxy) {
// rilascia il controllo del background device
backdevice.releaseDevice();
}
/**
* Questo metodo viene chiamato quando il gestore di risorse ci dice
* che abbiamo perso l’accesso ad una risorsa.
*/
public void notifyRelease(ResourceProxy proxy) {
// rilascia il controllo del background device. Sebbene non
// abbiamo il suo controllo, questo ci rende sicuri che tutto è
// sincronizzato.
backdevice.releaseDevice();
}
}
- 79 -
Sviluppo di un’applicazione MHP
Capitolo 4
4.4.3 GestoreSfondi.java
import javax.tv.xlet.XletContext;
//Gestisce gli sfondi della xlet.
//Utilizzato dalla classe principale "Main". I metodi si appoggiano alla
//classe BackgroundController per modificare l'immagine in background.
public class GestoreSfondi {
//Context della xlet in esecuzione.
private XletContext xContext;
private BackgroundController backgroundManager;
public GestoreSfondi(XletContext context){
backgroundManager = new BackgroundController();
xContext=context;
}
//
Carica l'immagine di sfondo della xlet.
public void displayBackgroundInitImage() {
if (backgroundManager.init()) {
backgroundManager.hideVideo(xContext,230,300,300,212);
backgroundManager.display("background2.mpg");
}
}
// Carica lo sfondo di uscita della Xlet.
- 80 -
Sviluppo di un’applicazione MHP
Capitolo 4
public void displayBackgroundExit() {
backgroundManager.dispose(xContext);
}
public void cutVideo() {
if (backgroundManager.init()) {
backgroundManager.hideVideo(xContext,54,300,0,0);
backgroundManager.display("background2.mpg");
}
}
}
4.4.4 InterfacciaGrafica.java
import java.awt.Color;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import org.havi.ui.*;
import org.havi.ui.event.HRcEvent;
//Questa classe amministra la parte grafica del frame
//principale gestendo l'accesso alle varie funzionalità e
//passando gli eventi ai processi attivi.
public class InterfacciaGrafica {
private HScene scene;
public static HScene scene2;
private HIcon[] b_1;
- 81 -
Sviluppo di un’applicazione MHP
Capitolo 4
private HIcon[] ba_1;
private HText mess;
private String [] messaggio=new String[3];
public static Keypad keypad;
final int su = 1 ;
final int giu = 2 ;
final int frame1=1;
final int frame2=2;
private int frameattivo=0;
private Prenota prenota;
private Registra registra;
private Info setup;
//Utilizzata per il polimorfismo.
private Strumenti strumento=null;
//Costruttore.
public InterfacciaGrafica(HScene scenemain){
//viene passato l'oggetto scene su cui verranno
//aggiunti i vari componenti grafici.
scene=scenemain;
//scene2=scenemain;
messaggio[0]="Riempi tutti i campi e conferma i dati.";
messaggio[1]="Fai il login, scegli il film da vedere e il posto
nella sala.";
messaggio[2]="Leggi le informazioni sul Cinema Italia.";
}
- 82 -
Sviluppo di un’applicazione MHP
Capitolo 4
//Crea i componenti grafici e li visualizza.
public void disegnaInit(){
mess = new HText (messaggio[0],210,100,450,50);
mess.setFont(new Font("Arial",Font.PLAIN,20));
mess.setHorizontalAlignment(HVisible.HALIGN_LEFT);
mess.setForeground(Color.white);
mess.setBordersEnabled(false);
mess.setBackgroundMode(HVisible.NO_BACKGROUND_FILL);
scene.add(mess);
//Crea la tastiera
keypad=new Keypad(scene);
keypad.setVisible(false);
scene.add(keypad);
b_1=new HIcon[3];
ba_1=new HIcon[3];
b_1[0]=new HIcon(Toolkit.getDefaultToolkit().getImage(
"registra_off_g.png"), 50, 100, 150, 50);
b_1[0].setVisible(false);
scene.add(b_1[0]);
b_1[1]=new HIcon(Toolkit.getDefaultToolkit().getImage(
"prenota_off_g.png"), 50, 160, 150, 50);
b_1[1].setVisible(true);
scene.add(b_1[1]);
b_1[2]=new HIcon(Toolkit.getDefaultToolkit().getImage(
"info_off.png"),50,220,150,50);
b_1[2].setVisible(true);
- 83 -
Sviluppo di un’applicazione MHP
Capitolo 4
scene.add(b_1[2]);
ba_1[0]=new HIcon(Toolkit.getDefaultToolkit().getImage(
"registra_on_g.png"), 50, 100, 150, 50);
ba_1[0].setVisible(true);
scene.add(ba_1[0]);
ba_1[1]=new HIcon(Toolkit.getDefaultToolkit().getImage(
"prenota_on_g.png"), 50, 160, 150, 50);
ba_1[1].setVisible(false);
scene.add(ba_1[1]);
ba_1[2]=new HIcon(Toolkit.getDefaultToolkit().getImage(
"info_on.png"),50,220,150,50);
ba_1[2].setVisible(false);
scene.add(ba_1[2]);
prenota = new Prenota(scene);
scene.add(prenota);
prenota.setVisible(false);
registra = new Registra(scene);
scene.add(registra);
registra.setVisible(false);
setup = new Info(scene);
scene.add(setup);
setup.setVisible(false);
scene.setVisible(true);
scene.requestFocus();
System.out.println("disegnata interfaccia");
}
- 84 -
Sviluppo di un’applicazione MHP
Capitolo 4
//Grafica pulsanti.Gestisce la grafica dei pulsanti
//in relazione al fatto che la funzione corrispondente
//sia attiva/attivabile, oppure non selezionata.
//In pratica gestisce i colori dei pulsanti;
//colore rosso: funzione attivabile
//colore giallo: funzione non attivabile.
public void setframeattivo (int numero){
b_1[numero].setVisible(false);
ba_1[numero].setVisible(true);
mess.setTextContent(messaggio[frameattivo],
HVisible.NORMAL_STATE);
mess.setBounds(210,100+frameattivo*60,450,50);
scene.repaint();
}
//Viene oscurata la parte grafica e
//si ferma il processo attivo.
//Richiamato del metodo destroyXlet nel momento di
//distruzione della xlet.
public void distruggi(){
this.scene.removeAll();
this.scene.setVisible(false);
}
public void premutoEnter(){
//Metodo vuoto.
- 85 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
//Ascoltatore degli eventi del telecomando.
//La gestione delle funzionalità è stata fatta utilizzando le
//interfacce Java. Questo permette di gestire i processi in
// maniera dinamica, passando gli eventi solo al processo attivo.
public void keyPressed (KeyEvent key) {
int pulsantePremuto = key.getKeyCode();
switch(pulsantePremuto){
case KeyEvent.VK_0:
case KeyEvent.VK_1:
case KeyEvent.VK_2:
case KeyEvent.VK_3:
case KeyEvent.VK_4:
case KeyEvent.VK_5:
case KeyEvent.VK_6:
case KeyEvent.VK_7:
case KeyEvent.VK_8:
case KeyEvent.VK_9:
case 520:
if (strumento!=null){
strumento.passaEvento(key);}
break;
//Tasto rosso.
case HRcEvent.VK_COLORED_KEY_0:
if (strumento!=null){
strumento.passaEvento(key);}
break;
- 86 -
Sviluppo di un’applicazione MHP
Capitolo 4
//Tasto verde.
case HRcEvent.VK_COLORED_KEY_1:
if (strumento!=null) {
strumento.stop();
strumento=null;
scene.add(mess);}
break;
//Tasto giallo.
case HRcEvent.VK_COLORED_KEY_2:
if (strumento!=null){
strumento.passaEvento(key);}
break;
//Tasto blu.
case HRcEvent.VK_COLORED_KEY_3:
if (strumento!=null){
strumento.passaEvento(key);}
break;
case HRcEvent.VK_UP:
if (strumento != null) {
strumento.passaEvento(key);
}
else {
b_1[frameattivo].setVisible(true);
if(frameattivo <= 2 && frameattivo > 0)
frameattivo--;
setframeattivo(frameattivo);
}
break;
- 87 -
Sviluppo di un’applicazione MHP
Capitolo 4
case HRcEvent.VK_DOWN:
if (strumento != null) {
strumento.passaEvento(key);
}
else {
b_1[frameattivo].setVisible(true);
if(frameattivo >= 0 && frameattivo < 2)
frameattivo++;
setframeattivo(frameattivo);
}
break;
case HRcEvent.VK_RIGHT:
if (strumento!=null) {
strumento.passaEvento(key);}
break;
case HRcEvent.VK_LEFT:
if (strumento!=null) {
strumento.passaEvento(key);}
break;
case HRcEvent.VK_ENTER:
if (strumento!=null) {
strumento.passaEvento(key);}
else {
scene.remove(mess);
Main.gestoreSfondi.cutVideo();
- 88 -
Sviluppo di un’applicazione MHP
Capitolo 4
//Funzione registra.
if(frameattivo == 0 &&
registra.isVisible() == false){
System.out.println("Registra");
if( strumento != null) strumento.stop();
strumento = registra;
strumento.start();
}
//Funzione prenota.
if(frameattivo == 1 &&
prenota.isVisible() == false){
System.out.println("Prenota");
if( strumento != null) strumento.stop();
strumento = prenota;
strumento.start();
}
//Funzione setup.
if(frameattivo == 2 &&
setup.isVisible() == false){
System.out.println("Setup");
if( strumento != null) strumento.stop();
strumento = setup;
strumento.start();
}
}
break;
default:
- 89 -
Sviluppo di un’applicazione MHP
Capitolo 4
break;
}
}
}
4.4.5 Keypad.java
import java.awt.Color;
import java.awt.Font;
import org.havi.ui.*;
import org.havi.ui.event.*;
//Questa classe implementa la tastiera stile cellulare.
public class Keypad extends HComponent {
private KeypadButton[] button;
private HContainer container;
private HScene scene;
private int bottone;
private boolean iniziato;
private long tempoInizio;
private int numeroPremuto;
private int letteraPremuta;
int length=0;
private char[] subChar=null;
private String puls;
private HText cancella;
- 90 -
Sviluppo di un’applicazione MHP
Capitolo 4
public Keypad(HScene scenemain) {
this.scene=scenemain;
}
public void start() {
bottone=-1;
iniziato=false;
letteraPremuta=0;
puls="";
System.out.println("creo tastiera");
container=new HContainer(0,0,720,576);
System.out.println("creato container");
button=new KeypadButton[10];
System.out.println("creato array bottoni tastiera");
//Crea i tasti da visualizzare.
button[0] = new
KeypadButton(container, "0","_0@",109,476,95,20);
button[1] = new
KeypadButton(container,"1",".1",60,350,95,20);
button[2] = new
KeypadButton(container,"2","abc2äå",109,350,95,20);
button[3] = new
KeypadButton(container,"3","def3",158,350,95,20);
button[4] = new
KeypadButton(container,"4","ghi4",60,392,95,20);
button[5] = new
KeypadButton(container,"5","jkl5",109,392,95,20);
- 91 -
Sviluppo di un’applicazione MHP
Capitolo 4
button[6] = new
KeypadButton(container,"6","mno6ö",158,392,95,20);
button[7] = new
KeypadButton(container,"7","pqrs7",60,434,95,20);
button[8] = new
KeypadButton(container,"8","tuv8",109,434,95,20);
button[9] = new
KeypadButton(container,"9","wxyz9",158,434,95,20);
cancella = new HText("Premi FRECCIA SINISTRA per
cancellare una lettera.",190,400,500,40);
cancella.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
cancella.setBordersEnabled(false);
cancella.setForeground(Color.white);
cancella.setFont(new Font("Arial",Font.PLAIN,20));
System.out.println("creati tutti i bottoni tastiera");
for (int i=0;i<=0;i++) {
button[i].setVisible(true);
container.add(button[i]);
}
container.add(cancella);
scene.add(container);
}
//Metodo chiamato quando si deve togliere la tastiera
public void remove() {
System.out.println("rimuovo tastiera");
container.removeAll();
scene.remove(container);
- 92 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
public void setTextNumber(HText textbox, int numero, int ta) {
int num;
if (ta==4 || ta==5) {
num=2;
}
else {
num=4;
}
char[] old=(textbox.getName()).toCharArray();
if (old.length==num) {}
else {
textbox.setName(textbox.getName()+
String.valueOf(numero));
System.out.println("Name+puls=\n"+textbox.getName());
textbox.setTextContent(textbox.getName(),
HVisible.NORMAL_STATE);
}
}
//Imposta il testo a seconda del tasto premuto e a seconda
//se il tasto è stato premuto più di una volta.
public void setText(HText textbox, int pulsante){
if (pulsante==HRcEvent.VK_LEFT)
{
System.out.println("Premuta freccia sinistra");
char[] old=(textbox.getName()).toCharArray();
- 93 -
Sviluppo di un’applicazione MHP
Capitolo 4
System.out.println("inizializzato old");
String name="";
for (int i=0;i<old.length-1;i++) {
name=name+String.valueOf(old[i]);
}
System.out.println("Name=\n"+name);
System.out.println("riempito name");
textbox.setName(name+puls);
System.out.println("Name+puls=\n"+name+puls);
textbox.setTextContent(textbox.getName(),
HVisible.NORMAL_STATE);
}
else {
numeroPremuto=pulsante-48;
subChar=button[numeroPremuto].getChar();
length=subChar.length;
if(numeroPremuto==bottone && iniziato==true) {
letteraPremuta++;
if (letteraPremuta>=length) {
letteraPremuta=0;
}
if (System.currentTimeMillis()-tempoInizio<900) {
puls=String.valueOf(subChar[letteraPremuta]);
System.out.println("Puls=\n"+puls);
if (puls.equals("_")) {
- 94 -
Sviluppo di un’applicazione MHP
Capitolo 4
puls=" ";
System.out.println("Puls2=\n"+puls);}
System.out.println("entrato in cambia carattere");
char[] old=(textbox.getName()).toCharArray();
System.out.println("inizializzato old");
String name="";
for (int i=0;i<old.length-1;i++) {
name=name+String.valueOf(old[i]);
}
System.out.println("Name=\n"+name);
System.out.println("riempito name");
textbox.setName(name+puls);
System.out.println("Name+puls=\n"+name+puls);
textbox.setTextContent(textbox.getName(),
HVisible.NORMAL_STATE);
tempoInizio=System.currentTimeMillis();
}
else {
letteraPremuta=0;
tempoInizio=System.currentTimeMillis();
puls=String.valueOf(subChar[letteraPremuta]);
if (puls.equals("_")) {
puls=" ";
System.out.println("Puls2=\n"+puls);}
iniziato=true;
textbox.setName(textbox.getName()+puls);
textbox.setTextContent(textbox.getName(),
HVisible.NORMAL_STATE);
- 95 -
Sviluppo di un’applicazione MHP
Capitolo 4
System.out.println("premuto per la prima
volta "+numeroPremuto);
}
}
else {
letteraPremuta=0;
tempoInizio=System.currentTimeMillis();
puls=String.valueOf(subChar[letteraPremuta]);
if (puls.equals("_")) {
puls=" ";
System.out.println("Puls2=\n"+puls);}
iniziato=true;
textbox.setName(textbox.getName()+puls);
textbox.setTextContent(textbox.getName(),
HVisible.NORMAL_STATE);
System.out.println("premuto per la prima
volta "+numeroPremuto);
}
bottone=numeroPremuto;
puls="";
}
}
}
- 96 -
Sviluppo di un’applicazione MHP
Capitolo 4
4.4.6 KeypadButton.java
import java.awt.*;
import org.havi.ui.*;
//Classe che implementa i tasti della tastiera.
public class KeypadButton extends HComponent{
private HText button;
private HText subButton;
private String numero;
private String lettere;
private HIcon border;
private char[] subChar=null;
public KeypadButton(HContainer container, String numero,
String lettere, int x, int y, int width, int length) {
super.setBounds(x,y,width,length);
this.numero=numero;
this.lettere=lettere;
subChar=lettere.toCharArray();
border=new HIcon(Toolkit.getDefaultToolkit().getImage(
"bordo2.jpg"));
button=new HText(this.numero,x,y,width/2,length);
button.setBackground(Color.yellow);
button.setBackgroundMode(HVisible.BACKGROUND_FILL);
button.setForeground(Color.blue);
button.setBordersEnabled(true);
button.setFont(new Font("Arial",Font.PLAIN,23));
subButton=new HText(this.lettere,x,y+20,width/2,length);
- 97 -
Sviluppo di un’applicazione MHP
Capitolo 4
subButton.setBackground(Color.yellow);
subButton.setBackgroundMode(
HVisible.BACKGROUND_FILL);
subButton.setForeground(Color.blue);
subButton.setBordersEnabled(true);
subButton.setFont(new Font("Arial",Font.PLAIN,16));
border.setBounds((button.getX())-2,(button.getY())-2,51,44);
container.add(button);
container.add(subButton);
container.add(border);
}
public String getNumero() {
return numero;
}
public char[] getChar() {
return subChar;
}
}
4.4.7 Comunica.java
import java.net.*;
import java.io.*;
//Questa classe permette alla xlet di comunicare con il server.
public class Comunica {
- 98 -
Sviluppo di un’applicazione MHP
Capitolo 4
private String IP;
private int port;
private Object obj;
private Object objW;
public Comunica(String sIP,int p){
port=p;
IP=sIP;
}
public Object Connetti(Object object){
obj=null;
objW=object;
try{
// Apre una connessione verso un server in ascolto
// sulla porta port all'indirizzo IP
System.out.println("Apertura Socket...");
Socket sock = new Socket(IP,port);
System.out.println("creato socket");
OutputStream s1out = sock.getOutputStream();
ObjectOutputStream oos =
new ObjectOutputStream(s1out);
System.out.println("impostato outpustream");
oos.writeObject(objW);
// Ricava lo stream di input dal socket sock
// ed utilizza un oggetto wrapper di classe BufferedReader
// per semplificare le operazioni di lettura
InputStream is = sock.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
try{
- 99 -
Sviluppo di un’applicazione MHP
Capitolo 4
obj=ois.readObject();}
catch (ClassNotFoundException e) {
System.out.println("Error: "+e.getMessage());
}
ois.close();
sock.close();
System.out.println("Chiusura connessione effettuata");
}catch (ConnectException connExc){
System.out.println("Errore nella connessione ");
obj="Errore nella connessione";
}
catch (IOException ex){
ex.printStackTrace();
}
return obj;
}
}
4.4.8 Strumenti.java
import java.awt.event.KeyEvent;
import org.havi.ui.*;
import org.havi.ui.HContainer;
//Questa classe viene estesa dai vari strumenti
//registra, prenota, info.
public class Strumenti extends HComponent{
protected HScene scene;
protected HContainer container;
- 100 -
Sviluppo di un’applicazione MHP
Capitolo 4
public Strumenti(HScene scenemain) {
scene = scenemain;
}
public void start() {}
public void stop() {
this.setVisible(false);
container.removeAll();
container.setVisible(false);
InterfacciaGrafica.keypad.remove();
scene.remove(container);
System.out.println("Stop "+this.toString());
Main.gestoreSfondi.displayBackgroundInitImage();
scene.repaint();
}
public void passaEvento(KeyEvent key) {}
}
4.4.9 Registra.java
import java.awt.Color;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import org.havi.ui.*;
import org.havi.ui.event.*;
//Questa classe implementa tutta la fase della registrazione
//di un nuovo utente.
- 101 -
Sviluppo di un’applicazione MHP
Capitolo 4
public class Registra extends Strumenti{
private HText [] campoTesto;
private HText riempi;
private HText user;
private HText password;
private HText nome;
private HText cognome;
private HText data;
private HText citta;
private HText indirizzo;
private HText regOK;
private boolean reg;
private HText invia;
private HText indietro;
private HIcon border;
private int testoAttivo;
public Registra(HScene scenemain) {
super(scenemain);
}
public void start() {
reg=false;
border=new
HIcon(Toolkit.getDefaultToolkit().getImage("bordo.jpg"));
testoAttivo=0;
- 102 -
Sviluppo di un’applicazione MHP
Capitolo 4
riempi=new HText("",400,450,200,30);
riempi.setFont(new Font("Arial",Font.PLAIN,20));
riempi.setHorizontalAlignment(HVisible.HALIGN_CENTER);
riempi.setForeground(Color.orange);
riempi.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
riempi.setBordersEnabled(false);
container=new HContainer(0,0,720,576);
campoTesto=new HText [9];
user= new HText ("Username:",340,100,100,20);
user.setFont(new Font("Arial",Font.PLAIN,20));
user.setHorizontalAlignment(HVisible.HALIGN_RIGHT);
user.setForeground(Color.white);
user.setBordersEnabled(false);
user.setBackgroundMode(HVisible.NO_BACKGROUND_FILL);
container.add(user);
campoTesto[0]=new HText("",450,100,170,20);
campoTesto[0].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[0].setHorizontalAlignment(
HVisible.HALIGN_RIGHT);
campoTesto[0].setForeground(Color.black);
campoTesto[0].setBackground(Color.white);
campoTesto[0].setBordersEnabled(true);
campoTesto[0].setBackgroundMode(
HVisible.BACKGROUND_FILL);
container.add(campoTesto[0]);
System.out.println("Aggiunto user");
- 103 -
Sviluppo di un’applicazione MHP
Capitolo 4
password= new HText ("Password:",340,130,100,20);
password.setFont(new Font("Arial",Font.PLAIN,20));
password.setHorizontalAlignment(HVisible.HALIGN_RIGHT);
password.setForeground(Color.white);
password.setBordersEnabled(false);
password.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
container.add(password);
campoTesto[1]=new HText("",450,130,170,20);
campoTesto[1].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[1].setHorizontalAlignment(
HVisible.HALIGN_RIGHT);
campoTesto[1].setForeground(Color.black);
campoTesto[1].setBackground(Color.white);
campoTesto[1].setBordersEnabled(true);
campoTesto[1].setBackgroundMode(
HVisible.BACKGROUND_FILL);
container.add(campoTesto[1]);
System.out.println("Aggiunto password");
nome= new HText ("Nome:",340,170,100,20);
nome.setFont(new Font("Arial",Font.PLAIN,20));
nome.setHorizontalAlignment(HVisible.HALIGN_RIGHT);
nome.setForeground(Color.white);
nome.setBordersEnabled(false);
nome.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
container.add(nome);
campoTesto[2]=new HText("",450,170,170,20);
- 104 -
Sviluppo di un’applicazione MHP
Capitolo 4
campoTesto[2].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[2].setHorizontalAlignment(
HVisible.HALIGN_RIGHT);
campoTesto[2].setForeground(Color.black);
campoTesto[2].setBackground(Color.white);
campoTesto[2].setBordersEnabled(true);
campoTesto[2].setBackgroundMode(
HVisible.BACKGROUND_FILL);
container.add(campoTesto[2]);
System.out.println("Aggiunto nome");
cognome= new HText ("Cognome:",340,200,100,20);
cognome.setFont(new Font("Arial",Font.PLAIN,20));
cognome.setHorizontalAlignment(HVisible.HALIGN_RIGHT);
cognome.setForeground(Color.white);
cognome.setBordersEnabled(false);
cognome.setBackgroundMode
(HVisible.NO_BACKGROUND_FILL);
container.add(cognome);
campoTesto[3]=new HText("",450,200,170,20);
campoTesto[3].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[3].setHorizontalAlignment
(HVisible.HALIGN_RIGHT);
campoTesto[3].setForeground(Color.black);
campoTesto[3].setBackground(Color.white);
campoTesto[3].setBordersEnabled(true);
campoTesto[3].setBackgroundMode(
HVisible.BACKGROUND_FILL);
container.add(campoTesto[3]);
- 105 -
Sviluppo di un’applicazione MHP
Capitolo 4
System.out.println("Aggiunto cognome");
data= new HText (
"Data di nascita (gg-mm-aaa):",190,230,250,20);
data.setFont(new Font("Arial",Font.PLAIN,20));
data.setHorizontalAlignment(HVisible.HALIGN_RIGHT);
data.setForeground(Color.white);
data.setBordersEnabled(false);
data.setBackgroundMode(HVisible.NO_BACKGROUND_FILL);
container.add(data);
campoTesto[4]=new HText("",450,230,35,20);
campoTesto[4].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[4].setHorizontalAlignment(
HVisible.HALIGN_RIGHT);
campoTesto[4].setForeground(Color.black);
campoTesto[4].setBackground(Color.white);
campoTesto[4].setBackgroundMode(
HVisible.BACKGROUND_FILL);
campoTesto[4].setBordersEnabled(true);
container.add(campoTesto[4]);
campoTesto[5]=new HText("",495,230,35,20);
campoTesto[5].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[5].setHorizontalAlignment(
HVisible.HALIGN_RIGHT);
campoTesto[5].setForeground(Color.black);
campoTesto[5].setBackground(Color.white);
campoTesto[5].setBackgroundMode(
HVisible.BACKGROUND_FILL);
campoTesto[5].setBordersEnabled(true);
- 106 -
Sviluppo di un’applicazione MHP
Capitolo 4
container.add(campoTesto[5]);
campoTesto[6]=new HText("",540,230,80,20);
campoTesto[6].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[6].setHorizontalAlignment(
HVisible.HALIGN_RIGHT);
campoTesto[6].setForeground(Color.black);
campoTesto[6].setBackground(Color.white);
campoTesto[6].setBackgroundMode(
HVisible.BACKGROUND_FILL);
campoTesto[6].setBordersEnabled(true);
container.add(campoTesto[6]);
System.out.println("Aggiunto data");
citta= new HText ("Città:",340,260,100,20);
citta.setFont(new Font("Arial",Font.PLAIN,20));
citta.setHorizontalAlignment(HVisible.HALIGN_RIGHT);
citta.setForeground(Color.white);
citta.setBordersEnabled(false);
citta.setBackgroundMode(HVisible.NO_BACKGROUND_FILL);
container.add(citta);
campoTesto[7]=new HText("",450,260,170,20);
campoTesto[7].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[7].setHorizontalAlignment(
HVisible.HALIGN_RIGHT);
campoTesto[7].setForeground(Color.black);
campoTesto[7].setBackground(Color.white);
campoTesto[7].setBackgroundMode(
HVisible.BACKGROUND_FILL);
campoTesto[7].setBordersEnabled(true);
- 107 -
Sviluppo di un’applicazione MHP
Capitolo 4
container.add(campoTesto[7]);
System.out.println("Aggiunto città");
indirizzo= new HText ("Indirizzo:",340,290,100,20);
indirizzo.setFont(new Font("Arial",Font.PLAIN,20));
indirizzo.setHorizontalAlignment(HVisible.HALIGN_RIGHT);
indirizzo.setForeground(Color.white);
indirizzo.setBordersEnabled(false);
indirizzo.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
container.add(indirizzo);
campoTesto[8]=new HText("",450,290,170,20);
campoTesto[8].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[8].setHorizontalAlignment(
HVisible.HALIGN_RIGHT);
campoTesto[8].setForeground(Color.black);
campoTesto[8].setBackground(Color.white);
campoTesto[8].setBackgroundMode
(HVisible.BACKGROUND_FILL);
campoTesto[8].setBordersEnabled(true);
container.add(campoTesto[8]);
System.out.println("Aggiunto indirizzo");
for (int i=0;i<9;i++) {
campoTesto[i].setName("");
}
invia= new HText ("INVIA",360,345,130,30);
invia.setFont(new Font("Arial",Font.BOLD,20));
invia.setForeground(Color.white);
invia.setBordersEnabled(false);
- 108 -
Sviluppo di un’applicazione MHP
Capitolo 4
invia.setBackground(Color.red);
invia.setBackgroundMode(HVisible.BACKGROUND_FILL);
container.add(invia);
System.out.println("Aggiunto invia");
indietro= new HText ("Indietro",520,345,130,30);
indietro.setFont(new Font("Arial",Font.BOLD,20));
indietro.setForeground(Color.blue);
indietro.setBordersEnabled(false);
indietro.setBackground(Color.green);
indietro.setBackgroundMode(HVisible.BACKGROUND_FILL);
container.add(indietro);
System.out.println("Aggiunto indietro");
border.setBounds((campoTesto[0].getX())-4,
(campoTesto[0].getY())-4,(campoTesto[0].getWidth())+8,
(campoTesto[0].getHeight())+8);
container.add(border);
container.setVisible(true);
scene.add(container);
System.out.println("Aggiunto container");
(InterfacciaGrafica.keypad).start();
scene.repaint();
System.out.println("Scene.repaint()");
super.setVisible(true);
}
//Messaggio visualizzato se l’utente non ha compilato tutti i campi
public void riempi(String s) {
System.out.println("entrato in riempi");
- 109 -
Sviluppo di un’applicazione MHP
Capitolo 4
riempi.setTextContent("Inserisci "+s,
HVisible.NORMAL_STATE);
container.add(riempi);
scene.add(container);
System.out.println("primo scene.repaint");
scene.repaint();
}
public void invia () {
System.out.println("entrato in invia");
if (campoTesto[0].getName()=="")
this.riempi("user");
else if(campoTesto[1].getName()=="")
this.riempi("password");
else if(campoTesto[2].getName()=="")
this.riempi("nome");
else if(campoTesto[3].getName()=="")
this.riempi("cognome");
else if(campoTesto[4].getName()=="")
this.riempi("data");
else if(campoTesto[5].getName()=="")
this.riempi("data");
else if(campoTesto[6].getName()=="")
this.riempi("data");
else if(campoTesto[7].getName()=="")
this.riempi("città");
else if(campoTesto[8].getName()=="")
this.riempi("indirizzo");
- 110 -
Sviluppo di un’applicazione MHP
Capitolo 4
else {
//Procede alla registrazione del nuovo utente,
// connettendosi al server tramite la classe Comunica.
ObjectRegistration obReg=new ObjectRegistration
(campoTesto[0].getName(),
campoTesto[1].getName(),
campoTesto[2].getName(),
campoTesto[3].getName(),
campoTesto[6].getName()+""+campoTesto[5].getName()
+"-"+campoTesto[4].getName(),
campoTesto[7].getName(),
campoTesto[8].getName());
Comunica comunica=new Comunica(Main.ip,8000);
String str=(String)(comunica.Connetti(obReg));
reg=true;
regOK=new HText(str,340,130,250,50);
regOK.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
regOK.setForeground(Color.white);
regOK.setFont(new Font("Arial",Font.PLAIN,22));
container.removeAll();
container.add(regOK);
indietro.setBounds(420,250,130,30);
container.add(indietro);
InterfacciaGrafica.keypad.remove();
scene.add(container);
- 111 -
Sviluppo di un’applicazione MHP
Capitolo 4
scene.repaint();
}
}
//Imposta la casella attiva.
public void setTestoAttivo(int numero)
{
border.setBounds((campoTesto[testoAttivo].getX())-4,
(campoTesto[testoAttivo].getY())-4,
(campoTesto[testoAttivo].getWidth())+8,
(campoTesto[testoAttivo].getHeight())+8);
System.out.println("impostato testo attivo");
}
public void passaEvento(KeyEvent key) {
int pulsantePremuto = key.getKeyCode();
switch(pulsantePremuto){
case HRcEvent.VK_UP:
if(reg==false) {
if(testoAttivo <= 8 && testoAttivo > 0) testoAttivo--;
setTestoAttivo(testoAttivo);
}
break;
case HRcEvent.VK_DOWN:
if (reg==false) {
if(testoAttivo >= 0 && testoAttivo < 8) testoAttivo++;
setTestoAttivo(testoAttivo);
}
break;
- 112 -
Sviluppo di un’applicazione MHP
Capitolo 4
case HRcEvent.VK_COLORED_KEY_0:
if (reg==false) {
this.invia();
}
break;
case HRcEvent.VK_0:
if (testoAttivo==4 || testoAttivo==5 || testoAttivo==6)
{
(InterfacciaGrafica.keypad).setTextNumber
(campoTesto[testoAttivo],0,testoAttivo);
break;
}
case HRcEvent.VK_1:
if (testoAttivo==4 || testoAttivo==5 || testoAttivo==6)
{
(InterfacciaGrafica.keypad).setTextNumber
(campoTesto[testoAttivo],1,testoAttivo);
break;
}
case HRcEvent.VK_2:
if (testoAttivo==4 || testoAttivo==5 || testoAttivo==6)
{
(InterfacciaGrafica.keypad).setTextNumber
(campoTesto[testoAttivo],2,testoAttivo);
break;
}
- 113 -
Sviluppo di un’applicazione MHP
Capitolo 4
case HRcEvent.VK_3:
if (testoAttivo==4 || testoAttivo==5 || testoAttivo==6)
{
(InterfacciaGrafica.keypad).setTextNumber
(campoTesto[testoAttivo],3,testoAttivo);
break;
}
case HRcEvent.VK_4:
if (testoAttivo==4 || testoAttivo==5 || testoAttivo==6)
{
(InterfacciaGrafica.keypad).setTextNumber
(campoTesto[testoAttivo],4,testoAttivo);
break;
}
case HRcEvent.VK_5:
if (testoAttivo==4 || testoAttivo==5 || testoAttivo==6)
{
(InterfacciaGrafica.keypad).setTextNumber
(campoTesto[testoAttivo],5,testoAttivo);
break;
}
case HRcEvent.VK_6:
if (testoAttivo==4 || testoAttivo==5 || testoAttivo==6)
{
- 114 -
Sviluppo di un’applicazione MHP
Capitolo 4
(InterfacciaGrafica.keypad).setTextNumber
(campoTesto[testoAttivo],6,testoAttivo);
break;
}
case HRcEvent.VK_7:
if (testoAttivo==4 || testoAttivo==5 || testoAttivo==6)
{
(InterfacciaGrafica.keypad).setTextNumber
(campoTesto[testoAttivo],7,testoAttivo);
break;
}
case HRcEvent.VK_8:
if (testoAttivo==4 || testoAttivo==5 || testoAttivo==6)
{
(InterfacciaGrafica.keypad).setTextNumber
(campoTesto[testoAttivo],8,testoAttivo);
break;
}
case HRcEvent.VK_9:
if (testoAttivo==4 || testoAttivo==5 || testoAttivo==6)
{
(InterfacciaGrafica.keypad).setTextNumber
(campoTesto[testoAttivo],9,testoAttivo);
break;
}
- 115 -
Sviluppo di un’applicazione MHP
Capitolo 4
case HRcEvent.VK_LEFT:
if (reg==false) {
(InterfacciaGrafica.keypad).setText
(campoTesto[testoAttivo],pulsantePremuto);
}
break;
case HRcEvent.VK_COLORED_KEY_1:
case HRcEvent.VK_COLORED_KEY_2:
case HRcEvent.VK_COLORED_KEY_3:
case HRcEvent.VK_ENTER:
default:
break;
}
}
}
4.4.10 Prenota.java
import java.awt.Color;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import org.havi.ui.*;
import org.havi.ui.event.HRcEvent;
//Questa classe si occupa della fase della prenotazione.
//Più precisamente, si occupa della fase di login.
public class Prenota extends Strumenti{
- 116 -
Sviluppo di un’applicazione MHP
Capitolo 4
private HText user;
private HText password;
private HText conferma;
private HText indietro;
private HText [] campoTesto;
private HIcon border;
private int testoAttivo;
private boolean filmFlag;
private Film disFilm;
private String user2;
private String pwd;
private Object film;
private HText riempi;
public Prenota(HScene scenemain) {
super(scenemain);
}
public void start() {
//Vengono impostate le varie caselle di testo, le scritte
//e i pulsanti.
testoAttivo=0;
filmFlag=false;
disFilm=new Film(scene);
disFilm.setVisible(false);
campoTesto=new HText [2];
border=new
HIcon(Toolkit.getDefaultToolkit().getImage("bordo.jpg"));
container=new HContainer(0,0,720,576);
- 117 -
Sviluppo di un’applicazione MHP
Capitolo 4
user= new HText ("Username:",340,100,100,20);
user.setFont(new Font("Arial",Font.PLAIN,20));
user.setHorizontalAlignment(HVisible.HALIGN_RIGHT);
user.setForeground(Color.white);
user.setBordersEnabled(false);
user.setBackgroundMode(HVisible.NO_BACKGROUND_FILL);
container.add(user);
riempi=new HText("",400,250,200,30);
riempi.setFont(new Font("Arial",Font.PLAIN,20));
riempi.setHorizontalAlignment(HVisible.HALIGN_CENTER);
riempi.setForeground(Color.orange);
riempi.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
riempi.setBordersEnabled(false);
campoTesto[0]=new HText("",450,100,170,20);
campoTesto[0].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[0].setHorizontalAlignment(
HVisible.HALIGN_RIGHT);
campoTesto[0].setForeground(Color.black);
campoTesto[0].setBackground(Color.white);
campoTesto[0].setBordersEnabled(true);
campoTesto[0].setBackgroundMode(
HVisible.BACKGROUND_FILL);
container.add(campoTesto[0]);
System.out.println("Aggiunto user");
password= new HText ("Password:",340,130,100,20);
password.setFont(new Font("Arial",Font.PLAIN,20));
password.setHorizontalAlignment(HVisible.HALIGN_RIGHT);
- 118 -
Sviluppo di un’applicazione MHP
Capitolo 4
password.setForeground(Color.white);
password.setBordersEnabled(false);
password.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
container.add(password);
campoTesto[1]=new HText("",450,130,170,20);
campoTesto[1].setFont(new Font("Arial",Font.PLAIN,20));
campoTesto[1].setHorizontalAlignment(
HVisible.HALIGN_RIGHT);
campoTesto[1].setForeground(Color.black);
campoTesto[1].setBackground(Color.white);
campoTesto[1].setBordersEnabled(true);
campoTesto[1].setBackgroundMode
(HVisible.BACKGROUND_FILL);
container.add(campoTesto[1]);
System.out.println("Aggiunto password");
for (int i=0;i<2;i++) {
campoTesto[i].setName("");
}
conferma= new HText ("ENTRA",360,190,130,30);
conferma.setFont(new Font("Arial",Font.BOLD,20));
conferma.setForeground(Color.white);
conferma.setBordersEnabled(false);
conferma.setBackground(Color.red);
conferma.setBackgroundMode(
HVisible.BACKGROUND_FILL);
container.add(conferma);
System.out.println("Aggiunto conferma");
- 119 -
Sviluppo di un’applicazione MHP
Capitolo 4
indietro= new HText ("Indietro",520,190,130,30);
indietro.setFont(new Font("Arial",Font.BOLD,20));
indietro.setForeground(Color.blue);
indietro.setBordersEnabled(false);
indietro.setBackground(Color.green);
indietro.setBackgroundMode(HVisible.BACKGROUND_FILL);
container.add(indietro);
System.out.println("Aggiunto indietro");
border.setBounds((campoTesto[0].getX())-4,
(campoTesto[0].getY())-4,(campoTesto[0].getWidth())+8,
(campoTesto[0].getHeight())+8);
container.add(border);
container.setVisible(true);
scene.add(container);
(InterfacciaGrafica.keypad).start();
scene.repaint();
super.setVisible(true);
}
//Visualizza un messaggio se non sono stati riempiti i campi..
public void riempi(String s) {
System.out.println("entrato in riempi");
riempi.setTextContent("Inserisci "+s,
HVisible.NORMAL_STATE);
container.add(riempi);
scene.add(container);
System.out.println("primo scene.repaint");
scene.repaint();
- 120 -
Sviluppo di un’applicazione MHP
Capitolo 4
}
//Cambia il colore del bordo della casella di testo attiva.
public void setTestoAttivo(int numero)
{
border.setBounds((campoTesto[testoAttivo].getX())4,(campoTesto[testoAttivo].getY())4,(campoTesto[testoAttivo].getWidth())+
8,(campoTesto[testoAttivo].getHeight())+8);
}
//Metodo chiamato quando viene premuto il tasto rosso
//del telecomando.
public void entra() {
System.out.println("entrato in invia");
if (campoTesto[0].getName()=="")
this.riempi("user");
else if(campoTesto[1].getName()=="")
this.riempi("password");
else {
//Avvia la comunicazione con il server.
Comunica com=new Comunica(Main.ip,8000);
user2=campoTesto[0].getName();
pwd=campoTesto[1].getName();
ObjectPrenotation pren=
new ObjectPrenotation(user2,pwd);
System.out.println("creato ObjectPrenotation");
film=com.Connetti(pren);
- 121 -
Sviluppo di un’applicazione MHP
Capitolo 4
System.out.println("ritornato film");
if (film instanceof ObjectFilm) {
//Viene visualizzato l’elenco dei film.
container.removeAll();
InterfacciaGrafica.keypad.remove();
scene.remove(container);
disFilm.disegna(user2,(ObjectFilm)film);
filmFlag=true;
}
if(film instanceof String) {
//Viene visualizzato un messaggio di errore.
user2="";
pwd="";
System.out.println(film);
HText pren2=
new HText((String)film,340,130,300,50);
pren2.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
pren2.setForeground(Color.white);
pren2.setFont(new Font("Arial",Font.PLAIN,22));
container.removeAll();
indietro.setBounds(440,200,100,20);
container.add(indietro);
InterfacciaGrafica.keypad.remove();
container.add(pren2);
- 122 -
Sviluppo di un’applicazione MHP
Capitolo 4
scene.repaint();
}
}
}
public void stop() {
if (filmFlag) {
disFilm.stop();
super.stop();
}
else super.stop();
}
public void passaEvento(KeyEvent key) {
int pulsantePremuto = key.getKeyCode();
switch(pulsantePremuto){
case HRcEvent.VK_UP:
if (filmFlag) {
disFilm.passaEvento(key);}
else {
if(testoAttivo <= 1 && testoAttivo > 0)
testoAttivo--;
setTestoAttivo(testoAttivo);
}
break;
case HRcEvent.VK_DOWN:
if (filmFlag) {
disFilm.passaEvento(key);}
- 123 -
Sviluppo di un’applicazione MHP
Capitolo 4
else {
if(testoAttivo >= 0 && testoAttivo < 1)
testoAttivo++;
setTestoAttivo(testoAttivo);}
break;
case HRcEvent.VK_ENTER:
System.out.println("Premuto enter in prenota");
if(filmFlag) {disFilm.passaEvento(key);}
else {System.out.println("bo");}
break;
case HRcEvent.VK_0:
case HRcEvent.VK_1:
case HRcEvent.VK_2:
case HRcEvent.VK_3:
case HRcEvent.VK_4:
case HRcEvent.VK_5:
case HRcEvent.VK_6:
case HRcEvent.VK_7:
case HRcEvent.VK_8:
case HRcEvent.VK_9:
case HRcEvent.VK_LEFT:
case HRcEvent.VK_RIGHT:
System.out.println("Premuta freccia in prenota");
if (filmFlag) {disFilm.passaEvento(key);}
else {
(InterfacciaGrafica.keypad).setText(
campoTesto[testoAttivo],
pulsantePremuto);}
- 124 -
Sviluppo di un’applicazione MHP
Capitolo 4
break;
case HRcEvent.VK_COLORED_KEY_0:
if (filmFlag) {disFilm.passaEvento(key);}
else {
this.entra();}
break;
case HRcEvent.VK_COLORED_KEY_3:
if(filmFlag) {
disFilm.passaEvento(key);
}
break;
case HRcEvent.VK_COLORED_KEY_2:
case HRcEvent.VK_COLORED_KEY_1:
default:
break;
}
}
}
4.4.11 Film.java
import org.havi.ui.*;
import org.havi.ui.event.HRcEvent;
import java.awt.Font;
import java.awt.Color;
import java.awt.event.KeyEvent;
//Questa classe si occupa della fase di prenotazione riguardante
- 125 -
Sviluppo di un’applicazione MHP
Capitolo 4
//la visualizzazione dei film disponibile e la scelta tra di essi.
public class Film extends Strumenti{
private HText[] titoli;
private int titoloInizio;
private HText conferma;
private HText indietro;
private String user;
private ObjectFilm film;
private boolean plateaFlag;
private int testoAttivo;
private Platea platea;
private Object posti;
public Film(HScene scenemain) {
super(scenemain);
}
//Visualizza l’elenco dei film disponibili.
public void disegna(String user,ObjectFilm film2) {
plateaFlag=false;
this.user=user;
this.film=film2;
platea=new Platea(scene);
platea.setVisible(false);
container=new HContainer(0,0,720,576);
titoli=new HText[4];
int y=120;
for (int i=0;i<=3;i++) {
System.out.println("entrato nel for");
- 126 -
Sviluppo di un’applicazione MHP
Capitolo 4
titoli[i]=new HText(film2.getNome(i),270,y,300,30);
System.out.println("creato HText");
titoli[i].setFont(new Font("Arial",Font.PLAIN,23));
titoli[i].setForeground(Color.white);
titoli[i].setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
container.add(titoli[i]);
System.out.println("Aggiunto film "+i);
y=y+50;
}
titoli[0].setBackgroundMode(HVisible.BACKGROUND_FILL);
titoli[0].setBackground(Color.orange);
titoli[0].setForeground(Color.blue);
titoloInizio=0;
testoAttivo=0;
conferma=new
HText("Premi OK per confermare",300,350,250,30);
conferma.setFont(new Font("Arial",Font.ITALIC,23));
conferma.setForeground(Color.orange);
conferma.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
container.add(conferma);
indietro= new HText ("Logout",360,400,130,30);
indietro.setFont(new Font("Arial",Font.BOLD,20));
indietro.setForeground(Color.blue);
indietro.setBordersEnabled(false);
indietro.setBackground(Color.green);
- 127 -
Sviluppo di un’applicazione MHP
Capitolo 4
indietro.setBackgroundMode(HVisible.BACKGROUND_FILL);
container.add(indietro);
scene.add(container);
scene.repaint();
}
//Metodo chiamato quando viene premuto il tasto OK del
//telecomando per scegliere un film.
public void entra() {
//Viene avviata la comunicazione con il server.
Comunica com=new Comunica(Main.ip,8000);
ObjectPrenFilm pren=new ObjectPrenFilm(testoAttivo+1);
System.out.println("creato ObjectPrenFilm");
posti=com.Connetti(pren);
System.out.println("ritornato posti");
if(posti instanceof ObjectPosti) {
//Viene visualizzata la piantina dei posti del cinema
//per il film scelto.
container.removeAll();
InterfacciaGrafica.keypad.remove();
scene.remove(container);
platea.disegna(user,(ObjectPosti)posti);
plateaFlag=true;
}
if(posti instanceof String) {
//Viene visualizzato il messaggio di errore
//ritornato dal server.
System.out.println(posti);
- 128 -
Sviluppo di un’applicazione MHP
Capitolo 4
HText pren2=new HText((String)posti,340,130,300,50);
pren2.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
pren2.setForeground(Color.white);
pren2.setFont(new Font("Arial",Font.PLAIN,22));
container.removeAll();
indietro.setBounds(440,200,100,20);
container.add(indietro);
InterfacciaGrafica.keypad.remove();
container.add(pren2);
scene.repaint();
}
}
public void setTestoAttivo(int i) {
titoli[titoloInizio].setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
titoli[titoloInizio].setForeground(Color.white);
titoli[i].setBackgroundMode(HVisible.BACKGROUND_FILL);
titoli[i].setBackground(Color.orange);
titoli[i].setForeground(Color.blue);
titoloInizio=i;
scene.repaint();
}
public void stop() {
if (plateaFlag) {
platea.stop();
- 129 -
Sviluppo di un’applicazione MHP
Capitolo 4
super.stop();
}
else super.stop();
}
public void passaEvento(KeyEvent key) {
int pulsantePremuto = key.getKeyCode();
switch(pulsantePremuto){
case HRcEvent.VK_UP:
if (plateaFlag) {platea.passaEvento(key);}
else {
System.out.println("premuto su in film");
if(testoAttivo<4 && testoAttivo>0) {
testoAttivo--;
this.setTestoAttivo(testoAttivo);
}
}
break;
case HRcEvent.VK_DOWN:
if (plateaFlag) {platea.passaEvento(key);}
else {
System.out.println("premuto giù in film");
if(testoAttivo>=0 && testoAttivo<3) {
testoAttivo++;
this.setTestoAttivo(testoAttivo);
}
}
break;
- 130 -
Sviluppo di un’applicazione MHP
Capitolo 4
case HRcEvent.VK_LEFT:
case HRcEvent.VK_RIGHT:
if (plateaFlag) {platea.passaEvento(key);}
break;
case HRcEvent.VK_COLORED_KEY_3:
if (plateaFlag) {platea.passaEvento(key);
this.entra();}
break;
case HRcEvent.VK_ENTER:
if (plateaFlag) {platea.passaEvento(key);}
else {
this.entra();
}
break;
}
}
}
4.4.12 PlateaPrenota.java
public class PlateaPrenota {
private PrenotaSingolo pren;
public PlateaPrenota(PrenotaSingolo pren) {
this.pren=pren;
}
public Object start() {
Comunica com=new Comunica(Main.ip,8000);
- 131 -
Sviluppo di un’applicazione MHP
Capitolo 4
Object platea=com.Connetti(pren);
return platea;
}
}
4.4.13 Platea.java
import java.awt.*;
import java.awt.event.*;
import org.havi.ui.*;
import org.havi.ui.event.HRcEvent;
//Questa classe si occupa di visualizzare la piantina dei posti
//relativi al film scelto (verde=libero, rosso=occupato) e ne
//gestisce la prenotazione.
public class Platea extends Strumenti {
private HText [][] posti1;
private int x;
private int y;
private int width;
private int length;
private int[] postoAttivo;
private int[] postoAttivoInizio;
private Image rosso;
private Image verde;
private Image stampa;
private HText conferma;
private HText indietro;
- 132 -
Sviluppo di un’applicazione MHP
Capitolo 4
private HText aggiorna;
private String user;
private ObjectPosti posto;
private int cont;
private HText verde_t;
private HText rosso_t;
private Color stamp;
public Platea(HScene scenemain) {
super(scenemain);
cont=0;
}
public void disegna (String user,ObjectPosti posto2) {
if (cont==1) {
container.removeAll();
}
verde_t=new HText("O");
verde_t.setForeground(Color.green);
verde_t.setFont(new Font("Arial",Font.BOLD,20));
verde_t.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
rosso_t=new HText("O");
rosso_t.setForeground(Color.red);
rosso_t.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
rosso_t.setFont(new Font("Arial",Font.BOLD,20));
this.user=user;
- 133 -
Sviluppo di un’applicazione MHP
Capitolo 4
this.posto=posto2;
conferma=new HText(
"Premi OK per prenotare il posto.",320,430,300,50);
conferma.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
conferma.setFont(new Font("Arial",Font.PLAIN,20));
conferma.setForeground(Color.white);
aggiorna= new HText ("Aggiorna",300,480,130,30);
aggiorna.setFont(new Font("Arial",Font.BOLD,20));
aggiorna.setForeground(Color.white);
aggiorna.setBordersEnabled(false);
aggiorna.setBackground(Color.blue);
aggiorna.setBackgroundMode(HVisible.BACKGROUND_FILL);
indietro= new HText ("Logout",450,480,130,30);
indietro.setFont(new Font("Arial",Font.BOLD,20));
indietro.setForeground(Color.blue);
indietro.setBordersEnabled(false);
indietro.setBackground(Color.green);
indietro.setBackgroundMode(HVisible.BACKGROUND_FILL);
postoAttivo=new int[2];
postoAttivoInizio=new int[2];
container=new HContainer(0,0,720,576);
posti1=new HText [15][20];
rosso=Toolkit.getDefaultToolkit().getImage("punto_rosso.png");
verde=Toolkit.getDefaultToolkit().getImage("punto_verde.png");
System.out.println("inizializzato posti");
x=240;
y=120;
- 134 -
Sviluppo di un’applicazione MHP
Capitolo 4
width=20;
length=20;
stampa=verde;
stamp=Color.green;
//Assegna al posto il colore verde o rosso a seconda
//del flag relativo impostato nel database.
for (int i=0;i<15;i++) {
for (int j=0;j<5;j++) {
if (posto.getLibero((i*20)+j)==1)
{stamp=Color.green;}
else {stamp=Color.red;}
posti1[i][j]=new HText("O");
posti1[i][j].setForeground(stamp);
posti1[i][j].setFont(
new Font("Arial",Font.BOLD,20));
posti1[i][j].setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
posti1[i][j].setBounds(x+j*20,y+i*20,width,length);
System.out.println("creato punto "+i+" "+j);
}
}
for (int i=0;i<15;i++) {
for (int j=0;j<5;j++) {
System.out.println("riga "+i+" colonna "+j);
//Visualizza la piantina dei posti.
container.add(posti1[i][j]);
- 135 -
Sviluppo di un’applicazione MHP
Capitolo 4
System.out.println("aggiunto al container punto
"+i+" "+j);
}
}
x=358;
for (int i=0;i<15;i++) {
for (int j=5;j<15;j++) {
if (posto.getLibero((i*20)+j)==1)
{stamp=Color.green;}
else {stamp=Color.red;}
posti1[i][j]=new HText("O");
posti1[i][j].setForeground(stamp);
posti1[i][j].setFont(
new Font("Arial",Font.BOLD,20));
posti1[i][j].setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
posti1[i][j].setBounds(x+(j-5)*20,y+(i)*20,
width,length);
System.out.println("creato punto "+i+" "+j);
}
}
for (int i=0;i<15;i++) {
for (int j=5;j<15;j++) {
System.out.println("riga "+i+" colonna "+j);
container.add(posti1[i][j]);
System.out.println("aggiunto al container punto
- 136 -
Sviluppo di un’applicazione MHP
Capitolo 4
"+i+" "+j);
}
}
x=570;
for (int i=0;i<15;i++) {
for (int j=15;j<20;j++) {
if (posto.getLibero((i*20)+j)==1)
{stamp=Color.green;}
else {stamp=Color.red;}
posti1[i][j]=new HText("O");
posti1[i][j].setForeground(stamp);
posti1[i][j].setFont(
new Font("Arial",Font.BOLD,20));
posti1[i][j].setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
posti1[i][j].setBounds(x+(j-15)*20,y+(i)*20,
width,length);
System.out.println("creato punto "+i+" "+j);
}
}
for (int i=0;i<15;i++) {
for (int j=15;j<20;j++) {
System.out.println("riga "+i+" colonna "+j);
container.add(posti1[i][j]);
- 137 -
Sviluppo di un’applicazione MHP
Capitolo 4
System.out.println("aggiunto al container punto
"+i+" "+j);
}
}
container.add(indietro);
container.add(conferma);
container.add(aggiorna);
posti1 [0][0].setBackground(Color.yellow);
posti1 [0][0].setBackgroundMode(
HVisible.BACKGROUND_FILL);
postoAttivoInizio[0]=0;
postoAttivoInizio[1]=0;
postoAttivo[0]=0;
postoAttivo[1]=0;
container.setVisible(true);
scene.add(container);
scene.repaint();
cont=1;
}
//Imposta lo sfondo del posto selezionato di colore giallo.
public void setAttivo(int i, int j) {
posti1[postoAttivoInizio[0]][postoAttivoInizio[1]]
.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
posti1[i][j].setBackground(Color.yellow);
- 138 -
Sviluppo di un’applicazione MHP
Capitolo 4
posti1[i][j].setBackgroundMode(
HVisible.BACKGROUND_FILL);
postoAttivoInizio[0]=i;
postoAttivoInizio[1]=j;
scene.repaint();
}
public void passaEvento(KeyEvent key) {
int pulsantePremuto = key.getKeyCode();
switch(pulsantePremuto){
case HRcEvent.VK_UP:
if (postoAttivo[0]<=14 && postoAttivo[0]>0)
postoAttivo[0]--;
this.setAttivo(postoAttivo[0],postoAttivo[1]);
break;
case HRcEvent.VK_DOWN:
if (postoAttivo[0]>=0 && postoAttivo[0]<14)
postoAttivo[0]++;
this.setAttivo(postoAttivo[0],postoAttivo[1]);
break;
case HRcEvent.VK_LEFT:
System.out.println("Premuta freccia sinistra in platea");
if (postoAttivo[1]<=19 && postoAttivo[1]>0)
postoAttivo[1]--;
this.setAttivo(postoAttivo[0],postoAttivo[1]);
break;
case HRcEvent.VK_RIGHT:
System.out.println("Premuta freccia destra in platea");
- 139 -
Sviluppo di un’applicazione MHP
Capitolo 4
if (postoAttivo[1]>=0 && postoAttivo[1]<19)
postoAttivo[1]++;
this.setAttivo(postoAttivo[0],postoAttivo[1]);
break;
case HRcEvent.VK_ENTER:
System.out.println("premuto enter in platea");
int numero=(postoAttivo[0]*20)+postoAttivo[1]+1;
if (posto.getLibero(numero-1)==1) {
//Se viene premuto OK ed il posto è libero crea
//un oggetto della classe PrenotaSingolo.
PrenotaSingolo pren=new PrenotaSingolo(
user,numero,posto.getCodice());
PlateaPrenota pp=new PlateaPrenota(pren);
String ris=(String)pp.start();
conferma.setTextContent(
ris,HVisible.NORMAL_STATE);
}
else {
//Se viene premuto OK ed il posto è occupato, viene
//visualizzato un messaggio di errore.
conferma.setTextContent("Posto occupato.",
HVisible.NORMAL_STATE);
}
conferma.setBounds(250,150,400,50);
container.removeAll();
HText blu=new HText("Indietro",310,250,130,30);
blu.setFont(new Font("Arial",Font.BOLD,20));
blu.setBackground(Color.blue);
- 140 -
Sviluppo di un’applicazione MHP
Capitolo 4
blu.setForeground(Color.white);
blu.setBackgroundMode(
HVisible.BACKGROUND_FILL);
container.add(blu);
indietro.setBounds(450,250,130,30);
container.add(conferma);
container.add(indietro);
scene.repaint();
break;
case HRcEvent.VK_COLORED_KEY_3:
container.removeAll();
break;
default:
break;
}
}
}
4.4.14 Info.java
import java.awt.Color;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import org.havi.ui.*;
import org.havi.ui.event.HRcEvent;
- 141 -
Sviluppo di un’applicazione MHP
Capitolo 4
//Questa classe visualizza alcune informazioni utili
//relative al cinema.
public class Info extends Strumenti{
private HText testo;
private HText indietro;
public Info(HScene scenemain) {
super(scenemain);
}
public void start() {
container=new HContainer(0,0,720,576);
testo=new HText("Il Cinema ITALIA è stato costruito nel
2000.\n"+"E' una struttura molto moderna
composta\n" +"da 3 sale grandi e 2 sale piccole
nelle quali \npotrete godervi il film " + "con grande
comodità.\n" +"Può trovarci in Ancona in via
Garibaldi n. 29." +"\n\nTelefono: 071000000\n\n"
+
"E-mail: [email protected]",
250,100,450,500);
testo.setFont(new Font("Arial",Font.PLAIN,22));
testo.setHorizontalAlignment(HVisible.HALIGN_LEFT);
testo.setVerticalAlignment(HVisible.HALIGN_LEFT);
testo.setBackgroundMode(
HVisible.NO_BACKGROUND_FILL);
testo.setForeground(Color.white);
container.add(testo);
- 142 -
Sviluppo di un’applicazione MHP
Capitolo 4
indietro= new HText ("Indietro",380,430,130,30);
indietro.setFont(new Font("Arial",Font.BOLD,20));
indietro.setForeground(Color.blue);
indietro.setBordersEnabled(false);
indietro.setBackground(Color.green);
indietro.setBackgroundMode(HVisible.BACKGROUND_FILL);
container.add(indietro);
System.out.println("Aggiunto indietro");
container.setVisible(true);
scene.add(container);
scene.repaint();
super.setVisible(true);
}
public void stop() {
this.setVisible(false);
container.removeAll();
container.setVisible(false);
scene.remove(container);
System.out.println("Stop "+this.toString());
Main.gestoreSfondi.displayBackgroundInitImage();
scene.repaint();
}
public void passaEvento(KeyEvent key) {
int pulsantePremuto = key.getKeyCode();
switch(pulsantePremuto){
case HRcEvent.VK_UP:
- 143 -
Sviluppo di un’applicazione MHP
Capitolo 4
case HRcEvent.VK_DOWN:
case HRcEvent.VK_COLORED_KEY_0:
case HRcEvent.VK_0:
case HRcEvent.VK_1:
case HRcEvent.VK_2:
case HRcEvent.VK_3:
case HRcEvent.VK_4:
case HRcEvent.VK_5:
case HRcEvent.VK_6:
case HRcEvent.VK_7:
case HRcEvent.VK_8:
case HRcEvent.VK_9:
case HRcEvent.VK_LEFT:
case HRcEvent.VK_COLORED_KEY_1:
case HRcEvent.VK_COLORED_KEY_2:
case HRcEvent.VK_COLORED_KEY_3:
case HRcEvent.VK_ENTER:
default:
break;
}
}
}
- 144 -
CONCLUSIONI
Il progetto sopra illustrato, è stato realizzato non senza difficoltà; la più
impegnativa è stata sicuramente la scoperta che lo standard MHP non
supporta il JDBC. Il problema è stato ovviato tramite l’utilizzo delle socket,
necessarie per connettersi al database MySQL residente in un server. E’ stato
necessario apprendere il funzionamento delle socket tramite le API Java.
L’obiettivo iniziale prefisso, cioè quello di sviluppare un’applicazione MHP
che utilizzasse il canale di ritorno, è stato raggiunto. Si è riusciti a creare
un’applicazione perfettamente funzionante su Set-Top Box che soddisfa i
criteri fissati inizialmente.
Il risultato è, pertanto, soddisfacente, sebbene possa anche rappresentare una
base per ulteriori sviluppi, quali utilizzare il modem PSTN come canale di
ritorno, invece che la ETHERNET, oppure si può pensare di permettere al
server di gestire il multithread.
Il lavoro svolto, dunque, è stato molto soddisfacente ed ha permesso, oltre ad
approfondire il linguaggio Java, di avere una certa formazione inerente una
tecnologia, quale la TV digitale terrestre, che potrebbe avere un’importante
evoluzione con conseguenti opportunità di lavoro e di ricerca.
Questa tecnologia, infatti, sembra essere molto innovativa e soprattutto non
presenta elevati costi di installazione (caratteristica molto importante per la
diffusione della stessa), in quanto è necessario solamente comprare il Set-Top
Box, senza bisogno di avere una parabola, dato che i canali possono essere
ricevuti senza problemi tramite la classica antenna TV. Si pensi, poi, alle
innumerevoli possibilità di utilizzo della televisione digitale terrestre: in un
prossimo futuro si potrebbe navigare in Internet, controllare il proprio conto
in banca, effettuare operazioni di e-commerce, scommettere, ecc.,
- 145 -
comodamente seduti sulla poltrona di casa. Questa rappresenta un
affascinante scenario che si potrebbe proporre grazie a questa tecnologia.
Ultimamente, in Italia, la TV digitale terrestre si sta diffondendo soprattutto
per la possibilità, concessa da alcune delle maggiori emittenti televisive
nazionali, di vedere partite di calcio, film, o altri eventi a pagamento, senza
necessità di attivare alcun abbonamento: l’utente paga solamente ciò che
vede. Questo è possibile grazie alla caratteristica del Set-Top Box di avere un
lettore di smart-card. L’utente compra una scheda (ricaricabile) di un certo
importo e, tramite la stessa, è abilitato alla visioni di determinati canali e, in
particolare, di alcuni eventi a pagamento. Il credito disponibile è memorizzato
nella smart-card e ad ogni evento scelto, il costo dello stesso viene detratto dal
credito della scheda.
Il vero problema, attualmente, è che praticamente quasi nessuna emittente
trasmette esclusivamente in digitale, e molto probabilmente la situazione
resterà così fino a quando non si arriva alla data dello switch-off
(spegnimento totale delle trasmissioni in analogico), data ancora non certa.
Forse, sarebbe necessario che lo stato fornisse qualche incentivo alle emittenti
TV per passare al digitale.
La televisione digitale terrestre, in conclusione, rappresenta una piattaforma
tecnologica che, oltre a migliorare la vita dei cittadini, potrebbe fornire
diverse opportunità di lavoro e molte possibilità di sviluppo.
- 146 -
BIBLIOGRAFIA
 http://www.mhp.org
 http://www.dvb.org
 http://www.havi.org
 http://java.sun.com/products/javatv
 http://sourceforge.net/project/xletview
 http://www.wikipedia.it
 http://www.mokabyte.it
 http://www.interactiveweb.org
 http://www.wmlscript.it
 Steve Morris, Anthony Smith-Chaigneau, Interactive TV Standards, Focal
Press
 Libro bianco sulla televisione digitale terrestre
- 147 -