Dezvoltareaăuneiăaplicaiiăpentruăverificareaăinteractivă [619960]

F 271.13/Ed.3 Fișier SMQ/Formulare

Anexa 8
MINISTERULăEDUCAğIEIăNA܉IONALEăȘIăCERCETĂRIIăȘTIINğIFICE
UNIVERSITATEA PETROL – GAZEăDINăPLOIEȘTI
FACULTATEA:ăLITEREăȘIăȘTIINğE
DEPARTAMENTUL: INFORMATICĂ,ăTEHNOLOGIAăINFORMAğIEI,ă
MATEMATICĂăȘIăFIZICĂ
PROGRAMUL DE STUDII: INFORMATICĂ
FORMAăDEăÎNVĂ܉ĂMÂNT:ă IF

Vizat
Facultatea LitereășiăȘtiinĠe
Aprobat,
Director de departament,
Conf. dr. inf. Gabriela Moise

LUCRAREăDEăLICENğĂ

TEMA: Dezvoltareaăuneiăaplica܊iiăpentruăverificareaăinteractivă
aăcuno܈tin܊eloră– „CarQuiz ”,ăpentruăplatforma Android

ConducătorăștiinĠific:
Lector dr. inf. DanielaăTudorică

Absolvent: [anonimizat]
2016

1

CUPRINS

1. Introducere ……………………………………………………………………………………………………. 2
2. Tehnologii ܈i unelte software folosite ………………………………………………………………. 4
2.1. Limbajul de programare Java …………………………………………………………………….. 4
2.2. XML – Extensible Markup Language ………………………………………………………….. 6
2.3. Sistemul de gestiune a bazelor de date SQLite …………………………………………….. 7
2.4. Mediul de dezvoltare Android Studio …………………………………………………………. 9
3. Dezvoltarea aplica Ġiei CarQuiz ………………………………………………………………………. 11
3.1. Configurarea mediului de dezvoltare Android Studio ………………………………….. 11
3.2. Configurarea emulatorului AVD – Android Virtual Device ………………………….. 13
3.3. Proiectarea ܈i implementarea bazei de date ………………………………………………… 16
3.3.1. Diagrama entitate-legatura …………………………………………………………………. 16
3.3.2. Implementarea bazei de date folosind SQLite ……………………………………….. 18
3.4. Realizarea aplica Ġiei CarQuiz …………………………………………………………………… 22
3.4.1. Implementarea aplica Ġiei…………………………………………………………………….. 24
3.4.2. Testarea aplica Ġiei ……………………………………………………………………………… 38
3.4.3. Compara Ġie cu o aplica Ġie similar ă ………………………………………………………. 42
4. Concluzii …………………………………………………………………………………………………….. 47
Bibliografie …………………………………………………………………………………………………….. 48
Anexa. Extrase de cod sursa ……………………………………………………………………………… 50

2
CAPITOLUL 1 – Introducere

Temaă acesteiă lucrăriă deă licenĠăă seă încadreazăă înă domeniulă “AplicaĠiiă webă
mobile”ă ܈iă esteă realizatăă peă b aza cuno܈tin܊eloră dobânditeă înă timpulă aniloră deă studiu,ă
precumă ܈iă aă celoră acumulateă înă urm a studiului bibliografiei. Pornind de la aceste
lucruri, din dorin ܊a de a descoperi tehnologii noi ,ă amă optată săă pășesc în universul
jocurilor, astfel încât mi- amăpropusăsăărealizezăoăaplica܊ie pentru platforma Android, cu
titlulă“ CarQuiz ”.ăăă
Motivulăpentruăcareăamăalesăaceastăătemăăesteăacelaăcă,ăprivindăcătre copilărie,ă
to܊iăneădoreamăsăă“creăm”ăunăjoc.ăPrinăintermediulăacest uia,ăpasiona܊iiădeăma܈iniăî܈iăpotă
testaă cuno܈tin܊ele șiă înă acelașiă timpă potă învăĠaă lucruriă noi . Utilizatorii pot folosi
aplicaĠiaăcuăajutorulăunuiădispozitivămobilăsauăalăuneiătablete.
Peă parcursulă elaborăriiă aplica܊ieiă Android,ă au fost urmăriteă oă succesiuneă deă
obiectiveă ܈iă deă cerin܊e,ă acesteaă fiindă detaliateă înă următoareleă capitoleă aleă lucrării .
InterfaĠaă aplicaĠieiă trebuieă săă fieă unaă prietenoasăă șiă ușoră deă utilizat,ă astfelă încâtă
feedback- ulăutilizatorilorăsăăfieăunulăpozitiv.
Obiectivulă principalăală lucrării constăăînădezvoltareaăuneiăaplica܊iiă Androidă deă
tipul quiz (chestionar)ăînădomeniulăautoturismelor.ăDatorităăexperien܊eiăplăcuteăpeăcareă
am avut-o în anii anteriori jucându- măă joculă Logoă Quiz [20] ܈iă pasiuniiă meleă pentru
autoturisme, m- amăgândităsăăcreezăunăjocăprinăcareăutilizatoriiăsăătrăiascăăoăexperienĠ ăă
asemănătoare,ăcuăoăinterfaĠăăplăcutăă܈iău܈orădeăutilizat.ăAmăalesăsăă le oferăpasiona܊iloră
deă ma܈iniă posibilitateaă deă a -܈iă testaă cuno܈tin܊eleă ܈iă ski ll-ul în acest joc distractiv
CarQuiz. Scopul acestui joc este caăutilizatorulăsăărecunoascăămașinaășiăsăăscrie marca
܈iămodelul corect.ăFiecareărăspunsăcorect aduc e un punctaj ce debloc hează noi niveluri.
Laă fiecareă nivelă nouă gradulă deă dificultateă cre܈te.ă Deă asemenea,ă creșteă șiă numărulă deă
mașiniăcareătrebuieăghicite . În cazul în care utilizatorul nu poate trece mai departe, nu
trebuieă săă se lase, poate folosi butonu lă “Hints ”ă pentruă aă primi indicii despre
automobilul selectat. Dacăăînsăăutilizatorulădoreșteăsăăseădocumenteze mai mult despre
oă anumităă ma܈ină,ă areă posibilitateaă săă acceseze Wikipediaă pentruă informa܊iiă
amănun܊ite.ăSunetulă܈iăvibra܊iileădinăjocă se pot schimba dinămeniulă“ Settings ”.ăAplicaĠiaă

3
conĠineă șiă opĠiuneaă Statistics,ă careă aratăă numărulă deă întrebări rezolvate, punctajul,
încercărileăe܈uateădară܈iănumărulădeăma܈iniăghiciteădinăprimaăîncercare.ă

Structura lucrăriiă
Lucrareaăesteăstructuratăăîn patruăcapitole,ădupăăcumăurmează:
 Capitolul 1 – Introducere,ăînăcareăsuntăilustrateăurmătoareleăaspecte:
-o prezentare succintăăaădomeniuluiăales ;
-motivul alegerii acestei teme;
-câteva date despre aplicaĠiaărealizată .
 Capitolul 2 – Tehnologii si unelte software folosite – sunt descrise pe scurt:
-limbajul de programare Java;
-limbajul de structurare a datelor XML;
-sistemul de gestiune a bazelor de date SQLite;
-mediul de dezvoltare Android Studio.
 Capitolul 3 – Dezvoltarea aplicaĠ iei CarQuiz – prezintăă detaliată pașiiă parcurșiă
pentruărealizareaăaplicaĠiei:
-configurareaămediuluiădeădezvoltareăAndroidăStudioășiăaăemulatoruluiă
AVD (Android Virtual Device);
-proiectareaășiăimplementareaăbazeiădeădate;
-implementareaăaplicaĠiei;
-testarea aplicaĠieiă realizateă șiă comparareaă acesteiaă cuă oă altăă aplicaĠieă
similarăădisponibilăăpeăpiaĠă.
 Capitolul 4 – Concluzii. În acest capitol este prezentat gradul de îndeplinire a
obiectiveloră propuseă șiă suntă identificateă posibileă direcĠiiă deă dezvoltareă aă
aplicaĠieiăînăviitor.

4
CAPITOLUL 2 – Tehnologii si unelte software folosite

În acest capitol sunt prezentate pe scurt tehnologiile șiăunelteleăsoftwareăfolositeă
pentruărealizareaăaplicaĠieiă CarQuiz.

2.1. Limbajul de programare Java

Limbajul Java a fost lansat în anul 1995, ca urmare a eforturilor firmei SUN
Microsystems, care aă încercată săă dezvolteă ună limbajă deă programareă pentruă
echipamentele inteligente de genul telefonului, cuptorului cu microunde, cardurilor,
detectoareloră deă fumă șiă aă altoră dispozitiveă miciă (en.ă smallă devices)ă – înă cadrulă așaă
numitului proiect Green. [14]
În prezent, c eleă maiă multeă aplica܊iiă distribuiteă suntă scriseă înă Java,ă iară noileă
evolu܊iiă tehnologiceăpermită utilizareaă saă܈iă peă dispozitiveă mobileăgenătelefon,ă tabletă,ă
agendă electronicăăetc.ă [17]
În continuare sunt enumerate caracteristicile principale ale limbajului Java [16] :
 Simplitate – limbajul ofer ăăposibilitatea de a scrie câ tă maiă ușoră ună codă fărăă
greșeli ;
 Robuste܊e ;
 eliminăăsurseleădeăeroriăceăpotăapăreaăprin:ă
-administrareaăautomatăăaămemoriei;
-eliminarea pointerilor.
 Securitate ce este asigurat ă prin:
-verificareaădinamicăăaăcodului;
-reguli stricte pentru rularea programelor.
 Neutru din punct de vedere arhitectural;
 Dinamicitate;
 Face disti nc܊ieăîntreălitereămiciă܈iămari;
 EsteămodelatădupăăCă܈iăC++;
 Compilat;
 Interpretat.
 intruc܊iunileăsuntăcititeălinieăcuălinieă܈iătraduseăînăinstrucĠuini ma܈ină.

5
Java este un limbaj de programare simplu deăfolosităchiară܈iăpentruăîncepători,ă
dară ܈iă pentruă programatoriiă careă voră săă creezeă înă specială aplica܊ii.ă Auă fostă introduseă
lucruriă noi,ă caă deă exempluă colectorulă deă gunoaieă careă rezolvăă problemaă dealocăriiă
memoriei într-un mod uniform. Compilatorul Java genereazăăintruc܊iunileăuneiăma܈iniă
virtualeăJava,ădarăexecu܊iaăaplica܊iilorăesteăinterpretată.ăDeăobicei,ăseăcompileazăăpăr܊ileă
programuluiăceăconsumăăfoarteămultătimp,ărestulărămânândăaăfiăinterpretate [16].
Limbajul Java este robust .ăLegareaăfunc܊iilorăesteărealizatăăînătimpulăexecu܊ieiă
܈iă informa܊iileă deă compilareă suntă pânăă înă momentulă înă careă seă ruleazăă aplica܊iaă
disponibile.ăJavaăgăse܈teăreferin܊eleănuleăatunciăcândăeleăsuntăfolositeăînăopera܊iileădeă
acces. Tablourile nu se parcurg prin intermediul pointerilor deoarece lipsesc din acest
limbaj [16].
Acest limbaj este unul cu securitate mărită.ă Cuă ajutorulă mecanismeloră CRCă
acestaăverificăălaăfiecareăîncărcareăcodul.ăRobuste܊eaălimbajuluiăesteăoăaltăătrăsăturăădeă
securitate. Java are incorporate facil itateădeăprotec܊ieăaăobiectelorăatâtălaăscriereăcâtă܈iălaă
citire.ă Nuă potă fiă accesateă variabileleă protejate,ă făcându -se o verificare în timp ce
programulăesteăexecutat.ăJavaăpoateăprotejaăre܊eauaălocală,ăresurseleăcalculatoruluiădară
܈iăfi܈ierel e pe care rul eazăăoăaplica܊ieă [16].
Oă altăă caracteristicăă aă limbajuluiă deă programareă Javaă esteă dinamicitatea .
Bbibliotecile de clase pot fi reutilizate, acesta fiind un avantaj.

LibrăriaăjQueryă

Pentru realizarea aplica Ġieiă s -aă folosit,ă deă asemenea,ă șiă bibliote ca Javascript
jQuery. Aceastăă bibliotec ă aăfostălansatăăînă2006ă,ăcuăscopulădeăaău܈uraăparcurgereaă
DOM -ului (Document Object Model reprezentând un pachet de interfeĠe)ă܈iă de a crea
cereri Ajax. Acesta a fost conceput pentru a func Ġiona pe toate versiunile de browsere
[12].
.

6
2.2. XML – Extensible Markup Language

XML (eXtensible Markup Language) este un limbaj de structurare a datelor,
acestaăaăapărutăînăaniiă80,ăcaă un descendent al SGML (Standard Generalized Markup
Language). XML este extensibil,ă independentă deă platformăă ܈iă suportăă
interna܊ionalizareaă܈iălocalizarea.ăDeăasemenea , XML esteăsimpluă܈iăaccesibil,ăpoateăfiă
editat,ămodificatău܈or,ănecesităăunăeditorătextăsimpluăprecumăNotepad,ăMicrosoftăWord,ă
etc. Este lipsit de suport în bro wsereăsauăalteăaplica܊ii.ăPrezintăăunădezavantajădeoareceă
esteădificilădeădecisăceăsăăfieăcon܊inută܈iăceăsăăfieăatribut,ăesteăunălimbajăstrict,ăînăcazulăînă
care apare o eroare în document, acestaănuăopre܈teărulareaăscriptului. [11].
XML oferăăposibilitateaădeăaămanipulaădateleăpeăplatformeădiferite,ăcaăstructurăă
܈iă tipă deă documentă fiind un limbaj simplu de citit. Într- ună XMLă avemă elementeă ܈iă
atribute, elementele sunt delimitate de 2 tag-uri, iar acestea pot fi goale.
Numeleă peă careă îlă areă elementulă delimitată trebuieă săă îndeplinească anumite
condi ܊ii:ă
-nuăpoateăîncepeăcuăcifreăsauăsemneădeăpunctua܊ie ;
-nuăpoateăîncepeăcuă“xml”;
-nuăpoateăcon܊ineăspa܊ii.
Daca un element contine mai multe elemente, pot apărea grade de rudenie intre
acestea .ăCelămaiăimportantălucruăesteăsăăexisteăunăelementărădăcinăăcareăsăăleăcon܊inăăpeă
toateăcelelalte.ăElementeleănuăpotăfiăîncruci܈ate.ăUnăelementăpoateăsăăcon܊inăăunulăsauă
mai multe atribute.
ÎnăXMLătrebuieăsăăexisteăunărândăînăcareăseămen܊ioneazăăcodificareaăfolosităă܈iă
versiunea limbajului.
Marcaj eleătrebuieăsăăasigureăoăsintax standardizatăăpeăcareăanalizatoareleăXMLă
oăpotăfolosiăpentruăaăutilizaăinforma܊iaăstocată.ăDeăasemeneaămarcajeleădescriuăstructuraă
ierahicăăaăcon܊inutuluiăprinărepartizareaăinforma܊ iei în elemente descrise prin atribute.
Deciă esteă eviden܊iatăă structuraă ierarhicăă aă întreguluiă documentă prină utilizareaă
marcajelor.
XML- ulăcuprindeăsec܊iuneaăProlog,ădefini܊iaătipuluiădeădocument,ăaceastaăfiindă
op܊ională,ă܈iăsec܊iuneaăînăcareăseăaflăăelementeleărădăcină.ă
Elementeleăpotăaveaăreferin܊ăăînăalteăelementeăcuăajutorulăatributelorăIDREF.ăDeă

7
preferat ar fi săăaparăăîntâiăelemntulă܈iăapoiăreferin܊ele.ăDeclarareaădatelorăseăfaceăprină
declara܊iiădeătipăEntityăsauăfolosindăa tribute de tip IDăpentruăoăindentificareăunică.

În concluzie XML- ulă oferăă posibilitateaă deă aă structuraă dateleă într -oă manierăă
proprieăcuătaguriăspecifice.ăAcestaăreprezintăăunălimbajăcomunădeoareceăcuăajutorulăluiă
punem schimba date intreăaplica܊ii.ă
 Editoare XML: Notepad++ , Eclipse , Notebeans , Altova , Oxygen XML .

2.3. Sistemul de gestiune a bazelor de date

