Implementarea Unui Framework de Sincronizare Baze de Date Între Un Server Central Si Multiple Dispozitive Mobile

UNIVERSITATEA DIN ORADEA

FACULTATEA DE INGINERIE ELECTRICĂ ȘI TEHNOLOGIA INFORMAȚIEI

PROGRAMUL DE STUDIU TEHNOLOGIA INFORMAȚIEI

FORMA DE ÎNVĂȚĂMÂNT IF

Proiect de diplomă

COORDONATOR ȘTIINȚIFIC

prof. dr. ing. Robert Győrödi

ABSOLVENT

Hencz David Zsolt

ORADEA

2016

UNIVERSITATEA DIN ORADEA

FACULTATEA DE INGINERIE ELECTRICĂ ȘI TEHNOLOGIA INFORMAȚIEI

PROGRAMUL DE STUDIU TEHNOLOGIA INFORMAȚIEI

FORMA DE ÎNVĂȚĂMÂNT IF

Implementarea unui framework de sincronizare baze de date între un server central și multiple dispozitive mobile

COORDONATOR ȘTIINȚIFIC

prof. dr. ing. Robert Győrödi

ABSOLVENT

Hencz David Zsolt

ORADEA

2016

Capitolul 1 – Introducere

Această lucrare prezintă procesul de dezvoltare a unei aplicații de tip client-server care sincronizează datele între ele printr-un framework de sincronizare care sincronizează datele din baza de date a serverului cu datele din baza de date a aplicațiilor mobile. Datele sincronizate sunt notițe, care sunt create folosind aplicația client. Utilizând programul pot fi create liste (to-do list), pot fi capturate imagini, sunete sau se pot desena schițe. După creare, o notiță este accesibilă de utilizatorul înregistrat cu un cont pe orice dispozitiv cu sistem de operare Android de oriunde datorită sincronizării. Serverul face parte din categorial aplicațiilor RESTful, ce permite folosirea lui cu orice aplicație client (Android, IOS, Windows sau aplicație Web).

Este o aplicație deosebit de utilă și datorită interfeței cu utilizatorul, care este proiectat să fie ușor de utilizat, poate fi folosită de orice persoană care are un dispozitiv mobil (cu sistem de operare Android) și conexiune la internet. Aplicația poate fi utilizată și fără conexiune la internet, notițele sunt salvate in memoria telefonului. Sincronizarea în acest caz se face când utilizatorul se conectează la internet.

Aplicația este structurată pe server, scris in Node.js și o aplicație client, dezvoltată pentru Android.

Am realizat această aplicație pentru că am vrut să fac o aplicație în care pot să adaug notițe cu: liste, imagini, audio si desene și să le am pe toate dispozitivele pe care le dețin (telefon mobil, tabletă, laptop etc).

Tehnologiile utilizate pentru dezvoltarea aplicației sunt tehnologii noi (Node.js, MongoDB, Android), destul de folosite la ora actuală. Aceste tehnologii sunt descrise în Capitolul 2. Am ales aceste tehnologii pentru că sunt gratuite (open-source) ceea ce face implementarea aplicației să fie ieftină.

Felul de proiectare și implementare a aplicatiei (despărțirea clientului de server) facilitează mentenanța și extinderea aplicației cu functionalități noi.

Lucrarea este structurată pe cinci capitole. Ea prezintă o scurtă introducere, prezentarea tehnologiilor folosite, arhitectura aplicației, implementarea aplicației si la final concluziile.

Primul capitol prezintă câteva noțiuni introductive despre felul aplicației, pentru ce am dezvoltat aplicația și tehnologiile folosite.

Capitolul 2 prezintă noțiuni despre tehnologiile folosite pentru dezvoltarea aplicației. Începe cu tehnologiile utilizate pentru crearea serverului (Node.js) și câteva framework-uri folosite: Express.js, Mongoose.js, Passport și arhitectura REST pe care se bazează serverul. Urmează descrierea bazei de date folosite, MongoDB, apoi formatul prin care se face schimbul de date între client și server (JSON). Capitolul continuă cu tehnologiile folosite pentru dezvoltarea aplicației client: Java și Android, iar la finalul capitolului este prezentat Material Design folosit pentru proiectarea și implementarea interfeței cu utilizatorul.

Capitolul 3 este dedicat arhitecturii aplicației. Începe cu formularea cerinței și arhitectura generală a aplicației. Se identifică componentele aplicației și se explică rolul acestora. Urmează prezentarea arhitecturii componentelor client și server cu explicarea funcționării acestora. Pentru fiecare componentă este prezentat modul de funcționare a sincronizării și autentificării. Sincronizarea este descrisă cu ajutorul schemelor care sunt explicate.

Capitolul 4 conține implementarea aplicației și descrie fiecare componentă (server și client) cu ajutorul diagramelor și imaginilor. Capitolul începe cu prezentarea implementării serverului cu schemele bazei de date apoi continuă cu prezentarea implemetării aplicației client. La finalul capitolului este prezentat modul de utilizare a aplicației client.

La final este prezentată concluzia referitoare la aplicația dezvoltată și sunt prezentate posibilele dezvoltări viitoare.

Capitolul 2 – Tehnologii Folosite

2.1 Node.js

Node.js este un mediu de rulare open-source, cross-platform folosit pentru dezvoltare backend-ului unei aplicații web. Modulele lui de bază sunt scrise în Javascript. El se bazează pe motorul Javascript V8 dezvoltat de Google. []

V8 este motorul de execuție Javascript dezvoltat de Google pentru Chrome în 2008. V8 scris în C++, compilează codul sursă scris în Javascript în cod mașină în loc să-l interpreteze în timp real. [1]

Arhitectura Node.js este prezentată in Figura 2.1. []

Node.js folosește libuv pentru gestionarea evenimentelor asincrone. Libuv este un nivel de abstractizare pentru rețele și sisteme de fișiere în Windows și sisteme bazate pe POSIX cum ar fi Linux, Mac OS X și Unix.

Funcționalitatea de bază a Node.js aparține bibliotecilor JavaScript. Legăturile în Javascript, scrise în C++, conectează aceste tehnologii între ele și sistemul de operare. [1]

Motorul V8 implementează ECMAScript (ECMA-265) care în prezent este cea mai rapidă mașină virtuală de Javascript.

Codul scris în Javascript este compilat de motorul V8 în cod mașină care se execută. Partea de server poate fi dezvoltat în întregime în Node.js. Node.js are o arhitectură bazată pe evenimente capabilă de I/E aincron. Acest model are ca scop optimizarea și scalabilitatea aplicațiilor web cu multe operații de intrare/ieșire sau aplicațiilor web în timp real (programe pentru comunicarea în timp real și jocuri care rulează în browser). [1]

Node.js permite crearea de servere Web și instrumente pentru rețele folosind JavaScript și o colecție de module care se ocupă de diverse funcționalități de bază.

Modulele asigură lucrul cu fișiere, lucrul cu rețeaua (DNS, HTTP, TCP, TLS/SSL, sau UDP), date binare(bufere), funcții de criptare a datelor, fluxuri de date și alte funcții de bază. Modulele Node.js utilizează un model bazat pe API pentru ușurarea dezvoltării aplicațiilor server.

Aplicațiile Node.js pot rula pe Mac OS X, Microsoft Windows, NonStop și servere Unix. Ele pot fi scrise și în CoffeeScript, TypeScript de la Microsoft (Javascript puternic tipizat) sau orice alt limbaj care poate fi compilat în JavaScript. [1]

În princiu Node.js este utilizat pentru crearea de programe rețelelor cum ar fi serverele Web, ceea ce face să fie similar cu PHP. Cea mai mare diferență între Node.js și PHP este că în PHP comanda următoare se execută după ce comanda anterioară se termină, în timp ce în Node.js comenzile se execută în paralel și sunt utilizate callback-uri pentru a semnala o eroare sau finalizarea comenzii. [1]

Node.js aduce programarea bazată pe evenimente în dezvoltarea serverelor web, care permite dezvoltarea rapidă folosind JavaScript. Dezvoltatorii pot crea servere scalabile fără utilizarea firelor de execuție, prin utilizarea unui model simplificat de programare care utilizează callback-uri pentru semnalizarea finalizării unui task. Node.js a fost creat pentru că în multe limbaje de programare orientate spre server concurența este dificil de implementat și de multe ori duce la performanță slabă. [1]

Node.js funcționează pe un singur fir de execuție, folosește apeluri I/E fără blocare, permițându-i să suporte zeci de mii de conexiuni concurente fără suportarea costului de schimbare a contextului. Arhitectura de partajarea a unui singur fir de execuție între toate cererile care utilizează modelul de observare este destinat să construească aplicații extrem de concurente, unde toate funcțiile care efectuează operații de intrare/ieșire trebuie să utilizeze callback-uri.

Pentru a găzdui bucla de evenimente pe un singur fir de execuție, Node.js folosește biblioteca libuv care utilizează un threadpool de dimensiune fixă care este responsabil de operațiile de intrare/ieșire asincrone fără blocare. [1]

Diferența între Node.js (cu un singur fir de execuție) și un server cu mai multe fire de execuție este prezentată în figurile 2.2 [] și 2.3 [3]. In figura 2.2 este prezentată serverul Node.js care primește mai multe cereri de la client care intră intr-un event-loop si accesarea bazei de date se face fără întreruperi. In figura 2.3 este prezentată un server cu mai multe fire de execuție care primește mai multe cereri de la client iar firele de execuție intră in așteptare pentru că accesarea bazei de date pate fi făcută de un singur fir de execuție la un moment dat.

Node.js nu permite scalarea verticală prin creșterea numărului de nuclee de procesor al mașinii, acest lucru este un dezavantaj al arhitecturii cu un singur fir de execuție, dar dezvoltatorii pot crește numărul de fire de execuție în libuv. Aceste fire de execuție sunt distribuite între nucleele sistemului de către sistemul de operare a serverului. [1]

Node.js poate fi combinat cu un browser, o bază de date orientată pe obiencte (MongoDB, CouchDB) și JSON pentru o stivă de dezvoltare unificată bazată pe JavaScript. [1]

Unul dintre cele mai mari avantaje ale folosirii Node.js este scrierea scripturilor atât pentru partea de server cât și pentru client în JavaScript. Cu Node.js codul scris în JavaScript pentru client poate fi ușor adaptat pentru server și invers. [1]

