Python for Series 60 Elvis Pfützenreuter – INdT [email protected] Original de Osvaldo Santana Neto ([email protected]) O que são celulares “Série 60” ou Symbian Smartphones com capacidade de processamento respeitável Sistema operacional Symbian Plataforma Série 60: Symbian + interface de usuário + recursos adicionais Restou apenas a Nokia no consórcio Symbian Desenvolvimento C++ para S60 SDK completo gratuito em http://forum.nokia.com SDK inclui emulador Alguns recursos mais avançados são pagos (JTAG) API C++ do Symbian é sui generis e canhestra Progressiva adoção de APIs open-source (Qt, OpenC) _LIT(KFileName, "C:\\file1"); RFile fd; RFs fs; fs.Connect(); CleanupClosePushL(fs); User::LeaveIfError(fd.Open(fs, KFileName, EFileShareExclusive | EFileWrite)); CleanupClosePushL(fd); TBuf8<8> buf; myFile.Read(0, buf); myFile.Close(); fs.Close(); CleanupStack::PopAndDestroy(2); char buf[8]; fd = open(“C:\\file1”, O_RDWR); int len = read(fd, buf, 8); close(fd); Por que desenvolver para S60 Mais de 150-200 milhões de celulares vendidos Distribuição do aplicativo: uma vez assinado, não sofre qualquer restrição Previsões ainda apontam como plataforma dominante para os próximos anos Várias opções de linguagem: J2ME, C++, Qt, Python Plataforma fechada aberta e SDK gratuito Existe mercado e comunidade de desenvolvedores Por que usar Python para S60 Desenvolvimento C++ é difícil Desenvolver para mobile é ainda mais difícil As APIs e ferramentas dos fabricantes não ajudam O Python “resolve” muitos destes problemas por introduzir uma camada de abstração Desvantagens do PyS60 Desempenho pode ser um problema solução: módulos Python escritos em C/C++ Nem toda a API C++ do Symbian está coberta solução: idem Salada de versões dos softwares Python PyS60 2.2 Série 60 <= 1.4.6 2nd Edition Symbian 6.x até 8.x 6600, 6681, N70 3rd Edition 9.x N85, N95, N82, N96 2.5 1.9.7, 2.0 3rd Edition 9.x N85, N95, N82, N96 5th Edition N97, XPressMusic Este curso é baseado no PyS60 1.9.7 para dispositivos 3rd Edition Obter e instalar o PyS60 https://garage.maemo.org/projects/pys60/ PyS60 para SDK Versão 3.2 Distribuição para Windows Distribuição genérica Obter e instalar o PyS60 (cont.) Interpretador (inclui OpenC PIPS) Shell interativo Auto-assinado para S60 3.2 Shell interativo Assinado Nokia “alta capacidade” Instalar via Bluetooth ou PC Suite; prefira instalar no cartão de memória (D:) Shell interativo PyS60 Terminal Bluetooth via Windows Terminal Bluetooth via Mac OS X Celular conecta Terminal Bluetooth via Linux Celular conecta Terminal via Bluetooth - PyS60 Aviso: O perfil “Serial Port” do Bluetooth é temperamental Tentar conectar algumas vezes É interessante parear e liberar antes Se nada mais der certo, tente desligar celular, computador, ou ambos Console/terminal via cabo USB Rodando PyS60 no emulador Python versus modelo de segurança Pacote SIS original não instalável Crypto Certificado X.509 do desenvolvedor Auto-assinado Assinado CA Symbian $$$ Capacidades requisitadas pelo aplicativo Vide Symbian Signed Open Signed !$ Pacote SIS assinado e instalável Escopo de distribuição requisitado Homologação $$$$$$$$$ Python versus modelo de segurança Pacote SIS de aplicativo Python - é um “executável” - pode ter menos capacidades que o runtime - suas capacidades determinam o que os scripts podem fazer - contém scripts e módulos Python - PyScriptShell = um simples aplicativo escrito em Python - FAQ como utilizar o PyScriptShell assinado pela Nokia? Runtime PyS60 Scripts Python - arquivos-texto - elementos passivos - Python_1.9.7.sis - é uma biblioteca - assinada pela Nokia - muitas capacidades Módulo em C/C++ (opcional) - tem de possuir no mínimo as mesmas capacidades do aplicativo Python versus modelo de segurança Shell high-capas assinado pela Nokia Instalar script no cartão de memória via USB; ou criar um pacote SIS (veremos mais adiante) Instalar scripts via Bluetooth ou SMS não funciona Truque: ZIPar e mandar IMPORTANTE: instalar PyS60 no cartão de memória (D:) D:\data\python\ D:\private\20022ee9\ Python versus modelo de segurança Comprando um celular Série 60 para fins de desenvolvimento Modelos que já utilizei com PyS60: N-Gage QD, 6600, 6681, N93, N95, N85 Prefira modelos recentes, 3rd Edition FP1 ou superior (N95, N85, N82, N96) Verifique a lista de compatibilidade do PyS60 para evitar surpresas Celulares 2nd Edition: última versão do PyS60 que suporta é a 1.4.6 Módulos Python específicos para Symbian http://pys60.garage.maemo.org/doc/s60/ http://wiki.opensource.nokia.com/projects/PyS60_documentation Módulos Python para Symbian Relativamente fáceis de usar Poucos tipos novos Mesmo método pode ser sync & async Strings “mágicas” Protocolos “informais” via listas/tuplas/dicts Diferença = passar callback como parâmetro Não esquecer dos módulos padrão Python Módulo e32 “Caixa de ferramentas” do Symbian Não serve para muita coisa, isoladamente Active Objects = análogo a main loop, glib No futuro, o Qt deve preencher esta função from e32 import * get_capabilities() drive_list() ao_sleep(1) ao_yield() is_ui_thread() s60_version_info x = Ao_lock() x.wait() # em outro lugar x.signal() x = Ao_timer() x.after(1, funcao) x.cancel() Módulo e32 (continuação) import appuifw import e32 trava = e32.Ao_lock() def callback_sair(): print “Apertou botao” e32.ao_sleep(1) trava.signal() # acorda def main(): global trava appuifw.app.exit_key_handler = callback_sair trava.wait() # dorme main() Módulo sysinfo Informações diversas sobre o dispositivo: sysinfo.battery() sysinfo.imei() sysinfo.signal_dbm() sysinfo.signal_bars() sysinfo.display_pixels() Módulo appuifw Acesso à UI, o mais complexo dos módulos S60 Quem já usou PyGTK+, vai achar familiar appuifw.app: classe Application appuifw.app.body: Canvas, ListBox ou Text appuifw.app.menu Dialogs modais Form (widget “composto”) Ligação de eventos/teclas a ações No futuro, o Qt deve tomar o lugar deste módulo Layout de uma aplicação S60 Módulo appuifw >>> import appuifw >>> appuifw.app.title = u"BLA" >> def tab_cb(n): ... print "Mudou para tab", n ... >>> appuifw.app.set_tabs([u"Um", u"Dois"], tab_cb) Mudou para tab 1 Mudou para tab 0 >>> appuifw.app.orientation = 'landscape' >>> appuifw.app.screen = 'large' Módulo appuifw >>> def menu_cb(*algo): ... print algo ... >>> appuifw.app.menu = \ [(u"Item um", menu_cb), (u"Item dois", menu_cb)] >>> () >>> appuifw.selection_list([u"AAA", u"BBB"]) 1 >>> appuifw.query(u"Digite texto", u"text") u'Inconstitucional' Módulo appuifw >>> appuifw.note(u"Fora Sarney", u"error") >>> def cb(*algo): ... print algo ... >>> f = appuifw.Form( [(u'Nome', 'text'), (u'Idade', 'number')]) >>> f.save_hook = cb >>> f.execute() ([(u'Nome', 'text', u'Boa'), (u'Idade', 'number', 18L)],) Módulo graphics Classe Image e função screenshot() Câmera gera imagens da classe Image Image implementa API drawable appuifw.Canvas idem >>> i = graphics.Image.open("E:\\teste.jpg") >>> i.ellipse((0, 0, 100, 100), fill=0xff0000) >>> i.save("E:\\teste2.jpg") Módulo camera Permite manipular a(s) câmera(s) Não funciona no emulador Symbian, mas há extensões para suprir esta função camera.cameras_available() i = camera.take_photo() i.save(u“E:\\imagem.jpg”) canvas = appuifw.Canvas() appuifw.app.body = canvas canvas.blit(i) # Image import e32, camera, appuifw, key_codes def finder_cb(im): # pode manipular a imagem antes canvas.blit(im) camera.start_finder(finder_cb) ... camera.stop_finder() i = camera.take_photo(size=(640,480)) Tirar foto usando a 2a câmera camera.take_photo(position=1) Não há viewfinder para 2a câmera Improvisar com take_photo()+blit() periódico ou tentar com camera.device[1].start_finder() # Copyright Jurgen Scheible import e32, camera, appuifw, key_codes def finder_cb(im): canvas.blit(im) def take_picture(): camera.stop_finder() pic = camera.take_photo(size = (640,480)) w,h = canvas.size canvas.blit(pic,target=(0, 0, w, 0.75 * w), scale = 1) pic.save('e:\\teste.jpg') def quit(): app_lock.signal() canvas = appuifw.Canvas() appuifw.app.body = canvas camera.start_finder(finder_cb) canvas.bind(key_codes.EKeySelect, take_picture) appuifw.app.title = u"Camera" appuifw.app.exit_key_handler = quit app_lock = e32.Ao_lock() app_lock.wait() import e32, camera, appuifw def finder_cb(im): canvas.blit(im) def status_cb(*algo): print algo canvas = appuifw.Canvas() appuifw.app.body = canvas camera.start_finder(finder_cb) camera.start_record(“e:\\video.mpeg”, status_cb) e32.ao_sleep(10) camera.stop_record() camera.stop_finder() camera.release() Módulos gles/glcanvas Módulo de acesso ao OpenGL/ES OpenGL/ES é acelerado por hardware nos celulares Nokia N93, N95 e N82 (N97?) Não será abordado aqui Exemplo: script gles.py Módulo audio Funciona no emulador audio.say(u”Bla”) Classe audio.Sound s = Sound.open(u”e:\\arquivo.wav”) s.record() Cumulativo, não trunca Se durante ligação, grava ligação s.stop() s.play() Módulo telephone telephone.dial(“5551234567”) telephone.hang_up() Fazer e atender ligações Gravação de áudio: vide módulo audio Módulo sensor API diferente em FP1 e >= FP2 3rd Edition FP1: Sensor (N95, N93) from sensor import * sensor_type = sensors()['RotSensor'] N95_sensor = Sensor(sensor_type['id'], sensor_type['category']) N95_sensor.set_event_filter(RotEventFilter()) def get_sensor_data(status): print status N95_sensor.connect(get_sensor_data) Módulo sensor >= 3rd Edition FP2 (N85, N96, N97...) import sensor from sensor import * accel = RotationData() # AccelerometerXYZAxisData() >>> accel.start_listening() True >>> accel.x -2 >>> import e32 >>> x = 1000 >>> while x > 0: ... x -= 1 ... print accel.x, accel.y, accel.z ... e32.ao_sleep(1) Módulo messaging messaging.sms_send(”99845555”, u”Oi”) messaging.mms_send(...) Repare na string Unicode! Permite passar um callback para receber o status do envio Módulo positioning >>> import positioning >>> positioning.modules() [{'available': 1, 'id': 270526860, 'name': u'Assisted GPS'}, {'available': 1, 'id': 270526858, 'name': u'Integrated GPS'}, {'available': 1, 'id': 270559509, 'name': u'Network based'}] >>> positioning.select_module(270526860) >>> positioning.set_requestors( [{"type":"service", "format": "application", "data": "test_app"}]) >>> positioning.last_position() >>> positioning.position() >>> # positioning.position(callback=cb) Módulo inbox Acesso a mensagens SMS incoming Callback para ser notificado de novas msgs. >>> import inbox >>> i = inbox.Inbox() >>> m = i.sms_messages() >>> i.content(m[0]) U'Meet me by 7pm at motel' >>> i.time(m[0]) 1130267365.03125 >>> i.address(m[0]) U'Vulnavia Phibes' >>> i.delete(m[0]) # SIGWIFE Módulos contacts/e32calendar Módulos razoavelmente complexos Explorar com base na documentação >>> import contacts >>> db = contacts.open() >>> db.find("Ana") [<Contact #33: "Ana Bolena">] >>> db[33].as_vcard() 'BEGIN:VCARD\r\n...END:VCARD\r\n' >>> import e32calendar >>> db = e32calendar.open() >>> db.find_instances(time.time(), \ time.time() + 30*86400) [{'id': 2, 'datetime': 1251226800.0}] >>> >>> db[2] <e32calendar.AppointmentEntry> >>> db[2].content u'Pendrive' >>> db[2].get_repeat() {'end': 4133905200.0, 'interval': 1, } Módulo btsocket Soquetes Bluetooth Controle de access points à Internet btsocket.socket(AF_BT || AF_INET, ...) Testar BT no console BT pode falhar Bug em bt_discover() (3rd Edition FP2) AP escolhido pelo usuário ou pelo aplicativo Sockets podem ligados a diferentes Aps Módulo padrão socket também disponível socket.set_default_access_point(u”Nome”) Módulo btsocket >>> bt_discover() # invoca UI ('00:23:12:3c:ba:a3', {u'Bluetooth-PDA-Sync': 3}) >>> bt_obex_discover() Traceback (most recent call last): File "<console>", line 1, in <module> error: (13, 'Permission denied') >>> bt_obex_discover('00:23:12:3c:ba:a3') ('00:23:12:3c:ba:a3', {u'OBEX Object Push': 10}) >>> bt_obex_send_file('00:23:12:3c:ba:a3', \ 10, u"e:\\teste.jpg") >>> s.connect(("00:23:12:3c:ba:a3", 10)) # bt_advertise_service # bt_rfcomm_get_available_server_channel Módulo btsocket >>> from btsocket import * >>> access_points() [{'iapid': 10, 'name': u'ASP'}, {'iapid': 2, 'name': u'bandalarga.claro.com.br'}, {'iapid': 9, 'name': u'EPX'}] >>> ap = access_point(9) >>> set_default_access_point(ap) >>> ap.start() >>> ap.ip() '192.168.141.9' >>> s = socket(AF_INET, SOCK_STREAM) >>> s.connect(("www.folha.com.br", 80)) >>> s.send("GET /\r\n\r\n") 9 >>> print s.recv(100) <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">... >>> s.close() >>> ap.stop() btsocket X socket btsocket = “soquetes” Symbian, limitados Não são aceitos por select() Não ingressam em grupos multicast etc. socket = soquetes do OpenC Limitação inclui soquetes BT Mais poderosos (multicast funciona) Única desvantagem: relação com access points Módulo select não “repete” notificações não funciona para write (Symbian) Módulo scriptext Platform Services API: acesso neutro a recursos do sistema (via strings) >= 3rd FP2, abordaremos “por cima” Application Manager, Sys Info Calendário, Contatos Location, Landmarks import scriptext Messaging m = scriptext.load('Service.Messaging', Sensors 'Imessaging') msgs = m.call("GetList", {"Type": u"Inbox"}) Media Management for msg in msgs: print msg['Sender'] Módulos e32db/e32dbm e32db: mini-banco de dados do Symbian Mesma idéia do SQLite e32dbm: Interface DBM para e32db anydbm é apelido de e32dbm em PyS60 >>> >>> >>> >>> import anydbm db = anydbm.open("E:\\teste.dbm", "c") db["a"] = "b" db.close() >>> db = anydbm.open("E:\\teste.dbm") >>> db {'a': 'b'} Outros módulos logs (registro de ligações e SMS) keycapture (captura eventos teclado) topwindow (Janela modal top-level) Ciclo de desenvolvimento Teste no PC (emuladores de API) Edição no PC Impl. APIs (pys60-compat) Teste no emulador Symbian Teste no celular Windows Moroso Emulador imperfeito Testando scripts PyS60 no PC Use módulos emuladores criadas por terceiros Muita atenção com o Unicode PyS60-compat (UI e gráficos) Lightblue (Bluetooth) Saiba quais APIs demandam ou retornam strings Unicode Tire proveito da orientação a objetos Python Crie módulos ”emuladores” para o PC PyS60 no emulador Symbian Instalar Carbide, Perl e SDK 3rd Edition FP1 ou FP2 Instalar PyS60 para SDK, casando a versão (FP1 ou FP2) Cygwin é muito utilizado por desenvolvedores Symbian profissionais EPOC32=C:\s60\devices\S60_3rd_FP2_SDK_v1.1\epoc32 $EPOC32\winscw\c\Data\python # scripts $EPOC32\winscw\c\resource\python25 # módulos PyS60-compat Distribuindo um aplicativo PyS60 Aplicativo = um script ou uma pasta Ensymble Vem na distribuição PyS60 Depende do Python 2.5 (não serve 2.4 ou 2.6) Gera e assina pacote SIS Determina módulos Python a embarcar Não elide necessidade de certificado $$$ Permite embutir outros SIS ...por exemplo, o runtime PyS60 facilita a distribuição de app. Python ao usuário final Criando um pacote SIS no Windows Criando um pacote SIS no Linux Criando um pacote SIS no MacOSX Instalando pacote SIS do PyS60 Criando extensões em C/C++ Implica em usar Windows e o SDK do S60 src\extras\elemlist ou elemlist.zip (curso) Capacidades >= aplicativo que vai importá-la (e.g. nosso “aplicativo” é o PyScriptShell) Opção 1: usar o PyScriptShell auto-assinado Opção 2: adquirir um certificado $$$ Links sobre PyS60 http://www.mobilenin.com/pys60/menu.htm http://sourceforge.net/projects/pys60-compat/ https://garage.maemo.org/projects/pys60 http://pys60.garage.maemo.org/doc/s60/ http://wiki.opensource.nokia.com/projects/PyS60_applications http://www.hiit.fi/files/fi/da/sdk2unix/ http://www.hiit.fi/files/fi/da/miso/utils/web/