SQLite reprezint ă o baz ă de date rela ܊ionalăă pentruă aă gestionaă informaĠiile la
nivel local, care nu necesita nicio configurare, putând fi astfelă introdusăă înă diverseă
sisteme de operare. [15]
Multe sisteme de gestiune a bazelor de date (SGBD) au fost dezvoltate în
ultimele decenii. DB2, Informix, Ingres, MySQL, Oracle, PostgreSQL, SQL Server,
Sybase sunt doar câteva, care au un succes comerci ală pentruă aplica܊iiă aleă bazeloră deă
date pentru întreprinderi. Exemple de sistemele de baze de date integrate, de success
includ Sybase iAnywhere, InterSystems Cache, Microsoft Jet. SQLite este o
completareărecentăăînăfamiliaărela܊ionalăă(SGBDR)ă܈iăesteăde asemena un sistem integrat
de baze de date de succes.
SQLiteă܈i -a început debutul pe 29 Mai 2000, ca publicareăini܊ialăăaăcoduluiăalfaă
cuăunănumărălimitatădeăcaracteristici.ăUltimaăversiuneălansatăăesteăSQLiteă3.8.9ăpeă08ă
Aprilie 2015.
Echipa de dezvolta reă SQLiteă continuăă săă lansezeă noiă versiuni,ă dară
caracteristicileădeăbazăă܈iămodulădeăoperareăalădatelorănuăoăsăăseămodificeămult.ăă
SQLite este o baz ă de date open-source care folose ܈te Structured Query
Language pentru facilitarea accesului la datele stocate. SQLite nu ocup ă foarte mult ă
memorie, acesta este de dimensiuni mici, aproximativ 250 KB, a fost proiectat pentru a
fi rapid, u ܈or de folosit, u ܈or de administrat si setat. [15]

8
SQLite con Ġine clase precum:
 SQLiteOpenHelper
 SQLiteDatabase
 Cursor
Sunt prezentate în continuare cele mai importante caracteristici ale SQLite. [8]
SQLite este dezvoltat în întregime folosind limbajul de programare ANSI C.
Esteă ună SGBDRă bazată peă SQLă u܈oră deă între܊inută ܈iă înă modă rezonabilă rapid.ă Areă
următoareleăcaracteris tici importante:
 Configurareaăzero:ăăNuătrebuieăsăă efectua ĠiăalĠiăpași pentru instalarea software-
ului SQLite înainte de a- lă folosi.ă Nuă existăă pași bineă stabili܊iă pentruă aă începeă
executarea programului SQLite.
 Incorporabilitatea: Nu e nevoie de un proces de server separat dedicat
programuluiăSQL.ăLibrăriaăSQLiteăesteăincorporatăăînăaplica܊ie.ă
 Interfa܊ăăsimplăăaăaplica܊iei:ăSQLiteăfurnizeazăăunămediuăSQLăpentruăaplica܊iileă
Căînă scopulămanipulăriiădatelor.ăNuăexistăăcerin܊eăspecialeăpentruăaplica܊ii,ăună
compilator normal C este de ajuns.
 Suportă tranzac܊ional:ă SQLiteă suportăă proprietă܊ileă ACIDă aleă tranzac܊iiloră deă
bază,ă܈iăanumeăatomicitatea,ăconsisten܊ă,ăizolareaă܈iădurabilitatea.ăNiciăoăac܊iuneă
a utilizatorilor sau a admistratorilor bazei de date nu este necesarăăînăcazulăuneiă
defec܊iuniăaăsistemuluiăpentruărecuperareaăbazeiădeădate.ă
 SQLiteă esteă oă librărieă thread -safe, iar multe fire în pr ocesulă uneiă aplica܊iiă potă
accesaăaceea܈iăbazăădeădateăsau unaădiferităăconcomitent.ă
 Ocupăă pu܊ină spa܊iu:ă Librăriaă SQLiteă ocupăă aproximativă 333KBă cuă toateă
caracteristicileă impliciteă activate.ă Spa܊iulă deă ocupareă poateă fiă redusă laă 250KBă
prin dezactivarea tuturor carcateristicilor avansate.
 Capacitateaădeăpersonalizare:ăSQLiteăoferăăunăcadruăbunăînăcareăpo܊iă definiă ܈iă
folosi func܊iiăSQLăpersonalizate,ăfunc܊iiăagregateă܈iăsecven܊eădeăcola܊ionare.ă
 Codă unic:ă SQLiteă acceptăă standardeleă UTF -8ă ܈iă UTF -16 bazate pe codificare.
UTF- 16ăacceptăădeasemeneaăformateleămiciă܈iămari.ă
 Dovadăă pierderiiă memoriei:ă Dacăă aplica܊iileă respectăă str ict protocoalele
recomandate de interactionarea cu SQLite, biblioteca afirmăăcăăniciodatăănuăvaă
pierde date.

9
 Cerin܊eădeămemorie:ăChiarădacăăSQLiteăpoateăutilizaăspa܊iuănelimitatăînăprocesulă
deăexecutare,ăpoateăfiăsetatăsăăfunc܊ionezeăcuăunăspa܊iuăminimăde 4KB pe stiv ă.
Aceastăăcaracteristicăăesteăfoarteă folositoareăpentruădispozitiveleămiciă(precumă
telefoanele),ădarăcuăcâtăexistăămaiămultăămemorieădisponibilă,ăcuăatâtăSQLiteăvaă
aveaăoăperforman܊ăămaiămare.ă
 Platformăămultiplă:ăSQLiteăfunc܊ioneazăăpeăLinux, Windows (Win32, WinCE,
WinRT),ă iOS,ă Maxă OSă Xă ܈iă peă alteă sistemeă deă operare.ă Deă asemeneaă
func܊ioneazăă܈iăpeăsistemeleădeăoperareăincorporateăprecumăAndroid,ăSymbian,ă
Oalm, VxWroks.
 Un singur fi܈ier:ă Fiecareă bazăă deă dateă esteă stocatăă înă întregimeă într -un singur
fi܈ieră nativ.ă Abordareaă unuiă singurăfi܈ieră faciliteazăă mutarea/copiereaă bazeiădeă
date dintr-un loc în altul.
 Platformăă încruci܈ata:ă SQLiteă permiteă mutareaă fișierelor între platforme. De
exemplu, se poate crea oăbazăădeădateăpeăunădispozitivă careăruleazăă cuăLinuxă
x86ă ܈iă se poate folosi aceea܈iă bazăă deă dateă (prină copiereaă fi܈ierului)ă peă ună
dispozitivă careă ruleazăă cuă Windows,ă ARMă sauă MACă fărăă căă fi܈ierulă săă fieă
alterat. De asemenea, se poate folosi aceea܈iăbazăădeădateăpeădispozitiveăcuă32 –
bi܊iăsauă64 -bi܊i.ă
 Compatibilitatea cu versiuni anterioare: SQLite 3 este compatibil cu orice
versiuneăcareăvaăapăreaăînăviitor.ăAstaăînseamnăăcăăoriceăbazăădeădateăcrea܊ăăcuă
SQLiteă3ăvaăputeaăfiăfolosităăpeăoăversiuneămaiănouă.ăDarăversiuneaă3ăaălibrărieiă
nu poate fun c܊ionaăcuăoăbazăădeădateăînăversiuneaă2.

2.4. Mediul de dezvoltare Android Studio

AplicaĠiaă CarQuiz aă fostă realizatăă înă Androidă Studio,ă ună mediuă integrată deă
dezvoltare folosită pentruă creareaă aplica܊iiloră laă ună nivelă avansat.ă Androidă Studioă
constituieă fi܈iereleă înă func܊ieă deă celeă maiă importanteă sec܊iuniă aleă aplica܊ieiă Androidă
(java,ăressourcesă܈iăscripturiă“grandle”).ă
AndroidăStudioăareăoăinterfatăăgraficăăpentruă instal are. În aceasta, se stabilesc
setărileă deă bazăă ܈iă seă adaugăă ună emulator.ă Interfa܊a aplica܊ieiă seă poateă vedeaă peă
dimensiuniă܈iărezolu܊iiădiferite.ă

10

Windows OS X Linux
Versiunea SO Microsoft Windows
10/8/7(32- sau 64-bit) Mac OS X 10.8.5 sau
mai mult, pana la
10.11.4 GNOME sau KDE
desktop
RAM 2 GB RAM minim, 8 GB RAM recomandat
Disk space 500 MB pentru Android Studio ܈i cel putin 1.5 GB pentru Android
SDK
Versiunea Java Java Development Kit
(JDK) 8 Java Development Kit
(JDK) 6 Java Development Kit
(JDK) 8
Rezolu ția ecranului 1280×800 minim

Tabelul 1. Cerin ܊e pentru instalarea platformei Android Studio[21]

11
CAPITOLUL 3 – Dezvoltarea aplica Ġiei CarQuiz

Acestă capitolă prezintăă dezvoltareaă aplicaĠieiă CarQuiz ,ă prină ilustrareaă pașiloră
parcurși:ă configurareaă mediuluiă Androidă Studioă șiă aă emulatoruluiă AVDă (Androidă
Virtuală Devices),ă proiectareaă șiă implementareaă bazeiă deă dateă aă aplicaĠiei,ă construireaă
interfeĠeiășiăprogramareaăactivităĠilorăasociateăaplicaĠiei.

3.1. Configurarea mediului de dezvoltare Android Studio

Ună primă pasă înă realizareaă aplicaĠieiă îlă reprezintăă instalareaă șiă configurareaă
mediuluiă deă dezvoltareă aă aplicaĠieiă (IDEă – Integrated Development Environment).
Astfel, programul Android SDK Manager este folosit pentru instalarea componentelor
܈iă pentruă actualizări,ă folosindă c alea Android Studio → Tools → Android → Android
SDK Manager ,ădupăăcumăseăobservăăînăFig.ă1.

Fig. 1. Instalarea și configurarea IDE Android SDK

12
Debugging
În Android Studio debugging- ulă aplicaĠiiloră seă faceă diferită faĠăă deă celelalteă
programe clasice, deoareceăacesteaăruleazăăpeăunăaltădispozitivădecâtăcelăpeăcareăseăfaceă
dezvoltarea. Pentruă aă realizaă depanareaă uneiă aplica܊iiă este nevoie de programe
specializate.ăAvândăînăvedereăcăădezvoltareaăseăfaceăpeăplatf orme mobile, apar anumite
evenimente ce trebuie tratate într-un anumit fel, de exemplu, apelurile mobile sau
descărcareaăbateriei.ăă
Android Debug Bridge seăutilizeazăăpentru interac܊iuneaăcu un dispozitiv creat
printr-un emulator sau cu un dispozitiv real. Calea catre instalare: sdk-path/platform-
tools/adb.exe. DDMS (Dalvik Debug Monitor System)
Tool- ulăcareăesteăintegratăînăAndroidăStudioăpentruădepanareaăuneiăaplica܊iiăesteă
DDMS.ă Acestaă folose܈teă ADB (Android Debug Bridge), tot un plugin, pentru a se
conecta la simulatoare sau dispozitive. Cu ajutorul acestuia, se pot vizualiza parametrii
deăfunc܊ionareăaădispozitivuluiă܈iăaăprogramelorărulate.ăAcestaăajutăălaăafișareaălog -urile
deăpeădispozitivăși a detaliilor despreăproceseleăcurenteă܈iă la controlul simulatoarelor.
ADB este un plugin dinamic, putând oferi informa܊iiăatâtădespreăsimulatoareleăpornite ,
câtă܈iăinforma܊iiădespreădispoziti vele conectate la calculator.
Log- urileădescriuătoateăac܊iunileăpeăcareădispozitivulăleăîndepline܈te,ăexcepĠ iile
apărute , precum ܈iăinforma܊iileănecesareăprocesuluiădeădepanare.ăAcesteaăaparăînăpanoulă
LogCat , care prezintăăceleămaiăimpo rtante informa܊iiăaleăDDMSășiăcareăp oate fi generat
prin functiile statice ale clasei log sauăcuăfunc܊iaă System.out.println() .
A ndroidă Studioă oferăă pos ibilitatea de a filtra mesaje Log, deoarece citirea
anumitorămesajeăpoateăfiădificilă.ăDDMSăpuneălaădispozi܊ieăEmulatorăControlăprinăcareă
se pot simulaă toateăfunc܊iileăunuiă telefonăreal. Se pot simula date primite de la GPS,
primirea SMS-urilor, primirea unui apel telefonic sau starea conexiunii de voce.
Un alt plugin foarte util este hierachyviewer , care permite vizualizarea
compozi܊ieiă ferestreloră într -oă structurăă ierarhică.ă ă Cuă ajutorul lui se pot vizualiza
paramet riiăfiecărui Viewă܈iătimpulădeăîncărcare.ă De asemenea, putemăsăăneăinspirămă din
modulă cumă esteă construităă interfaĠăă grafică aă alteiă aplica܊ii,ă deoareceă putemă analizaă
oriceăfelădeăaplica܊ieăinstalatăăpeădispozitiv.ăă
FișiereleăinstalateăaleăuneiăaplicaĠiiăAndroi d au extensia .apk (application kit).
StructuraăunuiăastfelădeăfișierăesteăceaăprezentatăăînăFig.ă2.

13

Fig. 2. Formatul unui fișier .apk [22]

3.2. Configurarea emulatorului AVD – Android Virtual Device

UrmătorulăpasăînădezvoltareaăaplicaĠieiăîlăconstituieăconfigurareaăunuiăemulatoră
pentru echipamente mobile. Astfel, se poate folosi AVD Manager (Android Virtual
Devices) pentru a crea si controla dispozitivele virtuale, utilizând calea Android Studio
→ Tools → Android → Android Virtual Devices Manager . (Fig. 3)

Fig. 3. Android Virtual Devices Manager

14
În momentul în care seă dorește rulareaă aplica܊iei , trebuie creat un dispozitiv
virtuală peă careă aceastaă săă ruleze.ă Înă Androidă elă seă nume܈teă Androidă Virtua l Device.
AVD (Androidă Virtuală Device)ă reprezintăă ună emulatoră înă careă putemă alegeă
componentele software ܈iăhardwareă(Fig.ă4).

Fig. 4. Configurarea emulatorului AVD

În fereastra în care seă creeazăă e mulatorul, se complet ează numele, targetul,
dimensiun eaă carduluiă SDă ܈iă dimensiuneaă ecranului.ă Ună lucruă importantă esteă bifareaă
căsu܊eiă Snapshot , deoarece se creeazăăunănouăAVD înăcareăseărealizeazăăoăimagineăaă
emulatorului în momentul închiderii, astfel încât la repornire, acestaă săă seă deschidăă
instantaneu (Fig. 5).

15

Fig. 5. Crearea emulatorului

Pentruă aă testaă aplica܊iaă webă realizată , trebuie creat câte un emulator pentru
fiecare dispozitiv, deoareceă dimensiuneaă ecranuluiă diferă.ă Utilizatoriiă trebuieă săă nuă
întâmpineădificultă܊iăatunciăcândădeschidăaplica܊ia.ăAcesteăemulatoareă dau posibilitatea
testăriiăaplica܊iei peăoăgamăădestulădeălargăădeădispozitive.ă
În momentul în care seăconfigurează AVD -ul, nivelul API este foarte important,
deoareceăacestaănuătrebuieăsăăfieămaiămicădecâtăcelăpeăcareăl -am sp ecificat la crearea
proiectului.

16
3.3. Proiectarea șiăimplementarea bazei de date

3.3.1. Diagrama entitate-leg ătură
Bazaădeădateăaăfostăproiectatăăpentruăstocareaădatelorădespreămașini,ăutilizatoriășiă
nivelurileăjoculuiășiăpentruămodelareaărelaĠiilorăd intre acestea.
MulĠimileă entitateă șiă legăturileă dintreă acesteaă suntă reprezentateă înă diagramaă
Entitate- Legătură,ăprezentată în Fig. 6. Seăpoateăobservaăcăăschemaăbazeiădeădateăesteă
constituităă dină mulĠimileă entitateă CARS,ă LEVELSă șiă USER.ă Pentruă fiecareă mulĠimeă
entitate, s- auăprecizatăatributeleă(șiăcheiaăprimară).ă
ÎntreămulĠimileăentitateăexistă următoarele asocieri (legături) :
 LEVELS au CARS (1,1);
 USER rezolva CARS (1, m);
 USER trece LEVELS (1, m);