npm este utilizat pentru instalarea, organizarea și administrarea modulelor Node.js din registrul npm. Pachetele din registrul npm variază de la simple biblioteci ca Underscore.js la pachete mai complexe cum ar fi Grunt. Alte framework-uri pentru Node.js: express.js, morgan, session, cookie-parser, body-parser, connect, mongoose etc.

Node.js are o comunitate de dezvoltare numeroasă și foarte activă. Oamenii furnizează module noi pentru extinderea functionalităților din Node.js. [1]

Instalarea modulelor se face cu comanda npm install.

Ex: npm install express

La realizarea acestei aplicații am folosit Node.js la implementarea serverului pentru construirea unei servicii de tip RESTful. Serviciul este de tip request-response (cerere-răspuns). Pentru implementarea serverului am folosit câteva framework-uri JavaScript: Express.js (pentru implementare serviciului cerere-răspuns), Passport (pentru autentificare) și Mongoose (pentru accesarea bazei de date).

2.1.1 Express.js

Express.js este un framework pentru aplicații web Node.js, folosit pentru crearea de aplicații web single-page, mulți-page și aplicații web hibride. Este framework-ul server standard pentru Node.j. El este un framework minimal care poate fi extinsă folosind plugin-uri. Express.js este partea backend din stiva de dezvoltare MEAN împreună cu bazele de date MongoDB și Angular JS framework-ul de frontend.

2.1.2 Passport

Passport este un middleware de autentificare compatibil cu Express.js pentru Node.js. Passport are rolul de autentificare a utilizatorilor printr-un set de plugin-uri numite strategii (strategies). Strategiile pot verifica un set de nume utilizator și parolă, autentificare folosind OAuth (de exemplu prin Facebook, Twitter sau Google), sau autentificare prin OpenID.

Passport menține autentificarea prin sesiune (session). Pentru ca autentificarea persistentă să funcționeze, utilizatorul autentificat trebuie să fie serializat în sesiune și deserializat la cereri ulterioare.

Passport nu impune nicio restricție cu privire la modul în care sunt stocate înregistrările utilizatorului, în schimb trebuie furnizate funcții care implementează serializarea și deserializarea. Într-o aplicație tipică aceste funcții se fac prin serializarea ID-ului utilizatorului și găsirea utilizatorului după ID la deserializare. []

2.1.3 Mongoose JS

Mongoose este un instrument de modelare pentru MongoDB și Node.js. Folosind Mongoose modelul de date este definită într-un singur loc, în cod. Schemele pentru MongoDB nu trebuie să fie create și legate prin ORM (Object relational mapping) la obiectele din proiect, ele pot fi pur și simplu definite ca structuri de date de tip JSON în proiect.

Mongoose este util atunci când vrem să interacționăm cu date structurate din MongoDB. El permite să definim scheme (schemas) pentru date și pentru interacțiunea cu baza de date.

Mongoose transformă datele din baza de date în obiecte JavaScript care pot fi folosite în aplicație. []

2.2 MongoDB

MongoDB este o bază de date NoSQL open-source, scrisă în C++, orientată pe obiecte. Clasificat ca bază de date NoSQL, MongoDB renunță la stocarea datelor în tabele din baze de date relaționale în favoarea documentelor JSON cum ar fi schemele dinamice (format BSON), ceea ce face integrarea datelor în anumite tipuri de aplicații mai ușoară și mai rapidă. []

MongoDB poate conține mai multe baze de date, colecții și indecși. În unele cazuri (baze de date și colecții) aceste obiecte pot fi create implicit. Odată create, ele se găsesc în catalogul sistemului db.systems.collection, db.system.indexes. Colecțiile conțin documente (format BSON). Aceste documente conțin la rândul lor mai multe câmpuri. În MongoDB nu există câmpuri predefinite spre deosebire de bazele de date relaționale, unde există coloanele care sunt definite în momentul în care tabelele sunt create. Nu există scheme pentru câmpurile dintr-un document, acestea precum și tipurile lor pot varia. Astfel nu există operația de „alter table” pentru adăugare de coloane. În practică este obișnuit ca o colecție să aibă o structură omogenă, deși nu este o cerință, colecțiile putând avea structuri diferite. Această flexibilitate presupune ușurința în migrarea și modificarea imaginii de ansamblu asupra datelor. [6]

În figura 2.4 [] este prezentată arhitectura de bază a bazei de date MongoDB.

MongoDB suportă căutări pe câmpuri, interogări în șir de caractere și căutare folosind expresii regulate. Interogările pot returna câmpuri specifice ale documentelor și funcții JavaScript definite de utilizator.

Indexarea pe fiecare din atribute se face în modul tradițional (RDBMS) asupra cheilor de regăsire ale documentelor prezentată in figura 2.5 []. [7]

Partiționarea datelor în MongoDB se face pe orizintală folosind sharding. Utilizatorul alege o cheie numită cheie shard, care determină cum vor fi distribuite datele.

Citirile și scrierile sunt distribuite pe partiții. Lipsa join-urilor face ca interogările distribuite să fie mai rapide.

MongoDB poate rula pe mai multe servere, echilibrează sarcina și duplică datele pentru a rămâne în funcțiune în caz de defecțiune a unui server.

MongoDB poate fi instalată pe sisteme de operare variate, incluzând Windows, Linux, Ubuntu, Debian, Mac OS X. Pe Windows XP nu se permite instalarea. [7]

MongoDB are drivere oficiale pentru o varietate de limbaje de programare populare și medii de dezvoltare. Administrarea bazei de date se face de cele mai multe ori prin linie de comandă cum ar fi mongo shell deoarece MongoDB nu include o interfață grafică. Există și programe de administrare cu interfață grafică prin care se poate face administrarea datelor de exemplu Robomongo. [7]

În dezvoltarea aplicației am folosit bazele de date MongoDB pentru salvarea datelor și utilizatorilor. Am ales o bază de date NoSQL pentru că este rapidă si datele sunt salvate sub formă de BSON care este ușor de convertit in obiect JavaScript pentru Node.js.

2.3 REST

REST (Reprezentațional state transfer) este un stil arhitectural constând dintr-un set coordinat de componente, conectori și date în cadrul unui sistem hipermedia distribuit, unde accentul se pune pe rolul componentelor și un set specific de interacțiuni între elemente de date, nu pe implementare. []

Scopul lui este de a crește performanța, simplitatea, vizibilitatea, portabilitatea și fiabilitatea aplicațiilor. REST este modelul arhitectural folosit în World Wide Web [9]. Arhitectura REST este prezentată in figura 2.6. []

Termenul REST a fost introdus în anul 2000 de Roy Fielding în teza sa de doctorat la UC Irvine. REST a fost folosit pentru a descrie arhitectura web, pentru a indentifica problemele, pentru a compara soluțiile alternative și pentru a asigura că protocoalele web-ului nu sunt încălcate. [9] Fielding a folosit REST pentru proiectarea HTTP 1.1.

Sistemele care sunt dezvoltate în stil arhitectural REST se numesc sisteme RESTful. Sistemele RESTful de obicei, dar nu întotdeauna, comunică prin HTTP (Hypertext Transfer Protocol) prin aceleași metodele de cerere (GET, POST, PUT, DELETE etc) pe care browserul le utilizează pentru comunicarea cu serverul. [9]

Proprietățile arhitecturale afectate de constrângerile stilului arhitectural REST sunt: performanța (interacțiunile dintre componente pot fi un factor dominant în eficiența rețelei), scalabilitatea (separarea clientului de server simplifică implementarea componentelor, reduce complexitatea conectorilor semantici, îmbunătățește performanța și crește scalabilitatea componentelor, simplitatea interfețelor, modificabilitatea componentelor, vizibilitate comunicării între componente de către agenții de servicii, portabilitatea componentelor și fiabilitatea).

Proprietățile arhitecturale ale REST sunt realizate prin aplicarea unor constrângeri specifice și interacțiunea componentelor și conectorilor. [9]

Dacă un serviciu încalcă o constrângere REST, el nu foate fi considerat RESTful.

O interfață uniformă separă cilentul de server. Această separare inseamana că, de exemplu, clientul nu se ocupă de stocarea datelor, care se face de către server, astfel portabilitatea codului client este îmbunătățită. [9]

O altă constrângere a comunicației client-server este nesalvarea contextului clientului de către server între cereri. Fiecare cerere venită de la client conține toate informațiile necesare pentru servirea cererii iar starea sesiunii este deținută de client. Starea sesiunii poate fi transferată de către server la un alt serviciu, cum ar fi o bază de date pentru a menține o stare persistentă pentru o perioada de timp și să permită autentificarea.

Constrângerea de interfață uniformă este fundamentală pentru proiectarea oricărui serviciu REST. Interfața uniformă simplifică și decuplează arhitectura, care permite părților să evolueze în mod independent. Cele patru constrângeri pentru această interfață uniformă sunt: identificarea resurselor (resursele individuale sunt identificate în timpul cererilor, de exemplu folosind URI-uri în sisteme REST bazate pe web, reprezentarea resurselor în server este diferită de reprezentarea care este trimisă clientului care poate fi: HTML, XML sau JSON.), manipularea resurselor prin aceste reprezentări, mesaje auto-descriptive și hipermedia ca motor al stării aplicației (HATEOAS Hypermedia as the engine of aplication state). [10]

Comunicarea dintre un server REST si client este prezentată în figura 2.7 [].

În aplicație am folosit arhitectura REST la proiectarea si implementarea serverului. Serverul răspunde la o cerere cu un răspuns generat pe baza datelor trimise odată cu cererea.

2.4 JSON

JSON (JavaScript Object Notation) este un standard de format care utilizează text lizibil pentru transmiterea datelor de formă cheie valoare. Este cel mai utilizat format de date folosit pentru comunicarea asincronă dintre browser și server (AJAJ), înlocuind XML care este utilizat de AJAX. []

JSON este un format independent de limbaj. Ea derivă din JavaScript, dar poate fi parcursă în multe limbaje de programare. Extensia fisierelui JSON este .json. [12]

JSON a crescut din nevoia de comunicare în timp real dintre server și browser fără plugin-uri folosite de browser ca Flash sau Java applets, care erau metodele dominante la începutul anilor 2000.

Douglas Crockford a menționat și popularizat pentru prima dată formatul JSON. La început formatul JSON s-a bazat pe un subset al limbajului JavaScript și este frecvent utilizat cu JavaScript, dar este un format independent de limbaj. [12]

