Introducció a aplicacions per Android
Continguts
Aquest taller pretèn donar a conèixer una plataforma en desenvolupament que permet dissenyar scripts en en Python per ser executats en Smartphones amb SO Android.
La plataforma es diu SL4A, que significa Scripting Layer for Android, i és una llibreria python de funcions que permeten aprofitar els perifèrics dels telèfons intel·ligents com l'accleleròmetre, el mòdul bluetooth, la càmara, etc.
SL4A està dissenyada per desenvolupadors i està en fase de qualitat alpha.
Requisits pel taller
- Portar Smartphone amb sistema operatiu Andoid + cable USB + portàtil (no cal que en porteu tots, penseu que ens dividirem per grups per tal de treballar millor
- Instal·lar els paquets/programes necessàris pel taller
- Tenir idees bastant frikis
Instal·lació de l'entorn
- Descarregar del Google Apps l'aplicació de lectura de QR i Codi de Barres: Barcode Scanner
Fer una foto al QR de la url següent: AndroidScripting, que instal·la l'aplicacio SL4A.
Instal·lar el paquet en el smartphone. Si hi ha algun problema de permisos, cal modificar la configuració de l'Smartphone perque accepti software de 3ers: Ajustes>Seguridad>Fuentes desconocidas
Entrar a l'aplicació SL4A>View>Interpreters>Add>Python 2.6.2, això descarregarà l'intèrpret en el telèfon.
- Instal·lar l'Android Debugging Bridge (adb command) en el nostre portàtil:
sudo add-apt-repository ppa:nilarimogard/webupd8 # Afegim un repositori sudo apt-get update # Actualitzem sudo apt-get install android-tools-adb # Instal·lem la comanda adb
Cal provar que, un cop fet els passos anteriors, si executem la comanda "adb devices", amb el nostre SmartPhone connectat via USB, hauria de detectar-lo i llistar la seva adreça MAC, per exemple:
ferran@ferran-laptop:~$ adb devices List of devices attached 4790046025f8bf1c device
En cas que no el detecti, cal comprovar que la opció de Depuració de USB del mòbil està activada. La podem trobar a: Settings>Opciones de desarrollador>Depuración USB.
Instruccións i comandes útils
Un cop ja tenim l'entorn muntat, la idea és programar còmodament en el nostre portàtil i, un cop tinguem l'script fet, traspassar-lo cap al Smartphone on serà executat.
La pàgina oficial on podem trobar tota la documentació del projecte SL4A: http://code.google.com/p/android-scripting/
Més concretament, l'API de la llibreria android la podem trobar a: http://code.google.com/p/android-scripting/wiki/ApiReference
La comanda per traspassar un script del PC cap al Smartphone:
adb push /path/to/script /path/to/smartphone
En concret, els scripts cal copiar-los sota /path/to/sl4a/scripts/, que normalment serà /storage/sdcard0/sl4a/scripts.
Un cop copiat, si accedim a l'aplicació SL4A ja ens apareixerà l'script en qüestió. Per executar-lo es polsa sobre el nom de l'script i es polsa sobre la rodeta o bé sobre la terminal.
Funcions de l'API interessants
En aquest apartat es comenten alguns dels mètodes més bàsics i alhora interessants que podem trobar per fer les primeres proves com a programadors d'aplicacions Android. Per més informació cal visitar la referència completa: http://code.google.com/p/android-scripting/wiki/ApiReference
Funcions simples
- droid.makeToast('missatge') : Mostra un missatge per pantalla
- droid.notify('titol','missatge') : Crea una notificació
droid.vibrate(temps) : Fa vibrar el telèfon. La variable temps ha de ser entera i expressa mil·lisegons
- droid.mediaPlay("path/to/song") : Permet reproduïr cançons mp3
- droid.webViewShow('url', True) : Mostra una pàgina web
- droid.viewMap('adreça') : Obre una cerca de mapa en l'aplicació Google Maps
Interfície d'Usuari
- droid.dialogShow() : Funció que s'ha d'aplicar sempre, després d'haver definit quin diàleg volem, per tal que es mostri per pantalla.
- droid.dialogDismiss() : Funció que esborra el diàleg de la pantalla. Cal aplicar-la sempre quan s'hagi acabat d'utilitzar aquell diàleg.
- droid.dialogGetResponse() : Permet obtenir els valors entrats per l'usuari en aquells diàlegs que ho permetin, com ara el dialogCreateTimePicker(), entre d'altres.
- droid.dialogCreateTimePicker() : Mostra un widget per escollir una hora. Requereix del dialogGetResponse() per bloquejar el widget fins que s'entri una resposta.
- droid.dialogGetPassword('titol','missatge') : Demana a l'usuari l'entrada d'un password. No requereix el dialogGetResponse(), ja és bloquejant ella mateixa. Tampoc requereix de dialogShow().
- droid.dialogGetInput('titol','missatge','text per defecte') : Demana a l'usuari un text amb els botons d'Acceptar i Cancelar.
- droid.dialogSetPositiveButtonText('Si') : Fixa 'Si' com a text en la pestanya per acceptar l'input d'un diàleg:
- droid.dialogSetNegativaButtonText('Nono') : Anàleg a l'anterior.
- droid.dialogSetSingleChoiceItems(llista) : Crea un diàleg de tria única entre els elements de la llista. Requereix fer un Set dels botons negatius i positius i també de dialogShow() i dialogGetResponse().
Utilització dels sensors
droid.startSensingTimed(a,b) : Inicia la sensorització indicant quin dels sensors volem llegir i el període de consulta. a és un enter i indica el sensor que volem llegir [1 = Tots, 2 = Accelerometre, 3 = Magnetometre and 4 = Llum]. b indica el període de consulta del sensor en milisegons.
- droid.sensorsReadAccelerometer() : Retorna el resultat d'una lectura de l'acceleròmetre. Per consultar els valors cal fer : valors = droid.sensorsReadAccelerometer().result, on valors és una tupla amb els valors de la component de la gravetat en cadascun dels eixos x, y i z.
- droid.stopSensing() : Atura la lectura dels sensors
- droid.sensorGetLight() : Retorna un valor que indica la lluminositat rebuda pel telèfon.
Localització GPS
Per fer una lectura de la latitud i longitud en la que es troba el dispositiu cal fer el següent:
- droid.startLocating() : Iniciar la localització
- time.sleep(10) : Esperar uns segons
- droid.getLastKnownLocation().result : Llegir la localització. Aquesta funció retorna un diccionari on la clau que ens interessa és ["passive"]["latitude"] i ["passive"]["longitude"]
- droid.viewMap("%s,%s" %(latitud, longitud)) : Amb aquests paràmetres ja podem situar la nostra posició en el mapa
Utilització del Bluetooth
Tot i que la facade Bluetooth(BT) és molt extensa, explicarem una breu descripció de les funcions bàsiques per utilitzar el BT. Partim de que la comunicació BT consta de un client i un servidor. On el servidor està esperant i el client demana al servidor l'establiment de la connexió.
droid.toggleBluetoothState(<bool True/False>): Funció que permet activar (passant com a parametre True) i desactivar el BT (passant com a paràmetre False). Funció utilitzada tant per el client com per el servidor.
droid.bluetoothMakeDiscoverable(<int temps>): Permet fer que el nostre dispositiu sigui visible a altres dispositius durant un temps determinat. Les unitats de temps que es passen com a paràmetres són segons. Funció utilitzada per el servidor.
droid.bluetoothAccept(<str uuid>,<int time_out>): Funció bloquejant utilitzada per el servidor, la funció espera fins que algun client sol·licita l'establiment de connexió. Els paràmetres que se li passen són UUID, identificador del servei i el temps que esperara la petició de connexió.
droid.bluetoothConnect(<str uuid>, <str mac>): Funció utilitzada per el client. Aquesta funció fa la petició de connexió al dispositiu destí amb adreça MAC que se li passa com a paràmetre. El paràmetre UUID te el mateix significat que a la funció anterior, aquest ha de coincidir amb la del servidor.
droid.bluetoothWrite(<str missatge>): Utilitzada per el client i el servidor envia el missatge.
droid.bluetoothRead(<int n>): Lectura de mida n bytes.
Utilització de la càmera
droid.cameraCapturePicture(<str path_desti>): Se li poden passar més paràmetres per determinar la resolució de la imatge. El paràmetre del path de destí és obligatori. Aquesta funció captura una fotografia.
droid.cameraInteractiveCapturePicture(<str path_desti>): Els paràmetres són els mateixos que la funció anterior. Aquesta funció permet capturar una fotografia utilitzant l'aplicació específica del dispositiu, amb totes les funcionalitats que aquesta ofereix.
- droid.cameraStartPreview(): Mostra per pantalla tot el que es veu per la càmera.
- droid.cameraStopPreview(): Para la visualització de la funció anterior.
Propostes d'scripts
Aquí es llisten tot un següit d'idees que es poden arribar a implementar fàcilment utilitzant les funcions que hem vist amb una mica de gràcia:
Detector boca-avall
Dissenyar un script que detecti quan el telèfon està boca-avall. Quan això passi cal que avisi d'alguna forma: Fent vibrar el telèfon, emetent algun so, enviant un correu...
Pistes:
- Una forma de detectar la posificó boca-avall del mòbil és utilitzant les funcions de lectura de l'acceleròmetre. Podeu mirar d'imprimir per pantalla múltiples lectures menrte que moveu el dispositiu, així sabreu quin dels eixos cal utilitzar i quins rang de valors obtenim.
- Un altre estratègia podria ser a partir del sensor de llum ... (Opció no explorada, però podeu probar ;))
Possible solució:
1 # -*- coding: utf-8 -*-
2 import android, time
3
4 # Aquest script consulta periòdicament l'acceleròmetre per tal de
5 # determinar si el telèfon mòbil és cap per vall. En cas que així sigui
6 # emet un so d'avis i vibra.
7
8 # Creem l'objecte Android
9 droid = android.Android()
10
11 # Definim l'interval de consulta als sensors
12 droid.startSensingTimed(2,5) # 2: escollim l'acceleròmetre, 5: període en milisegons
13
14 while True:
15 time.sleep(0.005) # Anem a dormir justament un temps de període per tal de no repetir lectures
16 [ax, ay, az] = droid.sensorsReadAccelerometer().result # Agafem el resultat de la lectura
17 print az
18 if az != None and az < -8:
19 droid.vibrate(500)
20 droid.ttsSpeak("Oju peligru")
21 time.sleep(1)
22
23 droid.stopSensing() # Parem les lectures dels sensors
24 droid.exit() # Marxem del programa
Disseny d'un nivell
Dissenyar un nivell: La idea seria, a partir de les lectures de l'acceleròmetre en algun dels eixos, aconseguir que una barra de progrés horitzontal estigui al 50% quan el dispositiu està plè i varii el seu percentatge en funció de la inclinació en l'eix indicat.
Pistes per la barra horitzontal:
- droid.dialogCreateHorizontalProgress('title','text') : Crea un diàleg de barra de progrés
- droid.dialogShow() : Mostra el diàleg per pantalla
- droid.dialogSetCurrentProgress(value) : Pinta la barra fins al value indicat
- droid.dialogDismiss() : Fa desapareixer el diàleg de la pantalla
Solució:
1 # -*- coding: utf-8 -*-
2 import android, time, math
3
4 # Aquest script implementa un nivell utilitzant l'acceleròmetre. Crea
5 # una barra de progrés horitzontal que indica la inclinació del
6 # telèfon en l'eix X.
7
8 # Creem l'objecte Android
9 droid = android.Android()
10
11 # Creem una finestra de barra horitzontal de progrés
12 droid.dialogCreateHorizontalProgress('Nivell d\'inclinació', 'El 100% són', 100)
13 # Fem que aparegui per pantalla
14 droid.dialogShow()
15
16 Period_ms = 5
17 Duration_s = 25
18
19 # Definim l'interval de consulta als sensors
20 droid.startSensingTimed(2,Period_ms) # 2: escollim l'acceleròmetre, 5: període en milisegons
21 droid.dialogSetCurrentProgress(50) # Definim l'estat inicial del progrés (50%: a la meitat)
22
23 i = 0
24 value = 0
25 while i < (Duration_s)/(Period_ms*1e-3):
26 i += 1
27 time.sleep(Period_ms*1e-3) # Anem a dormir justament un temps de període per tal de no repetir lectures
28 [ax, ay, az] = droid.sensorsReadAccelerometer().result # Agafem el resultat de la lectura
29 if ax:
30 ax = ax*(-1)
31 ax = ax + 9
32 if ax < -0.99:
33 value = 0
34 elif ax > 18.99:
35 value = 100
36 else:
37 value = (ax*100)/18
38 value = math.trunc(value)
39 droid.dialogSetCurrentProgress(value) # Fixem el nou valor de progrés de la barra horitzontal
40
41 droid.dialogDismiss() # Fem desaparèixer la finestra
42 droid.stopSensing() # Parem les lectures dels sensors
43 droid.exit() # Marxem del programa
Foto temporitzada
Dissenyar un script que faci una fotografia temporitzada. La idea és que mostri un menú on es demana a l'usuari el temps en segons que vol esperar a fer la fotografia. Un cop s'ha seleccionat, s'espera el temps indicat i la fa.
1 # -*- coding: utf-8 -*-
2 import android
3 from time import sleep
4 import os
5
6 # Aquest script implementa el sistema de fer una fotografía
7 # temporitzada. Demana a l'usuari el temps d'espera desitjat, s'espera
8 # i fa la fotografia.
9
10 ruta = "/storage/sdcard0/sl4a/scripts/fw13"
11
12 #Missatges
13 title = 'Captura d\'una foto'
14 message = ('Vol capturar una foto?')
15
16 droid = android.Android()
17
18 #Se crea el mensaje si se desea tomar la foto.
19 droid.dialogCreateAlert(title, message)
20 droid.dialogSetPositiveButtonText('Si')
21 droid.dialogSetNegativeButtonText('No')
22 droid.dialogShow()
23
24 resposta = droid.dialogGetResponse()
25
26 if resposta[1]['which'] == "positive":
27 temps = droid.dialogGetInput("Escrigui el temps despera per capturar la foto (en segons)","Temps:")
28 droid.makeToast("El temps despera es de: %s segons" %temps[1])
29 sleep(int(temps[1]))
30
31 if os.path.isfile("%s/latest.png" %ruta) == True:
32 os.remove("%s/latest.png" %ruta)
33
34 droid.cameraCapturePicture("%s/latest.png" %ruta)
35 nom = droid.dialogGetInput("Amb quin nom la voleu desar?","Nom:")
36
37 command = "mv %s/latest.png %s/%s.png"%(ruta, ruta, nom.result)
38 os.system(command)
39
40 droid.makeToast("Fi del programa")
41 else:
42 droid.makeToast('Fi del programa')
Lector de codi de barres mòbil
Dissenyar un script que permeti llegir els codis de barres dels productes d'una comanda entrant. Cal poder seguir entrant productes fins que no es digui el contrari. La idea és guardar el codi del producte i el nombre d'unitats. En el moment que s'acaba d'entrar comandes, s'envia per BlueTooth els resultats cap a un ordinador central, que podría ser el nostre portàtil, on es tractaran les dades en un full de càlcul.