Legătura <au>ă dintreă mul܊imeaă entitateă L EVELS ܈iă mul܊imeaă entitateă C ARS ,
dină punctă deă vedereă ală gradului,ă esteă oă legăturăă deă tipă binarăă astfelă încâtă leagăă douăă
mul܊imiăentitate,ăiarădinăpunct deăvedereăalăconectivită܊iiăesteăoălegăturăă (1,1) deoarece
unănivelăpoateăsăăcon܊inăăoăsingurăăma܈inăădeăunăanumitătip,ăiarăoăma܈inăăde un anumit
tipănuăpoateăsăăapărăăînămaiămulteăniveluri .
Legătura <rezolvă >ădintreămul܊imeaăentitateăUSERă܈iămul܊imeaăen titate CARS,
dină punctă deă vedereă ală gradului,ă esteă oă legăturăă deă tipă binarăă astfelă încâtă leagăă douăă
mul܊imiăentitate,ăiarădinăpunctădeăvedereăalăconectivită܊iiăesteăoălegăturăă (1,m) deoarece
ună utilizatoră poateă săă rezolveă ună anumită tipă deă ma܈ină,ă iară ună anumită tipă deă ma܈inăă
poateăfiărezolvatăădeămaiămul܊iăutilizatori.ă
Legătura <trece >ădintreămul܊imeaăentitateăUSER ܈iămul܊imeaăentitateăL EVELS ,
dină punctă deă vedereă ală gradului,ă esteă oă legăturăă deă tipă binarăă astfelă încâtă leagăă douăă
mulĠimi entitate, iar din pu nctădeăvedereăalăconectivită܊iiăesteăoălegăturăă (1,m), deoarece
ună utilizatoră poateă treceă ună anumită nivel,ă iară acelă nivelă poateă fiă trecută deă maiă mul܊iă
utilizatori.

17

Fig. 6. Diagrama Entitate- Legătură
CARS
LEVEL
USER
cars_position
s
cars_id
cars_level
cars_current
_
cars_answer
cars_solved
cars_info
cars_wiki
levels_solved
levels_id
levels_locked
levels_points
levels_numbe
r
levels_needed
cars_congrad
user_fbimage
user_solved
user_points
user_hints
user_sound
user_vibration
user_attempts
user_flawless
user_correction
s
user_fbname
user_id
AU

REZOLVA
TREC
E

18
3.3.2. Implementarea bazei de date folosind SQLite
Înăceleăceăurmeazăăesteăprezentatăămodalitateaădeăimplementareăaăbazeiădeădate,ă
cu ajutorul SQLite.
Baza deădateăcon܊ineă3ătabeleășiăanume : CARS, LEVELS, USER.
Tabela CARS cu schema (_id, level, position, answer, current_answer, solved,
căr_info,ăread_more,ăcongrad_message)ăareăcheiaăprimarăăatributul_idăcuăvaloriăuniceă
pentruă fiecareă autoturismă adăugat.ă Pe viitor, pentruă dezvoltareaă aplica܊iei , se pot
schimbaăsauăadă uga în baza de date alte niveluri sau autoturisme. În tabela CARS se
pot verific autoturismele, aflândădespreăacesteaăpozi܊iaăînănivelulăînăcareăseăaflă,ădacăă
autoturismulă aă fostă rezolvată ܈iă toateă informa܊ iile detaliate despre autoturism (de
exemplu,ăanulăconstruc܊iei,ădetaliiădespreămotor,ătipulădeăma܈inăăetc ).
CodulăsursăăpentruăcreareaătabeleiăCARSăesteăurmătorul:

private static final String CREATE_DATABASE_CARS =

"CREATE TABLE IF NOT EXISTS " + TABLE_CARS + "(" +
COLUMN_CARS_ID + " INTEGER PRIMARY KEY," +
COLUMN_CARS_LEVEL + " INTEGER," +
COLUMN_CARS_POSITION + " INTEGER," +
COLUMN_CARS_ANSWER + " TEXT," + z
COLUMN_CARS_CURRENT_ANSWER + " TEXT," +
COLUMN_CARS_SOLVED + " INTEGER DEFAULT 0," +
COLUMN_CARS_INFO + " TEXT," +
COLUMN_CARS_WIKI + " TEXT," +
COLUMN_CARS_CONGRAD + " TEXT" + ")";

Fig. 6 prezintăătabelaăCARSăpopulatăăcuăînregistrări.
Fig. 6. Tabela CARS

19
Tabela LEVELS cu schema (_id, number, solved, locked, points,
car_to_unlock)ă areă cheiaă primarăă atributulă _idă cuă valoriă uniceă pentruă fiecareă nivelă ală
aplica܊iei.ă Înă aceastăă tabelăă suntă prezentateă numărulă nivelului,ă dacăă nivelulă aă fostă
rezolvată sauă nu,ă punctajulă peă fiecareă nivelă ܈iă numărulă deă autoturismeă deă careă esteă
nevoie pentru deblo careaăurmătoruluiănivel.
CodulăsursăăpentruăcreareaătabeleiăLEVELSăesteăurmătorul:

private static final String CREATE_DATABASE_LEVELS =

"CREATE TABLE IF NOT EXISTS " + TABLE_LEVELS + "(" +
COLUMN_LEVELS_ID + " INTEGER PRIMARY KEY," +
COLUMN_LEVELS_NUMBER + " INTEGER," +
COLUMN_LEVELS_SOLVED + " INTEGER," +
COLUMN_LEVELS_LOCKED + " INTEGER DEFAULT 1," +
COLUMN_LEVELS_POINTS + " INTEGER DEFAULT 0," +
COLUMN_LEVELS_NEEDED + " INTEGER " + ")";

Fig.ă7ăprezintăătabelaăLEVELSăpopulatăăcuăînregistră ri.

Fig.7. Tabela LEVELS

Tabela USER cu schema (_id, solved, points, user_points, hints_left, sound,
vibration, attempts, corrections, fb_name, fb_image) are drept cheieăprimarăăatributulă
_idă cuă valoriă uniceă pentruă fiecareă utilizatoră ală aplica܊iei.ă Înă aceastăă tabelăă seă
înregistreazăă quiz -urileă rezolvateă deă user,ă punctajulă utilizatorului,ă indiciileă rămase,ă
setărileă peă careă acestaă leă salvează,ă numărulă deă încercăriă pentruă rezolvareaă unuiă quiz,ă
numărulăquiz -urilorărezolvateădinăprima(flawless),ănumărulădeăcorectăriă܈iădateleădeăpeă
Facebook, nu meleă܈iăpozaădeăprofil.ă

20
CodulăsursăăpentruăcreareaătabeleiăUSERăesteăurmătorul:

private static final String CREATE_DATABASE_USER =

"CREATE TABLE IF NOT EXISTS " + TABLE_USER + "(" +
COLUMN_USER_ID + " INTEGER PRIMARY KEY," +
COLUMN_USER_SOLVED + " INTEGER DEFAULT 0," +
COLUMN_USER_POINTS + " INTEGER DEFAULT 0," +
COLUMN_USER_HINTS + " INTEGER DEFAULT 0," +
COLUMN_USER_SOUND + " INTEGER DEFAULT 1," +
COLUMN_USER_VIBRATION + " INTEGER DEFAULT 1," +
COLUMN_USER_ATTEMPTS + " INTEGER DEFAULT 0," +
COLUMN_USER_FLAWLESS + " INTEGER DEFAULT 0," +
COLUMN_USER_CORRECTIONS + " INTEGER DEFAULT 0," +
COLUMN_USER_FBNAME + " TEXT," +
COLUMN_USER_FBIMAGE + " TEXT" + ")";

Tabela USER este cea din Fig. 8.

Fig. 8. Tabela USER

Fișierul DataBaseHelper reprezintăăopenhelper -ul aplica ܊iei.
 Clasa SQLiteOpenHelper
SQLiteOpenHelper are rolul de a crea ܈iăactualiza bazele de date, precum ܈iăversiunile
acestora.ăFolose܈ te evenimente precum:
-onCreate()- pentruăaăcreaăoănouăăbază de date;
-onUpdate – pentru a face upgrade la aplica ܊ie;
Prin intermediul clasei SQLiteOpenHelper putem ob ܊ine instan ܊a unei baze de
date cu ajutorul constructorului ܈i a metodei getWritableDatabase().
Versiun eaă bazeiă deă dateă joacă ună rolă important,ă aceastaă trebuieă incrementată
pentruăfiecareămodificareăadusă, deoarece nu dorim sa p ierdem datele, deci opera ܊iile
trebuieăfăcuteăăcuămareăaten܊ ie.

package carquiz.newbies.pro.database;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import carquiz.newbies.pro.carquiz.BuildConfig;