Cu toate că JSON este considerat ca un subset al limbajului JavaScript și ECMAScript, permite unele caractere în șiruri de caractere care sunt ilegale în JavaScript și ECMAScript.

JSON în sine a devenit un standard ECMA în 2013 (tandardul ECMA-404). [12]

Tipurile de date de bază folosite în JSON sunt: Number, String, Boolean, Array, Object și null. Spațiile sunt permise dar sunt ignorate. JSON nu oferă nicio sintaxă pentru comentarii.

Pentru ca un text de format JSON este sintactic un obiect JavaScript este foarte ușor pentru un program scris în JavaScript să parcurgă date sub formă de JSON. [12]

JSON este formatul utilizat în aplicație pentru transmiterea datelor între client și server. Am ales JSON pentru că poate fi convertit în obiect JavaScript și pentru că este mai lizibil decât XML. [12]

2.5 Tesseract

Tesseract este un motor optic de recunoaștere a caracterelor care funcționează pe diferite sisteme de operare. El este un software gratuit, lansat sub licență Apache. Inițial a fost dezvoltat de HP labs în Bristol, Anglia și Greeley Colorado între anii 1985 și1994. În anul 1996 au fost adăugate câteva modificări pentru compatibilitatea cu Windows. Codul este scris în C și C++. Dezvoltarea lui este sponsorizat de Google din anul 2006. Tesseract este considerat unul dintre cele mai exacte programe de recunoaștere a caracterelor (OCR) disponibil în prezent. []

El este disponibil pe sistemele de operare Linux, Windows și Mac OS X.

Până la versiunea 2 accepta doar imagini în format TIFF de text simplu pe o coloană. De la versiunea 3.0 suportă formatarea textului de ieșire și analiza paginii. [13]

Prima versiune putea detecta doar limba engleză. De la versiunea v2 au fost adăugate șase limbi (franceza, italiana, germana, spaniola, portugheza și olandeza). Versiunea 3 suportă limbile ideografice (chineza, japoneza) și scrisul de la dreapta la stânga (araba). Au fost incluse noi limbi araba, bulgara, catalana, chineza (simplificată și tradițională), croata, ceha, daneza, germana (script Fraktur), greaca, finlandeza, ebraica, hindi, maghiara, indoneziana, japoneza, coreeana, letona, lituaniana, norvegiana, poloneza, portugheza, româna, rusa, sârba, slovaca (standard și script-ul Fraktur), slovena, suedeza, thailandeza, turca, ucraineana și vietnameza.

În versiunea v3.04 lansată în iulie 2015 au fost adăugate încă 39 de limbi ajungând în total la peste 100 de limbi. [13]

Tesseract va produce o ieșire de calitate scăzută dacă imaginea de intrare este de calitate slabă.

În aplicație Tesseract este folosit pentru extragerea textului din imagini.

2.6 Java

Java este un limbaj de programare cu scop general bazat pe clase, orientat pe obiecte și proiectat pentru a avea cât mai puține dependințe de implementare. Acesta este destinat pentru a permite programatorilor de a scrie un cod și a rula pe orice dispozitiv. Codul Java compilat poate rula pe toate platformele care suportă Java fără a fi recompilat. Aplicațiile Java sunt compilate în bytecode care poate rula pe orice Java Virtual Machine (JVM), indiferent de arhitectura calculatorului.

Din 2016, Java este una dintre cele mai populare limbaje de programare, în special pentru aplicații web client-server.

Java a fost dezvoltat de către James Gosling la Sun Microsystems (care a fost cumpărată de Oracle Corporation) și a fost lansată în anul 1995 ca o componentă de baza a platformei Java din Sun Microsystems. Sintaxa limbajului este similar cu limbajele C șiC++, dar are mai puține facilități de nivel scăzut decât oricare dintre ele. Cea mai recentă versiune este Java 8. []

2.6.1 Istoric

James Gosling, Mike Sheridan, și Patrick Naughton au inițiat proiectul Java în iunie 1991. Java a fost proiectat inițial pentru televiziunea interactivă, dar era prea avansată pentru industria de televiziune digitală din vremea respectivă. Limbajul inițial a fost numit Oak (stejar în engleză) după un stejar, care se afla în curtea biroului lui Gosling. Mai târziu proiectul a primit numele de Green după care a fost redenumit în Java după cafeaua Java. Gosling a proiectat Java după sintaxa și stilul lui C/C++ cu care programatorii erau familiarizați.

Sun Microsystems a lansat prima versiune de Java 1.0 în anul 1995. Odată cu apariția Java 2 (lansat inițial ca J2SE 1.2 în decembrie 1998), versiunile mai noi au avut configurații multiple pentru diferite platforme. J1EE include tehologii și API-uri pentru aplicații enterprise, în timp ce J2ME avea API-uri optimizate pentru aplicații mobile. Versiunea Desktop a fost redenumită în J2SE. În 2006 versiunile J2 au fost redenumite în JavaEE, JavaME și Java SE din motive de marketing. [14]

2.6.2 Platforma Java

Unul dintre scopurile dezvoltării limbajului Java a fost portabilitatea, care înseamnă că un program scris în Java trebuie să ruleze similar pe orice combinație de harware sau sistem de operare. Acest lucru se realizează prin compilarea codului scris în Java într-o reprezentare intermediară numită bytecode, în loc de cod mașină specific arhitecturii calculatorului. Instrucțiunile din bytecode sunt similare cu codul mașină dar sunt destinate pentru a fi executate de către o mașină virtuală (VM), dezvoltat special pentru hardware-ul gazdă. Utilizatorii folosesc Java Runtime Environment (JRE) instalat pe calculatoarele lor pentru rularea aplicațiilor. Bibliotecile standard furnizează un acces generic la caracteristici cum ar fi: fire de execuție, lucrul cu rețeaua, grafică etc. [14]

Folosirea unui bytecode universal face portabilitatea să fie simplă, dar interpretarea bytecode-ului în cod mașină face programul să se execute mai lent decât executabilele native.

Odată cu introducerea compilatoarelor just-in-time (JIT) care compilează bytecod-ul în cod mașină în timpul rulării programului diferența de viteză dintre Java și executabilele native a mai scăzut. [14]

2.6.3 Performanța

Programele scrise în Java au o reputație de a fi mai lente și a consuma mai multă memorie decât programele scrise în c++, cu toate acestea, viteza de execuție a programelor Java s-a îmbunătățit semnificativ odată cu introducerea compilatoarelot just-în-time în 1997/1998 pentru Java 1.1. Odată cu lansarea versiunii 1.5 performanța a fost îmbunătățită prin adăugarea pachetului java.util.concurrent și alte collectii multi-core. Performanța a fost îmbunătățită și mai mult odată cu lansarea versiunii 1.6. [14]

Unele platforme pot executa codul Java direct în hardware cum ar fi microcontrolerele care rulează Java în hardware în loc de un program Java Virtual Machine.

2.6.4 Gestionarea automată a memoriei

Java utilizează colectarea automată a deșeurilor pentru getionarea memoriei în ciclul de viață a unui obiect. Programatorul poate să creeze obiecte iar Java runtime este responsabil pentru eliberarea memoriei când obiectul nu mai este folosit. Când nu mai există nicio referință la obiect memoria ocupată de acesta poate fi eliberată automat de către colectorul de deșeuri. Gestionarea automată a memoriei scutește programatorul de la sarcina de gestionare manuală a memoriei. În unele limbaje memoria se alocă la crearea unui obiect implicit în stivă sau explicit se alocă și se eliberează în heap, mai târziu gestinarea memoriei este responsabilitatea programatorului. Dacă programul nu eliberează memoria când obiectul nu mai este folosit apare un leak (gaură) în memorie. [14]

Colectarea deșeurilor poate să apară oricând. Ideal aceasta va avea loc când programul este inactiv. Dacă nu există suficientă memorie pentru alocarea unui obiect nou în heap atunci colectorul de deșeuri se declanșează, care poate duce la blocarea programului. [14]

Java nu suportă pointeri de tip C/C++. Acest lucru permite colectorului de deșeuri realocarea referințelor obiectelor și asigură siguranța. [14]

2.6.5 Sintaxa

Sintaxa limbajului Java este influențat de C++. În comparație cu C++ care combină sintaxa pentru programe structurate, generice și orientat pe obiecte, Java este exclusiv un limbaj orientat pe obiecte. Tot codul este scris în interiorul unei clase, iar fiecare tip de dată este un obiect cu excepție tipurilor de date primitive care nu sunt obiecte din motive de performanță.

Spre deosebire de C++, Java nu suportă supraîncărcarea operatorilor sau moștenirea multiplă. Moștenirea multiplă este realizată prin interfețe. Acest lucru simplifică limbajul și ajută la prevenirea erorilor. [14]

Fișierul sursă trebuie să fie numit după clasa publică pe care-l conține și extensia .java, de exemplu HelloWorldApp.java. Acesta trebuie să fie mai întâi compilată în bytecode, folosind un compilator java. După compilare rezultă un fișier numit HelloWorldApp.class, care se poate executa. [14]

Fișierul sursă poate să conțină o singură clasă publică, dar poate să conțină mai multe clase care nu sunt publice. O clasă care nu este declarată public poate fi stocată în orice fișier cu extensia .java. Compilatorul generează un fișier class pentru fiecare clasă definită în fișierul sursă. Numele fișierului class este numele clasei cu extensia .class. [14]

Metoda main este metoda care se apelează la executarea programului. Acesta trebuie să accepte un vector de șiruri de caractere, prin convenție are numele de args dar poate avea orice nume definită de programator. [14]

2.7 Android

Android este un sistem de operare pentru dispozitive mobile, în prezent dezvoltat de Google, bazat pe nucleul Linux și proiectat pentru dispozitive mobile cu touchscreen, cum ar fi smartphone-urile sau tabletele. Este cel mai bine vândut sistem de operare pe pe dispositive mobile din 2013. []

Android a fost inițial dezvoltat de Android Inc pe care Google a cumpărat-o în 2005 și a prezentat-o în 2007 odată cu fondarea Open Handset Alliance – un consorțiu de harware, software și companii de telefonie dedicat să dezvolte standardele pentru telefonia mobilă. [15]

