Metodă Software de Controlare a Unui Speaker Inteligent
FUNDAȚIA PENTRU CULTURĂ ȘI ÎNVĂȚĂMÂNT “IOAN SLAVICI” TIMIȘOARA
UNIVERSITATEA“IOAN SLAVICI” TIMIȘOARA
FACULTATEA DE INGINERIE
DOMENIUL CALCULATOARE ȘI TEHNOLOGIA INFORMAȚIEI
FORMA DE ÎNVĂȚĂMÂNT – ZI
Proiect de diplomă
CONDUCĂTOR ȘTIINȚIFIC
Prof. dr . ing. Mircea Vlăduțiu
ABSOLVENT
Butoi Cosmina Raluca
– 2016 –
FUNDAȚIA PENTRU CULTURĂ ȘI ÎNVĂȚĂMÂNT “IOAN SLAVICI” TIMIȘOARA
UNIVERSITATEA“IOAN SLAVICI” TIMIȘOARA
FACULTATEA DE INGINERIE
DOMENIUL CALCULATOARE ȘI TEHNOLOGIA INFORMAȚIEI
FORMA DE ÎNVĂȚĂMÂNT – ZI
Metodă software de controlare a unui speaker inteligent
CONDUCĂTOR ȘTIINȚIFIC
Prof. dr . ing. Mircea Vlăduțiu
ABSOLVENT
Butoi Cosmina Raluca
2016
UNIVERSITATEA DIN ORADEA
FACULTATEA de Inginerie Electrică și Tehnologia Informației
DEPARTAMENTUL Calculatoare și tehnologia informației
TEMA: METODĂ SOFTWARE DE CONTROLARE A UNUI SPEAKER INTELIGENT
Lucrare de Finalizare a studiilor a studentului: BUTOI COSMINA RALUCA
1). Tema lucrării de finalizare a studiilor: METODĂ SOFTWARE DE CONTROLARE A UNUI SPEAKER INTELIGENT
2). Termenul pentru predarea lucrării: 7.06.2016
3). Elemente inițiale pentru elaborarea lucrării de finalizare a studiilor: DOCUMENTAȚIE DE SPECIALITATE ȘI DESCRIERE COMPONENTE NECESARE PENTRU ELABORAREA PROIECTULUI
4). Conținutul lucrării definalizare a studiilor : PREZENTAREA UNEI METODE (APLICAȚIE) DE A CONTROLA UN SPEAKER INTELIGENT
5). Material grafic: PARTEA TEORETICĂ AJUTĂ LA ÎNȚELEGEREA PĂRȚII APLICATIVE , PROIECTUL CONȚINÂND ȘI REZULTATUL OBȚINUT ÎN URMA STUDIULUI BIBLIOGRAFIC
6). Locul de documentare pentru elaborarea lucrării:
FRONTIER SILICON TIMIȘOARA, BIBLIOTECA UNIVERSITĂȚII POLITEHNICA DIN TIMIȘOARA.
Data emiterii temei: 20. 10.2015
Coordonator științific
Prof. Dr. Ing. Mircea Vlăduțiu
REFERAT
PRIVIND LUCRAREA DE LICENȚĂ
A
ABSOLVENTULUI / ABSOLVENTEI : BUTOI COSMINA RALUCA
DOMENIUL Calculatoare și tehnologia informației
SPECIALIZAREA Tehnologia informației
PROMOȚIA 2016
Titlul lucrării: Metodă software de controlare a unui speaker inteligent
Structura lucrării:
Cap. I – Introducere
Cap II – Studiu bibliografic pentru fundamentarea teoretică a părții applicative
Cap III – Studiu de caz – Logica de funcționare a aplicației
Cap IV – Arhitectura aplicației
Aprecieri asupra conținutului lucrării de LICENȚĂ (finalizare a studiilor), mod de abordare, complexitate, actualitate, deficiențe:
Lucrarea se caracterizează printr-o construcție echilibrată cu o bună ponderare între dezvoltarea noțiunilor teoretice și descrierea aplicativă. Lucrare conține o parte aplicativă deosebit de consistentă. Autoarea dezvoltă în mod corect elemente teoretice esențiale, înșirându-le în lucrare doar în măsura în care contribuie la înțelegerea părții aplicative.
Lucrarea tratează o problematică de strictă actualitate, luând în considerare importanța domeniului sisteme încorporate (embedded systems).
Aprecieri asupra lucrării (se va menționa: numărul titlurilor bibliografice consultate, frecvența notelor de subsol, calitatea și diversitatea surselor consultate; modul în care absolventul a prelucrat informațiile din surse teoretice):
Sunt utilizate referințe bibliografice de marcă în domeniu, sursele bibliografice fiind alese în mod corespunzător.
Considerăm tematica dată spre rezolvare ca fiind integral soluționată. Materialul grafic este executat în mod îngrijit, fiind complementar părții redactate. Redactarea lucrării e realizată într-o manieră concisă.
(se va menționa: opțional locul de documentare și modul în care absolventul a realizat cercetarea menționându-se contribuția autorului):
Lucrarea are la bază un număr de 15 titluri bibliografice . Informațiile preluate din surse teoretice sunt citate în mod corespunzător , fiind inserate în lucrare pe măsură ce sunt implementate.
Concluzii (coordonatorul lucrării trebuie să aprecieze valoarea lucrării întocmite, relevanța studiului întreprins, competențele absolventului, rigurozitatea pe parcursul elaborării lucrării, consecvența și seriozitatea de care a dat dovadă absolventul pe parcurs):
În baza celor mai sus menționate, apreciez că lucrarea elaborată de absolventă este deosebit de valoroasă, fiind bazată pe un amplu studiu de literatură de specialitate, absolventa devedind reale competențe în domeniul embedded systems.
De asemenea, apreciez rigoarea în activitatea de elaborare a lucrării de licenă, precum și consecvența.
Redactarea lucrării respectă întocmai cerințele academice de redactare (părți, capitole, subcapitole, note de subsol și bibliografie).
Consider că lucrarea îndeplinește/ nu îndeplinește condițiile pentru susținere în sesiunea de Examen de LICENȚĂ (finalizare a studiilor) din IULIE 2016 și propun acordarea notei ………………
Oradea,
Data Conducător științific,
14. 06. 2015 Prof. Ing. Dr. Mircea Vlăduțiu
Cuprins
Cap. 1 INTRODUCERE
1.1 Contextul lucrării
Într-o era dominata din ce în ce mai mult de tehnologie, în care calea către internet este liberă și nerestricționată, efortul omenirii la dezoltarea tehnologiei în care se dorește obținerea maximului de confort cu un minim de efort este tot mai pregnant.
Această dorință și nevoie acută se materializează prin diverse sisteme automatizate, care au scopul de a facilita munca depusă de om.
1.2 Scopul proiectului
Proiectul a fost realizat cu scopul facilitării comunicării între speakerul inteligent (radio) și om, având ca element mediator sau de tranziție, device-ul utilizat (telefon), sporind confortul user-ului în interacțiunea cu speakerul.
Acest proiect face subiectul temei mele de licență, dar de asemenea reprezintă o mare parte din timpul meu, fiind elementul de creație al firmei din cadrul căreia fac parte (Frontier Silicon). El poate servi și în scop didactic altor studenți dornici de a arăta cunoștințele dobândite de-a lungul anilor de studiu.
1.3 Structura proiectului
Structura proiectului este constituită din trei părți complementare:
Studiu bibliografic – partea teoretică, în care sunt explicate noțiunile fundamentale care au stat la baza fundamentării aplicației.
Studiu de caz – în care este explicată logica de funcționare a aplicației.
Arhitectura aplicației – modul în care aceasta se desfașoară.
Cap. 2 STUDIU BIBLIOGRAFIC PENTRU FUNDAMENTAREA TEORETICĂ A PĂRȚII APLICATIVE
2.1 Sisteme încorporate ( Embedded systems) [1]
Un sistem încorporat reprezintă un sistem informatic sau orice dispozitiv care include un computer dar nu este el însuși un computer de uz general, având o funcție dedicată în cadrul unui sistem electric sau mecanic mai mare, deseori cu o constrângere în timp real.
Sistemele încorporate sunt sisteme la care calculatorul/microprocesorul sunt doar simple componente. Principalul scop al utilizării microprocesorului este să simplifice construcția sistemului și să ofere flexibilitate în proiectare și construcție.
Exemple:
– Vehicule (automobil, avion, …)
– Controlul traficului(autostradă, aerian, căi ferate, …)
– Controlul proceselor (uzina electrică, chimică …)
– Sisteme medicale (terapia prin iradiere, …)
– Telefonie, radio, comunicații prin satelit
– Jocuri de calculator
Un sistem încorporat este un sistem pe bază de microprocesor construit pentru a controla o funcție sau un domeniu de funcții particulare și care nu este proiectat pentru a fi programat de către utilizatorul final. Singura interacțiune cu utilizatorul se face în scopul realizării funcțiilor impuse sistemului – aplicației.
Un sistem încorporat folosește o combinație de hardware și software (o masină computațională) pentru a realiza o funcție specifică lucrând într-un mediu reactiv și care impune restricții de timp.
Sistemele încorporate sunt sisteme de prelucrare a informației înglobate în produse mai mari și care nu sunt de obicei vizibile utilizatorului.
În mod normal un sistem încorporat se obține prin încorporarea (includerea) unui calculator într-un sistem orientat pe o aplicație.
Cel mai simplu model de încorporare a unui calculator într-un sistem este prezentat in figura1.1.
2.1.1 Caracteristici ale sistemelor încorporate
Principalele caracteristici ale sistemelor încorporate sunt:
– Funcționalitate sofisticată, gradul de sofisticare fiind dependent de aplicație;
– Operarea în timp real – chiar daca nu este obligatorie, este caracteristică pentru multe din aplicațiile încorporate.
– Costuri de fabricație scăzute.
– Aplicații dependente de procesor – chiar dacă nu sunt obligatorii sunt frecvente
– Memorie restricționată
– Consum mic – multe din aplicațiile încorporate sunt destinate sa funcționeze pe baterii.
Am specificat mai devreme că o caracteristică importantă o constituie costurile de producție scăzute. Acestea au două componente:
– costurile pentru proiectarea și dezvoltarea produsului
– costurile de producție și vânzare pentru fiecare unitate de produs.
Costurile vor fi corelate cu numarul de unitați realizate: spre exemplu o aplicație foarte specifică (precum controlul comenzilor în cazul unui avion) va presupune costuri de proiectare mari, fiind posibilă utilizarea unor elemente hardware și software sofisticate și scumpe. La proiectarea unor telefoane celulare low cost însa se va avea în vedere în primul rand minimizarea costurilor.
2.1.2 Sisteme de timp real
Am specificat anterior că una dintre caracteristicile posibile ale sistemelor încorporate este operarea în timp real. În cele ce urmează vom încerca să definim caracteristicile operării de timp real.
O definiție simplă a operării de timp real este aceea ca operațiile trebuie finalizate în intervale de timp predefinite; altfel spus, funcționarea trebuie să respecte restricțiile de timp.
Se pot defini operații:
– Hard real time – la care depășirea intervalului de timp determină defecte, catastrofe (constrangeri RT critice la timp)
– Soft real time – la care depășirea intervalului de timp determină scaderea performanțelor (constrângeri RT sensibile la timp)
În cazul operării RT un răspuns garantat al sistemului trebuie să fie explicat fără a folosi argumente statistice.
Multe sisteme sunt sisteme multirată – ele primesc informații din exterior la intervale de timp diferite și sunt prelucrate în intervale de timp diferite.
2.1.3 Alte caracteristici ale sistemelor încorporate
Sistemele încorporate au de asemenea și alte caracteristici, ca de exemplu:
– Toleranța la defect – unele aplicații trebuie să continue să funcționeze chiar dacă unele componente soft sau hard sunt scoase din funcțiune (controlul zborului unui avion de exemplu)
– Siguranța – nu trebuie să provoace daune persoanelor sau proprietăților
– Funcționalitate predefinită – se pot realiza numai anumite funcții iar hadware-ul și software-ul cu care este dotat sunt destinate realizării acestor funcții predefinite
– Există posibilitatea ca anumite funcții predefinite să fie folosite foarte rar de-a lungul perioadei de utilizare, altfel spus, foarte rar vor fi folosite toate funcțiile ce pot fi programate
– Increderea – descrisă de proprietatea de a funcționa corect la un moment dat
– Mentenabilitatea – probabilitatea ca sistemul să lucreze corect o anumita perioadă, după apariția unor erori
– Disponibilitatea – probabilitatea ca sistemul să lucreze corect un timp dat
– Securitatea – asigurarea confidențialitătii datelor prelucrate
2.1.4 Tipuri de sisteme încorporate
Există o mare diversitate de sisteme încorporate care realizează funcții foarte diferite, de aceea sunt greu de găsit criterii clare de clasificare ale acestora. Un criteriu general acceptat este cel bazat pe funcțiile principale pe care acestea le implementează. Astfel se pot distinge:
– Sisteme încorporate similare calculatoarelor de uz general – acestea au ca principala sarcină raspunsul la comenzile operatorului;exemple agenda electronica, jocurile video, etc.
– Sisteme automate – ca raspuns la informațiile preluate din exterior prin intermediul senzorilor, sistemul reacționeaza prin comanda elementelor de execuție; exemple: controlul în bucla închisă pentru sisteme de timp real, controlul motorului autovehiculelor, controlului zborului, etc.
– Procesarea semnalelor: radar, sonar
– Comunicare și rețele – telefoane celulare, aplicații INTERNET (ROUTER)
2.1.5 Tipuri de funcții realizate de sistemele încorporate
Câteva exemple de funcții realizare de sistemele încorporate sunt:
– Legea de control
– Secvențierea logică
– Procesare semnale – sunt necesare pentru procesarea semnalelor de intrare primite de la senzori
– Interfațare specifică aplicației – depinde de tipurile de senzori și elemente de comandă cu care se interfațează
– Răspunsuri greșite – determină modul în care va acționa sistemul în caz de erori; este necesar ca în caz de eroare să nu apară o avarie catastrofică (să cadă sistemul) ci să aibă loc o deteriorare graduală (de exemplu în cazul descărcării bateriilor se emite un semnal de avertizare care să comunice utilizatorului acest lucru.
2.1.6 Arhitectura sistemelor încorporate
Vom prezenta în continuare o arhitectură mai completă. În figura 1.2. este prezentată o astfel de arhitectură. Se remarcă prezența blocului de bază care acum se extinde față de modelul simplu prezentat anterior, la acest bloc de bază adăugându-se mai multe elemente exterioare. În blocul de bază se remarcăCPU care comunică cu memoria, în care este depus software-ul ce permite controlul sistemului încorporat. Se remarcă de asemenea CAN-ul prin intermediul căruia sunt preluate semnalele analogice de la senzori, precum și CNA prin intermediul căruia CPU transmite semnalele de comandă spre elementele de execuție.
Se remarcă de asemenea prezența în blocul de bază a unei componente (special hardware) necesară deoarece în unele cazuri, CPU-ul nu este capabil să execute instrucțiunile soft-ului respectând condițiile real time.
Componente externe:
– Interfața operator – este menită să asigure atât primirea de date (comenzi) de la operatorul uman cât și să-l informeze despre funcționarea sistemului. Va fi constituită din butoane, ecran sau un simplu afișaj cu LED-uri.
– Blocul de diagnoză – este destinat diagnosticării sistemului determinate erorii și modului în care acestea pot fi remediate; acest bloc trebuie să lucreze chiar și în cazul în care sistemul nu este activ pentru a putea testa funcționarea corectă a tuturor componentelor sistemului
– Sisteme auxiliare – asigură alimentarea cu energie electrica a sistemului, răcirea și protecția mecanică
– Protecția electromagnetică externa – trebuie să asigure atât protecția cât și aspectul exterior al sistemului, aspect ce devine foarte important.
Fig. 1.2 Arhitectura complexă a unui sistem încorporat
2.1.7 Implementarea sistemelor încorporate
Principalele componente hardware sunt:
– element de procesare (microprocesor, microcontroler)
– elemente periferice
o dispozitive de intrare – ieșire
o Interfațare senzori și elemente de execuție
– Memorie
– Magistrală
Elementele sunt similare unui sistem de calcul de uz general
Deosebirile sunt determinate de natura și numărul intrarilor – ieșirilor. Acestea sunt mult mai diverse și mai numeroase în cazul sistemelor încorporate decât în cazul unui sistem de calcul de uz general.
Există două componente software principale:
– Software de sistem – care are funcții similare sistemului de operare din sistemul de calcul de uz general; trebuie remarcat că pe lângă cerințele impuse sistemelor de operare de uz general, în cazul sistemelor încorporate este necesar ca software de sistem să respecte și cerințele specifice sistemelor de timp real. O cerința specială este legată de faptul că de obicei programarea (în limbaj de nivel înalt) se face pe un calculator care emulează sistemul încorporat și de aceea sunt necesare cross asambloare și cross compilatoare. Astfel un compilator pentru PIC-uri va rula pe un PC; acesta va compila programul scris (în C de exemplu) și va genera un cod specific pentru PIC.
În unele cazuri există posibilitatea de a simula pe PC mediul (intrări, ieșiri) și de a testa complet funcționarea sistemului încorporat. În acest fel, codul în assambler generat pe PC este transferat și utilizat în sistemul încorporat. De asemenea, pentru depanarea programului, sistemul încorporat este cuplat cu un PC. Faptele preluate de la sistemul încorporat sunt preluate și interpretate pe PC.
– software de aplicație – este cel care individualizează sistemul încorporat respectiv. Dacă același soft de operare poate lucra pe mai multe tipuri de sisteme încorporate, soft-ul de aplicație este strict specific.
2.1.7.1 Caracteristici ale soft-ului utilizat în sistemele încorporate
Caracteristicile soft-ului utilizat în sistemele încorporate sunt următoarele:
– Programele trebuie să fie corecte din punct de vedere logic și temporal. Dacă corectitudinea logică este caracteristică tuturor programelor, corectitudinea temporală este impusă de cerințele de aplicație de timp real.
– Trebuie să asigure concurența fizică implicită deoarece un sistem încorporat poate lucra multiuser și multiproces.
– Siguranța în funcționare și toleranța la defect sunt obligatorii, soft-ul fiind cel care trebuie să asigure aceste proprietați.
– Soft-ul de aplicție este specific și are un scop unic.
– Funcționarea multitasking și concurența este determinată de faptul că un sistem încorporat trebuie să poata lucra cu mai multe intrări și ieșiri și cu evenimente multiple în mod independent – multe sisteme încorporate sunt obligate să lucreze multitasking. Separarea task-urilor simplifică programarea, dar cere comutarea într-un anumit fel, ănainte și înapoi printre diferite task-uri (programare multitasking). Concurența reprezintă aparenta execuție simultană a mai multor task-uri.
2.1.7.2 Cerințe în proiectarea sistemelor încorporate
In proiectarea unui sistem încorporat trebuie urmarită rezolvarea unor probleme specifice precum:
– Cât de mult hardware este necesar – care este lungimea cuvântului pentru CPU, dimensiunea memoriei, etc.
– Care va fi dimensiunea intervalului de timp care să asigure finalizarea operațiilor (intervalul de timp pentru finalizarea operațiilor în real-time) – un hard mai rapid sau un soft mai inteligent – un hard mai rapid înseamnă costuri de producție mai mari în timp ce soft-ul mai inteligent presupune cheltuieli de dezvoltare mai mari. Trebuie găsit un compromis care să asigure performanțe maxime cu costuri minime.
– Cum să se minimizeze consumul de energie – oprirea elementelor care nu sunt necesare, reducerea accesării memoriei.
2.1.7.3 Proiectarea sistemelor încorporate
Vom prezenta în continuare câteva principii și cerințe preliminare referitoare la proiectarea unui sistem încorporat. Menționăm ca aceste principii vor fi dezvoltate ulterior.
În proiectarea unui sistem încorporat trebuie luate în considerare diferite cerințe și interacțiuni dintre performanțele impuse asupra sistemului. Dintre principalele obiective ale proiectării amintim:
– performanțe (viteza, limite de timp în RT)
– funcționabilitate și interfața utilizator
– cost de producție
– consum de energie
– dimensiune, formă, protecție, etc.
– cerințe funcționale – ieșirea ca o funcție de intrare
În proiectarea și dezvoltarea sistemelor trebuie parcurse anumite etape, conform figurii 1.3
Fig. 1.3 Etape ale proiectării și dezvoltării sistemelor încorporate
Există câteva modalități de proiectare:
Proiectarea de sus în jos – se pornește de la descrierea cea mai abstractă și se lucrează pentru detaliere
Proiectarea de jos în sus – se pornește de la mici componente la mari sisteme
În proiectarea reală cele doua modalități sunt combinate.
2.1.7.4 Concluzii
Sistemele încorporate se regăsesc peste tot în jurul nostru – multe dintre acestea includ un hardware și un software complex.
Dezvoltarea unui sistem încorporat presupune rezolvarea unui mare număr de provocări.
S-au dezvoltat metodologii de proiectare care să ajute la gestionarea procesului de dezvoltare.
2.2 Platforma Android [2], [3]
Conform definiției, Android este o platformă software și un sistem de operare pentru dispozitive și telefoane mobile bazată pe nucleul Linux, dezvoltată inițial de compania Google, iar mai târziu de consorțiul comercial Open Handset Alliance. Android permite dezvoltatorilor să scrie cod gestionat în limbajul Java, controlând dispozitivul prin intermediul bibliotecilor Java dezvoltate de Google. Aplicațiile scrise în C și în alte limbaje pot fi compilate în cod mașină ARM și executate, dar acest model de dezvoltare nu este sprijinit oficial de către Google.
Platforma Android a fost lansată la 5 noiembrie 2007,de catre un consorțiu de 48 de companii de hardware, software și de telecomunicații ( fondarea Open Handset Alliance), consacrat dezvoltării de standarde deschise pentru dispozitive mobile. Google a lansat cea mai mare parte a codului Android sub licența Apache, o licență de tip free-software și open source. Platforma a rulat pentru prima dată pe telefonul T Mobile G1, lansat in 2008.
Pe telefoanele mobile din peste 190 de țări este prezentă platforma Android, fiind într-o continuă creștere. În fiecare zi un alt milion de utilizatori pornesc pentru prima dată dispozitivele care rulează Android și încep să caute aplicații, jocuri sau alt conținut digital.
Gratuitatea oferită de Android au făcut din acesta preferatul utilizatorilor și al dezvoltatorilor deopotrivă, înregistrând creșteri specatculoase în consumul de aplicatii, peste 1.5. miliarde de aplicații și jocuri fiind descărcate lunar de pe Google Play.
Platforma asigură în mod automat interfața grafică cu utilizatorul, dând de asemenea posibilitatea dezvoltatorului de a avea suficient control asupra modului în care va arăta interfața grafică pe diferite dispozitive.
Există numeroase avantaje pentru cei care aleg să dezvolte aplicații bazate pe platforma Android, printre care:
Android are „ rădacini ”- se află în interiorul unei game largi de dispozitive și reprezintă o platformă majoră pentru dezvoltatorii de aplicații.
Platforma Android este intr-adevăr o platformă deschisă în sensul că toate capacitățile telefonului sunt puse la dispoziția dezvoltatorului. De exemplu, putem înlocui aceste capacități (ex. e-mail) cu propriile aplicații.
Platforma Android este gratuită. Se pot descărca aplicații fără a plăti pentru acest lucru sau pentru platforma de dezvoltare.
Android dispune de numeroase capacități și servicii care pot fi refolosite. Are un suport predefinit pentru grafică de nivel înalt, de detectare a locației și de prelucrare a datelor.
Aplicațiile Android sunt scrise in Java, unul dintre cele mai răspândite limbaje de programare.
Îndrumare pentru dezvoltatori bazată pe framework: Deoarece Android este un framework – nu doar un toolkit format dintr-un set de librării – impune o structură în dezvoltarea aplicațiilor prin utilizarea unui model. În schimbul acestei constrângeri se obțin o serie de beneficii. Spre exemplu, în dezvoltarea unei aplicații, dezvoltatorul poate urmări o cale sistematică în conceperea unei aplicații robuste, ceea ce îi permite să se concentreze pe oferirea unor capabilități complexe în loc de a pierde timp cu punerea la punct a structurii aplicației, a unui design de nivel înalt sau a gestionării ciclului de viață a aplicației.
2.3 Arhitectura Sistemului Android [2], [3]
Arhitectura sistemului unui dispozitiv Android este compusă din urmatoarele elemente, așezate în straturi unul deasupra celuilalt, în următoarea ordine:
Nucleul Linux: fiecare dispozitiv Android rulează sistemul de operare Linux, cunoscut și sub denumirea de „ nucleul” Linux. Acesta acționează ca un strat de abstractizare și gestionare pentru hardware. Cu alte cuvinte, prezintă diferitele dispozitive Android într-un mod standard astfel încât dezvoltatorii să potă scrie o singură dată aplicația dar să o poată rula pe toate dispozitivele Android. Nucleul oferă de asemenea serviciile de sistem de bază precum securitate, gestionarea memoriei, gestionarea proceselor, crearea de rețele și driver-ele pentru dispozitive (cum ar fi tastatura și touchscreen).
Librării: acestea sunt librării native, C/C++ specifice dispozitivului, folosite de sistemul de operare dar și de numeroasele componente ale Android. Librăriile sunt de două tipuri: C și C++ care sunt considerate componente standard de Linux (de exemplu „libc”) și librării care conferă capacități Android relevante (de exemplu baza de date SQLite).
Android runtime: reprezintă amândouă aplicații native și librării Java care permit dezvoltarea de aplicații Java pentru Android.
Framework-ul aplicației: acesta este un set de clase standard Java folosite în dezvoltarea aplicațiilor.
Aplicațiile: reprezintă aplicațiile în sine. Acestea includ aplicațiile care vin împreună cu orice dispozitiv Android cât și cele scrise de dezvoltatori.
Fig 1.4 Straturile sistemului Android
Sursa: [Gargenta]
Bibliotecile native sunt luate din comunitățile open source, pentru a furniza serviciile necesare nivelului aplicației. Printre aceste biblioteci se numără: Webkit, SQLLite, OpenGL, etc.
Dalvik este o mașină virtuală Java proiectată special pentru Android. În mod tradițional fișierele sursă sunt compilate de către compilatorul Java și codul binar opținut se rulează pe mașina virtuală Java. Pentru Android codul binar Java opținut se recompilează folosind compilatorul Dalvik, iar codul binar astfel opținut este rulat în mașina virtuală Dalvik.
Frameworkul pentru Aplicații este un mediu bogat, care oferă numeroase servicii și biblioteci Android care vin în ajutorul dezvoltatorilor de aplicații mobile. Acesta este partea cea mai bine documentată a platformei Android.
Activitățile
O activitate este de obicei o singură imagine afișată utilizatorului pe ecranul dispozitivului mobil, la un moment dat. O aplicațe Android este alcătuită din mai multe activități, iar utilizatorul aplcației navighează printre ele. Activitățile sunt partea cea mai vizibilă a unei aplicații.
O activitate este în starea ”Starting” când încă nu există în memorie. În urma procesului de inițializare ea va trece în starea ”Running”. Acest proces de inițializare este unul foarte costisitor.
O activitate este în starea ”Running” atunci când este vizibilă pe ecran și utilizatorul poate interacționa cu ea. Activitatea se află în starea ”Paused” cand nu mai interacționează cu utilizatorul, dar este încă vizibilă.
”Stopped” este starea în care activitatea nu mai este vizibilă pe ecran, dar se află încă în memorie. Din această stare activitatea poate reveni în starea ”Running” sau poate să ajungă în starea ”Destroyed” dacă se șterge din memorie.
2.4 Framework-ul (Cadrul de aplicații) Android [2], [3]
Folosind doar Mașina virtuală Dalvik, putem scrie programe Java pentru Android. Pentru a veni și mai mult în ajutorul dezvoltatorilor, Android dispune de un set de componente scrise în Java, cunoscute colectiv sub numele de Framework-ul (Cadrul de aplicații) Android. Aceste componente sunt descrise în cele ce urmează:
Administratorul de activități (Activity Manager): Un container pentru toate aplicațiile Android care au fost scrise în Java. Acesta gestionează ciclul de viață a tuturor aplicațiilor Android. Aceasta presupune tratarea aspectelor de început și de sfârșit ale aplicației Android, precum și a stărilor intermediare.
Administratorul de fragmente (Fragment Manager): Un fragment reprezintă o porțiune din interfața cu utilizatorul a unei activități. Pot fi combinate multiple fragmente într-o singură activitate pentru a construi interfețe cu utilizatorul multi-parte cât și pentru reutilizarea fragmentelor în activități multiple. Administratorul de fragmente gestionează fragmentele și oferă si o interfață de programare a acestora.
Furnizorii de conținut (Content Providers): Încapsulează datele care trebuie partajate între aplicații. Aplicația de contacte de pe un dispozitiv Android este un furnizor de conținut.
Administratorul de resurse (Resource Manager): Facilitează accesul la resursele utilizate de programul curent.
Administratorul de locație (Location Manager): Oferă informații legate de locația dispozitivului, precum coordonatele GPS.
Administratorul de notificări (Notification Manager): Permite aplicației dezvoltate să prezinte evenimente utilizatorului (de regulă în timp ce acesta este ocupat facând altceva) pentru ca acesta să poată lua măsuri.
2.5 Bazele unei aplicații și activarea componentelor [2], [3]
Aplicațiile Android sunt compuse din una sau mai multe componente de aplicație (activități, servicii, furnizori de conținut, receptori de transmisie). Fiecare componentă joacă un alt rol în comportamentul de ansamblu al aplicației și fiecare poate fi activată individual (chiar și de către alte aplicații).
Fiecare aplicație Android trebuie să conțină un fișier manifest care trebuie să declare toate componentele aplicației și toate cerințete aplicației, precum versiunea minimă de Android necesară și orice configurație hardware necesară [2].
Resursele aplicației care nu fac parte din codul propriu-zis (imagini, fișiere audio etc.) trebuie să includă alternative pentru diferite configurații de dispozitive.
Activitățile, serviciile și broadcast receivers sunt activate de un mesaj asincron numit Intent. Intent-urile leagă componentele individuale unele de altele la rulare indiferent dacă componenta aparține aplicației tale sau altei aplicații.
Un Intent este creat cu un obiect Intent, care definește un mesaj pentru a activa o componentă specifică sau un tip sfecific de componentă. Un intent poate fi implicit sau explicit.
Pentru activități și servicii, un intent definește actiunea ce trebuie efectuată. De exemplu un Intent poate transmite o cerere pentru o activitate de a afișa o imagine sau de a deschide o pagină web. În anumite cazuri, se poate porni o activate pentru a primi un rezultat, caz în care activitatea de asemenea returnează rezultatul unui Intent [3].
Pentru Broadcast receivers, intentul definește anunțul care trebuie transmis.
Cealaltă componentă, content provider, nu este activată de către un Intent. Ea este activată când este vizată de către o cerere de la ContentReceiver.
Există metode separate pentru activarea fiecărui tip de componentă:
O activitate poate fi pornită prin transmiterea unui Intent către startActivity() sau startActivityForResult() atunci când dorim ca activitatea să returneze un rezultat.
Un serviciu poate fi pornit prin transmiterea unui Intent către startService(). Sau ne putem lega la un serviciu prin transmiterea unui Intent către bindService().
Putem efectua o interogare către un content provider apelând query() pe un ContentResolvaer.
Mai există un fișier XML specific aplicației numit Manifest. Înainte ca sistemul Android să pornească o componentă a aplicației, sistemul trebuie să știe de existența componentei citind fișierul AndroidManifest.xml, acesta este fișierul manifest specific aplicației. Aplicația trebuie să declare toate componentele în acest fișier. Fișierul Manifest mai face și alte lucruri în plus față de doar declararea componentelor aplicației precum:
Identifică permisiunile utilizatorului pe care aplicația le cere, precum accesul la internet astfel:
<uses-permissionandroid:name="android.permission.INTERNET"/>
Declară nivelul API minim necesar aplicației, în funcție de ce API-uri folosește aplicația astfel:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19"/>
Declară caracteristicile hardware sau software utilizate de către aplicație sau necesare aplicației precum camera, servicii bluetooth și altele.
Librăriile API de care aplicația trebuie să fie legată (altele decat API-urile framewor-ului Android), de exemplu librăriile Googe Maps.
2.5.1 Fișierul Manifest.XML
Scopul primar al manifest-ului este acela de a informa sistemul despre componentele aplicației. De exemplu am declarat activitatea existentă în felul următor:
<application
android:allowBackup= ”true”
android:icon = ”@drawable/ic_app”
android:label = ”@string/app_name”
android:supportsRtl = ”true”
android:theme = ”@style/AppTheme” >
<activity
android:name= ”.MainActivity”
android:label= ”@string/app_name”
android:theme = ”@style/AppTheme.NoActionBar”>
<intent-filter>
<actionandroid:name = ”android.intent.action.MAIN”/>
<category android:name = ”android.intent.category.LAUNCHER”/>
</intent-filter>
</activity>
<activityandroid:name = ”.SourcesListActivity”/>
<activityandroid:name = ”.BrowseActivity”></activity>
</application>
În elementul<application se găsesc urmatoarele atribute:
Atributulandroid:allowBackup="true"indică dacă aplicația este inclusă în sistemul de backup, permițând sau nu user-ului să își recupereze datele în urma unei acțiuni de backup executată pe device.
Atributul android:icon="@drawable/ic_app"indică icoana corespunzătoare aplicației care se găsește în resurse. Acest atribut se setează ca o referință către o resursă din drawable care conține definiția imaginii.
Atributul android:label="@string/app_name"este o etichetă vizibilă de către utilizator pentru activitate. Aceasta este afisată pe ecran, de obicei însoțită de către icoana activității. Această etichetă este setată ca o referință către o resursă String care conține numele aplicației.
Atributulandroid:supportsRTL="true" indică dacă aplicația suportă layout de tip right – to –left. Dacă este setat ca true și android:targetSdkVersion este setat având valoarea 17 sau mai mult, numeroase RTL APIs vor fi activate și folosite de sistem, astfel încât aplicația poate afișa mai multe RTL layout-uri. Dacă este setata ca false sau dacă android:targetSdkVersion este setat având valoarea 16 sau mai puțin, RTL APIs vor fi ignorate și nu vor avea efect la rotirea device-ului.
Atributul android:theme="@style/AppTheme.NoActionBar"este o referință către resursa de stil care definește o temă pentru toate activitățile.
În elementul<activityatributulandroid:name=".MainActivityspecifică numele complet al subclasei MainActivity care extinde clasa Activity și atributul android:label="@string/app_name"care specifică un string impreuna cu atributul android:theme = ”@style/AppTheme.NoActionBar”sunt folosite ca o etichetă pentru activitate vizibilă utilizatorului.
În interiorul elementului<activity este un element </intent-filter>.
Acțiunea pentru acesta este numită:
<action android:name="android.intent.action.MAIN"/>
și indică faptul că această activitate servește ca un punct de intrare pentru aplicație.
Categoria pentru acesta este numită:
<categoryandroid:name="android.intent.category.LAUNCHER"/>și indincă faptul că aplicația poate fi lansată din icoana corespunzatoare de pe dispozitiv.
Ultimele doua elemente <activitycu atributulandroid:name=". SourcesListActivityși android:name = ”.BrowseActivity”specifică numele complet al subclasei SourceListActivity respectiv al sublasei BrowseActivity care extind clasa Activity.
2.5.2 Caracteristici
Tabelul nr. 1
2.6 Software Development Kit (SDK) [2], [3]
Android SDK (Software Development Kit) este bazat pe limbajul Java. Programele Java sunt compilate cu ajutorul JDK (Java Development Kit). Toate aplicațiile și jocurile sunt scrise în Java și rulează pe dispozitive Android folosind JRE (Java Runtime Environment). Un program Java are o extensie .class și fișierul care conține codul sursă are o extensie .java. Programele construite cu Android SDK sunt compilate în pachete care pot rula pe platforma Android. Există două medii de dezvoltare principale pentru Java: Eclipse și NetBeans. Amândouă au puncte tari și puncte slabe, nefiind superioare unul altuia.
Tabelul nr.2
2.7 Native Development Kit (NDK) [2], [3]
Android NDK (Native Development Kit) permite scrierea de componente pentru aplicații sau jocuri în limbaj C++ nativ în loc de Java. NDK este o unealtă separată care se instalează după ce Android SDK a fost instalat. NDK nu permite scrierea unei întregi aplicații sau a unui întreg joc în C++. El este folosit pentru a suplimenta SDK cu suport pentru codul și librăriile C++ și este conceput să opereze ca un pod de legătură pentru multe dispozitive hardware pe care nu este disponibilă nici o librărie Java.
2.8 Application Programming Interface (API) [2], [3]
Nivelul API (Application Programming Interface) este o valoare întreagă care identifică în mod unic revizia framework-ului (cadrului de lucru) oferită de o versiune a platformei Android.
Platforma Android pune la dispoziție un framework (cadru de lucru) API pe care aplicațiile îl pot folosi să interacționeze cu sistemul Android care stă la bază. Framework-ul (cadrul de lucru) API se compune din:
Un set nucleu de pachete și clase
Un set de elemente și atribute XML pentru declararea unui fișier manifest
Un set de elemente și atribute XML pentru declararea și accesarea de resurse
Un set de Intent-uri
Un set de permisiuni pe care aplicația le poate solicita
Tabelul de mai jos specifică nivelul API suportat de fiecare versiune a platformei Android.
Tabelul nr.3
Cap. 3 STUDIU DE CAZ – LOGICA DE FUNCȚIONARE A APLICAȚIEI
Principiul de interacțiune între aplicația implementată și device-ul embedded (speaker sau radio) se face prin protocolul TCP/HTTP, trimițând comenzi către speaker, aceste comenzi fiind disponibile în librăria JAVA implementată în acest scop. Software-ul radioului permite aplicației să execute urmatoarele acțiuni:
Descoperirea speaker-lor și conectarea la acestea
Schimbarea sursei audio a speaker-ului
Navigarea
3.1 Descoperirea speaker-lor și conectarea la acestea [ANEXA 1]
SSDP sau Simple Service Discovery Protocol este un protocol de rețea folosit pentru descoperirea serviciilor suportate de un device din rețea. Acest lucru se realizează fără ajutorul unui server DHCP (Domain Host Configuration Protocol) sau DNS (Domain Name System) în rețeaua respectivă.
SSDP este bazat pe protoculul HTTPU și folosește protocolul de tip UDP pentru transmiterea mesajelor în rețea. Serviciile sunt ”anunțate în rețea” de către sistem pe adresa de multicast pe portul 1900. În IPv4 adresa de multicast este 239.255.255.250.
SSDP-ul folosește de asemenea și notificări HTTP pe rețea pentru a anunța sistemele prezente în rețea când sistemul ce transmite aceste notificări și-a pornit sau oprit serviciile.
Un client care dorește să descopere serviciile disponibile în rețea folosește metoda M-SEARCH. Răspunsuri la această metodă sunt trimise folosind adresele de ”unicast” la adresa IP de la care s-a primit mesajul de M-Search.
Un exemplu de cerere de tip M-Search este prezentat in fig 1.6, de mai jos:
Fig. 1.6 Mesaje de tip M-Search trimis de client
Parametrii mesajului de M-SEARCH sunt prezentate în tabelul de mai jos:
Parametrii mesajului de răspuns la un mesaj de tip M-SEARCH sunt prezentate în tabelul de mai jos:
Un exemplu de răspunsul la un mesaj de tip M-Search este prezentat in fig 1.7, de mai jos:
Fig. 1.7 Răspuns la mesajul de tip M-Search
Pentru a descoperi speakerele din rețea, aplicația Android, implementată în acest proiect, trimite un mesaj de M-Search pe adresa de multicast: 239.255.255.250 cu parametrul ST setat cu valoarea: ”ssdp:all” pentru a indica că se dorește un răspuns pentru fiecare serviciu disponibil pe speakere.
Dupa ce speaker-ul primește acest mesaj va răspunde la rândul lui cu un mesaj de tipul celui prezentat în figura Y pentru fiecare serviciu pe care îl are.
Aplicația Android va identifica serviciile necesare adăugarii speaker-ului în listă dar nu înainte de a accesa locația oferită de device în parametrul LOCATION al răspunsului. La această locație se află un fișier de tip XML care conține detaliile device-ului cum ar fi:
sursele audio disponibile (FM, Spotify, Internet Radio, Media Player etc.)
numele speaker-ului
versiunea de software
modelul speaker-ului( număr și nume )
lista serviciilor disponibile
În figura 1.8 de mai jos se află conținutul unei descrieri complete al unui speaker.
Fig 1.8 Descrierea completă a speaker-ului( dd.xml )
În urma acțiunii de selectare a speaker-ului din listă se trece la pasul următor care e crearea unei conexiuni directe cu speaker-ul folosind adresa IP și portul preluat din răspunsul mesajului de M-Search.
3.2 Schimbarea sursei audio a speaker-ului [ANEXA 2]
După acțiunea de selectare a speaker-ului din lista de speakere disponibilă, în aplicație se trece la pasul următor, care e afișarea tuturor surselor audio disponibile pe speaker.
Sursele disponibile sunt preluate din descrierea speaker-ului (dd.xml ) care se află la locația oferită în răspunsul speaker-ului la mesajul de M-Search.
Lista de surse preluată din descrierea speaker-ului are următorul format:
<fsns:X_Features>
IR, Media Player
</fsns:X_Features>
Lista surselor audio este prezentată în aplicație pentru a oferi utilizatorului posibilitatea de a controla sursa de pe care se dorește redarea audio.
Mai jos sunt prezentate pe scurt fiecare sursă disponibilă pe speaker:
IR:Această sursă permite redarea stațiilor/înregistrărilor radio disponibile pe internet prin portalul vTuner. Conexiunea cu portalul vTuner este facută de speaker, acesta oferind o lista de stații radio și/sau directoare în ecranul de navigare al aplicației.
Media Player: suportă redarea fișierelor audio de pe un device USB sau de pe serverele cu support UPnP de pe retea.
Schimbarea surselor audio se face prin selectarea sursei dorite din lista de surse oferită în aplicație. Aplicația va transmite comanda către speaker, acesta raspunzand cu FS_OK dacă acțiunea s-a executat cu success sau FS_FAIL în cazul în care sursa nu a putut fi schimbată.
3.3 Navigarea [ANEXA 3]
Navigarea permite selectarea unei stații, fișier audio, din sursa audio selectată, în scopul redării acelui fișier pe speaker.
Pentru executarea acestei acțiuni aplicația va trimite o comandă către speaker care returnează o lista cu fișiere/stațiile disponibile din meniul principal al sursei selectate.
Acțiunea de selectare se face prin trimiterea unei comenzi de selectare iar speaker-ul răspunde cu FS_OK sau FS_FAIL daca acțiunea s-a executat cu succes sau nu. Dacă s-a selectat un fișier speaker-ul transmite aplicației lista nouă din fișierul respectiv. În caz contrar, dacă s-a selectat o stație radio/fișier audio, speaker-ul va reda stația radio/fișierul audio.
Cap. 4 ARHITECTURA APLICAȚIEI
În acest capitol se vor prezenta în mod sumar principalele componentele arhitecturale ale aplicației.
4.1 Descoperirea speakerelor în rețea
În figura 1.9 se poate observa arhitectura modulului de program implementat pentru descoperirea speakerelor în rețea:
Fig 1.9 Schema arhitecturala – descoperirea speakerelor in retea
Acest modul de descoperire a speakerelor în retea este împărțit în două submodule principale:
Blocurile din schema arhitecturală de mai sus, de culoare verde reprezintă partea principală de inițializare a aplicației: inițializarea metodei de comunicare cu speaker-ul și inițializarea controalelor disponibile în aplicație.
Blocurile de culoare portocalie reprezintă principalele metode apelate în procesul de descoperire a speakerului în rețea.
Mai jos sunt prezentate pe scurt metodele utilizate aferente figurii 1.9:
Pornire SSDP Discovery: acest task are ca funcție pricipală trimiterea de mesaje de tip M-SEARCH pe rețea în scopul căutarii speakerelor.
Căutare speakere: Rolul acestei metode este de a recepționa mesajele de raspuns la M-SEARCH și filtrarea acestora în funcție de tipul speaker-ului.
Oprire SSDP Discovery( Oprirea task-ului de SSDP ): Oprirea acestui task se face dacă nu a mai fost găsit niciun speaker în urma a 5 încercări de căutare.
Temporizator: Temporizatorul va asigura o căutare de speakere în rețea, continuă, într-un interval definit. În cazul acestei aplicații căutarea se face în inteval de 2 minute.
“Search”(Acționare buton “search”): Aplicația deține și un buton de căutare manual, amplasată în partea de jos, dreapta. În urma acționării acestui buton, de către utilizator, toate speakerele descoperite recent vor fi șterse din listă, urmând a fi reluată căutarea în mod forțat. Această funcționalitate este utilă în cazul în care user-ul nu dorește a aștepta 2 min pentru ca lista să fie actualizată în mod automat ( funcționalitate asigurată de Temporizator ).
Afișarea speakerelor: Dacă criteriile de acceptare a speakerului descoperit în rețea sunt îndeplinite acesta va fi adăugat în lista de speakere și afișat pe ecranul telefonului.
4.2 Selectarea speakerului
În figura 2.0 de mai jos este prezentată schema arhitecturală corespunzătoare selectării speakerului din lista de speakere din aplicație.
În urma acțiunii de selectare a speakerului ,efectuată de către utilizator, aplicația va încerca să creeeze o conexiune de tip TCP cu speaker-ul. Dacă se detectează o eroare de rețea, procesul de conectare se va reluat automat, încercand de 3 ori consecutiv.
Următorul pas după conectarea la speaker este preluarea datelor importante de la acesta. Datele principale sunt conținutul listei de surse audio disponibile. Preluarea acestor date se face prin intermediul librăriei NetRemote care pune la dispoziție un API ce trimite la speaker o comandă în scopul obținerii unui răspuns valid conținând lista surselor audio.
Dacă răspunsul de la speaker a fost recepționat cu succes și este valid, atunci lista va fi afisată pe ecranul telefonului, în caz contrar lista nu va fi afișată, utilizatorul fiind nevoit să reia procesul de selecție al speakerului.
Fig 2.0 Schemă arhitecturală – selectarea speakerului
4.2 Selectare sursă audio
După cum s-a menționat anterior, selectarea speakerului are ca rezultat afișarea surselor audio disponibile. Decizia de afișare a acestor liste se face pe baza a două criterii principale:
Sursele audio sunt listate în lista de “features” returnată ca și răspuns la cererea descrierii speakerului( dd.xml )
Sursele audio sunt listate în lista returnată de către speaker în urma acțiunii de selectare a acestuia.
Această listă oferă utilizatorului posibilitatea de selectare a sursei curente de pe speaker. În cazul acestei aplicații sursele disponibile sunt urmatoarele( fig 2.1 ):
Internet Radio
Media Player – acestă sursă este împărțită în două sub-surse:
Shared Media
USB Playback
În urma acțiunii de selectare a sursei dorite, dacă sursa selectată este selectabilă, o comandă va fi transmisă de către libraria de NetRemote către speaker.
Răspunsul la comanda transmisă constă într-o listă; fiecărui element din lista primită îi corespunde un indice de afișare, acesta reprezentând ordinea afișării și posibilitatea de a folosi acest indice în acțiunea de navigare descrisă în următorul subcapitol.
Lista primită va fi procesată și afișată în mod corespunzător pe ecranul telefonului. Fiecărei surse audio disponibile îi corespunde o lista individuală, după cum urmează:
Internet Radio:
My Favourites – conține o listă de stații radio personalizată. Personalizarea acestei liste poate fi facută atât prin folosirea interfeței speakerului cât și prin folosirea interfeței web oferite de “Provider”.
Local Romania – lista stațiilor radio locale. Această listă folosește locația curentă a utilizatorului, oferindu-i acestuia access rapid la stațiile locale.
Stations – lista completă de stații radio disponibile, oferite de “Provider”.
My Added Stations – lista de stații adăugate de către utilizator folosind interfața web oferită de “Provider”.
Help – acest element oferă posibilitatea înregistrării speakerului în lista “Providerului” pentru oferirea accesului la interfața web pusă la dispoziție de acesta.
Media Player:
Shared media – după cum s-a menționat și mai sus, aceasta este una din sub-sursele disponibile în Media Player. Selectarea acestei sub-surse are ca efect căutarea de dispozitive cu suport “Media”, cum ar fi:
Windows – pc.
“Network Attached Storage”.
Telefoane mobile cu suport UPNP.
USB playback – această sub-sursa oferă posibilitatea de redare a fișierelor audio de pe un USB. Pentru aceasta este necesară conectarea dispozitivului la portul USB disponibil pe interfața speakerului.
Fig 2.1 Schemă arhitecturală – selectarea sursei audio
4.3 Navigare
Navigarea permite selectarea fișierelor/listelor disponibile în fiecare sursă audio selectată, dacă aceasta suportă funcționalitate.
În figura 2.2 este prezentată schema arhitecturală a procesului de navigare.
Ca urmare a acțiunii utilizatorului, de selectare a fisierului, aplicația va trimite o comandă de navigare către speaker prin intermediul modului NetRemote.
Răspunsul la această comandă poate fi de două tipuri:
Lista de fișiere/foldere selectabile
Lista de fișiere audio
Procesarea răspunsului la comanda de navigare este similară cu cea de selectare a sursei audio, prezentată anterior.
Procesul de navigare se ocupă doar cu navigarea în fișiere/foldere cu posibilitatea de returnare la grupul de fișiere accesat anterior, prin accesarea butonului de returnare din aplicație.
Fig 2.2 Schemă arhitecturală– navigare
Un exemplu simplu de navigare, în sursa Internet Radio, este prezentat în figura 2.3.
Fig 2.3 Exemplu de navigare
4.4 Selectarea conținutului audio
Selectarea conținutului audio este similar cu navigarea doar că selectarea nu este pe un fișier/folder ci pe un fisier audio.
Redarea acestor fișiere audio este facută de către speaker în momentul în care comanda de redare este trimisă de către aplicație.
Codecurile suportate de către speaker sunt următoarele:
MP3
AAC
MP4
FLAC
ALAC
În figura 2.2 este prezentată schema arhitecturală a procesului de selectare a conținutului audio.
După ce utilizatorul selectează fișierul audio, aplicația va aștepta răspunsul de confirmare de la speaker, urmând ca să se afișeze mesajul: ”Playing” urmat de numele fișierului audio selectat pentru o perioadă scurtă de timp.
Ca și informție persistentă se va afișa în partea de jos a aplicației, cu fundal gri, numele fișierului audio în redare și detaliile acesteia dacă sunt disponibile.
Numele fișierului audio în redare este preluat de aplicație printr-un API oferit de librăria NetRemote care oferă ca și răspuns numele acestui fișier.
Fig 2.4 Schemă arhitecturală – selectare conținut audio
ANEXE
ANEXA 1
MainActivity:
package com.frontier_silicon.discoverysampleapp;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Switch;
import android.widget.Toast;
import com.frontier_silicon.NetRemoteLib.Discovery.IDiscoveryServiceListener;
import com.frontier_silicon.NetRemoteLib.Discovery.ISSDPScanner;
import com.frontier_silicon.NetRemoteLib.NetRemote;
import com.frontier_silicon.NetRemoteLib.Node.NodeInfo;
import com.frontier_silicon.NetRemoteLib.Node.NodePlayInfoName;
import com.frontier_silicon.NetRemoteLib.Radio.IGetNodeCallback;
import com.frontier_silicon.NetRemoteLib.Radio.NodeErrorResponse;
import com.frontier_silicon.NetRemoteLib.Radio.Radio;
import com.frontier_silicon.NetRemoteLib.Radio.RadioHttp;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "DISCOVERYSAMPLE";
private static final boolean SHOW_GROUPS_DEFAULT = false;
private ListView mListView;
private ArrayAdapter<Speaker> mListAdapter;
private ArrayAdapter<Speaker> mGroupsListAdapter;
private List<Speaker> mSpeakerList;
private List<Speaker> mSpeakerGroupsList;
private IDiscoveryServiceListener mSSDPListener;
private NetRemote mNetRemote;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initNetRemote();
initListView();
initControls();
}
private void initControls() {
FloatingActionButton fabScan = (FloatingActionButton) findViewById(R.id.btnScan);
fabScan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startDiscovery();
}
});
changeListViewContent(SHOW_GROUPS_DEFAULT);
}
private void startDiscovery() {
startSSDPDiscovery();
}
@Override
public void onResume() {
super.onResume();
startDiscovery();
}
@Override
public void onPause() {
super.onPause();
stopSSDPDiscovery();
}
private void initListView() {
mSpeakerList = new ArrayList<>();
mSpeakerGroupsList = new ArrayList<>();
mListAdapter = new SpeakerArrayAdapter(this, R.layout.speaker_list_item, mSpeakerList);
mGroupsListAdapter = new SpeakerArrayAdapter(this, R.layout.speaker_list_item, mSpeakerGroupsList);
mListView = (ListView) findViewById(R.id.listDevices);
mListView.setAdapter(mListAdapter);
mListView.setEmptyView(findViewById(R.id.empty));
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Speaker selectedSpeaker = (Speaker) parent.getAdapter().getItem(position);
if (selectedSpeaker != null) {
onRadioClick(selectedSpeaker);
}
}
});
}
private void onRadioClick(Speaker selectedSpeaker) {
Log.i(TAG, "RADIO CLICKED: " + selectedSpeaker.mRadio);
if (selectedSpeaker.mRadio != null) {
openSourcesActivity(selectedSpeaker.mRadio);
}
}
private void openSourcesActivity(Radio radio) {
Intent i = new Intent(this, SourcesListActivity.class);
ConnectionManager.getInstance().setRadio(radio);
startActivity(i);
}
private void initNetRemote() {
Context context = getApplicationContext();
mNetRemote = new NetRemote(context.getPackageManager(), context);
//NetRemote.SetLogTraceFlag(NetRemote.TRACE_SSDP_BIT | NetRemote.TRACE_SSDP_DEBUG_BIT);
}
private void addSpeakerToList(final Speaker speaker) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!mSpeakerList.contains(speaker)) {
mSpeakerList.add(speaker);
} else {
Log.e(TAG, "addSpeakerToList EXISTS: " + speaker);
}
mListAdapter.notifyDataSetChanged();
}
});
}
private void addSpeakerToList(final Radio radio) {
Speaker newSpeaker = new Speaker(radio.getFriendlyName(), radio.getIpAddress(), 80, Speaker.DiscoveryType.SSDP);
newSpeaker.mRadio = radio;
((RadioHttp)radio).setPIN("1234");
addSpeakerToList(newSpeaker);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
return super.onOptionsItemSelected(item);
}
private void clearSpeakerList() {
runOnUiThread(new Runnable() {
@Override
public void run() {
mSpeakerList.clear();
mListAdapter.notifyDataSetChanged();
mSpeakerGroupsList.clear();
mGroupsListAdapter.notifyDataSetChanged();
}
});
mNetRemote.CloseAllRadios();
}
private void startSSDPDiscovery() {
stopSSDPDiscovery();
mSSDPListener = new IDiscoveryServiceListener() {
@Override
public void onRadioFound(Radio radio) {
Log.i(TAG, "onRadioFound: " + radio);
addSpeakerToList(radio);
}
@Override
public void onRadioLost(Radio radio) {
Log.i(TAG, "onRadioLost: " + radio);
}
@Override
public void onRadioUpdated(Radio radio) {
}
@Override
public void onScanError(ISSDPScanner.ScanError error) {
Log.i("DISCOVERYSAMPLE", "onScanError>>> " + error);
}
@Override
public void onScanStart() {
Log.i("DISCOVERYSAMPLE", "onScanStart>>> ");
}
};
mNetRemote.getDiscoveryService().addListener(mSSDPListener);
mNetRemote.getDiscoveryService().start();
}
private void stopSSDPDiscovery() {
if (mSSDPListener != null) {
mNetRemote.getDiscoveryService().removeListener(mSSDPListener);
mSSDPListener = null;
}
mNetRemote.getDiscoveryService().stop();
clearSpeakerList();
}
private void changeListViewContent(boolean showGroups) {
if (showGroups) {
mListView.setAdapter(mGroupsListAdapter);
} else { //show speakers
mListView.setAdapter(mListAdapter);
}
}
}
ANEXA 2:
SourcesListActivity:
package com.frontier_silicon.discoverysampleapp;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.frontier_silicon.NetRemoteLib.Node.BaseSysCapsValidModes;
import com.frontier_silicon.NetRemoteLib.Node.NodeInfo;
import com.frontier_silicon.NetRemoteLib.Node.NodeSysCapsValidModes;
import com.frontier_silicon.NetRemoteLib.Node.NodeSysMode;
import com.frontier_silicon.NetRemoteLib.Radio.IListNodeListener;
import com.frontier_silicon.NetRemoteLib.Radio.ISetNodeCallback;
import com.frontier_silicon.NetRemoteLib.Radio.NodeErrorResponse;
import com.frontier_silicon.NetRemoteLib.Radio.Radio;
import java.util.ArrayList;
import java.util.List;
public class SourcesListActivity extends AppCompatActivity {
private ListView mSourcesList;
private ArrayAdapter<NodeSysCapsValidModes.ListItem> mAdapter;
private List<NodeSysCapsValidModes.ListItem> mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sources_list);
setupControls();
}
private void setupControls() {
mList = new ArrayList<>();
mAdapter = new ArrayAdapter<NodeSysCapsValidModes.ListItem>(this, android.R.layout.simple_list_item_1, mList);
mSourcesList = (ListView) findViewById(R.id.listSources);
mSourcesList.setAdapter(mAdapter);
mSourcesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
NodeSysCapsValidModes.ListItem selectedMode = (NodeSysCapsValidModes.ListItem) parent.getItemAtPosition(position);
if (selectedMode != null) {
setModeAndStartBrowseActivity(selectedMode);
}
}
});
}
private void setModeAndStartBrowseActivity(final BaseSysCapsValidModes.ListItem selectedMode) {
Radio currRadio = ConnectionManager.getInstance().getRadio();
currRadio.SetNode(new NodeSysMode(selectedMode.getKey()), new ISetNodeCallback() {
@Override
public void SetNodeSuccess(NodeInfo node, Object userData) {
Intent openBrowse = new Intent(SourcesListActivity.this, BrowseActivity.class);
SourcesListActivity.this.startActivity(openBrowse);
}
@Override
public void SetNodeError(NodeInfo node, NodeErrorResponse error, Object userData) {
Toast.makeText(SourcesListActivity.this, "Error selecting mode " + selectedMode, Toast.LENGTH_LONG).show();
}
});
}
@Override
public void onResume() {
super.onResume();
updateSourcesList(ConnectionManager.getInstance().getRadio());
}
private void updateSourcesList(Radio radio) {
radio.getListNodeItems(NodeSysCapsValidModes.class, 0, -1, false, new IListNodeListener() {
@Override
public void onListNodeResult(ArrayList resultList, boolean isListComplete) {
if (resultList != null) {
mList.clear();
mList.addAll(resultList);
mAdapter.notifyDataSetChanged();
}
}
});
}
}
ANEXA 3:
BrowseActivity:
package com.frontier_silicon.discoverysampleapp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.frontier_silicon.NetRemoteLib.Node.BaseNavList;
import com.frontier_silicon.NetRemoteLib.Node.BaseNavState;
import com.frontier_silicon.NetRemoteLib.Node.BaseSysCapsValidModes;
import com.frontier_silicon.NetRemoteLib.Node.NodeInfo;
import com.frontier_silicon.NetRemoteLib.Node.NodeListItem;
import com.frontier_silicon.NetRemoteLib.Node.NodeNavActionNavigate;
import com.frontier_silicon.NetRemoteLib.Node.NodeNavActionSelectItem;
import com.frontier_silicon.NetRemoteLib.Node.NodeNavList;
import com.frontier_silicon.NetRemoteLib.Node.NodeNavState;
import com.frontier_silicon.NetRemoteLib.Node.NodePlayInfoName;
import com.frontier_silicon.NetRemoteLib.Node.NodePlayInfoText;
import com.frontier_silicon.NetRemoteLib.Node.NodeSysCapsValidModes;
import com.frontier_silicon.NetRemoteLib.Node.NodeSysMode;
import com.frontier_silicon.NetRemoteLib.Radio.IGetNodeCallback;
import com.frontier_silicon.NetRemoteLib.Radio.IListNodeListener;
import com.frontier_silicon.NetRemoteLib.Radio.ISetNodeCallback;
import com.frontier_silicon.NetRemoteLib.Radio.NodeErrorResponse;
import com.frontier_silicon.NetRemoteLib.Radio.Radio;
import java.util.ArrayList;
import java.util.List;
public class BrowseActivity extends AppCompatActivity {
private static final long NAVIGATE_BACK_KEY = 0xffffffffL;
private static final long WAIT_TIME_NAV = 2000;
private ListView mSourcesList;
private ArrayAdapter<NodeNavList.ListItem> mAdapter;
private List<NodeNavList.ListItem> mList;
private int mCurrentLevel = 0;
private View mPlaybackFooterView;
private TextView mLine1Text, mLine2Text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_browse);
setupControls();
}
@Override
public void onResume() {
super.onResume();
enableNavigation();
}
private void enableNavigation() {
Radio currRadio = ConnectionManager.getInstance().getRadio();
currRadio.SetNode(new NodeNavState(NodeNavState.Ord.ON), new ISetNodeCallback() {
@Override
public void SetNodeSuccess(NodeInfo node, Object userData) {
getBrowseItems();
}
@Override
public void SetNodeError(NodeInfo node, NodeErrorResponse error, Object userData) {
Toast.makeText(BrowseActivity.this, "Error enabling navigation", Toast.LENGTH_LONG).show();
}
});
mCurrentLevel = 0;
}
private void getBrowseItems() {
Radio currRadio = ConnectionManager.getInstance().getRadio();
try {
Thread.sleep(WAIT_TIME_NAV);
} catch (InterruptedException e) {
e.printStackTrace();
}
currRadio.getListNodeItems(NodeNavList.class, 0, -1, false, new IListNodeListener() {
@Override
public void onListNodeResult(ArrayList resultList, boolean isListComplete) {
if (resultList != null) {
mList.clear();
mList.addAll(resultList);
mAdapter.notifyDataSetChanged();
}
}
});
}
private void setupControls() {
mList = new ArrayList<>();
mAdapter = new ArrayAdapter<NodeNavList.ListItem>(this, android.R.layout.simple_list_item_1, mList);
mSourcesList = (ListView) findViewById(R.id.listItems);
mSourcesList.setAdapter(mAdapter);
mSourcesList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
NodeNavList.ListItem item = (NodeNavList.ListItem) parent.getItemAtPosition(position);
if (item != null) {
navigateSelectedItem(item);
}
}
});
mPlaybackFooterView = findViewById(R.id.layoutPlaybackFooter);
mLine1Text = (TextView) findViewById(R.id.textLine1);
mLine2Text = (TextView) findViewById(R.id.textLine2);
}
private void navigateSelectedItem(final NodeNavList.ListItem item) {
Radio currRadio = ConnectionManager.getInstance().getRadio();
if (item.getType() == NodeListItem.FieldType.PlayableItem) {
playItem(item);
} else {
currRadio.SetNode(new NodeNavActionNavigate(item.getKey()), new ISetNodeCallback() {
@Override
public void SetNodeSuccess(NodeInfo node, Object userData) {
mCurrentLevel++;
getBrowseItems();
}
@Override
public void SetNodeError(NodeInfo node, NodeErrorResponse error, Object userData) {
Toast.makeText(BrowseActivity.this, "Error navigating to " + item.getName(), Toast.LENGTH_LONG).show();
}
});
}
}
private void playItem(final BaseNavList.ListItem item) {
Radio currRadio = ConnectionManager.getInstance().getRadio();
currRadio.SetNode(new NodeNavActionSelectItem(item.getKey()), new ISetNodeCallback() {
@Override
public void SetNodeSuccess(NodeInfo node, Object userData) {
Toast.makeText(BrowseActivity.this, "Playing " + item.getName(), Toast.LENGTH_LONG).show();
updatePlaybackFooter();
}
@Override
public void SetNodeError(NodeInfo node, NodeErrorResponse error, Object userData) {
Toast.makeText(BrowseActivity.this, "Error playing to " + item.getName(), Toast.LENGTH_LONG).show();
}
});
}
private void updatePlaybackFooter() {
Radio currRadio = ConnectionManager.getInstance().getRadio();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mPlaybackFooterView.setVisibility(View.VISIBLE);
boolean uncached = true;
currRadio.GetNode(NodePlayInfoName.class, false, uncached, new IGetNodeCallback() {
@Override
public void GetNodeResult(NodeInfo node, Object userData) {
NodePlayInfoName nameNode = (NodePlayInfoName) node;
mLine1Text.setText(nameNode.getValue());
}
@Override
public void GetNodeError(Class nodeType, NodeErrorResponse error, Object userData) {
}
});
currRadio.GetNode(NodePlayInfoText.class, false, uncached, new IGetNodeCallback() {
@Override
public void GetNodeResult(NodeInfo node, Object userData) {
NodePlayInfoText textNode = (NodePlayInfoText) node;
mLine2Text.setText(textNode.getValue());
}
@Override
public void GetNodeError(Class nodeType, NodeErrorResponse error, Object userData) {
}
});
}
@Override
public void onBackPressed() {
if (mCurrentLevel > 0) {
navigateBack();
} else {
super.onBackPressed();
}
}
private void navigateBack() {
Radio currRadio = ConnectionManager.getInstance().getRadio();
currRadio.SetNode(new NodeNavActionNavigate(NAVIGATE_BACK_KEY), new ISetNodeCallback() {
@Override
public void SetNodeSuccess(NodeInfo node, Object userData) {
mCurrentLevel–;
getBrowseItems();
}
@Override
public void SetNodeError(NodeInfo node, NodeErrorResponse error, Object userData) {
Toast.makeText(BrowseActivity.this, "Error navigating back ", Toast.LENGTH_LONG).show();
}
});
}
}
BIBLIOGRAFIE
[1] http://www.qreferat.com/referate/informatica/Sisteme-incorporate358.php
[2] https://ro.wikipedia.org/wiki/Sistem_înglobat
[3]http://developer.android.com
[4] Wei – Meng Lee (2012), „ Beginning Android 4 Application Development”, Editura John Wiley & Sons, Inc
[5] Zigurd Mednieks, Laird Dornin, G. Blake Meike (2012) , „Programming Android 2nd edition”, Editura O’Reilly
[6] Marko Gargenta , „Learning Android” , Editura O’Reilly
[7] Jason Morris (2011), „Android User Interface Development”, Editura Packt Publishing
[8] Ștefan Tănasă, Ștefan Andrei, Cristian Olaru –2007, Editura Polirom , „Java de la 0 la Expert” , Ediția a II- a revizuită și adăugită
[9] Paul Pocatilu, Ion Ivan, Adrian Vișoiu, Felician Alecu, Alin Zamfiroiu, Bogdan Iancu, 2015, Editura ASE, „Programarea aplicațiilor Android”
[10] Anghel Octavia, Anghel Leonard, 2007, Editura Albastra, „Tehnologii XML – XML în JAVA – inițiere în XML”
[11] Mircea Cezar Preda, 2010, Editura Polirom, „ Introducere în programarea orientată pe obiect”
[12] Doina Logofătu, 2007, Editura Polirom, „Algoritmi fundamentali in JAVA”
[13] Eugen Petrac, Tudor Udrescu, 2006, Matrix Rom, „ Fundamente Java”
[14] Ioan Jurcă, 2006, Editura de Vest, „ Bazele programării orientate pe obiecte”
[15] Cristian Frăsinaru, 2005, Editura Matrixrom, „Curs practic de Java”
DECLARAȚIE DE AUTENTICITATE
A
PROIECTULUI DE FINALIZARE A STUDIILOR
Titlul proiectului: Metodă software de controlare a unui speaker inteligent
Autorul proiectului : BUTOI COSMINA RALUCA
Proiectul de finalizare a studiilor este elaborat în vederea susținerii examenului de finalizare a studiilor organizat de către Facultatea _______________I.E.T.I._________________________ din cadrul Universității din Oradea, sesiunea________iulie_________ a anului universitar __2016___________.
Prin prezenta, subsemnatul (nume, prenume, CNP):
BUTOI COSMINA RALUCA , [anonimizat],
declar pe proprie răspundere că aceast proiect a fost scris de către mine, fără nici un ajutor neautorizat și că nici o parte a proiectului nu conține aplicații sau studii de caz publicate de alți autori.
Declar, de asemenea, că în proiect nu există idei, tabele, grafice, hărți sau alte surse folosite fără respectarea legii române și a convențiilor internaționale privind drepturile de autor.
Oradea,
Data Semnătura
14.06.2016
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Metodă Software de Controlare a Unui Speaker Inteligent (ID: 118349)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