21
public class DataBaseHelper extends SQLiteOpenHelper{
private static String DB_PATH = "/data/data/carquiz.newbies.pro.carquiz/databases/" ;
private static String DB_NAME = "cars_quiz.db" ;
private final Context myContext ;
public DataBaseHelper(Context context) {
super (context, DB_NAME , null, 2);
this.myContext = context;
}
public void createDataBase() throws IOException{
boolean dbExist = checkDataBase();
if(dbExist){
}else{
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new Error( "Error copying database" );
}
}
}
private boolean checkDataBase(){
SQLiteDatabase checkDB = null;
try{
String myPath = DB_PATH + DB_NAME ;
checkDB = SQLiteDatabase. openDatabase (myPath, null, SQLiteDatabase. OPEN_READONLY );
} catch (SQLiteException e){
}
if(checkDB != null){
checkDB.close();
} return checkDB != null ? true : false ;
}
private void copyDataBase() throws IOException{
InputStream myInput = myContext .getAssets().open( DB_NAME );
String outFileName = DB_PATH + DB_NAME ;
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte [1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException{
String myPath = DB_PATH + DB_NAME ;
MyApplication. database = SQLiteDatabase. openDatabase (myPath, null, SQLiteDatabase. OPEN_READONLY );
}
@Override
public synchronized void close() {
if(MyApplication. database != null)
MyApplication. database .close();
super .close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Overri de
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
@Override
protected void finalize() throws Throwable {
this.close();
super .finalize();
}
}

22
Fi܈ierul MyAplication reprezintăăclasaăCursorăaăaplica܊ iei.
 Clasa Cursor
Aceastaă esteă folosită pentruă aă captaă rezultatulă interogă rilor. O interogare
returnează un obi ectădeătipăCursorăcareăpointează catre o linie din interogare.
Parcurgereaăacestuiaăseăfaceăcuăurmătoareleăfunc܊ ii :
– moveToNext();
– moveToPrevious();
– moveToFirst();
– moveToLast().
Determinarea pozi ܊iei se face cu ajutorul func ܊iilor:
– isFirst(), isLast();
– isBeforeFirst(), isBeforeLast().
Extragerea valorilor:
– getTIP(): getInt(), getString(), getFloat() etc. ;
– parametru: indexul coloanei.
Pentru ob ܊inereaănumaruluiădeăînregistrăriăseăfolose܈ te func ܊ia getCount().
Pentru ob ܊inerea coloanei se folose ܈te func ܊ia getColumnIndex().

3.4.ăDescriereaăaplicaĠ iei CarQuiz

Realizareaăefectivăăaăquiz -ului începe cu crearea în Android Studio a unui nou
proiect: File>New>New Project (Fig. 9) ,ăselectareaăechipamentelorăpeăcareăaplicaĠiaăvaă
rulaă(inclusiveăversiuneaădeăAndroid)ă(Fig.ă10)ășiăprogramareaăactivităĠiloră(Fig.ă11).

23

Fig. 9. Crearea unui nou proiect Android Studio

Fig. 10. Selectarea echipamentelor pe care aplicația va rula

24

Fig. 11. Programarea activităților

3.4.1. Implementarea aplica Ġiei

Într-oă aplicaĠieă Android,ă fișiereleă suntă constituiteă înă func܊ieă deă celeă maiă
importanteăsec܊iuniăaleăaplica܊ieiă(java,ăressourcesă܈iăscripturiă“grandle”)ă(Fig.ă12).

Fig. 12. Secțiunile aplicației Android

25

În directorul manifests seăaflăăfi܈ierulă AndroidManifest.xml ,ăfi܈ierădeătipăXMLă
care con܊ineăinforma܊iiădetaliateăaleăaplica܊ieiăpeăcareăleăprezintăăsistemulu i de operare
înainteăcăăacestaăsăărul eze aplica܊ia.ă
AndroidManifest.xml define܈teă pachetulă Javaă corespunzătoră aplica܊ieiă create ,
descrieă componenteleă aplicaĠieiă șiă numeșteă toateă claseleă careă implementeazăă aceste
componente .ăComponenteleăuneiăaplicaĠiiăsu nt:
 Activitățiă(Activity)
Fiecare ecran sau fereastr ă peăcareăutilizatorulăîlăvedeăreprezintăăoăactivitate,ăaiciă
avemă creatăă câteă oă interfa܊ăă pentruă fiecareă meniuă ală aplica܊iei . Acesteă activită܊iă suntă
independente,ăeleăreprezintăăoăsubclasăăaăclaseiăActivity.ă
 Serivicii (Service)
Acesteaăsuntăcomponenteleăcareălucreazăăînăfundalăpentruăaăinterac܊ionaăcuăalteă
proce seă sauă pentruă desfă܈urarea uneiă ac܊iuniă maiă îndelungateă fărăă căă utilizatorulă săă
ac܊ioneze.ăă
 Furnizorii de co nĠinut (Content Providers)
Ajutăăaplica܊iaă laăgestionareaăoricărorătipuriă deădateăindiferentă căăsuntă publiceă
sauăprivate.ăAcestaăpoateăfiăapelatădeăalteăaplica܊iiăpentruăfurnizareaădeădateădacăăesteă
dorit acest lucru. Implementarea unui furnizor de date reprezintăă oă subclasăă aă claseiă
ContentProvider.
 Receptori de broadcast (Broadcast receivers)
Ună receptoră capteazăă ܈iă răspundeă laă anunturileă deă interesă dină sistem,ă deă
exemplu: când bateria este pe cale de a se termin a.ă Ace܈tiaă nuă auă oă interfa܊ăă pentruă
utilizatori dar pot semnala compontele ale ap lica܊ieiă܈iăpotădaănotificări.ă
Înă acestaă suntă declarateă permisiunileă peă careă aplica܊iaă trebuieă săă leă con܊inăă
pentruă aă func܊ionaă ܈iă interac܊ionaă cuă por܊iuniă protejateă aleă API -ului (Application
Programming Interface). De asemenea,ăseăgăsescă܈iădeclaraĠiileăcareăoferăăposibilitateaă
aplica܊ieiăsăăfoloseascăăcomponenteleăaplica܊ieiăcurente.ăPermisiunileăsuntărestric܊iiăcareă
limiteazăăaccesulălaăoăanumităăpor܊iuneădinăcodăsauălaădateădeăpeămobilă܈iăaceastaăseă
diferen܊iazăăprintr -un text unic.

26
ConĠinutulă fișieruluiă AndroidManifest.xml pentruă aplicaĠiaă CarQuiz este
următorul:
<?xml version="1.0" encoding="utf -8"?>
<manifest package="carquiz.newbies.pro.carquiz"
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="2"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="21" />

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET "/>

<application
android:name="carquiz.newbies.pro.database.MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >

<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id" />

<activity
android:name=".QuizActivity"
android:label="@string/app_name"
android:screenOrientation="portrait" />
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait" >
</ activity >
<activity
android:name=".QuizSelectActivity"
android:label="@string/title_activity_level_grid_view"
android:screenOrientation="portrait" />
<activity
android:name=".SelectLevelActivity"
android:label="@string/title_activity_quiz_activ"
android:screenOrientation="portrait" />
<activity
android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation" />
<provider
android:name="com.facebook.FacebookContentProvider"
android:authorities="com.facebook.app.FacebookContentProvider447973458739805"
android:exported="true" />
<service
android:name="carquiz.newbies.pro.service.PlayAudio"
android:enabled="true" />
<activity android:name=".SettingsActivity" />
<activity android:name=".ProgressActivity" />
<activity android:name=".NewMainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</ intent-filter>
</ activity >
</application >

</manifest >

27
În directorul java/carquiz.newbies.pro/adapters seă găsescă listele,ă care se
implementeazăăfolosindă MVC (Model View Controller). Acesta areăcaăfuncĠionalitateă
gestiunea datelor ,ă răspunde rea laă interogăriă ܈iă realizareaă opera܊iilor de modificare a
datelor. View-ul redă prinăintermediulăinterfe܊eiăunămodelăcareăpermiteăinterac܊iuneaăcuă
utilizatorul. Controller-ul cont roleazăămodulădeăafi܈areă܈iărăspundeăinterogând modelul
(Fig. 13).

Fig. 13. MVC (Model View Controller) [23]

MVCă reprezintăă ună modelă arhitecturală careă separăă interfa܊aă graficăă deă
func܊ionalitateaă specificăă aă sistemuluiă permi܊ândă astfelă dezvoltarea,ă între܊inereaă ܈iă
testarea acestuia.
Un ListView esteă reprezentată deă oă listă deă elemente,ă careă poateă fiă parcursăă ܈iă
poateăfiăplasatăăpeăoriceătipădeăactivitate.ă
În directorul java/carquiz.newbies.pro/adapters seăgăsescăurmătoareleăclase:
– GridViewAdapter;
– Helper;
– LevelItem;

28
– LevelSelectAdapter;
– QuizItem;
– User.
În cazul în care se select ează ună nivelă ală aplica܊iei,ă cuă ajutorulă claseiă
GridViewAdapter sunt afi܈ate quiz-urile într- oălistăădeătipulăGrid.ăTotăaiciăseăverificăă
dacăăquiz -ul a fost rezolvat sau nu, iar dacăăacestaăaăfostă rezolvatăvaăapăreaăcaăfiindă
rezolvat ,ăașaăcumăseăvedeăînăelementeleădeăinterfaĠăădinăFig.ă14.

Fig. 14. Elemente de interfață: quiz nerezolvat, quiz rezolvat
Esteăprezentatăăînăcontinuareăclasaă GridViewAdapter :
public class GridViewAdapter extends ArrayAdapter {
private Context context ;
private int layoutResourceId ;
private ArrayList<QuizItem> data = new ArrayList<QuizItem>();
public static TypedArray cars_drawables ;
public GridViewAdapter(Context context, int layoutResourceId, ArrayList<QuizItem> data) {
super (context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
switch (data.get(0).getLevel()){
case 1:
cars_drawables = context.getResources().obtainTypedArray(R.array. level_one );
break ;
case 2:
cars_drawables = context.getResources().obtainTypedArray(R.array. level_two );
break ;
case 3:
cars_drawables = context.getResources().obtainTypedArray(R.array. level_three );
break ;
case 4:
cars_drawables = context.getResources().obtainTypedArray(R.array. level_four );
break ;
case 5:
cars_drawables = context.getResources().obtainTypedArray(R.array. level_five );
break ;
case 6:
cars_drawables = context.getResources().obtainTypedArray(R.array. level_six );
break ;
case 7:
cars_drawables = context.getResources().obtainTypedArray(R.array. level_seven );
break ;
case 8:
cars_drawables = context.getResources().obtainTypedArray(R.array. level_eight );
break ;
case 9:
cars_drawables = context.getResources().obtainTypedArray(R.array. level_nine );
break ;
case 10:
cars_drawables = context.getResources().obtainTypedArray(R.array. level_ten );
break ;
}
}

29
@Override
public View getView( final int position, View convertView, ViewGroup parent) {
View row = convertView;
ViewHolder holder = null;
if (row == null) {
LayoutInflater inflater = ((Activity) context ).getLayoutInflater();
row = inflater.inflate( layoutResourceId , parent, false );
holder = new ViewHolder();
holder. image = (ImageView) row.findViewById(R.id. iv_quiz_item_image );
holder. tint = (ImageView) row.findViewById(R.id. iv_tint_quiz );
holder. check = (ImageView) row.findViewById(R.id. iv_checked_quiz );
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}
final QuizItem item = data.get(position);
Drawable car_image = context .getResources().getDrawable( cars_drawables .getResourceId(position, -1));
holder. image .setImageDrawable(car_image);
if (item.getSolved() == 1) {
holder. tint.setVisibility(View. VISIBLE );
holder. check .setVisibility(View. VISIBLE );
} else {
holder. tint.setVisibility(View. INVISIBLE );
holder. check .setVisibility(View. INVISIBLE );
}
return row;
}
static class ViewHolder {
ImageView image , tint, check ;
}
}

Helper reprezintăă fi܈ierulă careă v a reda un sunet atunci când un quiz este
rezolvat.ă Acestă fi܈ieră nuă esteă folosită încă,ă fiind oă op܊iuneă careă a܈ă doriă săă oă adaugă peă
viitor.
Înăfi܈ierele LevelItem, QuizItem ܈iăUser suntăini܊ial izate datele din baza de date.
Fi܈ierulă LevelSelectAdapter reprezintăăunăadaptorăpentruăcolec܊iaădeăniveluri ale
aplica܊iei.ăAcestaăneăafi܈eazăănivelurile înăfunc܊ieădeărezultateleărezolvăr ii quiz-urilor de
cătreăuser.ăÎnăcazulăînăcareăunănivelăesteăblocat , vaăafi܈aănumărulăniveluluiă܈iănumărulă
de autoturisme nece sarădeblocăriiăacestuia (Fig.15).

Fig. 15. Nivel blocat

În cazul în care un nivel este deblocat, acestaă vaă afi܈aă numărulă nivelului,ă
numărulădeăautoturismeărezolvate,ăpunctajulăpentruăacelănivel,ăbaraădeăprogr es al acelui
nivelă܈iăbutonulă GO care permite intrarea în nivelul respetiv (Fig.16).

30

Fig. 16. Nivel deblocat

Esteăprezentatăăînăcontinuareăclasaă LevelSelectAdapter:
public class LevelSelectAdapter extends ArrayAdapter {
private ArrayList<LevelItem> mData = new ArrayList<LevelItem>();
private LayoutInflater mInflater ;
private Context context;
private String [] lvl_bkgs = new String[] { "aspid_gt" , "clubsportquattro" , "bmw_conc" ,
"concept_a" , "concept -rear"
, "bmw_conc" , "concept_a" , "concept -rear", "bmw_conc" , "concept_a" , "concept –
rear"};
private int solvedByNow = 0;
private TypedArray levels_backs ;
private User user;
private MyApplication mInstance ;
public LevelSelectAdapter(Context context, int ResourceId, ArrayList<LevelItem> levels,
int quiz_solved) {
super(context, ResourceId, levels);
this.context = context;
mInstance = (MyApplication)context.getApplicationContext();
mInflater = (LayoutInflater) context
.getSystemService(Context. LAYOUT_INFLATER_SERVICE );
mData = levels;
user = mInstance .getUser();
levels_backs = context.getResources().obtainTypedArray(R.array. levels_backs );
solvedByNow = quiz_solved;
for(int i = 0; i < mData.size(); i++)
{
if(mData.get(i).isLocked() && ( user.getQuiz_solved() >
mData.get(i).getNeeded())) {
mInstance .UpdateLevel( mData.get(i).getId(),
LocalDatabase. COLUMN_LEVELS_LOCKED , 0);
}
}
Log. e("test","Levels lenght " + mData.size());
}
@Override
public int getCount() {
return mData .size();
}
@Override
public long getItemId( int position) {
return position;
}

@Override
public View getView( final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
final LevelItem level = mData.get(position);
holder = new ViewHolder();
if(level.isLocked())
{
convertView = mInflater .inflate(R.layout. level_locked_item , null);
holder. level = (TextView)
convertView.findViewById(R.id. tv_level_number_locked );
holder. guess_more = (TextView)
convertView.findViewById(R.id. tv_guess_text_locked );
holder. locked_level = (ImageView)
convertView.findViewById(R.id. iv_locked_level );
} else
{

31
convertView = mInflater .inflate(R.layout. level_item , null);
holder. level = (TextView) convertView.findViewById(R.id. tv_level_number );
holder. points_level = (TextView)
convertView.findViewById(R.id. tv_points_per_level );
holder. cars_solved = (TextView) convertView.findViewById(R.id. tv_cars_solved );
holder. progress = (ProgressBar)
convertView.findViewById(R.id. pb_level_progress );
holder. start_level = (Button) convertView.findViewById(R.id. btn_start_level );
holder. level_background = (ImageView)
convertView.findViewById(R.id. iv_level_background );
}
convertView.setTag(holder);
if(level.isLocked())
{
holder. level.setText ("Level " + level.getNumber());
holder. guess_more .setText( "Guess " + (level.getNeeded() – solvedByNow ) + " more
cars to unlock" );
} else
{
holder. level.setText( "Level " + level.getNumber());
holder. cars_solved .setText( "Points: " + level.getPoints());
holder. progress .setProgress(Integer. valueOf(level.getTotal_solved()));
holder. points_level .setText( "Cars: " + level.getTotal_solved() + " / 14");
Drawable car_image =
context.getResources().getDrawable( levels_backs .getResourceId(position, -1));
Bitmap bitmap = ((BitmapDrawable)car_image).getBitmap();
Bitmap level_bmp = Utils. getRoundedCornerBitmap (bitmap, 25);
holder. level_background .setImageBitmap(level_bmp);
holder.start_level .setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto -generated method stub
MyApplication myapp = (MyApplication) context.getApplicationContext();
myapp.setTemp_level( mData.get(position));
Intent intent = new Intent(context, QuizSelectActivity. class);
intent.putExtra( "level_number" , "" + level.getNumber());
Bundle bundle = ActivityOptionsCompat. makeCustomAnimation (getContext(),
android.R.anim. fade_in, android.R.anim. fade_out ).toBundle();
context.startActivity(intent, bundle);
}
});
}
return convertView;
}
public class ViewHolder {
public TextView level, points_level , cars_solved , guess_more ;
public ProgressBar progress ;
public Button start_level ;
public ImageView locked_level , level_background ;
}
@Override
public Object getItem( int position) {
// TODO Auto -generated method stub
return null ;
}

}

32
Directorul carquiz con܊ineătoateăactivită܊ileăaplica܊ieiă܈iăanume:ă
 LoginActivity – r eprezintăăclasaăcuălayout -ul activity_login.xml înăcareăesteăafi܈ată
mesajulă“HelloăWorld!”.ăAceastaăaăfostăcreatăăpentruătestă (Fig.17).

Fig.17. Interfa ța testului “Hello World”
 NewMainActivity – reprezintăă activitateaă principalăă aă aplica܊ieiă dină careă r eies
celelateăinterfe܊e,ăareăcaălayoutăfi܈ierulă main_activity_layout.xml (Fig.18).

Fig. 18. Interfața principală a aplicației

 ProgressActivity – r eprezintăăactivitateaăînăcareăseăcalculeazăă܈iăseăafi܈eazăăquiz –
urile rezolvate ,ă punctajul,ă încercărileă gre܈iteă ܈iă quiz -urile rezolvate din prima
încercare; este reprezentat de layout-ul activity_progress.xml (Fig.19).

33

Fig.19. Statistici

 QuizActivity – reprezintăăactivitateaăînăcareăutilizatorulăintroduceărăspunsulăquiz –
ului,ădupăăcareăseăverificăădacăărăspunsulăesteăcorect.ăAiciăseăgăsescăurmătoareleă
func܊ii:ă
-func܊iaă useBombHint() oferăăutilizatoruluiăposibilitateaădeăa -܈iădaăseamaăcareă
esteă răspunsulă corectă prină arăta rea literelor amestecate din care se compune
răspunsulăcorect;ă
-func܊iaă useAutoCompletHint() oferăă posibilitateaă utilizatoruluiă deă aă completaă
răspunsulăquiz -ului pentru 25 de puncte;
-func܊iaă useLetterShowHint() oferăăposibilitateaăutilizatoruluiădeăaăscrieăoăliterăă
dinărăspunsulăcorec t al quiz-ului pentru 5 puncte
InterfaĠaăcorespunzătoareăacesteiăactivităĠiăesteăprezentatăăînăFig.ă20.

34

Fig. 20. Interfa ța unui quiz

 QuizSelectActivity – reprezintăă activitateaă înă careă suntă afi܈ateă q uiz-urile
aplica܊ieiă܈iăareă2ălayout -uri activity_quiz_select.xml pentruăafi܈areăin tr-oălistăădeă
tipulăgridă܈iă grid_item_layout.xml pentruămodulădeăafi܈areăaăquiz -ului rezolvat
(Fig. 21).

Fig. 21. Interfa ța select ării quiz-urilor

35
 SelectLevelActivity – reprezintăăactivitateaăînăcareăsuntăafi܈ateănivelurile aplica܊ieiă
într-oă listă ܈iă areă 2ă layout -uri: level_select.xml ܈iălevel_item.xml pentru
nivelurile deblocate (Fig.22).

Fig. 22. Interfa ța select ării nivelurilor
 SettingsActivity – reprezintăă activitateaă înă careă suntă declarateă setărileă pentruă
sunetă܈iăvibra܊ii,ăareăcaălayoută activity_settings.xml (Fig.23).

Fig. 23. Interfa ța setărilor

Pentru de finireaăuneiănoiăactivită܊iăseăcreeazăăoăclasăănouăăcareăextin de Activity
܈iăunălayoutăpe ntru aceasta, folosind calea File>New>Activity>Blank Activity ,ădupă

36
cum se observ ăăînăFig. 24.

Fig. 24. Crearea unei noi activități
 Activity name – clasaăjavaăcorespunzătoareăactivită܊ii ;
 Layout name – fi܈ierulă xml ce corespunde layout- uluiă activită܊ii (interfa܊aă
grafică) ;
 Title – textulăafi܈atăînăbaraădeăsusăaă aplica܊iei( ActionBar );
 Menu Ressource name – fi܈ierulăxmlăcorespunzătorămeniuluiăaplica܊iei .

Dupăăcreareaăuneiăactivită܊iăaceastaăseădeclarăăînăfi܈ierulă AndroidManifest.xml șiă
seăadaugăăc a unănouăelementăînăfi܈ierulă /res/values/strings.xml .ăDupăă aceasta, se
creeazăăoănouăăclasăăJava,ăfolosindăcaleaă File>New >Java Class (Fig.25).

Fig. 25. Crearea unei noi clase

37

Este creat apoi layout-ul pentru noua activitate, folosind calea File > New >
XML > Layout XML File (Fig.26).

Fig.26. Crearea unui fișier layout XML

În directorul database seă găse܈teă declara܊iaă bazeiă deă dateă locale prezentatăă înă
subcapitolul 3.3.2. Aici seă găsescă clasele DatabaseHelper , LocalDatabase ܈iă
MyApplication .
În folder-ul assets seă găsescă resurseă careă seă folosescă doară înă anumiteă
circumstan܊e.ă Înă elă seă găse܈teă baz a de date cars_quiz.db ܈iă alteă 2ă foldere,ă
“database_copy ”ăcareă con܊in o copie a bazei de date. In directorul keyboard seăaflăă
imaginile cuăfiecareăcifrăă܈iăliterăăînăparte,ădeoareceăamădorităcaătastaturaăsăăaibăăunăstilă
specific (Fig.27).
.
Fig. 27. Exemple de litere și cifre pentru tastatură

38
În directorul res seăgăsesc resurse leăaplica܊iei.ăAcesteaăcon܊inăimaginiă܈iăfi܈iereă
de tipul .xml, ca de exemplu:
 în directorul anim se gase ܈teăanimaĠiaă“shake” (agită)ăcareăseăfoloseșteăatunciă
cândăutilizatorulăgreșesteărăspunsulăunuiăquiz;
 în directorul drawable se găsesc:
– toate imaginile cu autoturisme leădinăaplicaĠie,ăacesteăimagini fiind de tipul:
.png, .jpg, .gif;
– fi܈iereădeătipul:ă.xmlă(seădefinescăculorileăsauăformele) ;
 în directorul layout seăgăsesc:
– fi܈iereădeătipulă.xmlăceădefinescăinterfaĠaăgraficăăș i poziĠionareaăelementeloră
pe ecran;
 în directorul menu seăgăsesc:
-fi܈iereădeă tip .xml (putem edita m eniulăuneiăaplicaĠ ii);
 în directorul mipmap seăgăseșteăinconiĠaăaplicaĠieiăpeămaiămulteădimensiuni;
 în directorul values seăpersonalizeazăăelementeleăaplica܊iei ;
 în directorul grandle scripts se pr obeazăă caă elementeleă necesareă să fie
disponibile.

3.4.2. Testarea aplicatiei

Interfa܊ăăprincipalăăesteăsimplăă܈iău܈orădeăutilizat.ăAiciăputemăgăsiăbutonulă Start ,
butonul Settings ܈iăbutonulă Statistics .ăAmăata܈atăintefeĠeiăoăimagineăsimplă , reprezentatăă
deăoăma܈ină.ăÎnăparteaăsuperioarăăse aflăălogo -ulăaplica܊iei , iar în partea inferi oarăăseă
aflăăbutoanele,ăașaăcumăseăobservăăînăFig.ă28.ăAplica܊iaăbeneficiazăă܈iădeăposibilitateaă
de a ne conecta la Facebook, oferind feedback.

39

Fig. 28. Interfata principala

Accesând butonul Start putem vizualiza nivelurile jocului, numerotateăcrescătoră
܈iăcuăoădificultateă crescând peămăsură.ăPentruădeblocareaănivelurilor trebuieăsăăghice܈tiă
unănumărădeăma܈ini.ăÎnăFig.ă29 putemăobservaăcăălaăfiecareănivelădeblocatăsuntăafi܈ateă
punctajulăcurentă܈iănumărulădeăquiz -uri rezolvate din acel nivel. La fiecare nivel blocat
suntem inform aĠi de câte quiz- uriămaiăavemănevoieăsăărezolvăm.ăÎnăparteaăinferioarăăaă
ferestreiă amă adăugată oă parteă pentruă reclameă google , care pot aduce un profit mic pe
contul de adsens.

Fig. 29. Nivelurile jocului

40
Dupăăceăamăalesăunăautoturismăavemăposibilitateaădeăaăscrieădinamicănumeleă܈iă
modelul autoturismului ,ăfolosindăinterfaĠaădinăFig.ă30.ăAplica܊iaăoferăăposibilitateaăde a
܈tergeăoăliterăădândăunăsingurăclickăpeăaceastaăoriăînăspa܊iulăalbădeăpeălângăărăspuns.
Putem modifica quiz-ul curent dinamic printr- ună “swipe”ă deă laă stângaă spreă
dreaptăăapărândăurmătorulăquizădeărezolvat.ăTotăînăfereastraăînăcareăseădăărăspunsulălaă
quiz-ul cu rent,ăavemă5ăiconi܊eă܈iăanume:ăă
 Butonulădeăinforma܊iiă – esteăactivăatunciăcândăutilizatorulăghice܈teă
răspunsul;ă
 Butonulăbombăăcareăîncearcăăsăăajuteăutilizatorulăarătându -i o serie
deălitereăaleatoareădinăcareăseăcompuneărăspunsul,ăbineîntelesăcontraăcost,ă
aceastaănecesităă15ăpuncteăpentruăaăoăfolosi;ă
 Butonul creion – scrieă oă literăă dină răspuns,ă aceastaă necesităă 5
puncte;
 Butonulă ochiă oferăă posibilit atea utilizatorului de a rezolva direct
quiz-ul curent pentru 25 de puncte;
 Butonul Facebook pentru conectare la Facebook.

Fig. 30. Interfața pentru un quiz

41
Dupăăghicireaărăspunsuluiăcorect,ăvaăapăreaăoăfereastrăăcuăunămesajădeăfelicitareă
utilizatorul primind 5ăpuncteă܈iăoăserieăscurtăădeăcaracteristiciăinforma܊ionaleăreferitoareă
la autoturismul din quiz- ulă curent.ă Acesteă informa܊iiă provină deă peă Wiki pedia, iar la
sfâr܈itulă informaĠ iilor, utilizatorul are posibilitatea de a citi mai multe detalii despre
autoturism direct pe Wikipedia (Fig. 31).

Fig. 31. Quiz rezolvat

În se tărileăaplica܊ieiăputemămodificaăvibraĠiileă܈iăsunetulă (Fig. 32).

Fig. 32. Setările aplicației

42
Pentru vizualizarea statisticilor, accesămă butonulă Statistics . Aici putem vedea
Logo- urileă rezolvate,ă punctajul,ă încercărileă e܈uateă ܈iă logo -urile rezolvate din prima
încercare (flawless) (Fig. 33).

Fig. 33. Statistici

3.4.3. Compara ție cu o aplica ție similar ă

Amărealizatăoăcompara܊ie întreădouăăaplica܊iiădeătipă„Quiz” șiăanume:ăCarQuiz
(aplica܊iaă creatăă șiă prezentatăă înă aceastăă lucrare)ă ܈i aplicaĠia LogosQuiz,ă oă aplica܊ieă
găsităăînăMarket [20], pentru a observa atât avantajele, câtă܈iădezavantajeleă fiecăreia .

InterfaĠaă principal
În Fig.ă34ăputemăobservaăcăăinterfa܊a aplica܊ iei CarQuiz (stânga) este mult mai
descriptivăă decât în jocul LogosQuiz (dreapta).

43

Fig. 34. Comparație pentru interfața principală
(CarQuiz – în stânga, LogosQuiz [20] – în dreapta)

InterfaĠaăcuănivelurileăjocu lui

În ceea ce prive șteănivelurileăjocului,ăseăpotăfaceăurmătoareleăremarci:
– înă interfaĠaă aplicaĠieiă CarQuiză suntă prezentateă numărulă deă quiz -uri
rezolvateășiăpunctajulăobĠinut.ăLaă nivelurile blocate,ăsuntemăinformaĠiădeă
numărulădeăautoturismeănecesareădeblocăriiăniveluluiărespective;
– înăaplicaĠiaăLogosQuizăbeneficiileădescriseăanteriorănuăsuntăprezente;
– înăaplicatiaăCarQuizănuăavemăposibilitateaădeblocăriiăunuiănivelăcuăbani,ă
cum este cazul a plicaĠieiăLogosQuiz.

ÎnăFig.ă35ăesteăprezentatăăinterfaĠaăfiecăreiăaplicaĠii,ăpentruănivelurileăjocului.

44

Fig. 35 . Comparație pentru interfața cu nivelurile jocului
(CarQuiz – în stânga, LogosQuiz [20] – în dreapta)

Modul de selectare a unui quiz
AplicaĠiaăCarQuizăseăridicăălaăstandardeleăaltorăaplicaĠiiădeătipăquizădisponibileă
peăpiaĠă,ădeoareceămodulădeăselectareăaăunuiăquizăesteăasemănătoră(Fig.ă36).

Fig. 36 . Comparație pentru modul de selectare a unui quiz
(CarQuiz – în stânga, LogosQuiz [20] – în dreapta)

45
InformaĠiiăsuplimentare
Un avantaj important ală aplica܊iei CarQuiz este acela căă înă momentulă găsiriiă
răspunsuluiă corect,ă putem afla informa܊iiă despre ma܈in a respectivă.ă AplicaĠiaă
LogosQuizănuădispuneădeăaceastăăfacilitateă(Fig.ă37).
Chiar ma i multă deă atât,ă înă aplicaĠiaă CarQuiz,ă printr -ună butonă „Readă more”ă
suntemăredirec܊iona܊iăcătre Wikipedia pentru o documentare maiăamănun܊ităă(Fig.ă38).

Fig. 37. Informații suplimentare
(CarQuiz – în stânga, LogosQuiz [20] – în dreapta)

Fig. 38. Redirecționare către Wikipedia [18]

46
Interfa Ġaăjoculuiăpentruăunărăspunsăgreșit
Înă cazulă înă careă răspunsulă esteă gre܈it,ă ambeleă aplica܊ii seă comportă asemănătoră
(Fig. 39).

Fig. 39. Răspuns greșit
(CarQuiz – în stânga, LogosQuiz [20] – în dreapta)

StatisticiășiăSetări
În aplica܊iaăCarQuizăputemăurmări statisticileă܈iăputemăsetaăsunetulă܈iăvibra܊iile,ă
înăschimbăînăaplica܊iaăLogosQuizănuăavemăacesteăop܊iuniă(Fig.40).

Fig. 40. Opțiuni de statistici și setări, în aplicația CarQuiz

47
CAPITOLUL 4 – CONCLUZII

Obiectivul în aceast ă lucrare deă licen܊ăă aă fostă realizareaă uneiă aplica܊ii
pentru platforma Android, utilizând mediul de dezvoltare Android Studio. În
prezent, majoritatea aplica Ġiilor Android sunt construite pe Android Studio sau
Eclipse.ăAplicaĠiaărealizatăăesteăunaădeătipăquizășiă aăfostăconceputăăpentruăaăfiă
dată înă folosin܊ăă tuturoră persoaneloră peă Googleă Play,ă magazinulă onlineă ală
Android-ului [24].
În urma documentăriiă în domeniul UX (User Experience) – satisfa c܊iaă
totalăăpeăcareăunăutilizatorăoăareădupăăceăaăfolosităaplica܊ia,ăamăreu܈ităsăăcreezăoă
interfa܊ăă“prietenoasa” , u܈orădeăutilizat.ăăConsiderăcăăutilizatorulăareăoăexperien܊ăă
plăcutăășiăînăacelașiătimpăutilă, întrucât înva܊ăădetaliiădespreăautoturismeăînt r-un
mediuăplăcută܈iăpo ate fiăchiarăredirec܊ionaăpeăsite -ul Wikipedia pentru mai multe
detalii.
Datorităădezvoltăriiăacesteiăaplica܊iiăamăreu܈ităsăăacumulezăoăgamăăvastăă
deăcuno܈tin܊eă despreă tehnologiile folosite.ăExperien܊ a aă fostă unaă plăcută , chiar
dacăă nuă aă fostă oă muncăă u܈oară,ă deoareceă amă lucrată în tr-un domeniu care îmi
place.
CaăposibileădirecĠiiăviitoareădeăîmbunătăĠireăaăaplicaĠieiăseăpotămenĠiona:ă
 Cre܈tereaănumăruluiă de niveluri din aplica܊ie ;
 Posibilitatea de a debloca nivelurile contracost;
 Cre܈tereaănumăruluiă de autoturisme;
 Posibilitatea de a crea o colec܊ieă de autoturisme de catre utilizator;
 Adăugareaă unui sunet la finalizarea unui quiz;
 Adăugarea op܊iunii de a selecta categoria de autoturisme;
 Adăugareaă unei sec܊iuniă de rating.
AplicaĠiaă CarQuiză vaă fiă datăă înă folosinĠăă tuturoră persoaneloră peă
magazinul online al android-ului Google Play, utilizatorii având posibilitatea de
aădescărcaăaplicaĠiaăgratuit.ă

48

BIBLIOGRAFIE

1. Axel Rauschmaye, Speaking JavaScript , EdituraăO’REILLY , 2014
2. Dușmănescu,ăD.,ă Baze de date, EdituraăUniversităĠiiădinăPloiești,ă2005
3. Ionescu, F., Baze de date relaționale și aplicații,Colecția Tehnologia informației,
Editura Tehica, 2004
4. Lucinda Dykes, XML for Dummies ,ăăăEditura Tittel, 2011
5. Perkins, J. B., SQL fără profesor în 15 zile, Editura Teora, 1997
6. P. Pocatilu, I. Ivan, Programarea aplicațiilor Android , Editura ASE, 2015
7. P. Pocatilu, Programarea dispozitivelor mobile , Editura ASE, 2012
8. Sibsankar, Haldar, SQLite Database System, 2015
9. Vladoiu Monica, Modelarea datelor in bazele de date rela ționale , Editura
Universita ĠiiăPetrol -Gaze din Ploiesti, 2008
10. Zigurd Mednieks, Laird Dornin, G.Blake Meike & Masumi Nakamura,
Programming Android , EdituraăO’REILLY , 2011

11. Andrei Ciorba, Cursuri XML , http://andrei.clubcisco.ro/cursuri/f/f-
sym/4ioc/labs/Lab%201%20XML.pdf , accesat pe data de 27.04.2016
12. Dana Damoc, Curs jQuery , http://dana-damoc.eu/blog/curs-jquery-lectia-1-
introducere-download-cdn- si-plasare- in-documentul-html/ , accesat pe data de
18.04.2016
13. EnăchescuăC.,ă Curs POO , Universitatea Petru- Maior Târgu- Mureș,ă
http://docs.oracle.com/javase/tutorial/ , accesat pe data de 20.05.2016
14. Enăchescuă C.,ă Curs POO , Universitatea Petru-Maior Târgu- Mureș,ă
http://upm.ro/intranet/ecalin/cd_educational/cd/javac/cap1.htm , accesat pe data
de 20.05.2016
15. Rosedu , Laborator Baze de date SQLite ,
http://android.rosedu.org/2015/laborator-05-baze-de-date , accesat pe data de
18.05.2016
16. Introducere in Java ,

49
http://www.matestn.ro/Kituri%20si%20documentatie/Carte%20JAVA%20in%2
0romana/introducere.html , accesat pe data de 19.05.2016
17. Wikipedia – Java (Programming Language),
https://ro.wikipedia.org/wiki/Java_(limbaj_de_programar e), accesat pe data de
20.05.2016
18. Wikipedia – Audi R8 ,
https://en.wikipedia.org/wiki/Audi_R8 – wikipedia audi r8 , accesat pe data de
18.03.2016
19. W3Schools Online Web Tutorials , www.w3school.com , accesat pe data de
22.05.2016
20. Logo Quiz Download,
https://play.google.com/store/apps/details?id=logos.quiz.companies.game ,
accesat pe data de 25.05.2016
21. Android Studio Download ,
https://developer.android.com/studio/index.html , accesat 15.05.2016
22. Structura unui fisier APK,
http://students.info.uaic.ro/~dumitru.prelipcean/android/Laborator1.pdf , accesat
pe data de 12.04.2016
23. Model View Controller http://android.rosedu.org/2015/laborator-07-liste- si-
meniuri , accesat pe data de 15.06.2016
24. Market Android , Google Play, http://play.google .com/‎ , accesat pe data de
20.06.2016

50
Anexa Extras de cod sursa

MainActivity.java
package carquiz.newbies.pro.carquiz;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.Toast;
import com.facebook.AccessToken;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.FacebookSdk;
import com.facebook.GraphRequest;
import com.facebook.GraphRequestAsyncTask;
import com.facebook.GraphResponse;
import com.facebook.login.LoginManager;
import com.facebook.login.LoginResult;
import junit.framework.Test;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import carquiz.newbies.pro.adapters.User;
import carquiz.newbies.pro.database.MyApplication;
public class MainActivity extends Activity implements View.OnClickListener{
private ImageButton progress , settings ;
private Button startch , leaderboard , get_hints , fb_login , test_firstpage ;
private Context context = this;
public static boolean serviceRunning = false ;
private CallbackManager callbackManager ;
private MyApplication myApp ;
private AccessToken accessToken ;
private User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout. activity_main );
myApp = (MyApplication)getApplicationContext();
myApp .initDB( this);
user = myApp .getUser();
callbackManager = CallbackManager.Factory. create ();
startch = (Button) findViewById(R.id. btn_startch );
startch .setOnClickListener( this);
leaderboard = (Button) findViewById(R.id. btn_leaderboard );
leaderboard .setOnClickListener( this);
get_hints = (Button) findViewById(R.id. btn_getHints );
get_hints .setOnClickListener( this);
settings = (ImageButton) findViewById(R.id. btn_settings );
settings .setOnClickListener( this);
progress = (ImageButton) findViewById(R.id. btn_progress );
progress .setOnClickListener( this);
test_firstpage = (Button) findViewById(R.id. btn_test_first );
test_firstpage .setOnClickListener( this);
LoginManager. getInstance ().registerCallback( callbackManager ,
new FacebookCallback<LoginResult>() {

51
@Override
public void onSuccess(LoginResult loginResult) {
Toast. makeText (MainActivity. this, "Login successful !" , Toast. LENGTH_SHORT ).show();
makeMeRequest();
}
@Override
public void onCancel() {
}
@Override
public void onError(FacebookException exception) {
Log.e("test" ,"Facebookexception : " + exception);
}
});
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id. btn_startch :
Intent i = new Intent( context , SelectLevelActivity. class );
startActivity(i);
break ;
case R.id. btn_settings :
i = new Intent( context , SettingsActivity. class );
startActivity(i);
break ;
case R.id. btn_progress :
i = new Intent( context , ProgressActivity. class );
startActivity(i);
break ;
case R.id. btn_test_first :
i = new Intent( context , TestFirstPage. class );
startActivity(i);
break ;
}
}
@Override
public void onBackPressed() {
finish();
}
@Override
protected void onActivityResult( int requestCode, int resultCode, Intent data) {
super .onActivityResult(requestCode, resultCode, data);
callbackManager .onActivityResult(requestCode, resultCode, data);
}
private void makeMeRequest() {
GraphRequest request = GraphRequest. newMeRequest (AccessToken. getCurrentAccessToken (),
new GraphRequest.GraphJSONObjectCallback() {
@Override
public void onCompleted(JSONObject jsonObject, GraphResponse graphResponse) {
if (jsonObject != null) {
try {
Log. e("test" ,"Facebook response json : " + jsonObject);
user.setFbImage( "http://graph.facebook.com/" + jsonObject.getString( "id" ) + "/picture" );
user.setFbName(jsonObject.getString( "name" ));
myApp .updateUserProgress( user);
} catch (JSONException e) {
e.printStackTrace();
}
} else if (graphResponse.getError() != null) {
switch (graphResponse.getError().getCategory()) {
case LOGIN_RECOVERABLE :
Log. d("error" ,
"Authentication error: " + graphResponse.getError());
break ;
case TRANSIENT :
Log. d("error" ,
"Transient error. Try again. " + graphResponse.getError());

52
break ;
case OTHER :
Log. d("error" ,
"Some other error: " + graphResponse.getError());
break ;
}
}
else
Log.d("parse" ,"Null jsonObject " );
}
});
request.executeAsync();
}
}