Codul sursă al sistemului de operare Android este lansat de Google sub licență open source. Este ideal pentru companiile care necesită un sistem de operare optimizat și ieftin pentru dispozitive high-tech. [15]

Interfața cu utilizatorul al sistemului de operare Android implicit se bazează pe manipularea directă, folosind touch-ul care corespunde cu acțiunile reale cum ar fi: swiping, tapping și pinching pentru manipularea obiectelor de pe ecran împreaună cu tastatura virtuală. Controlere de jocuri sau tastaturi fizice sunt compatibile prin BlueTooth sau USB. Accelerometre, giroscopuri și senzori de proximitate sunt folosite de câteva aplicații pentru a răspunde la diferite acțiuni, de exemplu ajustarea ecranului de la portret la landscape în funcție de modul în care dispozitivul este orientat, sau care să permită utilizatorului să navigheze vehiculul într-un joc de curse prin rotirea dispozitivului. [15]

Interfața cu utilizatorul a sistemului de operare este prezentată în figura 2.11. []

Aplicațiile pentru Android sunt scrise folosind Android software development kit (SDK) în limbajul Java, care are acces complet la API-uri Android. Java poate fi combinat cu C/C++. Limbajul Go este deasemenea compatibil de la versiunea 1.4, dar are acces la doar o parte din API-uri. [15]

SDK-ul include un set complet de instrumente de dezvoltare, inclusiv un program de depanare, biblioteci, un emulator bazat pe QEMU, documentație, exemple de cod și tutoriale.

Inițial mediul de dezvoltare pentru Android ales de Google a fost Eclipse folosind Android Development Toold(ADT), dar în decembie 2014 Google a lansat Android Studio, bazat pe IntelliJ IDEA, ca IDE pricipal de dezvoltare de aplicații. Alte instrumente de dezvoltare sunt disponibile, inclusiv un kit de dezvoltare nativ (NDK) pentru aplicații sau extensii C sau C++. [15]

Sunt disponibile tot mai multe aplicații pentru Android, care pot fi achiziționate prin descărcarea și instalarea unui fișier APK (Android aplication package), sau prin descărcarea lor folosind o aplicație de magazin de aplicații care permite utilizatorilor instalarea, actualizarea și ștergerea aplicațiilor din dispozitiv. Google Play Store este magazinul de aplicații instalat pe dispozitivele Android care respectă cerințele de compatibilitate Google. [15]

Arhitectura sistemului de operare Android este prezentată in figura 2.12[]. In figură este prezentată impărțirea sistemului de operare în mai multe nivele: nucleul Linux (cu driverele pentru cameră, Bluetooth, tastatură, Wifi etc), blibliotecile standard (SQLite, OpenGL ES, WebKit etc), Android Runtime (bibliotecile de bază și Dalvik Virtual Machine), framework-urile pentru aplicații și aplicațiile. [15]

Deoarece dispozitivele cu Android sunt de obicei alimentate de la baterie, Android este proiectat pentru a gestiona procesele astfel încât consumul de energie să fie cât mai mică. Când o aplicație nu este folosită, sistemul suspendă funcționarea acestuia, astfel încât, poate fi relansată imediat pentru că nu a fost închisă, dar nu consumă energie.

Android gestionează aplicațiile stocate în memorie în mod automat: când memoria este insuficientă sistemul începe invisibil și automat să închidă procesele inactive începând cu cele care au fost inactive pentru mai mult timp. [15]

Principala platformă hardware pentru Android este ARM (ARMv7 și ARMv8-A), cu arhitectură x86 și MIPS în versiunile ulterioare. De la versiunea 5.0 “Lollipop”, variantele pe 64 de biți de la toate platformele sunt suportate. Din anul 2012, au început să apară dispozitivele cu procesoare Intel. [15]

Cerințele minime de memorie RAM pentru dispozitivele care rulează Android 5.1 este de la 512 MB pentru ecrane cu densitate scăzută până la 1.8GB pentru ecrare cu densitate ridicată. Cantitatea de memorie recomandată pentru android 4.4 este de cel puțin 512MB de RAM. Android 4.4 are nevoie de o arhitectură de procesor de 32 de biți ARMv7, MIPS sau x86 și o unitate de procesare grafică OpenGL ES2.0. [15]

Google oferă actualizări majore pentru Android la fiecare șase sau nouă luni. Cea mai recentă versiune majoră este Android 6.0 “Marshmallow”.

Nucleul sistemului de operare Android se bazează pe nucleul sistemului de operare Linux. Începând cu aprilie 2014 dispozitivele Android folosesc versiunea 3.4 sau 3.10 a nucleului Linux. Versiunea nucleului depinde de platforma hardware a dispozitivului.

Stocarea flash pe dispozitivele Android este împărțită în mai multe partiții, cum ar fi /system pentru sistemul de operare, și /data pentru datele utilizatorului și instalarea aplicațiilor.

Peste nucleul Linux există biblioteci și API-uri scrise în C și aplicații software care rulează pe un framework de aplicație care include bliblioteci compatibile cu Java.

Până la versiunea 5.0, Android a folosit Dalvik ca mașină virtuală cu compilator just-in-time pentru executarea codului Dalvik “dex-code” (executabil Dalvik), care este tradus din bytecod Java. În Android 4.4 a fost introdusă Android Runtime(ART), ca un nou mediu de rulare, care utilizează compilare ahead-of-time(AOT) care compilează bytecod-ul în întregime în cod mașină la instalarea unei aplicații. În Android 4.4, ART a fost o funcție experimentală, nu a fost activată implicit dar a devenit singura opțiune de execuție în versiunea 5.0. [16]

În decembire 2015 Google a anunțat că următoarea versiune de Android va trece pe implementarea Java bazată pe OpenJDK.

2.8 Material Design

Material Design este un limbaj de proiectare a interfeței cu utilizatorul dezvoltat de Google. Se bazează pe idea de “carduri” care a apărut pentru prima dată în Google Now, Material Design folosește machete bazate pe grile, animații, transitii și efecte de adâncime ca ubrirea și iluminatul. []

Material Design poate fi utilizat în API de nivel 21 și mai nou prin intermediul blibliotecii appcompat V7, care este folosit pe aproape toate dispozitivele android fabricate după 2009. Google a lansat Api-uri pentru dezvoltatori pentru a încorpora limbajul de design în aplicațiile lor. Material Design a fost anunțat de Google în 25 iunie 2014 la conferința Google I/O 2014. [18]

Începând cu 2015 cele mai multe aplicații mobile Google pentru Android folosesc Material Design: Gmail, YouTube, Google Drive, Google Docs, Google Maps etc. Implementarea Material Design pentru aplicații web se numește Polymer, care este o bibliotecă de componente și API-uri pentru browser care include elemente din Material Design.

În figura 2.13 [] sunt prezentate câteva elemente din Material Design: toolbar-ul cu titlu, butoane, checkbox-uri radio button-uri, slider, floating action button, edittext etc.

În aplicație am folosit Material Design pentru proiectarea și implementarea interfeței grafice.

Capitlul 3 – Arhitectura

3.1 Cerințe

Se consideră o aplicație formată din server și client. Serverul este o aplicație RESTfull la care se pot conecta mai mulți clienți pentru sincronizarea datelor din baza de date locală cu baza de date a serverului. Comunicarea dintre client și server se face prin http în mod cerere-răspuns (request-response). Formatul pentru interschimbarea datelor este JSON. Pentru a avea acces la API-urile serverului, clientul trebuie să se autentifice. Această autentificare se face pe bază de nume utilizator și parolă. După autentificare utilizatorul primește o cheie (token), care este folosită de client pentru comunicarea cu serverul. În figura 3.1 [] este prezentată arhitectura formată dintr-un server și mai mulți clienți.

Serverul trebuie să fie compatibil cu diferite platforme (IOS, Android, Windows, Web). Această compatibili este asigurată de arhitectura RESTful a serverului, orice aplicație se poate conecta la server prin http, se poate autentifica, iar după autentificare poate folosi API-urile serverului pentru sincronizare.

3.2 Componentele sistemului

În figura 3.2 este prezentată arhitectura sistemului. Sunt prezentate componentele din care este alcătuit și legăturile dintre acestea.

Sistemul este format din următoarele componente: serverul, baza de date si clientul.

Serverul este alcătuit din două servicii majore serviciul de autentificare și serviciul de sincronozare. Responsabilitățile serviciului de autentificare sunt: înregistrarea clienților noi, identificarea clienților existenți, autentificarea clienților și generarea cheii de acces. Serviciul de sincronizare asigură sincronizarea datelor trimise de client cu datele din baza de date a serverului.

Clientul oferă interfața grafică utilizatorului. El se poate autentifica la server pentru sincronizarea datelor. În aplicația prezentată datele sunt notițe care conțin: un titlu, paragrafe de text, liste, imagini sau înregistrări audio. Aplicația client este folosită pentru construirea notițelor: capturarea de imagini, desenare, adăugarea de texte, adăugarea de liste sau înregistrare audio.

Baza de date este folosită pentru salvarea datelor. Ea conține datele despre utilizator (nume utilizator și parolă), cheile de acces și notițele. Baza de date folosită de aplicație este MongoDB, o bază de date NoSQL.

3.3 Arhitectura serverului

Serverul este o aplicație RESTful scrisă în Node.js care este responsabilă de sincronizarea datelor primite de la client cu datele din baza de date. În implementarea serverului sunt folosite mai multe framework-uri: Express.js, Passport, Mongoose.js.

Express.js este folosit la crearea unui API la care pot fi trimise cereri prin metodele de cerere http (GET, POST, PUT, DELETE).

Trimiterea datelor la server și răspunsul serverului sunt trimise sub formă de JSON.

Crearea unui utilizator se face prin trimiterea numelui de utilizator și parolei dorite prin POST la server. Serverul la primirea datelor verifică în baza de date dacă mai există utilizatorul, dacă da trimite un mesaj cu “numele de utilizator există”, dacă nu există salvează utilizatorul în baza de date. Parola se criptează înainte de salvare folosind bibliteca bcrypt-nodejs. După salvarea utilizatorului în baza de date, serverul trimite clientului un mesaj de salvare a utilizatorului.

