Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
su piattaforma Android
applicazioni per smartphone,
tablet e dispositivi embedded
che ci permetteranno di
interfacciarci col mondo
CORSO
elettronico esterno
e con i nostri progetti.
Prima puntata.
An
di
dr
Ch
ea
po
iap
ri
1
PROGRAMMIAMO CON
ndroid nasce nel 2007 da Google come nel mondo Android e prende-
A un sistema operativo open-source per
dispositivi embedded e negli anni successivi
remo familiarità con gli strumenti forniti
gratuitamente dalla comunità di sviluppo di
ha ottenuto sempre enormi consensi, tali da questo nuovo sistema operativo per poi dare
renderlo attualmente il più valido concorren- vita alle nostre prime applicazioni su qualsiasi
te di iOS di Apple. smartphone o tablet e con le quali saremo in gra-
Ad oggi, sono moltissimi gli smartphone do di controllare remotamente i nostri progetti
ed i tablet sui quali è installato Android, ed elettronici, impartire comandi e ricevere da essi
ultimamente stanno nascendo anche molti utili informazioni che potranno essere visualiz-
sistemi di sviluppo in grado di supportare zate sul display del nostro dispositivo.
questo sistema operativo che, essendo open- La comunità di sviluppo Android è, infatti, sem-
source, permette un facile adattamento ed pre in continua evoluzione (come è facilmente
un’ampia modularità verso vari dispositivi riscontrabile visitando il sito http://developer.
hardware, diversi tra loro per funzionalità e android.com) e ci fornisce tutti gli strumenti e le
caratteristiche, pronti a soddisfare ogni tipo librerie di codice per prendere il pieno possesso
di esigenza. del nostro smartphone e di tutti i suoi sensori e
moduli interni. Facilmente il dispositivo, smar-
Breve introduzione al corso tphone o tablet, su cui svilupperemo la nostra
In questo corso a puntate, ci addentreremo applicazione, avrà un modulo bluetooth inter-
Android.bat create project --target 1 --name AndroidApplication –path ./myProject --activity AndroidActivity --package
com.packagename.android.
Di seguito una breve descrizione dei parametri inseriti:
--target specifica la versione delle librerie usate; ad esempio per le librerie API 8 (Android 2.2) il valore
deve essere 1.
--name indica il nome del progetto
--path indica il percorso della directory in cui verrà creato il progetto con le sue sotto-directory.
--activity specifica il nome della classe principale che verrà creata in automatico
--package deve essere un nome univoco nel caso si voglia pubblicare l’applicazione sul market Google Play
e normalmente per questo motivo si usa un indirizzo web al contrario, ad esempio
com.packagename.android
e seguire a video i passi della compilazione. Al termine di essa, nella sotto cartella bin troveremo il risultato finale,
ovvero un file con estensione .apk e vedremo in seguito come poterlo testare direttamente sul dispositivo finale o sul
proprio pc, tramite emulatore.
Per comodità consigliamo di aggiungere alla variabile di ambiente PATH di windows la directory in cui abbiamo
installato i tool di Android in modo da poter eseguire i comandi da ogni posizione.
più offerte dalle versioni successive. Per gioco durante la compilazione, ma se voles-
questo motivo e per il fatto che attualmente simo avere a disposizione un pratico am-
nella grande maggioranza degli smartphone biente di sviluppo integrato che ci permetta
sono installate le versioni 2.2 o 2.3, consi- di editare i sorgenti, compilare e debuggare
gliamo di scegliere come libreria di svilup- su un emulatore o direttamente sul dispo-
po SDK la 2.2, ed eventualmente installare sitivo fisico in tempo reale, controllando il
successivamente versioni più recenti. flusso del programma, possiamo ricorrere
Tra i vari pacchetti installabili sono presenti ad Eclipse, l’IDE di sviluppo più usato
anche alcune librerie di Google che possono per programmare dispositivi embedded e
essere usate se si desidera impiegare nelle creato in Java. Esistono diverse versioni di
proprie applicazioni la funzionalità di navi- Eclipse scaricabili gratuitamente a questo
gazione nelle mappe geografiche sfruttando indirizzo http://www.eclipse.org/downloads,
il motore Google Maps. Al termine dell’
installazione avremo a disposizione i tool
necessari per compilare la prima nostra
applicazione, anche se per ora solo da linea
di comando. Infatti, grazie ad una serie di
comandi presenti nella sotto directory tools
che ora troveremo nel percorso in cui ab-
biamo precedentemente scelto di installare
SDK-Android, possiamo creare un progetto
minimale e successivamente compilarlo.
Maggiori dettagli al riguardo li potete trova-
re nel Box “Compilare da linea di comando”.
,
ECLIPSE, l ambiente di sviluppo grafico
Compilare da riga di commando è utile per
capire i vari passaggi ed i file che entrano in
Fig. 5
Fig. 6 Fig. 7
ma per i nostri scopi è sufficiente anche una nel sistema e configurarlo opportunamente.
versione base, come, per esempio, Eclipse Questo plugin si chiama ADT Plugin ed è
Galileo. scaricabile dal sito di Android al seguente
Sfortunatamente Eclipse non è in grado di indirizzo http://developer.android.com/sdk/
compilare nativamente sorgenti per An- eclipse-adt.html, oppure più comodamente
droid, ma è possibile scaricare un plugin on-line all’interno dell’Ide, cliccando sulla
gratuito, che permetterà di riconoscere la voce di menu Help e poi cliccando su Install
Tool-Chain di sviluppo Android installata New Software e riempiendo i campi con l’in-
Fig. 8
dirizzo opportuno come indicato in Fig. 5. se la build è andata a buon fine e nel caso
Al termine dell’installazione dovremo apri- contrario, ci darà indicazioni aggiuntive
re la finestra di dialogo Preferences accessi- sugli errori ed eventuali warning.
bile dalla voce di menu Window ed indicare
,
nel campo Android in quale directory risiede L emulatore Android
il Platform SDK; otterremo un elenco delle Rimandando maggiori dettagli di Eclipse
librerie installate simile a quello in Fig. 6. alle puntate successive possiamo concludere
A questo punto possiamo creare un nuovo analizzando un altro importante strumento
progetto Android come in Fig. 7 e seguire i che ci viene offerto dal pacchetto SDK Android
vari passi del wizard (che come potrete no- appena installato, e cioè l’emulatore. Questo
tare richiederanno l’inserimento degli stessi permetterà di testare l’applicazione e debug-
parametri visti nel caso di creazione da linea garla sul PC senza dover disporre necessaria-
di comando) prima di eseguire la prima mente di un dispositivo fisico e accelerando,
build cliccando col tasto destro sul nome così, i tempi di produzione.
del progetto nella vista PackageExplorer sulla Inoltre, offre un vantaggio non trascurabile su
parte sinistra dell’ Ide e cliccando infine su applicazioni Android destinate a funzionare su
Build Project. dispositivi dotati di caratteristiche hardware
Non ci soffermeremo in questa prima pun- diverse tra di loro, basti pensare alla risoluzio-
tata nel descrivere tutte le funzionalità di ne e alle dimensioni degli schermi di differenti
Eclipse, ma come primo passo sarà sufficien- marche e modelli.
te tenere d’occhio la “vista” Problems, nella Se infatti, avessimo intenzione di pubblicare
parte bassa dell’Ide che ci darà informazioni una nostra applicazione sul market Google
prima applicazione
ed eseguirla su un
dispositivo reale.
Seconda Puntata.
An
di
dr
Ch
ea
po
iap
ri
2
PROGRAMMIAMO CON
opo l’introduzione al mondo Android mente Open Source, è sviluppato in Java; es-
D della puntata precedente siamo pronti
a programmare la nostra prima applicazione
sendo un ambiente multi-linguaggio è possibile
sviluppare applicazioni programmando anche
sfruttando l’ambiente di sviluppo Eclipse in C/C++, a patto di installare i plugin necessari.
presentato in precedenza ed analizzando la È infatti bene ricordare che Eclipse, da solo, ci
struttura di un progetto nei suoi dettagli. consente di sviluppare programmi in Java, ma
Saremo in grado di testare il nostro prodot- non basta a creare un progetto Android. Nel
to sull’emulatore fornito dal plugin ADT di nostro caso programmeremo in Java, ma avremo
Android e finalmente di vederlo in azione comunque bisogno del plugin ADT (Android
sul nostro dispositivo. Sarà ancora un pro- Developers Tools) già installato nella puntata
getto senza particolari funzionalità pratiche e precedente, per permettere ad Eclipse di creare
privo di interfaccia grafica, ma ci permetterà un nostro progetto e di fornirci strumenti spe-
di comprendere il processo completo per cifici come l’emulatore, i driver, le librerie e un
programmare, testare e pubblicare una nostra insieme di esempi.
futura applicazione sul market Android. Esistono altri ambienti di sviluppo per pro-
grammare con Android (come ad esempio
Eclipse IntellijIDEA e NetBeans per citarne alcuni) , ma
Eclipse è un ambiente di sviluppo integrato abbiamo scelto di utilizzare Eclipse perchè è il
(IDE) nato da IBM e diventato successiva- più usato in ambito di applicazioni embedded;
del progetto conterrà un solo file con l’unica to per i più curiosi, perchè fornisce informa-
classe principale dell’applicazione. zioni su come prendere il controllo del nostro
Ogni file con estensione .java presente all’in- dispositivo e può suggerirci nuovi spunti per
terno di questa cartella verrà compilato all’ le nostre future applicazioni.
esecuzione del comando build, per cui se La directory bin contiene i file binari che
volessimo aggiungere le nostre classi basterà vengono utilizzati dall’applicazione, nonchè
creare un file all’interno della stessa cartella l’applicazione stessa in formato nativo (.dex)
ed aggiornare la vista premendo F5 o col co- ed il prodotto finale con estensione .apk. Ri-
mando Refresh. Questa cartella conterrà il co- cordiamo che il risultato ultimo della nostra
dice del progetto ma, come vedremo ora, da compilazione sarà un file .apk che è un file
sola non basta per generare il prodotto finale. compresso contenente al suo interno le risor-
La directory gen conterrà invece file autoge- se dell’applicazione, l’eseguibile nativo per
nerati dal progetto durante la compilazione; Android (.dex) e qualche altro file che sarà
questi contengono riferimenti alle risorse del possibile vedere rinominando il file apk con
progetto come ad esempio bottoni, immagini, estensione .zip. Il file con estensione .apk sarà
file audio e stringhe, ma dal momento che il solo che andremo ad uploadare sul market
non dobbiamo modificarli, possiamo tempo- android quando avremo terminato il nostro
raneamente trascurarla. progetto.
La directory Android 2.2 è in realtà un colle- La directory res contiene le risorse utilizzate
gamento ad un file precompilato .jar che non dal nostro progetto; questa cartella è a sua
si trova all’interno della cartella del progetto, volta suddivisa in altre sotto-directory in
ma nelle cartelle create al momento dell’in- base al tipo della risorsa specifica. È bene
stallazione del plugin ADT e contiene tutte analizzare meglio le cartelle ed i file contenu-
le librerie che ci permettono di sviluppare ti in questa directory, perchè assumono un
con Android. aspetto considerevole per quanto riguarda
Eclipse ci permette di visualizzarle tutte ed l’aspetto, lo stile e l’interfaccia grafica della
elencare anche le funzioni che ognuna di esse nostra applicazione e che quindi non va tra-
presenta. Questa caratteristica, anche se non lasciata perchè sarà il primo diretto contatto
è indispensabile, può tornare utile soprattut- con l’utente finale. Analizziamo perciò, di
essere associata ad un file di risorse diverso La prima volta che viene avviato l’emulatore
in modo da presentare un layout diverso e potranno trascorrere svariati secondi, ma
quindi una interfaccia grafica diversa. saremo in grado di seguire i vari passi (ed
La funzione setContentView() deve essere eventuali errori) del processo tramite la vista
chiamata una volta sola ed al momento della Console di Eclipse, al termine dei quali otter-
partenza dell’applicazione, pertanto viene remo una finestra come in Fig. 7.
ridefinito, tramite override, il metodo on- L’applicazione è ovviamente molto semplice,
Create() della classe base (Activity) al quale ma può servire per comprendere meglio al-
viene aggiunta proprio la funzione setCon- cuni meccanismi di Android. Da notare come
tentView(), dopo la classica onCreate() della la stringa “Hello world, HelloWordActivity!”
classe base. Con la keyword super viene, che compare nella parte alta dello schermo
infatti, indicato che la onCreate() da utilizza- non sia presente nel codice del file Hellowor-
re è quella della classe base Activity. dActivity.java esaminato in precedenza. La
spiegazione è che la stringa è inserita nel file
Test su emulatore di risorse strings.xml all’interno della cartella
Ora, per compilare, possiamo lanciare la res ed è identificata con il nome hello, questo
build cliccando col tasto destro sul progetto stesso nome lo ritroviamo nel file di risorse
e poi su Build Project sul menu; all’interno main.xml che rappresenta il nostro layout.
della cartella bin troveremo il file helloword. Questo file è stato autogenerato presentando
apk appena generato. Nel caso la compilazio- già al suo interno un primo semplice con-
ne non fosse andata a buon fine potremmo trollo, un TextView che presenta, tra le sue
leggere gli errori o i warnings nella finestra proprietà, la stringa iniziale che è appunto
situata nella parte inferiore di Eclipse ed in hello (Fig. 8).
particolare sulla vista chiamata Problems Durante la fase di emulazione è anche possi-
dove vengono indicate le righe interessate bile visualizzare i messaggi di log che vengo-
dagli errori. no inviati dal sistema Android verso l’ester-
A questo punto possiamo provare l’appli- no, tramite la vista LogCat di Eclipse, situata
cazione con l’emulatore, cliccando col tasto nella parte inferiore della finestra. Possiamo
destro sul progetto e poi su Run As e An- però, come vedremo nelle puntate successi-
droid Application come mostrato in Fig. 6. ve, inserire alcune righe di log personalizzato
Fig. 9
CORSO
protocollo Bluetooth
e soffermandoci in
questa puntata sulla’
interfaccia utente.
Terza Puntata.
di
An
dr
Ch
ea
po
iap
ri
3
PROGRAMMIAMO CON
bbiamo visto, nelle puntate precedenti, tramite la porta seriale. Lo schema di principio è
A come realizzare un semplice progetto
Android, ma ancora privo di controlli visuali
rappresentato in Fig. 1. Prima di analizzare l’har-
dware, occupiamoci del software e, più in detta-
ed interfaccia utente. In queste pagine verran- glio, dell’interfaccia grafica che verrà visualizzata
no mostrati i primi passi con cui daremo vita sul dispositivo Android.
ad una applicazione Android completa ed in
grado di comunicare con il mondo esterno. Il Software
Amplieremo, pertanto, la trattazione prece- Android gestisce l’interfaccia grafica tramite uno
dente analizzando l’inserimento di controlli o più file xml, mediante i quali possiamo defini-
grafici che ci consentiranno di variare la re quello che viene chiamato layout, ovvero la
luminosità di una striscia led RGB (o qualsiasi disposizione in cui andremo ad inserire i controlli
altro dispositivo luminoso) collegata su una necessari per la nostra applicazione.
piattaforma Arduino con lo shield RGB-Shield Al momento della creazione di un progetto ab-
presentato nella rivista numero 159. biamo già a disposizione un layout basilare che
Per realizzare tutto questo senza fili, utilizze- troviamo all’interno della sottocartella res/layout
remo il protocollo Bluetooth, visto che, ormai, come già visto nella puntata precedente.
tutti i dispositivi ne sono dotati, e lo useremo Questo file, però, sarà piuttosto scarno perchè
per comunicare con un altro modulo Bluetooth presenta solamente il controllo TextView, ovvero
(questa volta esterno), collegato ad Arduino una casella di testo (per chi programma con C#
Fig. 2
Fig. 3
Conclusioni
A questo punto, terminato l’aspetto grafico
della nostra applicazione, ci possiamo preoc-
cupare di scrivere il codice associato alle azio-
ni che verranno eseguite sui nostri controlli,
ovvero la gestione degli eventi, che analizze-
g
Fig. 5 remo nella prossima puntata.
la luminosita
CORSO
ri
4
Quarta puntata.
po
iap
Ch
ea
dr
An
di
PROGRAMMIAMO CON
bbiamo visto, nella puntata precedente,
A come gestire l’interfaccia grafica su un di-
spositivo Android; lo abbiamo fatto usando come
esempio l’inserimento nella nostra applicazione
di tre barre scorrevoli per variare la tonalità
di colore di una striscia a LED RGB, collegata
in remoto tramite un dispositivo Bluetooth e
Arduino. Ci eravamo lasciati con la presentazio-
ne del layout grafico senza preoccuparci della Fig. 1
gestione degli eventi; ora è giunto il momento di
analizzare il codice Android che ci permetterà
di associare alle azioni dell’interfaccia grafica gli
eventi che ci interessano, in modo da prendere
il controllo del modulo Bluetooth integrato nel
nostro smartphone ed inviare dati ad un altro
modulo Bluetooth esterno. Analizzeremo anche
il modulo necessario per ricevere dati dal nostro
smartphone, per tradurli in formato seriale e per
poi trasferirli ad Arduino. Lo schema di principio
dell’applicazione è rappresentato in Fig. 1.
if (_toggleOnOff.isChecked())
_toggleOnOff =(ToggleButton)findViewById(R. {
id.toggleButtonOnOff); // ...
// attivazione Bluetooth
//...
A questo punto possiamo modificare le proprie- }
tà del pulsante _toggleOnOff a nostro piacimento, else
{
modificando ad esempio la scritta (tramite // ...
metodo setText()) o il colore (tramite il metodo // chiusura Bluetooth
// ...
setBackgroundColor()) nel modo che appare nel }
listato; possiamo quindi associare la funzione }
}
(callback) che verrà chiamata quando clicche-
indispensabile.
Nello shield abbiamo anche un connettore sigla-
Per leggere o pilotare questi I/O è necessario to PCM, la cui piedinatura è la seguente:
entrare nella modalità comandi (da seriale locale • 1 = GND;
o direttamente da Arduino). Per controllare tali • 2 = P-OUT;
linee di I/O bisogna fare riferimento al comando • 3 = P-IN;
S*,<word> in cui word è una stringa esadecimale • 4 = P-CLK;
di 16 bit i cui 8 bit più significativi rappresenta- • 5 = P-CS.
no la maschera per determinare i pin di output
e di input, mentre gli 8 bit meno significativi L’interfaccia PCM offre la possibilità di inviare
corrispondono al valore (1 per portare il pin a via radio, ad un altro dispositivo Bluetooth, uno
livello alto e zero per portarlo a livello basso). La stream audio ad una velocità di trasferimento di
struttura è quella mostrata nella Fig. 4. 64 kbps. Per i nostri scopi questa possibilità non
Per esempio: viene sfruttata.
S*,0202 abilita GPIO9 come output e lo mette al L’ultimo connettore che vediamo è quello USB,
valore “1” che evidentemente veicola una connessione
S*,0E00 abilita mette tutti i GPIO dello strip a “0” USB; la sua piedinatura è:
• 1 = GND;
Il comando GK restituisce una stringa • 2 = DP;
esadecimale col valore dei pin allo stato attuale; • 3 = DM;
tali pin sono collegati anche ai pin di Arduino. • 4 = Vcc.
In particolare:
• GPIO9 è collegato ad A4; Collegando questo connettore al PC tramite un
• GPIO10 è collegato ad A3; cavo USB è possibile utilizzare la modalità “HCI
• GPIO11 è collegato ad A2. over USB” del modulo Bluetooth ed ottenere ve-
locità maggiori (fino a 3 Mbps). Tuttavia, questo
E adesso passiamo al connettore AD, i cui è possibile utilizzando solo la versione USB del
contatti sono solo ingressi analogici e possono modulo RN-42 (chiamata appunto RN-42-USB)
essere utilizzati dal modulo Bluetooth per ac- o aggiornando opportunamente il firmware
quisire alcune informazioni, come ad esempio il tramite il bus SPI.
livello di tensione sulla batteria. La piedinatura Bene, analizzati i connettori vediamo gli altri
di questo connettore è: elementi previsti nello shield, partendo dal
• AIO0; dip-switch SW1, che può collegare alcuni pin
• AIO1; (GPIO3, GPIO4, GPIO6, GPIO7) del modulo
• GND. Bluetooth a VCC (3,3V) tramite quattro resi-
stenze; questi pin servono per impostare alcune
In questa puntata del corso il connettore IO non modalità di funzionamento del modulo RN-42
viene usato. e sono normalmente collegati a massa tramite
Passiamo adesso al connettore SPI, la cui piedi- resistenze di pull-down integrate nel modulo.
natura è: Spostando il rispettivo dip verso la scritta “ON”
• 1 = S-MOSI; viene collegato il pin del modulo a Vcc e quindi
• 2 = S- SCLK; a livello logico 1, abilitando la relativa funzio-
• 3 = S-MISO; nalità. Tutti questi pin vengono interpretati al
• 4 = S-CS; momento dell’avvio, quindi cambiando lo stato
• 5 = GND. dei dip durante il funzionamento dello shield
Varie:
- Strip M/F 3 vie (2 pz.)
- Strip M/F 6 vie
- Strip M/F 8 vie (2 pz.)
- Strip M/F 10 vie
- Strip Maschio 2 vie
- Strip Femmina 3 vie
- Strip Femmina 4 vie (2 pz.)
- Strip Femmina 3 vie (3 pz.)
- Jumper
- Circuito stampato
non si otterranno gli effetti desiderati. vo dip, prima di alimentare lo shield; una volta
Le modalità si possono anche configurare tramite alimentato occorre riportarlo allo stato “0”, poi allo
software, entrando nella fase comando tramite la stato “1” , di nuovo allo stato “0” e ancora ad “1”.
sequenza di escape “$$$”. Ad ogni cambiamento di stato deve trascorrere un
Di seguito descriviamo i pin che fanno capo al secondo circa.
dip-switch. • MASTER. È collegato al pin GPIO6 del modulo
• AUTO. È collegato al pin GPIO3 del modulo Bluetooth. Per impostazione predefinita, il modulo
Bluetooth. Se abilitato, permette l’accoppiamento Bluetooth si comporta come un dispositivo slave
automatico con un altro dispositivo remoto Blueto- e quindi può venire rilevato da altri dispositivi
oth, senza pertanto dover digitare il codice segreto Bluetooth e connettersi ad essi, ma non è in grado
(detto “Passkey”). Se però il dispositivo remoto di iniziare per primo una connessione. Portando a
è settato per richiedere l’autenticazione, verrà ON il rispettivo dip, il modulo lavorerà in modali-
comunque richiesto l’inserimento della Passkey tà Master. In questa fase non potrà essere rilevato
per instaurare un collegamento sicuro. La Passkey da altri dispositivi, ma sarà esso ad effettuare
predefinita è 1234, ma può essere modificata, una connessione verso un particolare dispositivo
entrando in modalità comando, tramite sequenza remoto che avremo memorizzato in precedenza
di escape “$$$”. nella Flash del modulo RN-42, tramite il comando
• DEFAULT. È collegato al pin GPIO4 del modulo SR,<address> (in cui <address> è l’indirizzo MAC
Bluetooth. Permette di ripristinare tutti i settaggi del dispositivo remoto scelto). Nel caso in cui non
interni al modulo ai valori iniziali di “fabbrica”. ci fosse alcun indirizzo memorizzato, l’RN-42 effet-
Può essere utile quando vengono impartiti coman- tuerà una scansione e si connetterà al primo dispo-
di che portano il modulo in conflitto. Per effettuare sitivo remoto trovato. Sono inoltre possibili altre
questo reset , occorre portare verso ON il relati- modalità Master che variano dal modo più o meno
Listato 6
Lo shield Bluetooth descritto in questo
void loop()
{ progetto (cod. FT1032M) costa 34,00 Euro;
String strRec = getSerialLine();
per il MATERIALE
la scatola di montaggio comprende tutti i
digitalWrite(BOARD_LED, HIGH);
componenti, il modulo radio Roving Networks
Serial.println(“Rec:” + strRec + “\n”); RN-42, la basetta forata e serigrafata nonché
char colComponent = getComponentFromString(strRec); tutte le minuterie. Nello stesso progetto
int colValue = getColorFromString(strRec);
viene utilizzato un shield RGB (cod. RGB_
if(colComponent == ‘R’)
{
SHIELD) che costa 12,00 Euro nonché una
analogWrite(RED_LED, colValue); board Arduino UNO, Euro 24,50. Il modulo
}
else if(colComponent == ‘G’) Roving Networks RN-42 è anche disponibile
{
analogWrite(GREEN_LED, colValue); separatamente al prezzo di 21,00 Euro.
}
else if(colComponent == ‘B’)
Tutti i prezzi si intendono IVA compresa.
{
analogWrite(BLUE_LED, colValue); Il materiale va richiesto a:
} Futura Elettronica, Via Adige 11, 21013 Gallarate (VA)
}
Tel: 0331-799775 • Fax: 0331-792287 - www.futurashop.it
e funzionalita e
‘
approfittando per
introdurre nuovi
concetti Android.
Quinta puntata.
An
di
dr
Ch
ea
po
iap
ri
5
PROGRAMMIAMO CON
ella puntata precedente abbiamo ana-
N lizzato il firmware per Android e per
Arduino che permette di variare la lumino-
CREARE IL MENU
Per non appesantire ulteriormente il layout grafico
della schermata principale, gestiremo la possibilità
sità ed il colore di una striscia a LED RGB ad di programmare questa sequenza in una View de-
interfaccia I²C-Bus. Immaginiamo ora di volere dicata, che sarà pertanto richiamabile tramite una
che la nostra striscia (o anche un singolo LED voce di menu. Come saprete, uno dei tasti “fisici”
RGB) possa passare da un colore all’altro ad in uno smartphone Android è quello che permette
intervalli prestabiliti ed in tempi più o meno di mostrare nella parte bassa dello schermo un
rapidi; questo potrebbe essere utile, ad esem- menu contestuale con più opzioni, in modo da
pio, per creare effetti alba-tramonto in pre- arricchire l’applicazione con maggiori informazio-
sepi o modellini, senza dover ricorrere a più ni o configurazioni. Esistono due modi per creare
costose centraline dedicate. Dovremo perciò i menu: uno “statico”, che consiste nel ricorrere
aggiungere alla nostra applicazione una moda- a un file xml, e l’altro dinamico, in cui si possono
lità di programmazione tramite cui scegliere la aggiungere o togliere voci di menu direttamente
sequenza di colori che invieremo ad Arduino dal codice. Sono modi equivalenti nel risultato, ma
tramite Bluetooth. Quest’ultimo memorizzerà i quello dinamico ci permette di modificare le opzio-
dati nella propria EEPROM, così sarà in grado ni che compariranno nel menu anche a run-time, a
di riprodurre la sequenza anche una volta che seconda di determinate azioni compiute dall’uten-
la connessione Bluetooth sarà terminata. te. Vedremo comunque entrambe le soluzioni.
tua un controllo sull’Id della voce di menu quisire nuovi concetti riguardanti il mondo
selezionata (che viene restituito dall’ API Android.
di sistema getItemId()); in base al suo valore
effettueremo le nostre azioni, chiamando le CREARE NUOVE ACTIVITY
rispettive funzioni. Finora in questa applicazione abbiamo utiliz-
Adesso bisogna fare una piccola precisazione zato una singola Activity; in prima istanza,
a proposito della funzione getItemId(), la quale possiamo considerare un’Activity come la
ritorna un valore intero: nel caso avessimo finestra grafica che permette all’utente di
utilizzato il metodo dinamico per creare il no- interagire con l’applicazione. Fisicamente
stro menu, tale valore corrisponderà a quello un’Activity è una classe contenuta in un file
specificato nel metodo Add (Listato 2) e quin- sorgente con estensione .java (nel nostro
di, nel nostro caso, il valore 0 corrisponderà
alla prima voce di menu (“Scan”), il valore
1 alla seconda e così via. Se invece avessimo Listato 3
creato il menu utilizzando il file xml menuseq. @Override
public boolean onOptionsItemSelected(MenuItem item)
xml, allora la lettura del codice risulterebbe {
semplificata per via della stringa inserita nel super.onOptionsItemSelected(item);
switch(item.getItemId())
campo android:id del relativo item (Fig. 1) che {
ci permette di riscrivere il codice del Listato case 0:
3, utilizzando il prefisso R seguito dal nome startScannerActivity();
break;
dell’Id. case 1:
Il tutto sarà più chiaro leggendo il codice openSequencerView();
break;
così trasformato, nel Listato 4. In particolare, case 2:
abbiamo utilizzato tre voci di menu: la prima openAboutDialog();
break;
per effettuare la scansione dei dispositivi }
Bluetooth circostanti, la seconda per creare le return true;
nostre sequenze di luce ed infine la terza per }
Fig. 5
Tutti questi metodi (onCreate(), onStart(), tivity sta prendendo il suo posto per andare
onResume(), onPause(), onStop(), onDestroy()) in foreground, ed il metodo onStop() quando
vengono chiamati direttamente dal sistema proprio l’Activity non è più visibile. Infine, il
operativo e noi possiamo gestirli in modo at- metodo onRestart() è chiamato ogni qualvolta
tivo inserendo codice personalizzato a secon- l’Activity venga ridisegnata ed il metodo on-
da delle nostre esigenze, oppure demandare Destroy() appena prima che l’Activity venga
tutto alla super classe tramite, ad esempio, la distrutta.
riga di codice super.onStop() valida nel caso Per poter utilizzare l’Activity appena creata,
del metodo onStop(). non dobbiamo dimenticarci di informare
Possiamo spiegare brevemente questi meto- Android della sua esistenza; allo scopo la
di dicendo che la onCreate() viene chiamata aggiungiamo nel file AndroidManifest.xml,
una sola volta, non appena viene eseguita la già visto ed utilizzato nel corso delle puntate
startActivity() vista precedentemente. È pro- precedenti, che si presenterà come in Fig. 5.
prio qui che andremo ad impostare il layout Da notare il tag <intent-filter> che deve essere
grafico scelto per questa Activity (tramite la presente solo nell’ Activity principale, con
riga setContentView(R.layout.sequencer.xml) e la quale parte l’applicazione e dalla quale
ad aggiungere il nostro codice per associare verranno lanciate le altre Activity.
le azioni agli eventi generati dalla pressione Spiegate le generalità, vediamo ora come
di tasti e controlli generici. useremo le Activity in questa puntata.
Il metodo onStart() viene chiamato anch’esso
una sola volta e poco prima che l’Activity LIGHT SEQUENCER
venga fisicamente disegnata. Il metodo onRe- Premendo sulla voce di menu New Seq pre-
sume() viene chiamato prima che l’Activity cedentemente creata, apparirà ora una nuova
passi in stato running, quindi verrà chiamato finestra con i controlli che abbiamo aggiun-
la prima volta, ma anche ogni volta che l’Ac- to nel nuovo file di layout sequencer.xml. e
tivity esca dallo stato stopped e torni attiva. visibile in Fig. 6. Come noterete, sono gli
Il metodo onPause() viene chiamato quando stessi controlli usati nell’Activity principale,
l’Activity è ancora visibile, ma un’altra Ac- ma oltre a questi ci sono anche altri pulsanti
Fig. 6
Listato 8
<?xml version=”1.0” encoding=”UTF-8”?>
<resources>
<style name=”CustomSeekBar” parent=”android:Widget.SeekBar”>
<item name=”android:progressDrawable”>@drawable/custom_seek_bar_r</item>
<item name=”android:thumb”>@drawable/custom_seek_bar_thumb</item>
<item name=”android:thumbOffset”>0dip</item>
</style>
</resources>
possibilità in modo tutto sommato semplice: precedenza (nel nostro caso <CustomSeek-
riprendiamo il file di layout sequencer.xml Bar>) preoccupandoci solo delle dimensioni
ed aggiungiamo all’interno del tag <Seek- e della sua posizione all’interno della View.
Bar> che ci interessa modificare, il campo
android:progressDrawable, che imposteremo SCANSIONE BLUETOOTH
con un file di risorsa personalizzato (vedere Negli esempi fatti fino ad ora la comuni-
il Listato 6). cazione Bluetooth tra Android ed Arduino
Questo file di risorsa (@drawable/custom_seek_ è avvenuta cablando nel codice l’indirizzo
bar_R) è un file xml (nulla, però, ci vieta di MAC del modulo RN-42; ciò rende l’applica-
usare un’immagine) come quello visibile in zione poco flessibile e nel caso in cui volessi-
Fig. 7 in cui sono presenti due item: uno per mo riutilizzare questo stesso codice per gesti-
ridisegnare lo sfondo della barra di scorri- re un altro modulo Bluetooth ci troveremmo
mento (background) e l’altro per ridisegnare la fortemente vincolati.
Listato 9
public void startScannerActivity()
{
Log.v(TAG, “Start Scan”);
Intent btScanIntent = new Intent(this, BtScannerActivity.class);
startActivityForResult(btScanIntent, BtCore.REQUEST_DISCOVERY);
}
// after select, connect to device
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (requestCode != BtCore.REQUEST_DISCOVERY)
{
return;
}
if (resultCode != RESULT_OK)
{
return;
}
BluetoothDevice device = data.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
BtCore.serverAddressAfterScan = device.getAddress();
}
// BT isEnable
if (!_bluetooth.isEnabled())
{
Log.w(“RGB-CONTR-SCAN”, “Disable!”);
CORSO
finish();
return;
}
// Register Receiver
IntentFilter discoveryFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(_discoveryReceiver, discoveryFilter);
IntentFilter foundFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(_foundReceiver, foundFilter);
ProgressScan.indeterminateInternal(BtScannerActivity.this, _handler, “Scanning...”, _discoveryWorker,
new OnDismissListener()
{
public void onDismiss(DialogInterface dialog)
{
for (; _bluetooth.isDiscovering();)
{
_bluetooth.cancelDiscovery();
}
_discoveryFinished = true;
}
}, true);
}
private Runnable _discoveryWorker = new Runnable()
{
public void run()
{
// Start search device
_bluetooth.startDiscovery();
Log.d(“RGB-CONTR-SCAN”, “Starting Discovery”);
for (;;)
{
if (_discoveryFinished)
{
Log.d(“RGB-CONTR-SCAN”, “Finished”);
break;
}
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
}
}
}
};
protected void onListItemClick(ListView l, View v, int position, long id)
{
Log.d(“RGB-CONTR-SCAN”, “Click device”);
Intent result = new Intent();
result.putExtra(BluetoothDevice.EXTRA_DEVICE, _devices.get(position));
setResult(RESULT_OK, result);
finish();
}
servizio Android
ed approfondiamo
l’utilizzo di alcuni
sensori del nostro
smartphone, come
accelerometro e
localizzatore GPS.
ri
6
Sesta puntata.
po
iap
Ch
ea
dr
An
di
PROGRAMMIAMO CON
opo aver spiegato l’interazione tra il modu- sa impostabile (Fig. 1). Questo ci dà l’occasione di
D lo Bluetooth RN-42 e Android, ora vedremo
come gestire direttamente chiamate e messaggi
fare una panoramica sui sensori di movimento e sul
localizzatore GPS di Android, ma anche di introdurre
GSM e in che modo interagire con i sensori di un nuovo concetto Android che è il “servizio”, il quale
movimento e localizzazione dello smartphone ci risparmia di dover tenere sempre attiva e a pieno
allo scopo di pilotare lo shield Arduino GSM schermo la nostra applicazione durante il suo ciclo di
presentato nelle puntate precedenti. In parti- vita. Anche se questa applicazione nasce per scopo
colare, dopo questa lezione saremo in grado di didattico, potrà comunque tornarci utile per realizzare
attivare dispositivi esterni collegati allo shield, automatismi comandati a distanza, come ad esempio
tramite una chiamata gestita internamente dalla un apricancello o un avviso di presenza.
nostra applicazione, ed impartire diversi coman-
di grazie ad SMS personalizzati. SERVIZIO ANDROID
Potremo dotare la nostra applicazione di mag- Mentre nell’applicazione descritta nel fascicolo prece-
giori funzionalità: ad esempio far partire una dente (RGBLedController) abbiamo sempre avuto a che
chiamata verso un numero telefonico prestabilito fare con le Activity, che sono classi dotate di un’inter-
in seguito ad uno “scuotimento” ripetuto dello faccia grafica verso l’utente e con le quali è possibile
smartphone, oppure appena questo si troverà in interagire attivamente, questa volta occorre fare in
prossimità di una certa zona geografica, anch’es- modo che il nostro codice funzioni in background,
Listato 1
// GSMService.java
@Override
public void onCreate()
{
Toast.makeText(this, “Service Created”, Toast.LENGTH_LONG).show();
Log.d(TAG, “onCreate”);
// sensor
_sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor s = _sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
_sensorManager.registerListener(_accelerometerSensorListener, s, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
public void onStart(Intent intent, int startid)
{
Toast.makeText(this, “Service Started”, Toast.LENGTH_LONG).show();
Log.d(TAG, “onStart”);
_statusService = true;
}
@Override
public void onDestroy()
{
Toast.makeText(this, “Service Stopped”, Toast.LENGTH_LONG).show();
Log.d(TAG, “onDestroy”);
_sensorManager.unregisterListener(_accelerometerSensorListener);
_sensorManager = null;
_statusService = false;
}
public void onSensorChanged(SensorEvent event)
{
float[] values = event.values;
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
{
long curTime = System.currentTimeMillis();
// update every 100ms.
if ((curTime - lastUpdate) > 100)
{
long diffTime = (curTime - lastUpdate);
lastUpdate = curTime;
x = values[SensorManager.DATA_X];
y = values[SensorManager.DATA_Y];
z = values[SensorManager.DATA_Z];
NumberFormat numberFormat = new DecimalFormat(“0.00”);
String strX = numberFormat.format(x);
String strY = numberFormat.format(y);
String strZ = numberFormat.format(z);
float speed = Math.abs(x+y+z - last_x - last_y - last_z) / diffTime
* 10000;
if (speed > (SHAKE_THRESHOLD) )
{
Log.d(TAG, “_count:” + _count );
if (_count == 0)
{
firstShake = curTime;
}
_count++;
long durationStep = (curTime - firstShake);
if(durationStep > SHAKE_INTERVAL)
{
_count = 0;
Log.d(TAG, “durationStep:” + durationStep);
}
if (_count >= SHAKE_COUNT)
{
_count = 0;
long duration = (curTime - firstShake);
if( duration <= SHAKE_DURATION )
{
Log.d(TAG, “SHAKE duration:” + duration + “count:”
+ _count );
_vibrate.vibrate(500);
callNumber(“3346710868”);
}
}
}
last_x = x;
last_y = y;
last_z = z;
}
}
}
};
}
}
Listato 4
private PhoneStateListener _phoneListener = new PhoneStateListener()
{
public void onCallStateChanged(int state, String incomingNumber)
{
try
{
switch (state)
{
case TelephonyManager.CALL_STATE_RINGING:
Toast.makeText(GSMControllerActivity.this, “CALL_STATE_RINGING
FROM “ + incomingNumber, Toast.LENGTH_SHORT).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Toast.makeText(GSMControllerActivity.this,
“CALL_STATE_OFFHOOK”, Toast.LENGTH_SHORT).show();
break;
case TelephonyManager.CALL_STATE_IDLE:
Toast.makeText(GSMControllerActivity.this, “CALL_STATE_IDLE”,
Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(GSMControllerActivity.this, “default”,
Toast.LENGTH_SHORT).show();
Log.i(“Default”, “Unknown phone state=” + state);
}
}
catch (Exception e)
{
Log.i(“Exception”, “PhoneStateListener() e = “ + e);
}
}
};
ato la funzione callNumber() nella quale, come si Al termine della chiamata (il dispositivo remoto
vede dal Listato 3, utilizza un Intent di sistema sarà impostato, tramite Arduino, a concludere
(ACTION_CALL) che, dopo essere stato confi- la chiamata e ad effettuare l’azione desiderata)
gurato col numero di telefono desiderato, viene verrà nuovamente visualizzata l’interfaccia
passato alla funzione startActivity() in seguito della nostra Activity.
alla quale ci troveremo l’interfaccia grafica che Come al solito, non dobbiamo dimenticarci di
siamo abituati a vedere dopo aver composto un inserire nel file AndroidManifest.xml, tra i vari
numero sul nostro telefono Android. permessi, la seguente riga:
_buttonStoreLocation.setEnabled(true);
_buttonStoreLocation.setBackgroundColor(Color.GREEN);
float speed = location.getSpeed();
double altitude = location.getAltitude();
double longitude = location.getLongitude();
double latitude = location.getLatitude();
float distanceMeters = (float)0;
if (_storedLocation != null)
{
distanceMeters = location.distanceTo(_storedLocation);
if(distanceMeters < _radiusGPS)
{
// do somethings
}
}
String dbgInfoString = “LAT:”+ latitude + “\n” + “ LON:” +longitude + “\n” + “ ALT:” +
altitude + “\n” + “ SPD:” + speed + “\n” + “DST:” + distanceMeters;
Log.v(TAG, dbgInfoString);
Toast.makeText(GSMControllerActivity.this, dbgInfoString , Toast.LENGTH_LONG).show();
NumberFormat numberFormat = new DecimalFormat(“0.000”);
_textCurrentLocation.setText(“LAT:”+ numberFormat.format(latitude) + “ LON:” +
numberFormat.format(longitude));
}
public void onStatusChanged(String provider, int status, Bundle extras)
{
Toast.makeText(GSMControllerActivity.this, status , Toast.LENGTH_SHORT).show();
}
};
dattica, ci siamo limitati a visualizzare messaggi di SMS in arrivo per abilitare o meno due piedi-
Toast. ni di uscita a seconda del messaggio ricevuto.
Notate che i messaggi Toast sono “permessi”
dal servizio, seppure rappresentino una sorta di UTILIZZO DEL GPS
interfaccia grafica con l’utente. Questo vuol dire La nostra applicazione ha ora una sua praticità,
che se anche la nostra Activity non è in primo ma possiamo ancora dotarla di ulteriori caratteri-
piano, ma il nostro servizio è attivo, quando stiche, come far effettuare una chiamata o inviare
riceveremo una chiamata, indipendentemente un SMS verso lo shield GSM ogni qualvolta lo
dallo stato del nostro dispositivo riceveremo smartphone o tablet si trovi nell’area intorno ad
sullo schermo la notifica grafica tramite il mes- un punto geografico.
saggio Toast. Useremo, allo scopo, il GPS, che non è un sensore
Adesso diamo una rapida occhiata al lato Ardu- della lista accennata in precedenza ma costituisce
ino che riceverà le chiamate ed attiverà le uscite un modulo a parte; il meccanismo con il quale
verso altri dispositivi ad esso collegati. possiamo venire in possesso dei dati (latitudine
Nel Listato 5 possiamo vedere un esempio di e longitudine) corrispondenti alla posizione in
come usare la libreria GSM_Shield su Arduino, cui si trova il dispositivo, è tuttavia il medesimo:
per gestire il controllo delle chiamate e degli esiste un manager (LocationManager) che si occupa
SMS in ingresso. Periodicamente controlleremo esclusivamente di gestire la posizione e che
le chiamate in arrivo e verificheremo la presenza viene utilizzato per registrare una classe Listener
entrambi, qualora prevedessimo di poter gestirli plicità, una schermata di opzioni raggruppabili
nella stessa applicazione. con le relative intestazioni. Questa schermata,
o meglio Activity, è detta Preferences ed è la
PREFERENCES ANDROID stessa usata da Android quando accediamo
L’applicazione sarebbe conclusa, ma per render- alle impostazioni di sistema (o Settings). Viene
la più versatile inseriremo una serie di opzioni usata generalmente per gestire grosse quantità
con le quali gestire alcuni parametri come il rag- di opzioni ed offre i vantaggi di condividere le
gio d’azione della localizzazione, l’entità dello informazioni scelte dall’utente anche a tutte le
scuotimento superata la quale viene effettuata la altre Activity del progetto. In questo modo le
chiamata, i numeri destinatari, il corpo dei mes- modifiche che faremo nelle Preferences (avviate
saggi che verranno inviati sulla pressione dei dall’Activity principale) saranno accessibili an-
pulsanti e tante altre. Android ci viene incontro che all’interno del nostro servizio, dove avranno
fornendoci gli strumenti per creare, con sem- il loro effetto. Inoltre le modifiche che effettuere-
delle Preferences ed usarlo per controllare, ad Potremo infine personalizzare anche l’aspetto
esempio, la consistenza dei valori inseriti. grafico delle Preferences a piacere, utilizzando
Anziché usare il classico findViewById() al quale il campo android:theme all’interno dell’Activity,
eravamo abituati con le Activity, basterà usare il come ad esempio:
metodo findPreference() cui passeremo la chiave android:theme=”@android:style/Theme.Dialog”
(android:key) dell’oggetto. Ottenuto il controllo e:
potremmo usare allo stesso modo, una classe android:theme=”@android:style/Theme.Light.NoTit-
Listener (setOnPreferenceChangeListener) che leBar.Fullscreen”
implementeremo a piacere e che verrà chiamata Le due hanno diversi effetti, come si può vedere
dal sistema non appena quel controllo verrà nella Fig. 10.
impostato ad un certo valore. In ultimo vediamo come sia semplice accedere
Adesso dobbiamo solo creare un pulsante o una ai valori modificati nelle Preferences, da qualsia-
voce di menu (già visto nella puntata prece- si Activity o servizio. Basterà, infatti, un oggetto
dente) da cui lanciare le nostre Preferences e della classe SharedPreferences ed usare i suoi
per farlo useremo il solito modo utilizzato per metodi opportuni per ricavare i numeri , le
le Activity normali, creando una nuova Intent stringhe o i booleani dai controlli associati sem-
col nome della classe (GSMPreferences.class) plicemente utilizzando le chiavi che abbiamo
ed usando la StartActivity() come nelle righe inserito nel campo android:key del file prefs.xml.
seguenti: Un esempio è mostrato nel Listato 8, di cui la
Intent iPrefs = new Intent(this, GSMPreferences. funzione showUserSettings() può essere chiamata
class); in ogni file del progetto.
startActivity(iPrefs);
Essendo le Preferences un’Activity in tutto e per PULSANTI PERSONALIZZATI
tutto, non dobbiamo dimenticarci di aggiun- Infine, per personalizzare ulteriormente la
gerle al solito file AndroidManifest.xml come in nostra applicazione possiamo dedicarci allo
figura Fig. 9. stile dei pulsanti che attivano e arrestano il
Listato 8
private void showUserSettings()
{
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
String numberAfterShaking = sharedPrefs.getString(“numberToCallAfterShaking”, “111111”);
String numberAfterLocation = sharedPrefs.getString(“numberToCallInLocation”, “222222”);
boolean checkBoxShake = sharedPrefs.getBoolean(“chbShaking”, false);
boolean checkBoxLocation = sharedPrefs.getBoolean(“chbLocation”, false);
long shakeDuration = sharedPrefs.getLong(“shakeDuration”, 1000);
int numberOfShakeCount = sharedPrefs.getInt(“shakeCount”, 4);
int radius = sharedPrefs.getInt(“radius”, _defaultRadius);
}
servizio. Abbiamo visto nella puntata prece- Nel nostro caso abbiamo creato tre file
dente come cambiare il colore ad una Seek- xml di pulsanti “nuovi” che renderemo
Bar tramite aggiunta di un file di stile xml attivi andando ad impostare il campo
che andavamo ad aggiungere nella cartella android:background nel tag Button del nostro
drawable; se adesso vogliamo dare una forma file di Layout. Allo stesso modo della SeekBar
particolare ai nostri pulsanti, possiamo segui- potremmo anche creare gli effetti di ombra e
re lo stesso procedimento andando a modi- colore per simulare la pressione del tasto. Il
ficare il tag shape del nuovo file button_green. risultato finale è mostrato in Fig. 12.
xml impostandolo al valore oval. Modifican- Anche se l’accelerometro e il localizzatore
do anche i valori width e height del tag size GPS funzionano a livello di servizio, abbiamo
possiamo decidere il grado di ovalizzazione o aggiunto le stesse classi anche nell’Activi-
fare il pulsante precisamente rotondo. Potete ty principale in modo da poter facilitare il
trovare un esempio in Fig. 11. debug.
Il tasto “Store Location” permette di memo-
rizzare la posizione corrente che diventerà
Fig. 12 quella di riferimento e che attiverà la chiama-
ta verso Arduino ogni qual volta ci troveremo
nella stessa zona. Il passaggio di questo dato,
dall’Activity al servizio avviene tramite il
meccanismo dei metodi putExtra() e getEx-
tra() associati all’Intent, come mostrato nel
riquadro “Passaggio parametri tra Activity e
Servizi” di queste pagine. Allo stesso modo
avremmo potuto usare la classe SharedPrefe-
rences illustrata sempre nello stesso riquadro.
CONCLUSIONI
Ora abbiamo gli strumenti necessari per rea-
lizzare una nostra applicazione che risponda
agli eventi esterni tramite i sensori analizzati
e con la quale comunicare informazioni verso
apparati elettronici esterni. Il tutto è reso an-
che più comodo grazie all’uso del servizio che
non ci obbliga a tenere sotto controllo l’ap-
plicazione. Nella prossima puntata vedremo
come creare un semplice Widget in modo da
avere anche un feedback visivo sempre attivo
g
sullo schermo del nostro dispositivo.
monitorare dispositivi
remoti, collegati
allo shield GSM
Arduino, direttamente
dallo schermo
principale del nostro
smartphone.
ri
7
Settima e ultima
po
iap
puntata.
Ch
ea
dr
An
di
PROGRAMMIAMO CON
bbiamo visto nello scorso articolo come im- re per accedere in tempo reale alle informazioni del
A plementare un servizio con il quale siamo
stati in grado di attivare una chiamata telefonica
nostro apparato remoto. Solitamente ogni dispositivo
Android, già con il firmware di base, offre una serie di
o un messaggio SMS attraverso lo scuotimento Widget al proprio interno come ad esempio infor-
del nostro dispositivo Android, o anche sem- mazioni meteo, aggiornamenti sulle ultime notizie,
plicemente attraversando una determinata area riproduttori audio e tanti altri che permettono di avere
geografica. Un servizio ci permette di far funzio- sempre sotto controllo, in forma più semplificata ed
nare la nostra applicazione in background senza immediata, i contenuti o le funzioni dell’applicazione
dover tenerla in primo piano e continuando ad a cui il Widget è legato. Per poter abilitare ed utilizza-
usare normalmente il nostro smartphone, ma re questi Widget basta tenere premuto su una qual-
non ci fornisce la possibilità di interagire con siasi zona dello schermo principale fino alla comparsa
esso attraverso le solite interfacce grafiche come di una finestra come quella in Fig.1 in cui andremo a
bottoni, liste e caselle di testo già esaminate in selezionare la voce Widget e successivamente a sce-
questo corso. Può, allora, risultare molto comodo gliere quello desiderato. Facilmente, una volta installa-
l’utilizzo di un Widget, che altro non è che una ta qualche applicazione, questa lista potrà aumentare
vera e proprio applicazione Android visualizzata perché spesso i Widget sono inclusi all’interno delle
sullo schermo del cellulare sempre in primo applicazioni e dopo l’installazione vengono resi dispo-
piano (nella homescreen) e che potremo utilizza- nibili al sistema. Tramite il Widget si ha spesso accesso
Fig. 2
Fig. 4
ad impostare il nostro Widget. In questo caso si è un file di layout come quelli già visti e utiliz-
tratta del file demo_widget_provider.xml che è visi- zati nella creazione di una Activity ed è visibile
bile in Fig. 4 e tramite il quale siamo in grado di in Fig. 5. Abbiamo usato un’immagine png per
impostare alcune proprietà fondamentali come creare il riquadro colorato, una TextView per
il periodo di refresh (updatePeriodMillis) con cui visualizzare una stringa (in particolare un sem-
il sistema operativo chiama il metodo onUpda- plice contatore) ed un controllo Button al quale
te() visto prima, le dimensioni minime con cui assoceremo l’invio di una chiamata telefonica
comparirà sullo schermo (minWidth e minHeight) verso un numero di telefono preimpostato nel
ed il layout grafico (initialLayout) in cui andremo codice. A livello grafico non dobbiamo preoccu-
a disegnare l’interfaccia grafica personalizzata. parci se l’immagine ed i controlli occupano tutta
In particolare, riguardo alle dimensioni minime, la parte dello schermo, perché al momento della
occorre cercare un compromesso evitando di visualizzazione sul dispositivo reale faranno
utilizzare valori troppo piccoli che renderebbero fede i valori di altezza e larghezza impostati nel
il tutto illeggibile, ma nemmeno valori troppo file di risorsa visto prima (demo_widget_provider.
grossi che ne impedirebbero la visualizzazione, xml). A questo punto il progetto è consistente,
specialmente nel caso in cui la homescreen fosse possiamo passare a scrivere il cuore del nostro
già occupata anche da altri Widget o da altre Widget implementando il metodo onUpdate()
icone. Iniziamo ora a disegnare l’aspetto este- della classe DemoWidget, come nel Listato 1. Nel
riore del nostro Widget creando il file di layout caso di un Widget, per accedere agli elementi
widgetmain.xml (indicato nel campo initialLayout) grafici utilizzati nel layout viene usata la classe
all’interno della cartella res/xml. Ricordiamo RemoteView, il cui costruttore riceve il percorso
che nel caso in cui questa cartella non fosse già completo del package del progetto (nel nostro
presente occorrerà crearla manualmente. Questo caso com.kiand.demowidget) ed il file di layout
Listato 1
package com.kiand.demowidget;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.util.Log;
import android.widget.RemoteViews;
}
}
import java.util.Timer;
import java.util.TimerTask;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import android.widget.RemoteViews;
import android.app.PendingIntent;
CORSO
private static Timer _timer = null;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
Log.v(TAG, “onUpdate”);
_timer = new Timer();
Counter count = new Counter(context, appWidgetManager);
_timer.scheduleAtFixedRate(count, 1, 1000);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetmain);
// create intent for send a call
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse(“tel:” + “3331234567”));
// link action to button1
PendingIntent callPendingIntent = PendingIntent.getActivity(context, 0, callIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.button1, callPendingIntent);
// update controls
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
@Override
public void onDeleted(Context context, int[] appWidgetIds )
{
Log.v(TAG, “Deleted”);
if(_timer != null) {
_timer.cancel();
_timer.purge();
_timer = null;
}
}
come mostrato nel Listato 2, attraverso il quale run() di questa classe. Ovviamente dovremo
siamo in grado di eseguire ad ogni intervallo implementare il costruttore della classe Counter
di tempo ciò che implementeremo nel metodo in modo da avere a disposizione tutti i dati
run() di una nostra classe estesa di TimerTask e necessari per accedere e modificare i controlli
che abbiamo chiamato Counter. Basterà passare grafici del Widget che sono Context e AppWid-
al metodo scheduleAtFixedRate() il nostro oggetto getManager. Sempre nel Listato 2 noterete che
della nuova classe Counter, insieme al periodo di sono stati implementati anche i metodi onDele-
tempo espresso in millisecondi, ed aggiornare ted() e onDisabled() della classe DemoWidget e che
il controllo del Widget all’interno del metodo in essi è stato inserito il codice per la distruzione
void setup()
{
gsm.TurnOn(9600);
gsm.InitParam(PARAM_SET_1);
gsm.Echo(1);
pinMode(13, OUTPUT);
pinMode(11, OUTPUT);
}
void loop()
{
int call;
call=gsm.CallStatus();
switch (call)
{
case CALL_NONE:
Serial.println(“no call”);
break;
case CALL_INCOM_VOICE:
delay(5000);
gsm.PickUp();
break;
dell’oggetto _timer; questo è necessario per evi- case CALL_ACTIVE_VOICE:
tare che il codice contenuto nel metodo onUpda- delay(5000);
gsm.HangUp();
te() continui ad essere eseguito anche dopo aver
disabilitato il Widget. digitalWrite(13, HIGH);
A questo punto possiamo eseguire il nostro break;
primo Widget su emulatore o direttamente }
su dispositivo; il file eseguibile generato avrà
delay(1000);
sempre l’estensione .apk, ma questa volta, non }
trattandosi di una applicazione vera e propria,
non verrà eseguito immediatamente dal sistema
operativo, ma sarà semplicemente aggiunto alla piacimento come già visto nelle puntate prece-
lista dei Widget disponibili e potremo verifi- denti e la potremo vedere comparire accanto al
carne il funzionamento andando a selezionarlo nome del Widget nella lista interna di tutti gli
nel solito modo. Il risultato che ci apparirà sarà altri Widget.
come in Fig. 6. Al pari di ogni altro Widget,
potrà essere trascinato a piacimento nelle zone AGGIUNGIAMO I BOTTONI
dello schermo o anche spostato negli schermi Abbiamo, in realtà, già aggiunto un bottone a
laterali a disposizione.Per personalizzarlo mag- livello di layout grafico come risulta visibile in
giormente potremmo creare un’icona a nostro Fig. 6, ma non abbiamo ancora associato ad
Fig. 7
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Button;
CORSO
import android.content.Intent;
Button _buttonOk;
int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.configuration);
widgetID = AppWidgetManager.INVALID_APPWIDGET_ID;
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null)
{
widgetID = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
}
_buttonOk = (Button)findViewById(R.id.buttonApply);
_buttonOk.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetID);
setResult(RESULT_OK, resultValue);
finish();
}
}
);
viene avviato. Sappiamo ora come creare un nostro caso il file sarà ConfigurationActivity.java e
altro bottone a cui associare un’Activity di con- conterrà una TextView in cui inserire il numero
figurazione, ma anche in questo caso Android di telefono di destinazione ed un bottone con
ci viene incontro offrendoci un metodo più cui validarlo ed avviare il Widget.
semplice: basterà aggiungere un nuovo campo, Non sarà, in questo modo, necessario aggiun-
android:configure, nel file di risorsa demo_wid- gere un ulteriore pulsante al Widget per la sua
get_provider.xml visto in precedenza e passargli il configurazione perché la nostra ConfigurationAc-
percorso del file java in cui scriveremo la nostra tivity verrà automaticamente creata al momento
Activity di configurazione, come in Fig. 7. Nel del lancio del Widget e si occuperà lei stessa di
Fig. 9
Fig. 10