ProgressActivity.java
package carquiz.newbies.pro.carquiz;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import carquiz.newbies.pro.adapters.User;
import carquiz.newbies.pro.database.MyApplication;
public class ProgressActivity extends Activity {
private TextView solved , solved_procent , user_poin ts, attempts , attempts_procent , perfect , perfect_procent ;
private MyApplication myApp ;
private User user;
private int nr_quizes = 0, solved_quizes , attempted = 0, flawless = 0, points ;
private AdView mAdView ;
@Override
protected voi d onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout. activity_progress );
initializeView();
mAdView = (AdView) findViewById(R.id. adView );
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest. DEVICE_ID_EMULATOR )
.build();
mAdView .loadAd(adRequest);
myApp = (MyApplication)getApplicationContext();
user = myApp .getUser();
nr_quizes = myApp .getNumberofQuizes();
solved_quizes = user.getQuiz_solved();
attempted = user.getAttempts();
flawless = user.getFlawless();
points = user.getPoints();
solved .setText( "" + user.getQuiz_solved());
if(nr_quizes != 0 && solved_quizes != 0) {
solved_procent .setText(( int) (100 * solved_quizes / nr_quizes ) + " %" );
}
if(attempted !=0) {
attempts .setText( "" + user.getAttempts());
}
if(attempted !=0 && solved_quize s != 0) {
attempts_procent .setText(( int)(100 * attempted / (attempted + solved_quizes )) + " %" );
}
perfect .setText( "" + flawless );
if(flawless != 0 && solved_quizes != 0 ){
perfect_procent .setText(( int)(100 * flawless / solved_quizes ) + " %" );
}
user_points .setText( "" + points );
}
protected void initializeView() {
solved = (TextView) findViewById(R.id. tv_quiz_solved_stx );
solved_procent = (TextView) findViewById(R.id. tv_procent_solved_stx );
user_points = (TextView) findViewById(R.id. tv_users_points_stx );

53
attempts = (TextView) findViewById(R.id. tv_guess_attempts_stx );
attempts_procent = (TextView) findViewById(R.id. tv_procent_attempts_stx );
perfect = (TextView) findViewById(R.id. tv_flawless_guess_stx );
perfect_procent = (TextView) findViewById(R.id. tv_flawless_procent_stx );
}
@Override
public void onPause() {
if (mAdView != null) {
mAdView .pause();
}
super .onPause();
}
@Override
public void onResume() {
super .onResume();
if (mAdView != null) {
mAdView .resume();
}
}
@Override
public void onDestroy() {
if (mAdView != null) {
mAdView .destroy();
}
super .onDestroy();
}
}