Pentru autentificarea utilizatorului se folosește Passport. Clientul transmite numele de utlizator și parola prin POST, serverul verifică dacă utilizatorul există în baza de date, dacă nu trimite mesajul utilizatorul nu a fost găsit. Dacă numele de utilizator există în baza de date, se verifică dacă parola este corectă folosind biblioteca bcrypt-nodejs. Dacă parola este greșită serverul trimite mesajul “parolă incorectă”. Dacă numele de utilizator și parola au fost corecte, serverul trimite clientului o cheie (token) prin care se poate face accesarea API-urilor folosite la sincronizare. Trimiterea numelui de utilizator la server și cheii la client este ilustrată în figura 3.2.

Cheia este un șir de caractere format din 32 de caractere generat folosind biblioteca Node.jd rand-token. Ea expiră după un anumit timp. Dacă cheia a expirat, clientul va trimite încă o dată numele de utilizator și parola pentru a solicita o altă cheie. Durata de viață scurtă a cheilor asigură protecția datelor de pe server. Dacă aplicația client încearcă să apeleze un API pentru sincronizare cu cheia expirată, serverul trimite un mesaj cu textul “token expired”.

Serverul folosește o bază de date MongoDB, bază de date NoSQL în care datele sunt salvate sub formă de BSON. Aplicația folosește MongooseJS pentru accesarea bazei de date. Pentru salvarea datelor în baza de date, Mongoose foloșeste scheme. Schemele definite în aplicație sunt: user (pentru utilizatori), note (pentru notițe) si token (pentru chei).

Schema user are următoarele câmpuri: username (nume utilizator) de tip String, password (parola) de tip String si token referință la schema token.

var userSchema = mongoose.Schema({

username: String,

password: String,

token: {

type: Schema.Types.ObjectId,

ref: 'Token',

default: null

}

});

Câmpurile din schema token sunt: value (valoare) de tip String, user (utilizator) referință la schema utilizator si expireAt (timpul după care expiră cheia) de tipul Date.

var tokenSchema = mongoose.Schema({

value: String,

user: {

type: Schema.Types.ObjectId,

ref: 'User'

},

expireAt: {

type: Date,

expires: 60000,

default: Date.now

}

});

Schema note, reprezentarea notiței sub formă de JSON, care este salvată în baza de date are următoarele câmpuri: title (titlul) de tipul obiect cu câmpurile position (poziția textului în notiță) de tipul Number si text (textul titlului) de tipul String, texts (textele din notiță) un array (vector) de obiecte cu câmpurile position și text, labels (tag-urile notiței care sunt folosite de către client la găsirea notiței) este un array de String-uri, checkListItems (listele de tipul checklist) un array de obiecte cu câmpurile checked, position si text, bulletedListItems (listele de tip bullet) un array de obiecte cu câmpurile position și text, images (imaginile din notiță) un array de obiecte cu câmpurile position si text (calea unde este salvată imaginea), audios (înregistrările audio din notițe) array de obiecte de forma position, text (calea unde este salvată înregistrarea) și duration (durata inregistrării), reminder un obiect cu câmpurile start (data la care începe evenimentul), end (data la care se termină evenimentul) si before (cu cât timp înainte de before se produce notificarea) , created_at (când a fost creată notița), edited (când a fost modificată notița) de tipul number, event (dacă este eveniment) de tipul boolean, trashed (dacă este in coșul de gunoi) de tipul Boolean, deleted (dacă notița a fost ștearsă) de tipul Boolean și user referintă la utilizatorul de care apartine notița.

var noteSchema = mongoose.Schema({

titles: {position: Number, text: String },

texts: [{position: Number, text: String}],

labels: [String],

checkListItems: [{ checked:{ type: Boolean, default: false },

position: Number,

text: String

}],

bulletListItems: [{ position: Number,

text: String

}],

numberListItems: [{ number: Number,

position: Number,

text: String

}],

images: [{ text: String,

position: Number

}],

audios: [{ text: String,

position: Number,

duration: Number

}],

reminder: {start: Number, end: Number, before: Number, color: String},

created_at: Number,

edited: Number,

event: Boolean,

trashed: Boolean,

deleted: {type: Boolean,

default: false},

user: {

type: Schema.Types.ObjectId,

ref: 'User'

}

});

După ce se autentifică și primește o cheie, clientul poate să sincronizeze notițele din baza de date locală cu baza de date a serverului. Această sincronizare se face prin API-urile disponibile. Prima data se face o cerere http cu metoda GET la adresa http://IP:PORT/getNotes cu un timestamp care reprezintă ultima dată când clientul s-a sincronizat cu serverul. Prima dată serverul verifică dacă cheia utilizatorului există și nu este expirată. Dacă cheia este expirată se trimite un mesaj de eroare de forma “token expired”. După verificarea cheii se face o căutare în baza de date după notițele care au fost adăugate sau modificate după data primită sub formă de timestamp. Dacă nu s-a găsit nicio notiță serverul trimite clientului un array gol și timestamp-ul la care s-a făcut sincronizarea care este salvată de client și folosită la următoarea sincronizare. Dacă au fost găsite notițe acestea sunt returnate de Mongoose sub formă de array de obiecte. Se parcurge acest array pentru găsirea notițelor care au imagini sau înregistrări audio. Dacă o notiță are imagini folosind calea la care se află, salvată în baza de date, se citește imaginea și se convertește în base64 String cu ajutorul bibliotecii fs (file system) din Node.js. Această conversie se face pentru că imaginea sub formă de JPEG nu poate fi trimisă clientului. Imaginea convertită este salvată în obiectul note în loc de calea imaginii. La fel se face și pentru înregistrările audio, se convertește din 3gp în base64 String. După aceste conversii notitele sunt trimise clientului sub formă de JSON. Acest JSON conține un array de obiecte note și data la care s-a făcut sincronizarea. În figura 3.3 este prezentată comunicarea dintre server și client la cererea notițelor.

După această operație clientul efectuează un POST la adresa http://IP:PORT/setNotes în care trimite notițele care au fost adăugate în baza de date locală și nu au fost trimise incă la server. Clientul trimite pe rând fiecare notiță nouă sub formă de JSON. Serverul la primirea datelor creează un obiect nou de tipul note si completează fiecare câmp cu datele primite de la client. Dacă notița contine imagini, acestea sunt sub formă de base64 String, care sunt convertite în imagini de tipul JPEG. Calea la care a fost salvată imaginea este salvată în baza de date. La înregistrările audio se face la fel, base 64String este convertită în 3gp și salvată pe disc iar calea este salvată în baza de date. După salvare baza de date creează un ID pentru notița care este trimisă clientului împreună cu timestamp-ul pentru ultima sincronizare sub formă de JSON. Acest ID este utilizat de client pentru a face distincția între notițele care au fost sincronizate și care nu au fost. Trimiterea notițelor de către client la server este prezentată in figura 3.4.

După trimiterea notițelor la server, clientul trebuie sa trimită notitele care au fost actualizate pe client. Acest lucru se face pritr-o cerere http cu metoda PUT la adresa http://IP:PORT/notes. Actualizarea este asemănătoare cu trimiterea notițelor noi, singura deosebire este că aici se face un update în loc de insert.

După actualizarea notițelor se face ștergerea notițelor care sunt marcate ca deleted în baza de date a clientului. Acest lucru se face prin metoda DELETE la adresa http://IP:PORT/notes. Clientul trimite ID-urile notițelor care trebuie șterse. Ștergerea notițelor constă din setarea câmpului deleted pe adevărat în baza de date de pe server și trimiterea clientului un JSON cu mesajul de forma “deleted” și timestamp-ul la care s-a efectuat sincronizarea.

După actualizare sau ștergere câmpul created_at al notiței este setată la data la care s-a efectuat acțiunea. La următorul GET notițele actualizate sau șterse sunt trimise clientului. Clientul verifică dacă notița a fost ștearsă (câmpul deleted este adevărat), în acest caz șterge notița din baza de date locală. După verificarea câmpului deleted verifică dacă mai există o notiță în baza de date locală care are ID-ul (care a fost generat de baza de date) notiței primite, dacă da face un update.

În figura 3.6 este prezentată sincronizarea completă a clientului cu serverul.

3.3 Arhitectura clientului

Clientul este o aplicație pentru sistemul de operare Android dezvoltat folosind limbajul de programare Java. Folosind aplicația utilizatorii pot crea notițe care se salvează în baza de date locală aflată pe dispozitivul pe care este instalată aplicația. Utilizatorii pot accesa serverul pentru sincronizarea bazei de date care se află pe dispozitiv cu baza de date a serverului. Pentru sincronizare, aplicația trebuie să se autentifice cu un nume de utilizaror și o parolă pentru obținerea unei chei (token) cu care pot fi apelate API-urile de sincronizare. Înainte de autentificare utilizatorul trebuie să se înregistreze cu un nume de utilizator și o parolă. Contul utilizatorului format din nume de utilizator și parolă este folosit pentru sincronizarea notițelor de pe mai multe dispositive. Dispozitivele pe care utilizatorii se autentifică cu același cont sincronizează baza de date cu baza de date a serverului și implicit se sincronizează între ele. Astfel putem avea notițele pe toate dispozitivele pe care le deținem (telefoane mobile, tablete).

Arhitectura bazată pe un server cu multiple dispositive mobile este prezentată în figura 3.7. Dispozitivele cu sistemul de operare Android se conectează la server prin internet. Serverul la rândul lui este conectat la o bază de date.

Aplicația salvează notițele într-o bază de date locală SQLite, care este un tip de bază de date SQL folosit în aplicații Android.

Baza de date conține o singură tabelă în care sunt salvate notițele numită notes. Câmpurile tabelei notes sunt aceleași cu câmpurile din schema note prezentat la arhitectura serverului.

Sincronizarea din punct de vedere al clientului este alcătuită din mai multe cereri http adresate serverului.

La instalarea aplicație utilizatorul trebuie să-și creeze un cont. După crerea contului, utilizatorul trebuie să se autentifice. Dacă nu s-a produs nicio eroare în timpul autentificării, clientul primește o cheie (token) de acces. Cheia este salvată de către aplicație folosind clasa SharedPreferences în mod privat.

Cheia este folosită în continuare pentru sincronizarea datelor cu serverul până la expirarea ei. Când expiră cheia, aplicația se reautentifică automat cu numele de utilizator și parola, care au fost salvate la prima autentificare, și primește o cheie nouă.

Sincronizare începe cu o cerere http cu metoda GET prin care se trimite la server data la care s-a efectuat ultima sincronizare și cheia. Serverul după verificarea cheii trimite notițele care au fost adăugate sau modificate după data trimisă. Notițele sunt trimise sub formă de JSON clientului. Clientul parcurge JSON–ul și construiește o listă de obiecte Note.

Pentru fiecare notiță din listă este verificată dacă există în baza de date locală. Dacă notița există în baza de date locală se verifică dacă notița are câmpul deleted setat pe adevărat. Dacă da, notița se șterge din baza de date locală. Dacă nu este deleted se verifică dacă notița locală este dirty (dirty înseamnă că a fost modificată dar modificarea nu a fost sincronizată cu serverul) se verifică data la care a fost actualizată notița locală și notița venită de la server. Versiunea finală este cea mai recentă modificare. Dacă nu este dirty se actualizează notița locală cu cea venită de la server.

Dacă notița venită de la server nu există în baza de date locală se salvează.

După cererea notițelor de la server se efectuează trimiterea notițelor noi din baza de date locală. Aplicația face o căutare în baza de date locală după notițe care nu au câmpul created_at null. Câmpul created_at este null dacă notița nu a fost încă trimisă la server. Funcția care caută notițele returnează o listă de obiecte de tipul Note.

Se parcurge lista și se trimite fiecare notiță la server. Dacă notița a fost salvată în baza de date a serverului, id-ul se returnează și este salvat în câmpul created-at al notiței.

După trimiterea notițelor noi se face actualizarea notițelor de pe server care sunt dirty în baza de date locală. Câmpul dirty se pune pe adevărat de aplicație când se efectuaează o schimbare asupra notiței.

Aceste operații sunt efectuate intr-o clasă numită SyncAdapter care extinde clasa AbstractThreadedSyncAdapter, o implementare abstractă a clasei SyncAdapter. Sync Adapter este un framework de la Google folosit pentru sincronizare. Avantajele folosirii acestei clase pentru sincronizare sunt: transferul de date între client și server se poate face la anumite intervale de timp sau la apăsarea unui buton, clientul inițiează un transfer cu serverul doar dacă există conexiune la internet, ajută la imbunătățirea performanței bateriei (permite dezvoltatorului să centralizeze toate sarcinile de transfer de date ale aplicației într-un singur loc, astfel incât pot rula în același timp, deasemenea este programată să se facă împreună cu transferul de date din alte aplicații, acești factori reduc numărul de comutare în rețea cee ce reduce consumul bateriei), autentificarea utilizatorului se face automat (dacă aplicația necesită autentificare, gestionarea contului și autentificarea pot fi integrate în transferul de date). []

În figura 3.8 [] este prezentată arhitectura unei aplicații bazate pe Sync Adapter. Arhitectura este formată din mai multe componete: baza de date, Content Provider, Account Manager Sync Manager, AbstractThreadedSyncAdapter etc.

În baza de date SqliteDB sunt salvate datele care se sincronizează cu serverul. Content Provider-ul este utilizat pentru accesarea bazei de date. Account Manager–ul oferă acces la un registru centralizat de conturi online ale utilizatorului. Utilizatorul introduce o singură dată datele de conectare (nume utilizator și parolă) care sunt salvate de către această clasa. Clasa care extinde clasa AbstractAccountAuthenticator este responsabilă de autentificarea utilizatorului și salvarea cheii de acces. Authenticator Service este un serviciu folosit pentru autentificare când aplicația nu este lansată (nu se află în memorie). Serviciul Sync Service este folosit la sincronizarea datelor când aplicația nu se află in execuție.

În clasa care extinde AbstractThreadedSyncAdapter se fac operațiile de transfer cu serverul. În cazul aplicație prezentate clasa SyncAdapter extinde AbstractThreadedSyncAdapter și este responsabilă de transferul datelor cu serverul. În SyncAdapter se fac operațiile de sincronizare a notițelor.

În clasa Authenticator care extinde AbstractAccountAuthenticator se face adăugarea unui cont în AcountManager când se introduce numele de utilizator și parola la prima deschidere a aplicației. Dacă la efectuarea unei sincronizări serverul răspunde cu “token expired” (cheie expirată), clasa AccountManager reautentifică utilizatorul pentru obținerea unui token nou.

Figura 3.9 [] prezintă ordinea în care sunt apelate componentele framework-ului SyncAdapter. Prima dată este apelată SyncAdapter care apelează clasa Authentication care dacă nu găsește un cont in AccountManager apelează Login Fragment pentru introducerea unui cont. După ce utilizatorul introduce un cont Authentication autentifică utilizatorul și obține cheia de acces după care Sync Adapter poate să inceapă sincronizarea prin apelarea metodelor dintr-o clasa SyncHelper care accesează baza de date printr-un ContentProvider.

Capitolul 4 – Implementare

4.1 Implementarea serverului

Serverul este alcătuit din mai multe fișiere JavaScript (Node.js). server.js este fișierul de bază unde se includ bibliotecile, se face conectarea la baza de date și se creează routerele. Rrouter-ul este folosit pentru crearea link-urilor la care pot fi trimise cereri http.

Conectarea la baza de date se face folosind mongoose prin comanda mongoose.connect(configDB.url). Fișierul configDB conține url-ul la care se află baza de date.

Fișierul package.json este un fișier JSON care conține toate bibliotecile folosite de aplicația server de exemplu: "bcrypt-nodejs": "0.0.3", "body-parser": "latest", connect-mongo": "^1.1.0", "express": "^4.13.4", "mongoose": "^4.4.10", "passport": "^0.3.2" etc.

Fișierul auth.js conține funcțiile de înregistrare și autentificare a utilizatorilor. Pentru înregistrare trebuie trimisă o cerere http cu metoda POST la link-ul http://IP:PORT/auth/signup iar la autentificare tot prin metoda POST la adresa http://IP:PORT/auth/login.

Fișierul secure.js conține funcțiile pentru generare de cheie (token). Pentru generare de token, clientul trebuie să facă o cerere http prin metoda GET la adresa http://IP:PORT/secure/getToken. Această cerere poate fi executată doar dacă utilizatorul este autentificat.

Funcțiile de sincronizare din fișierul api.js pot fi apelate doar dacă clientul trimite o cheie validă. Acest lucru este verificat de Passport.

În fișierele din directorul models note.js și user.js sunt schemele folosite de mongoose.js pentru salvarea datelor în baza de date.

Fișierul passport.js conține funcțiile care sunt folosite de auth.js pentru înregistrarea și autentificarea utilizatorilor folosind Passport și funcția care verifică dacă cererea venită de la client la api.js conține o cheie validă.

În directorul images sunt salvate imaginile venite de la aplicația client sub formă de JPEG iar calea imaginilor sunt salvate în baza de date. Directorul audios conține înregistrările audio în format 3gp.

Programe folosite pentru dezvoltarea server-ului sunt: Visual Studio Code (pentru scrierea codului JavaScript), Robomongo (pentru vizualizarea grafică al bazei de date MongoDB) și Postman (pentru testare);

4.2 Implementarea aplicației client

Clientul este o aplicație Android dezvoltat folosind limbajul java. Software-ul folosit pentru dezvoltarea aplicației este Android Studio. În afară de Android Studio am mai folosit Genymotion (pentru testare) și Inkscape (pentru desenare).

Permisiunile folosite în aplicație sunt:

android.permission.ACCESS_NETWORK_STATE

android.permission.INTERNET

android.permission.MANAGE_ACCOUNTS

android.permission.READ_SYNC_SETTINGS

android.permission.READ_SYNC_STATS

android.permission.USE_CREDENTIALS

android.permission.WRITE_SYNC_SETTINGS

android.permission.AUTHENTICATE_ACCOUNTS

android.permission.GET_ACCOUNTS

android.permission.MEDIA_CONTENT_CONTROL

android.permission.READ_EXTERNAL_STORAGE

android.permission.WAKE_LOCK

android.permission.CAMERA

android.permission.RECORD_AUDIO

android.permission.VIBRATE

Aplicația Android este folosită pentru crearea de notițe și sincronizea acestora cu serverul.

La prima rulare a programului după instalare apare pe ecran formularul pentru autentificare prezentată în figura 4.2. Pentru autentificare utilizatorul trebuie să creeze un cont, pentru acest lucru trebuie apăsată butonul Signup care deschide formularul de înregistrare din figura 4.3.

În formularul de înregistrare trebuie completată numele de utilizator și parola. Parolele din cele două câmpuri Password trebuie să fie aceeași altfel apare un mesaj de eroare deasupra butonului. După completarea câmpurilor trebuie apăsat butonul SIGNUP care trimite datele serverului. Numele de utilizator este verificat de server dacă mai există, dacă da apare un mesaj de eroare. Dacă nu apare nicio eroare contul a fost creat si se deschide formularul de autentificare. În acest formular trebuie completat numele de utilizator (care poate fi o adresă de mail sau orice nume) și parola. Pentru autetificare trebuie apăsat butonul LOGIN. După apăsarea butonului datele sunt trimise serverului care le verifică. Dacă nu există numele de utilizator sau parola este incorectă se afișează un mesaj de eroare. Dacă nu apare mesaj de eroare autentificarea a fost reușită și serverul trimite o cheie clientului cu care se pot accesa API-urile de sincronizare.

După autentificare apare pagina principală a aplicației prezentată în figura 4.4. Aceasta este alcătuită dintr-un toolbar, partea de sus cu titlul (Notes) și butoanele pentru meniu, căutare

și schimbarea vizualizării notițelor. În afară de toolbar mai există un buton (floating action button) de adăugare a notițelor “+” în partea de dreapta jos. Notițele sunt incărcate într-un recycler view. Clasele folosite pentru această pagină sunt NotesFragment (pentru interfața grafică și acțiunile care se execută la apăsarea butoanelor), NotesAdapter care se foloșeste pentru adăugarea datelor (notițelor) in recycler view.

Prin apăsarea butonului “+” se deschide pagina de adăugarea de noțite din figura 4.5. În partea de sus avem butoanele pentru ieșirea din adăugare , pentru adăugare de reminder, adaugare de tag-uri , și butonul ieșire fără salvare .