QuizActivity.java
package carquiz.newbies.pro.carquiz;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.support.v4.view.GestureDetectorCompat;
import android.util.Log;
import android.view.Display;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;

54
import android.widget.Toast;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.share.ShareApi;
import com.facebook.share.Sharer;
import com.facebook.share.model.SharePhoto;
import com.facebook.share.model.SharePhotoContent;
import com.facebook.share.widget.ShareDialog;
import carquiz.newbies.pro.adapters.GridViewAdapter;
import carquiz.newbies.pro.adapters.Helper;
import carquiz.newbies.pro.adapters.LevelItem;
import carquiz.newbies.pro.adapters.LevelSelectAdapter;
import carquiz.newbies.pro.adapters.QuizItem;
import carquiz.newbies.pro.adapters.User;
import carquiz.newbies.pro.database.LocalDatabase;
import carquiz.newbies.pro.database.MyApplication;
import carquiz.newbies.pro.service.PlayAudio;
import uk.co.deanwild.flowtextview.FlowTextView;
public class QuizActivity extends Activity implements OnClickListener, View.OnTouchListener,
GestureDetector.OnGestureListener {
private int [] buttonsId = { R.id. btn_a , R.id. btn_b , R.id. btn_c , R.id. btn_d , R.id. btn_e , R.id. btn_f , R.id. btn_g ,
R.id. btn_h , R.id. btn_i , R.id. btn_j ,
R.id. btn_k , R.id. btn_l , R.id. btn_m , R.id. btn_n , R.id. btn_o , R.id. btn_p , R.id. btn_q ,
R.id. btn_r , R.id. btn_s , R.id. btn_t , R.id. btn_u , R.id. btn_w , R.id. btn_y , R.id. btn_z , R.id. btn_x , R.id. btn_v };
private int [] numbersId = {R.id. btn_unu , R.id. btn_doi , R.id. btn_trei , R.id. btn_patru , R.id. btn_cinci , R.id. btn_sase ,
R.id. btn_sase , R.id. btn_sapte , R.id. btn_opt , R.id. btn_noua , R.id. btn_zero , R.id. btn_minus };
private ArrayList<ImageButton> letterButtons , numberButtons ;
private ImageButton infoBtn , bombBtn , letterWriteBtn , quizCompleteBtn , fb_share , erase_letter ;
private ImageButton keyChange , backButton ;
private int position = 0, pos = 0, i = 0, total = 0, btns_index = 0, LetterWidth , bomb_uses = 0, letterCompUses =
0;
private int max_answer_line_length , words_in_answer , answer_line_width = 11, answer_blank =
R.drawable. blank ;
private char [] answer , writtenAnswer ;
private boolean numLetters = false , keyboardActive = true, autocompleteUsed = false ;
private LinearLayout letters , numbers , answers_back , continue_layout , keyboard_layout ;
private RelativeLayout next_quiz , prev_quiz , hints_layout ;
private ImageView next_quiz_img , prev_quiz_img , quiz_photo , checked ;
private LinearLayout [] Answer_ll ;
private Button close_quiz , read_more , close_hint_letters ;
private ArrayList<Button> answer_btns = new ArrayList<>();
private QuizItem car_item ;
private MyApplication myApp ;
private User you_user ;
private ScrollView info_scroll ;
private TextView car_info , user_points , congrads_message , cars_solved ;
private Vibrator vibe;
private long [] vibrate_pattern_true = {0, 200, 200, 200},
vibrate_pattern_false = {0, 500};
private Animation shakeAnimation ;
private int corrections = 0, attempts = 0, hints_used = 0;
private String [] congrads = {"FLAWLESS !" , "PERFECT !" , "GOOD JOB !" , "NOT BAD…" , "YOU
FINALLY DID IT…" , "BETTER LATER\nTHEN NEVER" };
private boolean show_letter = false , showAlertDialog = true, sounds = true, vibrations = true, levelUpdated =
false ;
private String ans_leng ;
private ArrayList<QuizItem> all_quizes = new ArrayList<QuizItem>();
private MediaPlayer mp;
private int level_points ;
private LevelItem current_level ;
private FlowTextView flowTextView ;
private int seconds_to_complete = 0;
private Timer T;
private GestureDetectorCompat mDetector ;
private RelativeLayout hint_letters_layout ;
private CallbackManager callbackManager ;
private ShareDialog shareDialog ;

55
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout. activity_quiz );
myApp = (MyApplication)getApplicationContext();
myApp .initDB( this);
callbackManager = CallbackManager.Factory. create ();
shareDialog = new ShareDialog( this);
if(myApp .getSharedPreferences( "MY_PREFS" , MODE_PRIVATE ).getBoolean( "show_hint_dialog" ,true))
showAlertDialog = true;
else
showAlertDialog = false ;
you_user = myApp .getUser();
car_item = myApp .getTempQuiz();
Log. e("test" ,"Car item name " + car_item .getAnswer());
all_quizes = myApp .getCars( "" + car_item .getLevel());
current_level = myApp .getTemp_level();
level_points = current_level .getPoints();
bomb_uses = 0;
levelUpdated = false ;
if(you_user .getVibration() == 1)
vibrations = true;
else
vibrations = false ;
if(you_user .getSound() == 1)
sounds = true;
else
sounds = false ;
shakeAnimation = AnimationUtils. loadAnimation (this, R.anim. shake );
makeInitializations();
quiz_photo .setBackgroundResource(GridViewAdapter. cars_drawables .getResourceI d(car_item .getPosition(), -1));
keyChange = (ImageButton) findViewById(R.id. btn_keychange );
keyChange .setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
if(numLetters )
{
numbers .setVisibility(View. GONE );
letters .setVisibility(View. VISIBLE );
} else
{
letters .setVisibility(View. GONE );
numbers .setVisibility(View. VISIBLE );
}
numLetters = !numLetters ;
}
});
for (int i = 0; i < buttonsId .length ; i++)
letterButtons .add((ImageButton) findViewById( buttonsId [i]));
for (int i = 0; i < buttonsId .length ; i++)
letterButtons .get(i).setOnClickListener( new KeyboardClickListener( buttonsId [i]));
for (int i = 0; i < numbersId .length ; i++)
numberButtons .add((ImageButton) findViewById( numbersId [i]));
for (int i = 0; i < numbersId .length ; i++)
numberButtons .get(i).setOnClickListener( this);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size. x;
int height = size. y;
LetterWidth = width / 13;
Log. e("test" ,"Width size " + width);
String intentAns = car_item .getAnswer();
ans_leng = intentAns.replace( "_", "");
Log. e("test" , "Answer without _ " + ans_leng + " and lenght " + ans_leng .length());
writtenAnswer = new char [ans_leng .length()];
for(int p = 0; p < writtenAnswer .length ; p++)

56
writtenAnswer [p] = '@';
answer = ans_leng .toCharArray();
generateAnswerButtons( car_item .getAnswer());
Log. e("test" ,"Answer " + car_item .getAnswer());
for(int i = 0; i < answer_btns .size(); i++)
{
answer_btns .get(i).setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v)
{
final int clk = (Integer)v.getTag();
if(show_letter )
{
show_letter = false ;
writtenAnswer [clk] = ans_leng .charAt(clk);
Drawable draw_answ = Helper. getDrawableFromAssets (QuizActivity. this,
"keyboard/" + ans_leng .charAt(clk) + ".png" );
answer_btns .get(clk).setBackgroundDrawable(draw_answ);
if (clk < position )
position = clk;
else
setnextPosition();
} else
if (answer [clk] != ' ' && keyboardActive ) {
corrections ++;
you_user .setCorrections( corrections );
Log. e("test" ,"New correction applied !!!" );
writtenAnswer [clk] = '@';
answer_btns .get(clk).setBackgroundResource(R.drawable. blank );
if (clk < position )
position = clk;
else
setnextPosition();
}
}
});
}
answers_back .setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
eraseLastLetter();
}
});
erase_letter .setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
eraseLastLetter();
}
});
if(car_item .getPosition() != 0) {
Drawable car_image =
getResources().getDrawable(GridViewAdapter. cars_drawables .getResourceId(( car_item .getPosition() – 1), -1));
prev_quiz_img .setImageDrawable(car_image);
}

if(car_item .getPosition() != ( all_quizes .size() – 1)) {
Drawable car_image =
getResources().getDrawable(GridViewAdapter. cars_drawables .getResourceId(( car_item .getPosition() + 1), -1));
next_quiz_img .setImageDrawable(car_image);
}
if(car_item .getSolved() == 1)
{
keyboard_layout .setVisibility(View. GONE );
continue_layout .setVisibility(View. VISIBLE );
hints_layout .setVisibility(View. INVISIBLE );
congrads_message .setText( car_item .getMessage());
autocompleteAnswer();

57
} else {
Log. e("Update" ,"Current answer " + car_item .getCurrent_answer());
for(int i = 0; i < ans_leng .length(); i++)
{
if(car_item .getCurrent_answer().charAt(i) != '@') {
Drawable draw_answ = Helper. getDrawableFromAssets (this, "keyboard/" +
car_item .getCurrent_answer().charAt(i) + ".png" );
answer_btns .get(i).setBackgroundDrawable(draw_answ);
}
writtenAnswer [i] = car_item .getCurrent_answer().charAt(i);
}
if (ans_leng .contains( "series" )) {
int start = ans_leng .indexOf( "series" );
for (int i = start; i < (start + 6); i++) {
Drawable draw_answ = Helper. getDrawableFromAssets (this, "keyboard/ " + ans_leng .charAt(i) +
".png" );
answer_btns .get(i).setBackgroundDrawable(draw_answ);
writtenAnswer [i] = ans_leng .charAt(i);
}
}
T = new Timer();
T.scheduleAtFixedRate( new TimerTask() {
@Override
public void run() {
runOnUiThread( new Runnable()
{
@Override
public void run()
{
seconds_to_complete ++;
}
});
}
}, 1000, 1000);
if(ans_leng .contains( "-"))
for(int i = 0; i < ans_leng .length(); i++)
if(ans_leng .charAt(i) == '-')
{
Drawable draw_answ = Helper. getDrawableFromAssets (this, "keyboard/" + '-' + ".png" );
answer_btns .get(i).setBackgroundDrawable(draw_answ);
writtenAnswer [i] = ans_leng .charAt(i);
}
setnextPosition();
}
letterWriteBtn .setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
if(myApp .getSharedPreferences( "MY_PREFS" ,MODE_PRIVATE ).getBoolean( "show_hint_dialog" ,false ) &&
keyboardActive )
{
useLetterShowHint();
} else {
if (keyboardActive ) {
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(QuizActivity. this);
LayoutInflater inflater = QuizActivity. this.getLayoutInflater();
View dialogView = inflater.inflate(R.layout. alertdialogcuston , null);
dialogBuilder.setView(dialogView);
final AlertDialog alertDialog = dialogBuilder.create();

TextView title = (TextView) dialogView.find ViewById(R.i d.tv_dialog_title );
title.setText( "Show a letter" );
TextView message = (TextView) dialogView .findViewById(R.id. tv_dialog_message );
message.setText( "Tap the letter you want to show, for only 5 points." );
final CheckBox show_again = (CheckBox) dialogView.findViewById(R.id. cb_show_alert );
Button cancel_d = (Button) dialogView.f indViewById(R.id. btn_cancel_dialog );
Button use = (Button) dialogView.findView ById(R.id. btn_use_help );
cancel_d.setOnClickListener( new OnClickListener() {

58
@Override
public void onClick(View v) {
if (show_again.isChecked()) {
myApp .getSharedPreferences( "MY_PREFS" ,
MODE_PRIVATE ).edit().putBoolean( "show_hint_dialog" , false ).commit();
showAlertDialog = false ;
}
alertDialog.dismiss();
}
});
use.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
if (show_again.isChecked())
myApp .getSharedPreferences( "MY_PREFS" ,
MODE_PRIVATE ).edit().putBoolean( "show_hint_dialog" , false ).commit();
if (you_user .getPoints() >= 5) {
useLetterShowHint();
} else {
Toast. makeText (QuizActivity. this, "You do not have enough points ! Watch a video, " +
"and you get 15 points." , Toast. LENGTH_LONG ).show();
}
alertDialog.dismiss();
}
});
alertDialog.show();
}
}
}
});
bombBtn .setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
if(myApp .getSharedPreferences( "MY_PREFS" ,MODE_PRIVATE ).getBoolean( "show_hint_dialog" ,false ) &&
keyboardActive )
{
useBombHint();
} else {
if (keyboardActive ) {
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(QuizActivity. this);
LayoutInflater inflater = QuizActivity. this.getLayoutInflater();
View dialogView = inflater.inflate(R.layout. alertdialogcuston , null);
dialogBuilder.setView(dialogView);
final AlertDialog alertDialog = dialogBuilder.create();
TextView title = (TextView) dialogView.find ViewById(R.id. tv_dialog_title );
title.setText( "Show containing characters" );
TextView message = (TextView) dialogView .findViewById(R.id. tv_dialog_message );
message.setText( "Shows you the answer's containing characters for 15 points." );
final CheckBox show_again = (CheckBox) dialogView.findViewById(R.id. cb_show_alert );
Button cancel_d = (Button) dialogView.f indViewById(R.id. btn_cancel_dialog );
Button use = (Button) dialogView.findView ById(R.id. btn_use_help );
cancel_d.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
if (show_again.isChecked())
myApp .getSharedPreferences( "MY_PREFS" ,
MODE_PRIVATE ).edit().putBoolean( "show_hint_dialog" , false ).commit();
alertDialog.dismiss();
}
});
use.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
if (show_again.isChecked())
myApp .getSharedPreferences( "MY_PREFS" ,
MODE_PRIVATE ).edit().putBoolean( "show_hint_dialog" , false ).commit();
if (you_user .getPoints() >= 15) {

59
useBombHint();
} else {
Toast. makeText (QuizActivity. this, "You do not have enough points ! Watch a video, " +
"and you get 15 points." , Toast. LENGTH_LONG ).show();
}
alertDialog.dismiss();
}
});
alertDialog.show();
}
}
}
});
quizCompleteBtn .setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
if (myApp .getSharedPreferences( "MY_PREFS" , MODE_PRIVATE ).getBoolean( "show_hint_dialog" ,
false ) && keyboardActive ) {
useAutocompleteHint();
} else {
if (keyboardActive ) {
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(QuizActivity. this);
LayoutInflater inflater = QuizActivity. this.getLayoutInflater();
View dialogView = inflater.inflate(R.layout. alertdialogcuston , null);
dialogBuilder.setView(dialogView);
final AlertDialog alertDialog = dialogBuilder.create();
TextView title = (TextView) dialogView.find ViewById(R.id. tv_dialog_title );
title.setText( "View the answer" );
TextView message = (TextView) dialogView .findViewById(R.id. tv_dialog_message );
message.setText( "Autocompletes the answer for 25 points." );
final CheckBox show_again = (CheckBox) dialogView.findViewById(R.id. cb_show_alert );
Button cancel_d = (Button) dialogView.f indViewById(R.id. btn_cancel_dialog );
Button use = (Button) dialogView.findView ById(R.id. btn_use_help );

cancel_d.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
if (show_again.isChecked())
myApp .getSharedPreferences( "MY_PREFS" ,
MODE_PRIVATE ).edit().putBoolean( "show_hint_dialog" , false ).commit();
alertDialog.dismiss();
}
});
use.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
if (show_again.isChecked())
myApp .getSharedPreferences( "MY_PREFS" ,
MODE_PRIVATE ).edit().putBoolean( "show_hint_dialog" , false ).commit();
if (you_user .getPoints() >= 25) {
useAutocompleteHint();
} else {
Toast. makeT ext(QuizActivity. this, "You do not have enough points ! Watch a video, " +
"and you get 15 points." , Toast. LENGTH_LONG ).show();
}
alertDialog.dismiss();
}
});
alertDialog.show();
}
}
}
});
float density = getResources().getDisplayMetrics(). density ;
Log. e("test" , "Screen density " + density);
flowTextView .setTextSize(18 * density);
flowTextView .setText( car_item .getCar_info());

60
mDetector = new GestureDetectorCompat( this, new MyGestureListener());
fb_share .setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
Bitmap car_bitmap = BitmapFactory. decodeResource (getResources(),
GridViewAdapter. cars_drawables .getResourceId( car_item .getPosition(), -1));
publishImage(car_bitmap);
}
});
if(!myApp .getSharedPreferences( "MY_PREFS" ,MODE_PRIVATE ).contains( "hint_showed" ))
{
hint_letters_layout .setVisibility(View. VISIBLE );
myApp .getSharedPreferences( "MY_PREFS" ,MODE_PRIVATE ).edit().putBoolean( "hint_showed" ,true).commit();
} else {
hint_letters_layout .setVisibility(View. GONE );
}
close_hint_letters .setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
hint_letters_layout .setVisibility(View. GONE );
}
});
}
private void eraseLastLetter() {
if (keyboardActive )
for (int j = (writtenAnswer .length – 1); j >= 0; j –) {
if (writtenAnswer [j] != '@') {
Drawable draw_answ = Helper. getDrawableFromAssets (QuizActivity. this, "keyboard/" + "blank" +
".png" );
answer_btns .get(j).setBackgroundDrawable(draw_answ);
writtenAnswer [j] = '@';
corrections ++;
you_user .setCorrections( corrections );
Log. e("test" , "New correction applied !!!" );
Log. e("test" , "Answer lenght " + answer_btns .size() + " current position " + position + " deleted
position " + j);
if (position > j || position == -1)
position = j;
j = – 1;
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event){
this.mDetector .onTouchEvent(event);
return super .onTouchEvent(event);
}
@Override
public void onClick(View v) {
switch (v.getId ()){
case R.id. btn_unu :
if((position != -1) && keyboardActive ) {
String uri = "drawable/unu" ;
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '1';
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. btn_doi :
if((position != -1) && keyboardActive ) {
String uri = "drawable/do i";
int imageResource = getResources().getIdentifier(uri, null, getPackageName());

61
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '2';
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. btn_trei :
if((position != -1) && keyboardActive ) {
String uri = "drawable/trei" ;
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '3';
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. btn_patru :
if((position != -1) && keyboardActive ) {
String uri = "drawable/patru" ;
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '4';
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. btn_cinci :
if((position != -1) && keyboardActive ) {
String uri = "drawable/cinci" ;
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '5';
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. btn_sase :
if((position != -1) && keyboardActive ) {
String uri = "drawable/sase" ;
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '6';
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. btn_sapte :
if((position != -1) && keyboardActive ) {
String uri = "drawable/sapte" ;
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '7';

62
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. btn_opt :
if((position != -1) && keyboardActive ) {
String uri = "drawable/opt" ;
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '8';
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. btn_noua :
if((position != -1) && keyboardActive ) {
String uri = "drawable/noua" ;
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
answer_btns .get(position ).setBackgroundResource(imageResource);
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '9';
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. btn_zero :
if((position != -1) && keyboardActive ) {
String uri = "drawable/zero" ;
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '0';
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. btn_minus :
if((position != -1) && keyboardActive ) {
String uri = "drawable/minus" ;
int imageResource = getResources().getIdentifier(uri, null, getPackageName( ));
answer_btns .get(position ).setBackgroundResource(imageResource);
writtenAnswer [position ] = '-';
if(position == (total – 1))
checkAnswerChangePosition();
else
setnextPosition();
} else
ShakeAgain();
break ;
case R.id. ibtn_back :
onBackPressed();
break ;
}
}
private void setnextPosition() {
for(int k = 0; k < writtenAnswer .length ; k++)

63
{
if(writtenAnswer [k] == '@') {
position = k;
k = writtenAnswer .length ;
break ;
}
if(k == ( writtenAnswer .length -1))
checkAnswerChangePosition();
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent. ACTION_DOWN :
if(v.getId() == R.id. rl_next_quiz ) {
mp = MediaPlayer. create (this, R.raw. roar_engine );
mp.setLooping( true);
mp.setVolume(0.2f, 0.7f);
mp.start();
} else if (v.getId() == R.id. rl_previous_quiz )
{
mp = MediaPlayer. create (this, R.raw. back_up_sound );
mp.setLooping( true);
mp.setVolume(0.2f, 0.7f);
mp.start();
}
break ;
case MotionEvent. ACTION_UP :
mp.stop();
if(v.getId() == R.id. rl_next_quiz )
{
showNextQuiz();
} else if (v.getId() == R.id. rl_previous_quiz )
{
showPreviousQuiz();
}
break ;
}
return true ;
}
private void showNextQuiz()
{
Log. e("test" ,"Car solved bool value " + car_item .getSolved());
UpdateLevelifNeeded();
if(car_item .getPosition() != ( all_quizes .size() – 1))
{
car_item .setCurrent_answer(String. valueOf (writtenAnswer ));
myApp .updateCarAnswer( car_item );
QuizItem new_car = all_quizes .get(car_item .getPosition() + 1);
getIntent().putExtra( "answer" , new_car.getAnswer());
myApp .setTempQuiz(new_car);
recreate();
overridePendingTransition(R.anim. fade_in , R.anim. fade_out );
} else
onBackPressed();
}
private void showPreviousQuiz()
{
Log. e("test" ,"Car solved bool value " + car_item .getSolved());
UpdateLevelifNeeded();
if(car_item .getPosition() != 0)
{
car_item .setCurrent_answer(String. valueOf (writtenAnswer ));
myApp .updateCarAnswer( car_item );
QuizItem new_car = all_quizes .get(car_item .getPosition() – 1);
getIntent().putExtra( "answer" , new_car.getAnswer());
myApp .setTempQuiz(new_car);

64
recreate();
overridePendingTransition(R.anim. fade_in , R.anim. fade_out );
} else
onBackPressed();
}
@Override
public boolean onDown(MotionEvent e) {
return false ;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false ;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false ;
}
@Override
public void onLongPress(MotionEvent e) {

}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log. d("test" , "onFling: " + e1.toString() + e2.toString());
if((e2.getX() – e1.getX() > 15))
{
showNextQuiz();
} else if ((e1.getX() – e2.getX() > 15))
{
showPreviousQuiz();
}
return true ;
}
public class KeyboardClickListener implements OnClickListener {
int index ;
public KeyboardClickListener( int index) {
this.index = index;
}
@Override
public void onClick(View arg0) {
if((position != -1) && keyboardActive ) {
String pressed = arg0.getTag().toString();
String uri = "drawable/" + pressed;
int imageResource = getResources().getIdentifier(uri, null, getPackageName());
answer_btns .get(position ).setBackgroundResource(imageResource);

writtenAnswer [position ] = pressed.charAt(0);
if(position == (total – 1))
{
checkAnswerChangePosition();
}
else
setnextPosition();
} else
ShakeAgain();
}
}
private void ShakeAgain()
{
answers_back .startAnimation( shakeAnimation );
if(vibrations )
vibe.vibrate( vibrate_pattern_true , -1);
}
private void checkAnswerChangePosition()

65
{
position = -1;
T.cancel();
Log. e("test" , "Seconds to complete quiz : " + seconds_to_complete );
if(Arrays. equals (writtenAnswer , answer )) {
if(corrections == 0 && hints_used == 0) {
congrads_message .setText( congrads [0]);
you_user .setFlawless( you_user .getFlawless() + 1);
car_item .setMessage( congrads [0]);
} else if (attempts == 0 && autocompleteUsed == false )
{
congrads_message .setText( congrads [1]);
car_item .setMessage( congrads [1]);
} else if (attempts > 5)
{
congrads_message .setText( congrads [5]);
car_item .setMessage( congrads [5]);
} else
{
congrads_message .setText( congrads [2]);
car_item .setMessage( congrads [2]);
}
hints_layout .setVisibility(View. INVISIBLE );
car_item .setSolved(1);
myApp .updateCarContent( car_item );
you_user .setPoints( you_user .getPoints() + 5);
you_user .setQuiz_solved( you_user .getQuiz_solved() + 1);
myApp .updateUserProgress( you_user );
keyboardActive = false ;
checked .setVisibility(View. VISIBLE );
if(vibrations )
vibe.vibrate( vibrate_pattern_false , -1);
user_points .setText( "" + you_user .getPoints());
cars_solved .setText( "" + you_user .getQuiz_solved());
answers_back .setVisibility(View. INVISIBLE );
info_scroll .setVisibility(View. VISIBLE );
Log. e("test" , "Total solved " + you_user .getQuiz_solved());
keyboard_layout .setVisibility(View. GONE );
continue_layout .setVisibility(View. VISIBLE );
all_quizes = myApp .getCars( car_item .getLevel() + "");
checkAndUnlockNextLevel();
if (!autocompleteUsed )
{
if (bomb_uses == 1 && letterCompUses < 2)
{
int new_level_points = 3 – letterCompUses ;
if(new_level_points > 0) {
myApp .UpdateLevel( current_level .getId(), LocalDatabase. COLUMN_LEVELS_POINTS ,
(new_level_points + level_points ));
}
} else if (bomb_uses == 0)
{
int new_level_points = 5 – letterCompUses ;
if(new_level_points > 0) {
myApp .UpdateLeve l(current_level .getId(), LocalDatabase. COLUMN_LEVELS_POINTS ,
(new_level_points + level_points ));
}
}
}
} else {
Toast. makeText (getApplicationContext(), "Try again !" , Toast. LENGTH_SHORT ).show();
answers_back .startAnimation( shakeAnimation );
attempts ++;
you_user .setAttempts( you_user .getAttempts() + attempts );
if(vibrations )
vibe.vibrate( vibrate_pattern_true , -1);
}

66
}
private void checkAndUnlockNextLevel()
{
switch (you_user .getQuiz_solved()) {
case 10:
myApp .UpdateLevel(2, "locked" , 0);
Toast. makeText (getApplicationContext(), "Level 2 unlocked !" , Toast. LENGTH_SHORT ).show();
break ;
case 20:
myApp .UpdateLevel(3, "locked" , 0);
Toast. makeText (getApplicationContext(), "Level 3 unlocked !" , Toast. LENGTH_SHORT ).show();
break ;
case 35:
myApp .UpdateLevel(4, "locked" , 0);
Toast. makeText (getApplicationContext(), "Level 4 unlocked !" , Toast. LENGTH_SHORT ).show();
break ;
case 45:
myApp .UpdateLevel(5, "locked" , 0);
Toast. makeText (getApplicationContext(), "Level 5 unlocked !" , Toast. LENGTH_SHORT ).show();
break ;
case 60:
myApp .UpdateLevel(6, "locked" , 0);
Toast. makeText (getApplicationContext(), "Level 6 unlocked !" , Toast. LENGTH_SHORT ).show();
break ;
case 75:
myApp .UpdateLevel(7, "locked" , 0);
Toast. makeText (getApplicationContext(), "Level 7 unlocked !" , Toast. LENGTH_SHORT ).show();
break ;
case 90:
myApp .UpdateLevel(8, "locked" , 0);
Toast. makeText (getApplicationContext(), "Level 8 unlocked !" , Toast. LENGTH_SHORT ).show();
break ;
case 105:
myApp .UpdateLevel(9, "locked" , 0);
Toast. makeText (getApplicationContext(), "Level 9 unlocked !" , Toast. LENGTH_SHORT ).show();
break ;
case 115:
myApp .UpdateLevel(10, "locked" , 0);
Toast. makeText (getApplicationContext(), "Level 10 unlocked !" , Toast. LENGTH_SHORT ).show();
break ;
default :
break ;
}
}
void generateAnswerButtons(String answer) {
for (int i = 0; i < Answer_ll .length ; i++) {
Answer_ll [i].removeAllViews();
}
int word_count = 1;
ArrayList<Integer> wp_list = new ArrayList<Integer>();
ArrayList<Integer> wl_list = new ArrayList<Integer>();
for (int i = 0; i < answer.length(); i++) {
if (answer.charAt(i) == '_') {
wp_list.add(i);
if (word_count == 1) {
wl_list.add(i);
} else {
wl_list.add(wp_list.get(word_count – 1) – wp_li st.get(word_count – 2) – 1);
}
word_count++;
}
}
wp_list.add(answer.length());
if (word_count > 1) {
wl_list.add(answer.length() – wp_list.get(word_count – 2) – 1);
} else {
wl_list.add(answer.length());

67
}
max_answer_line_length = getMaxAnswerLineLength(wl_list);
words_in_answer = wl_list.size();
int cur_word = 1;
int k = 0;
while (cur_word <= word_count) {
if (cur_word == 1) {
for (int i = 0; i < wl_list.get(0); i++) {
addAnswerButton( Answer_ll [0], i, false , 0);
}
} else {
if (Answer_ ll[k].getChildCount() + wl_list.get(cur_word – 1) <= answer_line_width ) {
for (int i = 0; i < wl_list.get(cur_word – 1); i++) {
addAnswerButton( Answer_ll [k], i, true, k);
}
} else {
if (k < 3) {
k++;
}
for (int i = 0; i < wl_list.get(cur_word – 1); i++) {
addAnswerButton( Answer_ll [k], i, false , k);
}
}
}
cur_word++;
}
}
int getMaxAnswerLineLength(ArrayList<Integer> wl_list) {
int k = 0;
ArrayList<Integer> buf = new ArrayList<Integer>();
for (int i = 0; i < wl_list.size(); i++) {
buf.add(i, 0);
}
int max = wl_list.get(0);
for (int i = 1; i < wl_list.size(); i++) {
if (max + wl_list.get(i) <= answer_line_width ) {
max += wl_list.get(i);
} else {
buf.add(k, max);
max = wl_list.get(i);
k++;
}
}
for (int i = 0; i < buf.size(); i++) {
if (buf.get(i) > max) {
max = buf.get(i);
}
}
return max;
}
private void addAnswerButton(LinearLayout l, int index, boolean spaceNeeded, int line) {
final Button b = new Button( this);
b.setTag( btns_index );
int wh = (Utils. getScreenSize ().x – 10 * words_in_answer ) / (max_answer_line_length >= 8 ?
max_answer_line_length : 8);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( LetterWidth , (int)(LetterWidth * 1.27), 0);
lp. gravity = Gravity. CENTER_HORIZONTAL ;
lp. leftMargin = spaceNeeded && index == 0 ? 15 : 0;
lp. rightMargin = 5;
b.setLayoutParams(lp);
b.setPadding(2, 2, 2, 2);
b.setBackgroundResource( answer_blank );
l.addView(b);
answer_btns .add(b);
btns_index ++;
}
@Override

68
protected void onPause() {
super .onPause();
myApp .updateUserProgress( you_user );
}
private void autocompleteAnswer()
{
keyboardActive = false ;
checked .setVisibility(View. VISIBLE );
keyboard_layout .setVisibility(View. GONE );
continue_layout .setVisibility(View. VISIBLE );
for(int i = 0; i < ans_leng .length(); i++)
{
Drawable draw_answ = Helper. getDrawableFromAssets (this, "keyboard/" + ans_leng .charAt(i) + ".png" );
answer_btns .get(i).setBackgroundDrawable(draw_answ);
}
final Handler handler = new Handler();
handler.postDelayed( new Runnable() {
@Override
public void run() {
answers_back .setVisibility(View. INVISIBLE );
info_scroll .setVisibility(View. VISIBLE );
}
}, 2000);
}
private void publishImage(Bitmap car_bitmap) {
SharePhoto photo = new SharePhoto.Builder()
.setBitmap(car_bitmap)
.build();
SharePhotoContent content = new SharePhotoContent.Builder()
.addPhoto(photo)
.build();
shareDialog .show(content);
}
@Override
public void onBackPressed() {
super.onBackPressed();
Log. e("test" , "Car solved bool value " + car_item .getSolved());
UpdateLevelifNeeded();
car_item .setCurrent_answer(String. valueOf (writtenAnswer ));
myApp .updateCarAnswer( car_item );
you_user .setAttempts( you_user .getAttempts() + attempts );
you_user .setCorrections( you_user .getCorrections() + corrections );
myApp .updateUserProgress( you_user );
}
public void openWikipediaPage(View view)
{
goToUrl( car_item .getWiki_url());
}
private void goToUrl (String url) {
Uri uriUrl = Uri. parse (url);
Intent launchBrowser = new Intent(Intent. ACTION_VIEW , uriUrl);
startActivity(launchBrowser);
}
private void makeInitializations() {
letterButtons = new ArrayList<ImageButton>();
numberButtons = new ArrayList<ImageButton>();
letters = (LinearLayout) findViewById(R.id. letter_row );
numbers = (LinearLayout) findViewById(R.id. numbers_row );
quiz_photo = (ImageView) findViewById(R.id. quiz_image );
checked = (ImageView) findViewById(R.id. checked );
checked .setVisibility(View. INVISIBLE );
close_hint_letters = (Button) findViewById(R.id. btn_close_letters_hint );
erase_letter = (ImageButton) findViewById(R.id. btn_erase );
seconds_to_complete = 0;
hints_layout = (RelativeLayout) findViewById(R.id. rl_hints_layout );
hints_layout .setVisibility(View. VISIBLE );
info_scroll = (ScrollView) findViewById(R.id. scroll_car_info );

69
info_scroll .setVisibility(View. INVISIBLE );
vibe = (Vibrator) getSystemService(Context. VIBRATOR_SERVICE );
infoBtn = (ImageButton) findViewById(R.id. ib_quiz_info );
bombBtn = (ImageButton) findViewById(R.id. ib_quiz_explode );
letterWriteBtn = (ImageButton) findViewById(R.id. ib_quiz_show_letter );
quizCompleteBtn = (ImageButton) findViewById(R.id. ib_quiz_write_answer );
backButton = (ImageButton) findViewById(R.id. ibtn_back );
flowTextView = (FlowTextView) findViewById(R.id. ftv);
backButton .setOnClickListener( this);
user_points = (TextView) findViewById(R.id. tv_users_points );
user_points .setText( "" + you_user .getPoints());
fb_share = (ImageButton) findViewById(R.id. ib_quiz_fb_share );
continue_layout = (LinearLayout) findViewById(R.id. ll_continue_layout );
keyboard_layout = (LinearLayout) findViewById(R.id. ll_keyboard_layout );
keyboard_layout .setVisibility(View. VISIBLE );
continue_layout .setVisibility(View. GONE );
next_quiz = (RelativeLayout) findViewById(R.id. rl_next_quiz );
prev_quiz = (RelativeLayout) findViewById(R.id. rl_previous_quiz );
next_quiz .setOnTouchListener( this);
prev_quiz .setOnTouchListener( this);
next_quiz_img = (ImageView) findViewById(R.id. iv_next_quiz_car );
prev_quiz_img = (ImageView) findViewById(R.id. iv_prev_quiz_car );
congrads_message = (TextView) findViewById(R.id. tv_congrads_text );
cars_solved = (TextView) findViewById(R.id. tv_cars_solved_now );
cars_solved .setText( "" + you_user .getQuiz_solved());
close_quiz = (Button) findViewById(R.id. btn_close_quiz );
close_quiz .setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
myApp .updateUserProgress( you_user );
}
});
hint_letters_layout = (RelativeLayout) findViewById(R.id. rl_letters_hint );
Answer_ll = new LinearLayout[3];
Answer_ll [0] = (LinearLayout) findViewById(R.id. answer_line_1 );
Answer_ll [1] = (LinearLayout) findViewById(R.id. answer_line_2 );
Answer_ll [2] = (LinearLayout) findViewById(R.id. answer_line_3 );
answers_back = (LinearLayout) findViewById(R.id. ll_answer_back );
}
private void UpdateLevelifNeeded()
{
if (!autocompleteUsed && car_item .getSolved() == 1)
{
if (bomb_uses == 1 && letterCompUses < 2)
{
int new_level_points = 3 – letterCompUses ;
if(new_level_points > 0) {
myApp .UpdateLevel( current_level .getId(), LocalDatabase. COLUMN_LEVELS_POINTS ,
(new_level_points + level_points ));
}
} else if (bomb_uses == 0)
{
int new_level_points = 5 – letterCompUses ;
if(new_level_points > 0) {
myApp .UpdateLevel( current_level .getId(), LocalDatabase. COLUMN_LEVELS_POINTS ,
(new_level_points + level_points ));
}
}
}
}
class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
private static final String DEBUG_TAG = "Gestures" ;
@Override
public boolean onDown(MotionEvent event) {
Log. d(DEBUG_TAG ,"onDown: " + event.toString());
return true ;

70
}
@Override
public boolean onFling(MotionEvent event1, MotionEvent event2,
float velocityX, float velocityY) {
Log. e("test" , "onFling: " + event1.toString()+event2.toString());
if((event2.getX() – event1.getX() > 15))
{
showPreviousQuiz();
} else if ((event1.getX() – event2.getX() > 15)) {
showNextQuiz();
}
return true ;
}
}
protected void useBombHint()
{
bomb_uses ++;
char [] shuffledAnswer = Utils. getShuffleAnswer (ans_leng .toUpperCase());
String characters = "";
for(int i = 0; i < shuffledAnswer. length ; i++)
characters += shuffledAnswer[i] + " ";
Toast. makeText (QuizActivity. this, characters,Toast. LENGTH_LONG ).show();
you_user .setPoints(( you_user .getPoints() – 15));
myApp .updateUserProgress( you_user );
user_points .setText( "" + you_user .getPoints());
cars_solved .setText( "" + you_user .getQuiz_solved());
}
protected void useAutocompleteHint(){
hints_layout .setVisibility(View. INVISIBLE );
autocompleteAnswer();
autocompleteUsed = true;
car_item .setMessage( congrads [2]);
myApp .updateCarContent( car_item );
you_user .setPoints(( you_user .getPoints() – 25));
you_user .setQuiz_solved( you_user .getQuiz_solved() + 1);
myApp .updateUserProgress( you_user );
user_points .setText( "" + you_user .getPoints());
cars_solved .setText( "" + you_user .getQuiz_solved());
keyboard_layout .setVisibility(View. GONE );
continue_layout .setVisibility(View. VISIBLE );
checkAndUnlockNextLevel();
}
protected void useLetterShowHint() {
show_letter = true;
letterCompUses ++;
you_user .setPoints(( you_user .getPoints() – 5));
myApp .updateUserProgress( you_user );

user_points .setText( "" + you_user .getPoints());
cars_solved .setText( "" + you_user .getQuiz_solved());
}
@Override
protected void onActivityResult( final int requestCode, final int resultCode, final Intent data) {
super .onActivityResult(requestCode, resultCode, data);
callbackManager .onActivityResult(requestCode, resultCode, data);
}
}

QuizSelectActivity.java
package carquiz.newbies.pro.carquiz;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;

71
import android.widget.TextView;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import java.util.ArrayList;
import carquiz.newbies.pro.adapters.GridViewAdapter;
import carquiz.newbies.pro.adapters.QuizItem;
import carquiz.newbies.pro.adapters.User;
import carquiz.newbies.pro.database.MyApplication;
public class QuizSelectActivity extends Activity {
private GridView gridView ;
private GridViewAdapter gridAdapter ;
private ArrayList<QuizItem> cars = new ArrayList<QuizItem>();
private MyApplication myapp ;
private TextView level_nr ;
private User user;
private boolean sound = true;
private AdView mAdView ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout. activity_quiz_select );
level_nr = (TextView) findViewById(R.id. tv_level_number_select );
mAdView = (AdView) findViewById(R.id. adView );
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest. DEVICE_ID_EMULATOR )
.build();
mAdView .loadAd(adRequest);
myapp = (MyApplication)getApplicationContext();
user = myapp .getUser();
if(user.getSound() == 1)
sound = true;
else
sound = false ;
level_nr .setText( "Level " + getIntent().getStringExtra( "level_number" ));
gridView = (GridView) findViewById(R.id. gridView );
gridView .setOnItemClickListener( new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
final int position , long id) {
myapp .setTempQuiz( cars.get(position ));
Intent intent = new Intent(QuizSelectActivity. this, QuizActivity. class );
intent.putExtra( "answer" , cars.get(position).getAnswer());
startActivity(intent);
overridePendingTransition(R.anim. fade_in , R.anim. fade_out );
}
});
@Override
protected void onResume() {
// TODO Auto-generated method stub
super .onResume();
if (mAdView != null) {
mAdView .resume();
}
cars = myapp .getCars(getIntent().getStringExtra( "level_number" ));
gridAdapt er = new GridViewAdapter( this, R.layout. grid_item_layout , cars);
gridView .setAdapter( gridAdapter );
gridAdapter .notifyDataSetChanged();
}
@Override
public void onBackPressed() {
super .onBackPressed();
}
@Override
public void onPause() {
if (mAdView != null) {
mAdView .pause();
}

72
super .onPause();
}
@Override
public void onDestroy() {
if (mAdView != null) {
mAdView .destroy();
}
super.onDestroy();
}
}
SelectLevelActivity.java
package carquiz.newbies.pro.carquiz;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import java.util.ArrayList;
import carquiz.newbies.pro.adapters.LevelItem;
import carquiz.newbies.pro.adapters.LevelSelectAdapter;
import carquiz.newbies.pro.adapters.User;
import carquiz.newbies.pro.database.MyApplicatio n;
public class SelectLevelActivity extends Activity {
private ListView level_list ;
private ArrayList<LevelItem> levels = new ArrayList<LevelItem>();
private MyApplication myApp ;
private LevelSelectAdapter adapter ;
private User user;
private AdView mAdView ;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super .onCreate(savedInstanceState);
setContentView(R.layout. level_select );
level_list = (ListView) findViewById(R.id. lv_levels );
mAdView = (AdView) findViewById(R.id. adView );
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest. DEVICE_ID_EMULATOR )
.build();
mAdView .loadAd(adRequest);
myApp = (MyApplication)getApplicationContext();
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super .onResume();
if (mAdView != null) {
mAdView .resume();
}
levels = myA pp.getLevels();
user = myApp .getUser();
adapter = new LevelSelectAdapter( this,R.layout. level_item , levels , user.getQuiz_solved());
level_list .setAdapter( adapter );
adapter .notifyDataSetChanged();
}
@Override
public void onPause() {
if (mAdView != null) {
mAdView .pause();
}
super .onPause();
}
@Override
public void onDestroy() {
if (mAdView != null) {
mAdView .destroy();
}

73
super .onDestroy();
}
}

SettingsActivity.java
package carquiz.newbies.pro.carquiz;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Toast;
import com.facebook.AccessToken;
import com.facebook.AccessTokenTracker;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.GraphRequest;
import com.facebook.GraphResponse;
import com.facebook.login.LoginResult;
import com.facebook.login.widget.LoginButton;
import com.facebook.share.ShareApi;
import com.facebook.share.Sharer;
import com.facebook.share.model.ShareLinkContent;
import com.facebook.share.model.SharePhoto;
import com.facebook.share.model.SharePhotoContent;
import com.facebook.share.widget.ShareDialog;
import org.json.JSONException;
import org.json.JSONObject;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import carquiz.newbies.pro.adapters.User;
import carquiz.newbies.pro.database.MyApplication;
public class SettingsActivity extends Activity {
private CheckBox sound , vibration ;
private MyApplication myApp ;
private User user;
private LoginButton loginButton ;
private CallbackManager callbackManager ;
private AccessTokenTracker accessTokenTracker ;
private Button share_now ;
private ShareDialog shareDialog ;
private AdView mAdView ;
@Override
public void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout. activity_settings );
callbackManager = CallbackManager.Factory. create ();
sound = (CheckBox) findViewById(R.id. cb_sound );
vibration = (CheckBox) findViewById(R.id. cb_vibration );
mAdView = (AdView) findViewById(R.id. adView );
AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest. DEVICE_ID_EMULATOR )
.build();
mAdView .loadAd(adRequest);
shareDialog = new ShareDialog( this);
// optional
shareDialog .registerCallback( callbackManager , new FacebookCallback<Sharer.Result>() {
@Override
public void onSuccess(Sharer.Result result) {
Log. e("Share" , "Share successfull !!!" );
}

74
@Override
public void onCancel() {
Log. e("Share" , "Share canceled !!!" );
}
@Override
public void onError(FacebookException error) {
Log. e("Share" , "Share with error !!!" + error.getMessage());
}
});
myApp = (MyApplication)getApplicationContext();
myApp .initDB( this);
user = myApp .getUser();
Log. e("Settings" , "User name " + user.getFbName() + " , user image " + user.getFbImage());
if(user.getSound() == 1)
sound .setChecked( true);
else
sound .setChecked( false );
if(user.getVibration() == 1)
vibration .setChecked( true);
else
vibration .setChecked( false );
loginButton = (LoginButton) findViewById(R.id. btn_facebook_login_settings );
loginButton .setPublishPermissions( "publish_actions" );
loginButton .registerCallback( callbackManager , new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
// App code
Toast. makeText (SettingsActivity. this, "Login successful !" , Toast. LENGTH_SHORT ).show();
makeMeRequest();
accessTokenTracker .startTracking();
}
@Override
public void onCancel() {
}
@Override
public void onError(FacebookException exception) {
}
});
accessTokenTracker = new AccessTokenTracker() {
@Override
protected void onCurrentAccessTokenChanged(AccessToken oldAccessToken,
AccessToken currentAccessToken) {
if (currentAccessToken == null) {
user.setFbImage( "");
user.setFbName( "");
myApp .updateUserProgress( user);
}
}
};
share_now = (Button) findViewById(R.id. btn_share_fb );
share_now .setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ShareDialog. canShow (ShareLinkContent. class )) {
Uri uri=Uri. parse ("R.drawable.l10_c0" );
SharePhoto photo = new SharePhoto.Builder()
.setImageUrl(uri)
.setCaption( "Need help! Do you know what car is this?" )
.build();
SharePhotoContent content = new SharePhotoContent.Builder()
.addPhoto(photo)
.build();
shareDialog .show(content);
}
}
});
}