Prin apăsarea butonului ieșire (săgeată), aplicația închide pagina de adăugare și revine la pagina principală. Prin apăsarea butonului de adăugare de reminder apare un dialog în care se poate selecta data și ora la care dorim să ne anunțe aplicația (figura 4.6). Dacă apăsăm pe dată apare un meniu de tipul spinner în care putem selecta data de azi (Today), mâine (Tomorrow), sau putem selecta data (Pick a date…). Dacă apăsăm pe selectare dată apare un calendar unde putem selecta data (figura 4.7). După ce selectăm data putem selecta ora. Prin apăsarea pe oră apare tot un meniu spinner unde putem selecta ora (Pick a time…) care deschide un ceas unde putem selecta ora (figura 4.8) sau avem opțiunea peste o oră (“In an hour”) care setează ora pe ora actuală plus unu. Dacă dorim să salvăm reminder-ul apăsăm pe butonul de salvare (SAVE). Cu butonul CANCEL se iese din dialog. Dacă salvăm reminder-ul în partea de jos apare data și ora adăugată.

Dacă dorim să adăugăm tag-uri, care sunt folosite pentru găsirea mai usoară a notițelor, trebuie să apăsăm pe butonul de adăugare tag-uri. După ce apăsăm butonul apare un dialog de unde putem selecta tag-urile pe care vrem să le adăugăm la notiță sau putem șterge sau adăuga tag-uri (figura 4.9). Adăugarea unui tag la notiță se face prin selectarea checkbox-ului corespunzător tag-ului. Sunt trei tag-uri predefinite “Home”, “School” și “Work”. Pentru adăugarea de tag-uri noi trebuie sa le scriem în chenarul “Add tag” despărțite prin spațiu.

După adăugare, tag-ul apare în partea de jos lângă reminder (figura 4.10).

Mai jos în pagina de adăugare este un câmp Title, aici putem introduce titlul notiței. După titlu avem un câmp Note unde putem introduce text. Prin apăsare pe un câmp text (Note) apar trei butoane cu care putem seta formatul textului pe îngroșat (bold), înclinat (italic), sau subliniat (underlined). Celelate trei butoane sunt pentru schimbarea câmpului în text, checklist sau bulletlist (figura 4.11).

În partea de jos a ecranului este un toolbar cu șase butoane care sunt folosite pentru adăugarea de elemente: liste, imagini, desene, înregistrări audio sau câmpuri text.

Primul buton este folosit la adăugarea de imagini. Imaginile pot fi adăugate din memoria dispozitivului (Choose image) sau putem face o fotografie (take photo) (figura 4.12). Dacă alegem opțiunea de adăugare din memorie, se deschide un dialog în care selectăm aplicația de la care dorim să alegem imaginea (figura 4.13).

Opțiunea Take photo deschide o fereastră unde putem face o fotografie cu camera dispozitivului (figura 4.14).

Butonul de sus este folosit pentru reglarea blitz-ului care poate fi inactiv, activ sau automat.

Dacă apăsăm pe butonul albastru se salvează imaginea care apare pe ecran și apare în colțul din dreapta jos imaginea salvată (figura 4.15). La apăsarea butonului verde imaginea este adăugată în notiță, unde se poate desena pe ea folosind unealta de desenare prin apăsare lungă pe imagine.

Dacă imaginea conține text putem folosi funcția OCR pentru extragerea textului.

Pentru aceasta imaginea trebuie să fie de calitate bună (să nu fie intunecată sau neclară). Pentru extragerea textului trebuie sa apăsăm pe imagine si să selectăm “Grab text”, în partea de jos apare un mesaj (figura 4.16). Când dispare mesajul, textul extras este adăugat la notiță sub formă de câmp de text.

Următorul buton este pentru desenare. La apăsarea lui se deschide fereastră pentru desenare (figura 4.17). În partea de sub se află butoanele înapoi (care închide fereastra de desenare și se întoarce la crearea notiței) și butoanele undo și redo , iar în partea de jos uneltele pentru desenare si ștergere. Ștergerea se poate face selectând butonul

sau “CLEAR CANVAS” pentru golirea canvas-ului (figura 4.18). Următoarele trei butoane , și sunt folosite pentru desenare. Dacă selectăm o unealtă de desenare și tragem în sus de el apare o grilă din care putem selecta culoarea cu care dorim să desenăm și grosimea liniei (figura 4.19). Diferența dintre cele trei unelte de desenare este grosimea cu care putem desena. Pentru fiecare unealtă poate fi selectată o culoare de desenare separată, acest lucru ajută când vrem sa desenăm ceva cu o culoare si să colorăm cu alta.

După ce terminăm desenarea trebuie apăsat butonul înapoi. La închiderea ferestrei desenul este salvat pe dispozitiv și adăugat la notiță.

La apăsarea butonului apare un meniu din care putem alege dacă dorim să înregistrăm sunet sau să începem o introducere de text folosind speech-to-text (figura 4.20).

Dacă alegem opțiunea speech-to-text (vorbire în text) apare iconița pe ecran și putem începe să vorbim, care este transformat în text când ne oprim. Transformarea se face folosind boblioteca Google de transformare a vorbirii în text. Textul este adăugat la notiță sub formă de câmp de text. Opțiunea înregistrare audio este folosită pentru înregistrarea sunetelor. La apăsarea butonului apare pe ecran un buton cu care putem opri înregistrarea si un contor care numără durata înregistrării (figura 4.21). La apăsarea butonului de oprire, înregistrarea este salvată și adăugată la notită. În cadrul notiței apare un câmp de înregistrare audio pe care putem să-l redăm folosind butonul de pornire. Câmpul mai conține un progressbar care arată în timpul redării trecerea timpului și un text cu durata înregistrării (figura 4.22).

Următoarele butoane din toolbar-ul de jos sunt pentru adăugare de text checklist sau bulletlist .

Când am terminat cu adăugarea elementelor în notiță putem apăsa butonul șterge care nu salvează modificările sau butonul înapoi pentru salvarea modificărilor. Oricare din aceste două butoane închide pagina de adăugare și deschide pagina principală cu notițele. Aici putem schima modul de vizualizare a notițelor cu butonul din dreapta sus în grilă (figura 4.23) sau listă (figura 4.24).

Fiecare notiță are un titlu, care poate fi un șir de caractere gol, un text, data la care a fost adăugată sau modificată și iconițele pentru reminder și tag-uri. Iconița pentru reminder apare doar dacă în notiță este setat un reminder. Iconița pentru tag-uri arată câte tag-uri sunt associate notiței și este prezentă doar dacă notița are una sau mai multe tag-uri.

Prin tragerea notiței la dreapta sau la stânga, ea este trimisă în coșul de gunoi, de unde se pot șterge definitiv. După ștergerea notiței apare un mesaj în partea de jos a ecranului (figura 4.25) unde există un buton “UNDO”, care anulează trimiterea notiței în coșul de gunoi.

Dacă apăsăm pe una dintre notițe se deschide pagina de vizualizare din figura 4.26. Aici putem vizualiza toate elementele notiței, putem selecta checkbox-urile, asculta înregistrările audio sau prin apăsarea butonului de editare (din colțul dreapta jos) putem deschide notița în mod editare. În partea de stânga sus este butonul , care deschide meniul din figura 4.27. Din meniu putem filtra notițele prin selectarea unui tag sau putem deschide coșul de gunoi (trash, figura 4.28). Din coș putem scoate notițele prin apăsare lungă sau putem să le stergem

definitiv prin tragerea la dreapta sau la stânga.

Butonul de căutare deschide pagina de căutare din figura 4.29 unde putem căuta notițe prin introducerea unui text. Căutarea se face după toate câmpurile si tag-urile.

Din fereastra de căutare putem iesi cu butonul înapoi.

Capitolul 5 – Concluzii

Aplicația prezentată în această lucrare contribuie la gestionarea eficientă a notițelor unui utilizator care folosește mai multe dispozitive cu sistem de operare Android. Această gestionare eficientă este oferită de posibilitatea folosirii aplicației client fără conexiune la internet și sincronizarea clientului cu serverul când există conexiune la internet. Dacă utilizatorul este autentificat cu același cont pe fiecare dispozitiv și dispozitivele se sincronizează cu serverul se face automat și sincronizarea între dispositive.

Prin realizarea acestei aplicații am vrut să invăț cum se dezvoltă o aplicație client-server și cum se face sincronizarea între cele două aplicații. Prin dezvoltarea aplicației prezentate am învățat cum se folosesc framework-urile descries în capitolul 2.

Este o aplicație ușor de folosită datorită interfeței cu utilizatorul care este foarte sugestivă.

Structura aplicației (separarea clientului de server) crește mentenabilitatea și ușurează extinderea funcționalităților acesteia în viitor.

O posibilă dezvoltare viitoare ar fi crearea de aplicații client pe mai multe sisteme de operare mobile (IOS, Windows), desktop (Windows, Mac OSX) și dezvoltarea unei aplicații client web.

Alte posibile dezvoltări viitoare ar fi posibilitatea de schimbare a fontului, mărimii fontului sau culorii fontului la adăugarea notiței în aplicația client, adăugarea mai multor tipuri de liste, gruparea notițelor pe directoare, partajarea notițelor cu alți utilizatori (cu drepturi de acces), lucrul în echipă și adăugarea unui chat pentru lucrul în echipă.

Bibliografie

[1] https://en.wikipedia.org/wiki/Node.js, Consultat la 04.03.2016 și 08.06.2016

[2] http://khan.io/2015/02/25/the-event-loop-and-non-blocking-io-in-node-js/, Consultat la 08.03.2016 și 09.06.2016

[3] https://strongloop.com/strongblog/node-js-is-faster-than-java/, Consultat la 04.03.2016

[4] http://passportjs.org/, Consultat la 12.03.2016 și 09.05.2016

[5] Holmes, Simon: Mongoose for Aplication Development, 2013, pp. 12-14.

[6] https://en.wikipedia.org/wiki/MongoDB, Consultat la 08.03.2016 și 09.06.2016

[7] http://siliconangle.com/files/2013/08/MongoDB-Architecture.jpg, Consultat la 08.03.2016 și 09.06.2016

[8] http://www.slideshare.net/mongodb/retail-referencearchitecture-productcatalog, Consultat la 08.04.2016

[9] https://en.wikipedia.org/wiki/Representational_state_transfer, Consultat la 22.03.2016 și 13.05.2016

[10] http://prideparrot.com/blog/archive/2012/3/creating_a_rest_service_usingaspnet_web_api, Consultat la 21.03.2016 și 29.05.2016

[11] http://docs.sitefinity.com/for-developers-web-services, Consultat la 25.04.2016 și 09.06.2016