75
@Override
public void onBackPressed() {
super .onBackPressed();
if(sound .isChecked())
user.setSound(1);
else
user .setSound(0);
if(vibration .isChecked())
user.setVibration(1);
else
user .setVibration(0);
myApp .updateUserProgress( user);
}
@Override
protected void onActivityResult( int requestCode, int resultCode, Intent data) {
super .onActivityResult(requestCode, resultCode, data);
callbackManager .onActivityResult(requestCode, resultCode, data);
}
private void makeMeRequest() {
GraphRequest request = GraphRequest. newMeRequest (AccessToken. getCurrentAccessToken (),
new GraphRequest.GraphJSONObjectCallback() {
@Override
public void onCompleted(JSONObject jsonObject, GraphResponse graphResponse) {
if (jsonObject != null) {
try {
Log. e("test" , "Facebook response json : " + jsonObject);
user.setFbImage( "http://graph.facebook.com/" + jsonObject.getString( "id" ) + "/picture" );
user.setFbName(jsonObject.getString( "name" ));
myApp .updateUserProgress( user);
} catch (JSONException e) {
e.printStackTrace();
}
} else if (graphResponse.getError() != null) {
switch (graphResponse.getError().getCategory()) {
case LOGIN_RECOVERABLE :
Log. d("error" ,
"Authentication error: " + graphResponse.getError());
break ;
case TRANSIENT :
Log. d("error" ,
"Transient error. Try again. " + graphResponse.getError());
break ;
case OTHER :
Log. d("error" ,
"Some other error: " + graphResponse.getError());
break ;
}
}
else
Log.d("parse" ,"Null jsonObject " );
}
});
request.executeAsync();
}
private void publishImage(Bitmap car_bitmap) {
SharePhoto photo = new SharePhoto.Builder()
.setBitmap(car_bitmap)
.build();
SharePhotoContent content = new SharePhotoContent.Builder()
.addPhoto(photo)
.build();
ShareApi. share (content, null);
}
@Override
public void onPause() {
if (mAdView != null) {
mAdView .pause();

76
}
super .onPause();
}
@Override
public void onResume() {
super .onResume();
if (mAdView != null) {
mAdView .resume();
}
}
@Override
public void onDestroy() {
if (mAdView != null) {
mAdView .destroy();
}
super .onDestroy();
}
}

Similar Posts