[12] https://en.wikipedia.org/wiki/JSON, Consultat la 11.04.2016 și 21.05.2016

[13] https://en.wikipedia.org/wiki/Tesseract_(software), Consultat la 27.04.2016 și 09.05.2016

[14] https://en.wikipedia.org/wiki/Java_(programming_language), Consultat la 11.04.2016 și 02.06.2016

[15] https://en.wikipedia.org/wiki/Android_(operating_system), Consultat la 01.05.2016 și 03.06.2016

[16] https://en.wikipedia.org/wiki/Android_(operating_system)#/media/File:Android_6.0.1_H ome_Screen_Nexus_7.png, Consultat la 22.05.2016 și 01.06.2016

[17] https://en.wikipedia.org/wiki/Android_(operating_system)#/media/File:Android-System-Architecture.svg, Consultat la 29.03.2016

[18] https://en.wikipedia.org/wiki/Material_Design, Consultat la 12.05.2016 și 13.06.2016

[19] https://en.wikipedia.org/wiki/Material_Design#/media/File:Material_Design.svg, Consultat la 25.05.2016

[20] https://en.wikipedia.org/wiki/Client%E2%80%93server_model#/media/File:Clientserver-model.svg, Consultat la 13.05.2016

[21] https://developer.android.com/training/sync-adapters/index.html, Consultat la 22.05.2016 și 04.06.2016

[22] http://www.kpbird.com/2015/09/android-simple-syncadapter.html, Consultat la 01.06.2016 și 03.06.2016

[23] http://remotexpert.net/wp-content/uploads/2013/10/SyncAdapter.png, Consultat la 24.04.2016 și 20.05.2016

[24] Chodorow, Kristina: MongoDB: The Definitive Guide, 2013, pp. 3-5

Anexa 1 – Lista figurilor

Figura 2.1 Arhitectura Node.js

Figura 2.2 Comunicarea între serverul Node.js și baza de date fără blocări

Figura 2.3 Comunicarea între server cu mai multe fire de execuție și baza de date cu blocări

Figura 2.4 Arhitectura MongoDB

Figura 2.5 Căutarea în baza de date MongoDB

Figura 2.6 Arhitectura REST

Figura 2.7 Comunicarea cu serviciul REST

Figura 2.8 Sigla JSON

Figura 2.9 Sigla Java

Figura 2.10 Sigla Android

Figura 2.11 Interfața grafică a sistemului de operare Android

Figura 2.12 Arhitectura sistmeului de operare Android

Figura 2.13 Elemente Material Design pentru Android

Figura 3.1 Arhitectura client server

Figura 3.2 Componentele sistemului

Figura 3.3 Comunicarea dintre server si client la autenficare

Figura 3.4 Cererea notițelor

Figura 3.5 Trimiterea notițelor

Figura 3.6 Sincronizare dintre client și server

Figura 3.7 Serverul cu multiple dispozitive mobile

Figura 3.8 Sync Adapter

Figura 3.9 Etapele Sincronizarii

Figura 4.1 Strunctura proiectului server

Figura 4.2 Formularul de autentificare

Figura 4.3 Formularul de înregistrare

Figura 4.4 Pagina principală

Figura 4.5 Pagina de adăugare

Figura 4.6 Dialogul pentru adăugare de reminder

Figura 4.7 Selectare dată

Figura 4.8 Selectarea orei

Figura 4.9 Dialogul pentru adăugare de tag-uri

Figura 4.10 Reminder-ul si tag-ul adăugat

Figura 4.11 Butoanele petru formatarea textului

Figura 4.12 Opțiunile pentru adăugare de imagini

Figura 4.13 Dialog pentru selectarea aplicației de unde preluăm imaginea

Figura 4.14 Camera de fotografiat

Figura 4.15 Imaginea salvată

Figura 4.16 Mesajul afișat în timp ce se extrage textul

Figura 4.17 Fereastra de desenare

Figura 4.18 Unealta de ștergere

Figura 4.19 Selectarea culorii și grosimii pentru desenare

Figura 4.20 Meniu pentru înregistrare sunet sau speech-to-text

Figura 4.21 Înregistrare audio

Figura 4.22 Redare înregistare audio

Figura 4.23 Modul de vizualizare grilă

Figura 4.24 Modul de vizualizare listă

Figura 4.25 Mesajul de mutare in coș

Figura 4.26 Pagina de editare

Figura 4.27 Meniu

Figura 4.28 Coșul de gunoi

Figura 4.29 Fereastra de căutare

Anexa 2 – Dependințe utilizate

Server:

"bcrypt-nodejs": "0.0.3",

"body-parser": "latest",

"connect-flash": "^0.1.1",

"connect-mongo": "^1.1.0",

"cookie-parser": "latest",

"ejs": "latest",

"express": "^4.13.4",

"express-session": "latest",

"mongoose": "^4.4.10",

"passport": "^0.3.2",

"passport-http-bearer": "^1.0.1",

"passport-local": "^1.0.0",

"rand-token": "^0.2.1"

Client:

com.google.code.gson:gson:2.4'

com.android.support:design:23.4.0'

com.android.support:appcompat-v7:23.4.0'

com.android.support:recyclerview-v7:23.4.0'

com.android.support:cardview-v7:23.4.0'

com.android.support:design:23.4.0'

com.squareup.picasso:picasso:2.5.2'

com.android.support:support-v4:23.4.0'

com.sothree.slidinguppanel:library:3.2.1'

de.hdodenhof:circleimageview:2.0.0'

com.wdullaer:materialdatetimepicker:2.3.0'

com.rmtheis:tess-two:5.4.1'

com.github.bumptech.glide:glide:3.7.0'

com.android.support:multidex:1.0.1'

Similar Posts

  • Perspective de Dezvoltare a Agentiei de Turism

    === 3d8380bc255968e91db59b48d6f813c29a1a8335_98714_1 === UNIVERSITATEA FACULTATEA DE ECONOMIA TURISMULUI INTERN ȘI INTERNAȚIONAL E.C.T.S LUCRARE DE LICENȚĂ PERSPECTIVE DE DEZVOLTARE A AGENȚIEI DE TURISM SOL TURISM COORDONATOR ȘTIINȚIFIC ABSOLVENT BUCUREȘTI 2017 CUPRINS INTRODUCERE……………………………………………………………………………………………..3 Cap.1 PRINCIPALELE CARACTERISTICI ALE AGENȚIEI DE TURISM SOL TURISM…………………………………………………………………………………………………..5 1.1 Scurt istoric………………………………………………………………………………………………..5 1.2 Obiectul de activitate……………………………………………………………………………………6 1.3 Structura organizatorică și managementul resurselor umane………………………………………….7 1.4…

  • Enseigner Le Francais Aux Jeunes Enfants a Travers Les Moyens Audio Visuels

    === 451fbfee0b2150fea8dd8a69fd9dbb88427c9de3_153461_1 === Ѕommairе 1. Avant-рroрoѕ oc 2. Lеѕ mоγеnѕ audiо-viѕuеlѕ oc 2.1 Lеѕ dосumеntѕ audіо oc2.1.1 Сaraсtérіѕtіquеѕ généralеѕ еt dіffісultéѕ ocрartісulіèrеѕ 2.1.2. ocLеѕ étaреѕ dе la соmрréhеnѕiоn/рrоduсtiоn оralе oc 2.1.3. Lеѕ ѕuрроrtѕ ocѕоnоrеѕ utiliѕéѕ 2.1.4 ocΕnѕеignеr lе vосabulairе à l’aidе dеѕ dосumеntѕ audiо oc 2.2 Lеѕ dосumеntѕ a audiо-ocviѕuеlѕ 2.2.1 ocϹaraсtériѕtiquеѕ généralеѕ еt diffiсultéѕ…

  • Calitatea Serviciilor Prestate de Sc Ista Shared Services Srl

    UNIVERSITATEA „NICOLAE TITULESCU” FACULTATEA DE ȘTIINȚE ECONOMICE PROGRAMUL DE STUDII: ADMINISTRAREA AFACERILOR LUCRARE DE LICENȚĂ DISCIPLINA MANAGEMENTUL CALITATII TEMA STUDIU DE CAZ PRIVIND CALITATEA SERVICIILOR PRESTATE DE SC ISTA SHARED SERVICES SRL Coordonator științific conf. univ. dr. Costel Stanciu [anonimizat] București 2016 CUPRINS INTRODUCЕRЕ Un sеrviciu еstе rеprеzеntat dе rеzultatеlе gеnеratе dе avtivitați la carе…

  • Elaborarea Actelor Normative

    ȘCOALA NAȚIONALĂ DE STUDII POLITICE ȘI ADMINISTRATIVE FACULTATEA DE ADMINISTRAȚIE PUBLICĂ ELABORAREA ACTELOR NORMATIVE COORDONATOR ȘTIINȚIFIC: PROF. UNIV. DR. IOAN VIDA ABSOLVENT: SPĂTĂREANU TIBERIU ALEXANDRU BUCUREȘTI 2016 CUPRINS INTRODUCERE Scopul urmărit în prezenta lucrare, „Elaborarea actelor normative” este acela de a-i familiariza pe cei care nu posedă cunoștințe în acest domeniu cu elementele ce stau…

  • Dimensiunea Mistagogică a Postului Mare

    UNIVERSITATEA DIN CRAIOVA FACULTATEA DE TEOLOGIE ORTODOXĂ Lucrare de licență Dimensiunea Mistagogică a Postului Mare Coordonator, Lect. Univ. Dr. Cristian Cercel Absolvent, ADRIAN ALEXANDRU IGNAT CRAIOVA 2016 Postul Mare are o greutate covârșitoare în actul mântuirii pe care Mântuitorul Iisus Hristos a darut-o lumii și pe care noi, prin eforturi personale consistente și continue, trebuie…

  • Didactica Structurilor de Poveste In Invatamntul Specialdocx

    === Didactica structurilor de poveste in invatamntul special === DIDACTICA STRUCTURILOR DE POVESTE IN INVATAMANTUL SPECIAL Cuprins: Capitolul I: -Preliminarii ……………………………………………………………………………………. Capitolul I. Harta conceptuala a orientarii educationale la copiii cu dificultati de invatare 1.1. Conceptualizarea orientarii educationale la copiii cu dizabilitati perspective sociopedagogica 1.3. Repere psihopedagogice ale orientarii educationale la copiii cu dizabilitati din…