Proiect de diplomă [304631]

Universitatea “Politehnica” [anonimizat] a dispozitivelor inteligente bazate pe platforma Android și asistență la navigare către destinații fixe sau în mișcare

Proiect de diplomă

prezentat ca cerință parțială pentru obținerea titlului de

Inginer în domeniul Inginerie Electronică și Telecomunicații

programul de studii de licență Rețele și Software de Telecomunicații

2017

Copyright © 2017 [anonimizat] a reproduce și de a [anonimizat].

Cuprins

Lista cu Figuri:

Figura 1.1: Arhitectura Android 17

Figura 2.1: Arhitectura sistemului de localizare 22

Figura 2.2: Arhitectura clientului 22

Figura 2.3: Controlul autentificării și autorizării 24

Figura 2.4: Activitatea principală a sistemului (FF) 25

Figura 2.5: Modul secundar. Direcția către o locație dată (FL) 25

Figura 2.6: Modul Google Maps 26

Figura 3.1: Componența bazei de date 27

Figura 3.2: Ierarhia activităților 39

Figura 3.3: Interfața grafică a activității Login 59

Figura 3.4: Interfața grafică a activității Register 60

Figura 3.5: Interfața grafică a activității Meniu 60

Figura 3.6: Interfața grafică a activității MapsActivity 61

Figura 3.7: Interfața grafică a activităților InsertCoord și GetID 61

Figura 3.8: Interfața grafică a activității MainActivity 62

Figura 3.9: Interfața grafică a activității FindLoc 62

[anonimizat] a [anonimizat], a devenit în zilele noastre o necesitate primordială. [anonimizat].

[anonimizat] 190 de țări din lume [1]. [anonimizat], Android oferă numeroase posibilități de dezvoltare atât pentru producătorii de telefoane și dispozitive inteligente cât și pentru dezvoltatorii de software și aplicații.

Proiectul de diplomă cu titlul “Sistem de localizare în timp real a dispozitivelor inteligente bazate pe platforma Android și asistență la navigare către destinații fixe sau în mișcare” a [anonimizat], având un impact uriaș la nivel mondial.

[anonimizat] a [anonimizat], să nu mai știm unde ne aflăm și cum să ajungem la destinația finală.

Aplicația realizată este un sistem care vine în ajutorul persoanelor care doresc să se întâlnească și nu sunt familiarizate cu o [anonimizat] e [anonimizat]. Atunci când nu se cunoaște o locație, există tendința de a [anonimizat]. [anonimizat] o confuzie.

[anonimizat] a [anonimizat], în timp real și oferind asistență la navigare. Destinația poate să fie fixă (o locație anume) sau dispozitivul partener pe care îl presupunem în mișcare. Dispozitivele pot fi telefoane mobile inteligente, tablete, SmartWatch-uri sau orice alt dispozitiv de tipul“HandHeld” [2].

Contribuția practică, originală a proiectului constă în faptul că:

S-a proiectat și implement o aplicație de monitorizare a poziției GPS pentru terminale mobile inteligente, cu sistem de operare Android, pe baza unei arhitecturi client-server.

Aplicația va permite monitorizarea poziției GPS a terminalului mobil cu ajutorul unui API HTTP securizat, precum și navigarea către alte dispozitive mobile aflate în sistem, dar și către destinații fixe prestabilite, cu condiția respectării intimității utilizatorilor și a condițiilor de securitate ale conturilor acestora.

Tema proiectului prezintă noutate prin faptul că, deși în momentul actual există un număr mare de sisteme ce au funcții similare, acestea sunt gândite pentru aplicații diferite și sunt puține cele care dau posibilitatea ca ambele dispozitive să fie în mișcare având localizarea făcută în timp real.

Prin localizarea cu ajutorul GPS-ului telefoanelor mobile ale celor doi parteneri și cu ajutorul interfeței grafice, se arată direcția necesară pentru a micșora distanța dintre ei, economisind timp și evitând o situație neplăcută.

Majoritatea aplicațiilor sunt sisteme care sunt implementate in domeniul militar, inaccesibile publicului larg, care să fie utilizate în viața cotidiană.

Prin realizarea acestui proiect, am urmărit posibilitatea utilizării lui în domeniul medical și social, atât în supravegherea persoanelor bolnave de diabet, inima, Alzheimer etc, dar și în cazurile sociale ca: pierderea copiilor in diferite locații, a persoanelor în excursii, dezorientarea bătrânilor etc.

Structura și implementarea proiectului

In realizarea practică a acestui sistem de localizare s-a implementat:

– Server-ul central de monitorizare și serviciul web pentru interacțiunea cu dispozitivele mobile, precum și baza de date aferentă;

– Interfața grafică de navigare și orientare a utilizatorilor în cadrul aplicației pentru dispozitivele mobile;

– Sistemul de control al accesului utilizatorilor (autentificare) și autorizarea acestora;

– Sistemul de comunicație între utilizatori și transmitere a poziției GPS.

Au fost utilizate următoarele tehnologii sau platforme: Java și PHP, MySQL și arhitectura REST, tehnologie care stă la baza serviciilor web, etc.

Structura lucrării

In cadrul acestui proiect de diploma, capitolele sunt structurate astfel:

Primul capitol prezintă aspectele teoretice ale tehnologiile folosite: realizarea bazei de date (DB) cu ajutorul limbajul SQL, clase Java, limbajul PHP, arhitectura REST bazata pe protocolul HTTP, realizarea interfeței grafice cu ajutorul limbajului XML.

Capitolul al doilea prezintă arhitectura sistemului de localizare în timp real a dispozitivelor inteligente, interacțiunea dintre componentelor hardware și software dar, și interdependența dintre componentele software ce permit funcționarea lui.

Capitolul al treilea prezintă modul de implementare a bazei de date și a serviciului web bazat pe protocolul de comunicație HTTP, prezentarea modului de funcționare a funcțiilor PHP, a codului sursa Java care stă la baza aplicației Android, dar și interfața grafică ce permite interacțiunea cu utilizatorul. Totodată se prezintă și elementele de control și securitate al accesului utilizatorilor, autorizarea lor și modul de protejare a informației.

Capitolul 1: Aspecte teoretice. Tehnologii folosite

În realizarea sistemului de localizare s-a utilizat platforma Android, dezvoltată de Google pe baza nucleul Linux. Acesta permite crearea de aplicații și jocuri inovative pentru dispozitive mobile în limbajul Java [3].

Android este gândit să funcționeze pe un număr mare de dispozitive diferite între ele, el fiind o aplicație de tip ,,open-source”. El este apoi adaptat de producătorii de telefoane mobile pentru echipamentele lor hardware. Se pot adapta anumite resurse pentru a facilita această compatibilitate. De exemplu: se pot crea fișiere grafice XML pentru fiecare dimensiune de ecran și sistemul alege fișierul XML potrivit [3].

Aplicațiile sunt programe software ce extind funcționalitatea dispozitivului și se comportă ca niște utilizatori ai sistemului Linux, fiind izolate între ele [4].

Figura 1.1: Arhitectura Android [5]

În figura 1.1 se poate observa arhitectura unui sistem ce rulează Android. Un program ce are rolul de a crea o interfață între componentele hardware și cele software se numește driver. Nucleul Linux conține toți driverii necesari utilizării componentelor hardware de bază printre care cel de WIFI, GPS, ecran, tastatură, senzori, etc. Urmează nivelul de abstractizare hardware (HAL) ce constă în mai multe tipuri de bilioteci, fiecare implementând o interfață pentru o anumită componentă precum modulele de senzori, bluetooth, interfețe grafice, GPS și altele. El oferă interfețe standard care pun la dispoziție capabilitățile hardware nivelului Java API Framework.

Nivelul Android Runtime se bazează pe nucleul Linux pentru a crea fire de execuție și a gestiona o valoare mică de memorie, fiecare aplicație având propriul proces și propria instanță de Android Runtime. El este gândit să ruleze mai multe mașini virtuale pe dispozitive cu memorie puțină. S-a implementat după versiunea Android 5.0, pâna atunci existând Dalvik. Multe dintre componentele și serviciile sistemului Android, precum HAL și Android Runtime, sunt scrise în limbajele C și C++. Pentru a putea fi accesate și utilizate de către API de pe nivelul superior, s-a introdus nivelul cu librării native C/C++. Tot setul de caracteristici al sistemului de operare Android sunt accesibile prin API scrise în limbajul Java. Aceste API reprezintă blocurile necesare pentru a crea aplicații Android simplificând reutilizarea nucleului, componente și servicii modulare ale sistemului. Printre aceastea se numără: Resource Manager ce permite accesul la resurse ca fișiere grafice, elemente grafice, poze sau fișiere ce conțin informații; Activity Manager ce gestionează ciclul de viață a unei aplicații și ajută cu navigarea în interiorul ei.

Ultimul nivel îl reprezintă aplicațiile. Acestea funcționează pe baza nivelelor inferioare. Aplicația sistemului de localizare numită WhichWayIGo funcționează tot la acest nivel [5].

Dispozitivele moderne Android sunt mult mai mult decât simple platforme ce permit doar simple comunicații sau navigare pe internet. Ele sunt dispozitive extra-senzoriale ce folosesc senzori hadware. Sensor Manager este utilizat pentru a administra senzorii pe dispozitivele Android. Se preferă ca să nu se interacționeze cu senzorii hardware direct. Aceștia sunt reprezentați de obiectele Sensor ce descriu proprietățile senzorului. Printre aceste proprietăți se numără: tipul senzorului, numele, producătorul, precum și detaliile despre precizie și domeniu de valori [6].

Începând cu 2015, Google a decis ca mediul de dezvoltare integrat (IDE) oficial să devină Android Studio. Există și medii de dezvoltare alternative, printre cele mai cunoscute fiind Eclipse și NetBeans. Acestora li se adaugă un plugin specific pentru a putea crea aplicații.

În realizarea acestui proiect s-a utilizat Android Studio, care permite configurarea unui emulator, oferă instrumente de urmărire a performanței aplicației și depanarea ei. Acesta conține un număr mare de biblioteci specifice fiind susținut de Google. În componența lui are și un editor al interfeței ce permite modificarea și plasamentul componentele grafice. Se oferă posibilitatea de a configura un emulator care să simuleze aplicația ce a fost scrisă folosind limbajul Java, dar și urmărirea performanțelor, a utilizării conexiunii la internet, memoria ocupată și multe altele.

Elementele cele mai des utilizate în crearea unei aplicații realizate în Android Studio sunt:

Fișierele ce conțin codul sursă Java,

Fișierul Manifest ce conține AndroidManifest.xml furnizează informațiile generale referitoare la aplicație (activitățile definite, permisiunile, etc),

Fișierele cu resurse ce conțin fișierele grafice XML, șiruri de caractere ale UI, imagini, etc.

Clasa AsyncTask este o clasă abstractă ce este utilizată în implementare, care se extinde și oferă cadrul de bază pentru un proces asincron de lungă durată. Ea conține 3 metode principale:

onPreExecute( ) ce rulează pe firul de execuție principal, pregătește procesul și anunță printr-un mesaj utilizatorul că urmează procesul,

doInBackground( ) rulează pe un alt fir de execuție și conține codul pentru procesul de lungă durată ce trebuie executat,

onPostExecute( ) este apelată când procesul s-a terminat. Lucrează pe firul de execuție principal și primește valorile rezultate de la doInBackground [7].

Fișierele XML definesc în limbaj de marcare XML, interfețele grafice ale aplicației Android. Fiecare dintre acestea conține un container layout. Etichetele XML sunt fragmente din aceste fișiere care sunt utilizate pentru a defini atât tipul containerelor layout, cât și elementele interfeței grafice. Aceste elemente Android le numește widget și există în interiorul containerului layout. Se folosesc etichetele părinte pentru a defini containerul layout și etichetele copil pentru a popula acest container cu widget-urlie interfeței grafice [8]. Astfel, interfața pentru fiecare componentă a aplicației este definită utilizând o ierarhie a obiectelor. Acest arbore ierarhic poate fi simplu sau complex, dar simplitatea oferă cea mai bună performanță [9].

Conexiunea la internet se realizează prin protocolul HTTPS. Pentru a se realiza această conexiune este necesară definirea unei permisiuni în fișierul Manifest (anexa 1.10). Se creează conexiunea utilizând un URL și se întoarce o secvență ce se poate citi. Se pot, de asemenea seta diferiți parametri precum metoda HTTPS utilizată, și altele [10]. Printre metodele cele mai utilizate sunt GET, POST, DELETE, etc. În particular, metoda GET este utilizată în implementarea sistemului. Ea întoarce informația ce este definită de URL. Se poate ca informația întoarsă să fie adăugată în memoriile cache spre deosebire de POST [11]. Protocolul HTTP stă la baza serviciilor web de tipul REST, WDSL, SOAP asigurând transportul de informație.

Serviciile web sunt servere web create cu scopul de a ajuta cu funcționalitățile unui site sau unei aplicații. Programele client utilizează un API pentru a comunica cu serviciile web. Dacă un API respectă stilul arhitectural REST ne rezultă un REST API, acesta constând într-un ansamblu de resurse interconectate. Modul prin care REST API adresează o anumită resursă este prin URI [12]. Arhitectura REST se bazează pe protocolul HTTP pentru a apela o anumită resursă.

Serviciile web REST impun anumite caracteristici în crearea arhitecturii sistemului:

1)Client-Server – Constrângerea principală este reprezentată de separarea și tratarea separată a serverului și a clientului. World Wide Web sau doar Web este un sistem în care clienții și serverele au funcții diferite și se pot implementa folosind orice limbaj de programare sau tehnologie atâta timp cât au o interfață uniformă.

2)Uniform interface – Interacțiunile dintre componentele Web – adică clienții, serverele și alte elemente din rețea – depind de uniformitatea interfețelor lor. Dacă oricare dintre componente se îndepărtează de standardele stabilite, atunci sistemul de comunicații Web se întrerupe.

3)Layered System – Constrângerile de sistem stratificat permit diferitelor elemente intermediare din rețea, cum ar fi proxy-urile și gateway-urile, să fie distribuite în mod transparent între un client și server folosind interfața uniformă a Web-ului. În general, un element intermediar din rețea va intercepta comunicarea client-server cu un anumit scop. Dispozitive din rețea sunt folosite în mod obișnuit pentru a asigura securitatea, cache-ul de răspuns și echilibrarea încărcării.

4)Cache – Pentru a îmbunătăți eficiența rețelei, se adaugă stilului REST contextele cache. Folosirea memoriilor cache pentru salvarea copiilor anumitor resurse reprezintă una dintre cele mai importante constrângeri ale arhitecturii web. Constrângerile de cache instruiesc un server web să declare în ce măsură se poate adăuga în cache datele fiecărui răspuns. Datele de răspuns din cache pot contribui la reducerea latenței percepute de client, la creșterea disponibilității și fiabilității globale a unei aplicații și la controlul încărcării unui server web. Altfel spus, cache-ul reduce costul global al Web-ului. O memorie cache poate exista oriunde de-a lungul căii de rețea între client și server.

5)Stateless – Constrângerea lipsei de stare dictează faptul că un server web nu este obligat să memoreze starea aplicațiilor clientului. În consecință, fiecare client trebuie să includă toate informațiile contextuale pe care le consideră relevante pentru fiecare interacțiune cu serverul web. Serverele web solicită clienților să gestioneze complexitatea comunicării stării aplicației, astfel încât serverul web să poată servi un număr mult mai mare de clienți. Acest compromis este un factor care contribuie la scalabilitatea stilului arhitectural al Web-ului.

6) Code on demand – Web-ul utilizează des codul la cerere, o constrângere care permite serverelor web să transfere temporar către clienți programe executabile, cum ar fi script-uri sau plugin-uri. Codul la cerere tinde să stabilească o legătură tehnologică între serverele web și clienții lor, deoarece clientul trebuie să poată înțelege și executa codul pe care îl descărcă la cerere de la server. Din acest motiv, codul la cerere este singura constrângere a stilului arhitectural Web care este considerată opțională [12].

Modelul web, de tip ,,open source”, cunoscut ca și LAMP conține sistemul de operare Linux, serverul HTTP Apache, sistemul de gestiune a bazelor de date relaționale MySQL și limbajul de programare PHP. Acest model este ușor de implementat și oferă toate funcționalitățile de bază necesare unui server web.

,,PHP (acronim recursiv pentru PHP: Hypertext Preprocessor) este un limbaj de scripting de uz general, cu cod-sursă deschis (open source), utilizat pe scară largă, și care este potrivit în special pentru dezvoltarea aplicațiilor web și poate fi integrat în HTML” [13].

„Codul-sursă PHP este încorporat între niște instrucțiuni de procesare de început și de sfârșit speciale <?php și ?>, care permit intrarea și să ieșirea din "modul PHP". Ceea ce face PHP să difere de un JavaScript de partea clientului este codul, care este executat pe server, generând HTML care este apoi trimis către client. Clientul va primi rezultatele rulării acelui script, fără a putea cunoaște codul-sursă ce stă la bază. Se poate configura serverul web să proceseze toate fișierele HTML cu PHP, și atunci nu există nici o modalitate ca utilizatorii să afle cum funcționează” [13].

PHP este disponibil pentru multe sisteme de operare și pentru serverele web și poate accesa bazele de date cele mai comune, inclusiv MySQL. PHP poate fi rulat ca un program separat sau compilat ca un modul de utilizare cu un server Web [14].

Un API definește clasele, metodele, funcțiile și variabilele pe care aplicația va trebui să le apeleze pentru a-și îndeplini sarcinile dorite. În cazul aplicațiilor PHP care au nevoie să comunice cu bazele de date, API-urile necesare sunt de obicei expuse prin extensii PHP. În MySQL, termenul conector se referă la un software care permite aplicației să se conecteze la serverul de baze de date MySQL. Un driver este un software conceput pentru a comunica cu un anumit tip de server de baze de date. De asemenea, driver-ul poate apela o bibliotecă Aceste biblioteci implementează protocolul utilizat pentru a comunica cu serverul de bază de date MySQL [14].

Baza de date MySQL se poate gestiona fie prin comenzi date în terminal, fie prin instalarea unui program numit phpMyAdmin ce permite administrarea și gestionarea bazei de date. În crearea bazei de date și gestionare ei s-a utilizat a doua metodă.

O greșeală ce se poate face de un dezvoltator de software web este să acorde toata încrederea utilizatorului în introducerea unei comenzi SQL. O comandă SQL inteligent scrisă poate ocoli controalele de acces, în consecință să treacă peste metodele de autentificare și verificările de autorizație, iar câteodată poate chiar să faciliteze accesul la comenzile de sistem. Injectarea directă a comenzilor SQL este o tehnică în care atacatorul creează sau modifică comenzile SQL pentru a scoate la iveală datele sensibile, sau pentru a suprascrie o anumită valoare, sau chiar pentru a executa comenzi periculoase la nivel de sistem. Acest lucru este înfăptuit de către aplicația care preia valoarea de intrare a utilizatorului, îl combină cu parametrii statici pentru a forma o comandă SQL [15].

Capitolul 2: Arhitectura sistemului de localizare

2.1 Descrierea arhitecturii și funcționalitatea modulelor

În realizarea sistemului de localizare în timp real a dispozitivelor inteligente avem nevoie de:

Componente Hardware

Senzor accelerometru

Senzor magnetic

Sistemul GPS al telefonului inteligent

Server cu conexiune la internet

Componente Software

Baza de date

Funcțiile PHP ce permit gestionarea valorilor în DB

Serviciile web ce leagă clientul de DB

Codul sursă al aplicației Android

Interfața grafică a aplicației Android

Elemente de securitate

Telefoanele mobile inteligente vin echipate cu diferite tipuri de senzori, printre care cei mai uzuali sunt accelerometrul, senzorul magnetic, senzorul de proximitate, senzorul de lumina, etc. Sistemul folosește accelerometrul împreună cu senzorul magnetic și cu receptorul GPS pentru realizarea funcției de bază și anume localizarea și afișarea direcției de mers pentru a găsi telefonul partener.

Atunci când accelerometrul detectează mișcare se presupune că s-a schimbat poziția telefonului și se declanșează procedura de actualizare a locației.

Senzorul magnetic este apelat pentru a indica nordul, direcție cardinală ce este folosită ca un reper comun între 2 clienți parteneri, facilitând simplificarea algoritmului de calcul a direcției ce trebuie urmată de parteneri pentru a se găsi.

Serverul web face legătura între clienții sistemului ce se vor conecta la internet pentru a introduce în baza de date locația lor curentă. Pe acest server se găsește baza de date și fișierele cu funcțiile PHP, ce urmează să fie accesate din telefonul inteligent.

Baza de date se folosește ca un mediu comun între telefoanele inteligente. Ea s-a utilizat cu scopul de a obține o centralizare a tuturor informațiilor necesare localizării (coordonate geografice și momentul în care au fost introduse în baza de date), dar și pentru a salva detaliile cu caracter personal al utilizatorilor pentru autentificare.

În continuare este nevoie ca baza de date să poată să fie accesată de un client în vederea autentificării, a introducerii de valori și citirea câmpurilor de interes. În vederea obținerii acestei legături dintre baza de date și client se folosesc niște funcții scrise în limbaj PHP ce realizează funcționalitățile menționate. Se poate astfel defini necesitatea pentru următoarele funcții: Autentificare, Deconectare, Creare de cont nou, Introducerea coordonatelor în baza de date, Citire a coordonatelor telefonului partener din baza de date, Citirea tuturor utilizatorilor.

Aceste funcții sunt scrise în limbajul PHP și conțin operații pe șiruri de caractere și condiții logice de egalitate. Descrierea modului de funcționare a acestor funcții este prezentată în capitolul 3.

Serviciile web alese pentru a permite funcționalitatea sistemului sunt serviciile REST, ce permit un schimb ușor de informații între baza de date și client fiind bazate pe metodele de cerere HTTP.

O componentă software importantă o reprezintă codul sursă al aplicației ce înglobează toate componentele prezentate anterior, făcând posibilă interacțiunea telefonului inteligent cu serverul, localizarea și memorarea poziției geografice prin activarea GPS-ului și apelarea acestuia la un interval constant, calculele bazate pe orientarea dispozitivului în spațiu și navigarea acestuia către locația dorită.

În figura 2.1, este prezentată structura arhitecturii sistemului de localizare. Clienții utilizează protocolul HTTP sau HTTPS pentru a se conecta la server și apelează serviciile REST pentru a se conecta cu baza de date.

Figura 2.1: Arhitectura sistemului de localizare

În figura 2.2, este prezentată arhitectura clientului și se poate observa dependența între codul sursă ce apelează senzorii dispozitivului inteligent pentru a realiza funcționalitatea sistemului cât și afișarea diferitelor informații pentru client, spre exemplu direcția de urmat și distanța până la partener.

Figura 2.2: Arhitectura clientului

Interfața grafică este bazată pe fișierele XML ce se asociază activităților aplicației Android. În acest mod se adaugă toate elementele grafice necesare afișării direcției de urmat și a altor informații referitoare la poziția partenerului cât și editoarele de text ce se folosesc la introducerea de informații ce urmează să fie prelucrate.

Elementele de securitate se referă la măsurile luate pentru a proteja datele cu caracter personal al utilizatorilor, elementele de autentificare și autorizare și nu în ultimul rând la transportul informației printr-un protocol securizat și anume HTTPS.

Sistemul de localizare funcționează cu multe valori, însă cele mai importante sunt: coordonatele geografice, data și ora când acestea au fost introduse în baza de date, ID-ul utilizatorului căruia îi corespund coordonatele, gradul de disponibilitate ce indică posibilitatea ca el să fie localizat de alți utilizatori, informațiile de autentificare și autorizare, dacă un anumit utilizator este sau nu autentificat. Aceste informații se găsesc atât în baza de date cât și în aplicația Android.

În dezvoltarea codului sursă ce rulează pe telefonul clientului s-au definit următoarele 3 moduri de funcționare:

Modul principal: cu un dispozitiv inteligent alegem un partener ce se află la distanță și pe care dorim să îl localizăm. Localizarea se face prin intermediul telefonului inteligent pe care acest partener îl are asupra sa. Se afișează direcția de mers, dar și distanța rămasă până la întâlnirea celor doi. Acesta este referit în lucrare ca FF (FriendFinder).

Modul secundar: se introduc de la tastatură coordonatele geografice a unei locații și se afișează direcția și distanța până la ea, referit în lucrare și ca FL (FindLocation).

Modul Google Maps: prin folosirea API de la Google pentru hărțile lor, aplicația ne arată pe hartă locația curentă și locația telefonului căutat.

Aceste moduri de funcționare sunt bazate pe următoarele 9 activități din aplicația Android:

Login

Register

Logout

Meniu

GetID

MainActivity

InsertCoord

FindLoc

MapsActivity

Activitățile principale ale sistemului de localizare sunt MainActivity, FindLoc și MapsActivity ce corespund celor 3 moduri de funcționare și sunt prezentate împreună cu controlul autentificării și autorizării.

În figura 2.3 se poate observa existența claselor Login, Logout și Register ce exind clasa Activity și clasele AttemptLogin, AttemptLogout și AttemptRegister ce extind clasa AsyncTask, ultima este o clasă ce permite rularea ultimilor 3 pe firul de execuție a interfeței grafice. Aceste 6 clase lucrează împreună în realizează funcțiile de autentificare, deconectare și crearea unui cont nou.

Figura 2.3: Controlul autentificării și autorizării

În figura 2.4 se arată dependența claselor Meniu, GetID, MainActivity de clasa Activity, clasă ce o extind. De asemenea, MainActivity implementează interfata SensorEventListener, interfață ce face posibil accesul la valorile furnizate de senzorii dispozitivului inteligent. Clasa MyLocationListener implementează interfața LocationListener, care permite localizarea telefonului prin GPS.

Figura 2.4: Activitatea principală a sistemului (FF)

În figura 2.5 este prezentat modul secundar de funcționare, mod ce include clasele InsertCoord, Meniu și FindLoc ce extind clasa Activity. Clasa InsertCoord implementează interfața SensorEventListener ce permite obținerea valorilor măsurate de senzori.

Figura 2.5: Modul secundar. Direcția către o locație dată (FL)

În figura 2.6 se observă extinderea clasei FragmentActivity de către clasa MapsActivity și implementarea de către MapsActivity a interfeței OnMapReadyCallback, interfața proprie Google și care permite afișarea hărților și permite un set de funcții specifice.

Figura 2.6: Modul Google Maps

2.2 Cazuri de utilizare

Aplicația privind sistemul de localizare prezentat în lucrare vine în asistența persoanelor care doresc să se întâlnească și care nu sunt familiarizate cu locația în care se află. Pentru a evita furnizarea unor repere generale ori necunoscute de ambele părți, această aplicație îi va ajuta la navigarea reciprocă a unuia către celălalt.

O altă utilizare a aplicației este atunci când cele două persoane se găsesc într-o zonă aglomerată, moment în care mișcarea continuă cât și lipsa unor repere relevante fac imposibilă întâlnirea.

În ultimii ani, acoperirea rețelelor de telefonie mobilă a crescut foarte mult, aceasta incluzând și versanți muntoși. Astfel, în cazul unui accident, fie ca se petrece în zone de șes sau în zone montane greu accesibile, în baza de date va fi memorată ultima locație a telefonului, locație ce va ajuta echipajele de salvare. De asemenea, în cazul unor activități periculoase precum: drumețiile, alpinismul, vâslirea pe ape repezi (eng. „rafting”) și multe altele, sistemul poate fi utilizat ca metoda de precauție și prevenire.

Sistemul de localizare poate fi utilizat și în domeniul medical și social, pentru persoanele bolnave de diabet, boli de inima, Alzheimer, etc ce necesită supraveghere permanentă, dar și în cazurile sociale ca: localizarea copiilor în diferite situații, dezorientarea bătrânilor etc, atâta timp cât presupune existența unui telefon mobil.

O altă utilizare este atunci când se pleacă în grup spre o anumită destinație fie cu mașina sau pe jos. În cazul în care se folosesc mașinile, în zonele urbane aglomerate, șoferii și-ar dori să știe unde sunt restul persoanelor din grup, aplicația venind în ajutorul lor. Același lucru în cazul excursioniștilor.

Capitolul 3: Sistemul de localizare

3.1 Baza de date și serviciile web

În realizarea sistemului, așa cum este menționat in capitolul 2, este necesară existența unui Server care să conțină o bază de date necesară stocării de informații și să permită accesul clienților la un anumit set de funcții asupra ei. Din motive administrative și de securitate este permisă clienților modificarea anumitor câmpuri și există condiții de securitate implementate pentru a menține integritatea sistemului.

Se instalează pe un calculator conectat la internet modelul web, de tip ,,open source”, cunoscut ca și LAMP, ce conține sistemul de operare Linux, serverul HTTP Apache, sistemul de gestiune a bazelor de date relaționale MySQL și limbajul de programare PHP, calculator ce va fi numit acum server web.

Baza de date MySQL se poate gestiona fie prin comenzi date în terminal, fie prin instalarea unui program numit phpMyAdmin ce permite administrarea și gestionarea bazei de date. În crearea bazei de date și gestionare ei s-a utilizat a doua metodă. Structura DB se găsește în anexa 4.

În figura 3.1 se poate observa baza de date ce va fi folosită în continuare numită „localizare” și conținutul ei format din două tabele:

Tabela ,, utilizatori”

Tabela ,, poziții”

Figura 3.1: Componența bazei de date

Tabela utilizatori memorează informații despre client, ori de câte ori se realizează înregistrarea unui cont nou sau când se realizează autentificarea și autorizarea. În această tabelă se regăsesc informații privind datele cu caracter personal ale utilizatorilor, precum câmpurile:

ID este câmpul ce identifică unic fiecare utilizator în parte și după care se face căutarea și alegerea telefonului partener,

NickName este numele pe care clientul îl setează în momentul înregistrării,

Pass reprezintă parola pe care utilizatorul a introdus-o în momentul înregistrării,

Login este un câmp ce ne arată dacă respectivul utilizator este autentificat sau nu.

Tabela poziții memorează informații referitoare la coordonatele geografice ale utilizatorilor atunci când baza de date primește aceste date de la aplicația Android. În această tabelă se găsesc următoarele câmpuri:

ID are aceleași funcții ca și în tabela utilizatori,

Latitudine,

Longitudine,

DataTimp reprezintă data și ora când informațiile au fost introduse în baza de date,

NickName reprezintă același nume care a fost introdus de client și are aceeași valoare ca și câmpul din tabela utilizatori,

Status este un câmp ce arată disponibilitatea unui client de a fi găsit. Valoarea de 0” reprezintă modul Invizibil și ”1” modul Vizibil.

În realizarea legăturii clientului cu baza de date este necesară existența unor servicii web. Serviciile web alese pentru a permite funcționalitatea sistemului sunt serviciile REST, ce permit un schimb ușor de informații între baza de date și client fiind bazate pe metodele de cerere HTTP. Prin intermediul arhitecturii REST se interoghează și se lansează cereri serverului web. Metoda HTTP aleasă este ,,GET” fiind metoda utilizată pentru a obține o resursă de la server fără a oferi un volum mare de informații pentru a fi procesate. Fiecare cerere este identificată prin URL și informația este transmisă pentru a fi introdusă în baza de date sau în cazul descendent, înregistrarea din DB cerută prin cerere este găsită și serverul răspunde clientului Android cu informația cerută.

Metoda ,,GET” transmite informații prin adăugarea la sfârșitul URL-ului a datelor ce se doresc a fi transmise. Lungimea unui URL este limită la 2048 de caractere și din acest motiv metoda ,,GET” are un volum de informații limitat. În cazul transmisiunii de informație de la clientul Android la baza de date, nu există necesitatea de a transmite mai multă informație decât această limită.

În momentul realizării unei cereri a unui serviciu, către serverul web, de către aplicația Andoid, nu se memorează contextul în care această accesare s-a realizat. Cererea pentru un anumit serviciu conține toată informația necesară pentru a funcționa serviciul web apelat. În acest caz nu este necesară memorarea contextului unei cereri pentru a avea o sesiune interactivă cu utilizatorul cum se întâmplă în alte cazuri. Astfel nu se alocă memorie dinamic pentru a memora și gestiona informațiile și starea unui client pe parcursul a mai multor cereri. Acest lucru este de dorit pentru că în anumite utilizări ale sistemului, precum cele de salvare, este necesară o introducere în baza de date a coordonatelor cât mai rapid și simplu. Introducerea se face astfel printr-un singur mesaj și trebuie să nu depindă de mesajele anterioare. În cazul în care conexiunea la internet fluctuează, cum se poate întâmpla în zonele montane din cauza reliefului, a lipsei de antene de transmisie/recepție ce ar oferi suficientă acoperire, ar putea să nu se realizeze încărcarea locației dintr-un singur mesaj, situație ce ar putea produce implicații tragice.

În cazul unei cereri, răspunsurile primite de către dispozitivul inteligent de la server, sunt salvate în memoriile cache ale diferitelor echipamente de rețea intermediare. Informațiile sunt transmise prin intermediul URL, iar răspunsul este format dintr-un număr mic de caractere. Conexiunea este făcută prin metoda GET a protocolului HTTP și permite unor anumite copii ale acestor informații să fie salvate prin memoriile cache ale rețelelor, cu scopul reducerii traficului și a încărcării serverului.

Un utilizator când face o cerere către o informație din baza de date nu cunoaște dacă acel server este serverul final sau dacă este legat la un server intermediar. Acest lucru folosește la o distribuire a cererilor pe mai multe servere intermediare, reducând încărcarea serverului final. Serverele intermediare pot fi structurate ierarhic și oferă funcții și servicii nivelelor superioare. În implementarea sistemului de localizare este utilizat un singur server datorită numărului redus de utilizatori creând o încărcare mică pentru acesta.

O caracteristică a arhitecturii REST este că în unele cazuri un server poate să extindă sau să personalizeze funcționalitatea aplicației clientului transferând cod executabil, dar nu este utilizat în toate cazurile. Modul în care sistemul de localizare este proiectat, nu utilizează aceasta caracteristică deoarece tot codul necesar este inclus în aplicația Android.

Interfața grafică uniformă simplifică sistemul și permite o dezvoltare ulterioară independentă a fiecărei componente în parte a arhitecturii [12].

În implementarea serviciilor REST se folosește limbajul PHP care realizează conexiunea și schimbul de informații dintre clientul Android și server. Fișierele realizate sunt următoarele:

Settings – conține setările de bază,

Datacon – realizează conexiunea la baza de date aflată pe server,

PutPosition – introduce o nouă locație în baza de date,

GetPosition – citește o anumită înregistrare și o trimite ca răspuns la aplicația Android,

GetIDs – răspunde cu o listă a ID-urilor și NickName-ul aferent,

Login,

Logout,

Register.

Fișierul Settings

Acesta conține setările de bază.

$MySqlHostname = "localhost";

$MySqlUsername = "********";

$MySqlPassword = "********";

$db = "localizare";

În acest fișier sunt declarate ca variabile hostname-ul serverului, numele de utilizator, parola acestuia și numele bazei de date apelată. Numele de utilizator și parola se referă la accesul în baza de date pentru a avea posibilitatea de a modifica și introduce informație. Acestea sunt diferite de ID și Pass care sunt informațiile de autentificare a clienților către conturile lor.

$row1BgColor = "#FFFFFF";

$row2BgColor = "#C0C0C0";

$dbConnectionFile = "include(\"datacon.php\");";

Sunt declarate două variabile care reprezintă culorile rândurilor din DB. O ultima variabilă este setată să includă fișierul de conexiune a bazei de date ,,datacon.php”.

Fișierul datacon

Prin intermediul acestui fișier se realizează conecțiunea la baza de date:

include("settings.php");

$dblink=MYSQL_CONNECT($MySqlHostname, $MySqlUsername, $MySqlPassword) OR DIE("Unable to connect to database");

În acest fișier se include fișierul ,,Settings” și se creează o variabilă care realizează legătura către baza de date numită ,,dblink”. Se folosesc informațiile de autentificare pentru baza de date, definite în fișierul ,,settings”. În cazul în care nu se poate realiza conexiunea, se afișează un mesaj de eroare și se iese din script.

@mysql_select_db("$db") or die( "Unable to select database");

În cazul în care conexiunea se realizează, se selectează baza de date definită în fișierul ,,settings.php”, iar dacă eroarea se produce în acest stadiu, se afișează mesajul de eroare prezentat și se iese din script.

Fișierul PutPosition

Această funcție este apelată din aplicația Android printr-un URL pentru a introduce în baza de date poziția dispozitivului curent. De exemplu pentru următorul URL, valorile conținute de acesta sunt:

http://xxx.xxx.xxx.xxx/FF/putPosition.php?id=7&n=Alex&La=50&Lg=25&st=1

ID=7

NickName=,,Alex”

Latitudine= 50

Longitudine= 25

Status=1

Valoarea ,,xxx.xxx.xxx.xxx” reprezintă adresa IP a unui server privat. Dacă câmpul login din tabela utilizatori este egal cu “1” atunci valorile sunt introduse. În caz contrar se ignora cererea.

include("datacon.php");

$cuvant=$_GET['id'];

$nick=$_GET['n'];

$lat=$_GET['La'];

$lon=$_GET['Lg'];

$st=$_GET['st'];

Fișierul include ,,datacon.php” pentru a realiza conexiunea la baza de date și preia din URL apelat din aplicație, valorile menționate mai sus pe care le salvează în niște variabile.

banlist = array

(

"insert", "select", "update", "delete", "distinct", "having", "truncate", "replace", "handler", "like", "as", "or", "procedure", "limit", "order by", "group by", "asc", "desc"

);

Se creează o matrice cu toate comenzile SQL în vederea realizării unei testări împotriva unui posibil atac asupra bazei de date, în care se încearcă injectarea de comenzi SQL.

if ( eregi ( "[a-zA-Z0-9]+", $cuvant ) )

{

$cuvant = trim ( str_replace( $banlist,'', strtolower ( $cuvant )));

}

else

{

$cuvant = NULL;

}

Dacă se primește un ID, de format text sau numeric, se elimină spațiile albe și toate eventualele comenzile SQL ce sunt memorate în matrice și care ar putea fi primite prin această valoare. Valoarea ID este apoi convertită în litere minuscule. În cazul în care valoarea primită prin ID nu este text, se setează implicit ca NULL.

$query = "select login from utilizatori where ID=$cuvant";

$result = MYSQL_QUERY($query);

if ($result==1)

{

$queryselect = "select * from pozitii where ID=$cuvant";

$resultselect = MYSQL_QUERY($queryselect);

$numbersearchselect = mysql_Numrows($resultselect);

if ($numbersearchselect>0)

{

$querysearch = "update pozitii set DataTimp=now(),Latitudine=$lat, Longitudine=$lon, Status=$st where ID=$cuvant";

$resultsearch = MYSQL_QUERY($querysearch);

}

else

{

$querysearch = "insert into pozitii (DataTimp,ID,NickName,Latitudine,Longitudine,Status) VALUES (now(),$cuvant,'$nick', $lat, $lon,$st)";

$resultsearch = MYSQL_QUERY($querysearch);

}

}

Se face o interogare a valorii Login din tabela utilizatori. Dacă aceasta este ,,0” cererea se ignoră, iar dacă aceasta este ,,1” în continuare se generează o interogare a bazei de date unde se selectează toate câmpurile din tabela poziții pentru înregistrarea cu valoarea ID.

Dacă există cel puțin un câmp selectat, atunci se realizează o interogare în care se actualizează pentru această înregistrare data și ora, latitudinea, longitudinea și disponibilitatea. În cazul în care nu există nici un câmp selectat, atunci se introduce informațiile menționate mai sus ca o înregistrare nouă în tabela poziții.

Această funcție introduce ultima valoare transmisă către server, valori ce reprezintă în momentul respectiv informațiile despre ultima poziție cunoscută a respectivului client.

Fișierul GetPosition

Această funcție este apelată din aplicația Android printr-un URL ce conține ID-ul corespunzător dispozitivului partener. Forma acestui URL este:

http://xxx.xxx.xxx.xxx/FF/getPosition.php?id=45

Funcția ,,getPosition.php” selectează din tabela poziții înregistrarea corespunzătoare a ID-ului și întoarce aplicației informațiile despre ultima poziție cunoscută a telefonului partener. Acestea sunt următoarele:

Latitudine

Longitudine

Status

DataTimp

include("datacon.php");

$cuvant=$_GET['id'];

Fișierul include ,,datacon.php” pentru a realiza conexiunea la baza de date și preia din URL-ul apelat din aplicație, valoarea ID-ului cerut ce va fi salvată într-o variabilă.

Ca și în cazul lui ,,putPosition”, deoarece utilizatorul este cel ce introduce valoarea ID este necesară o verificare împotriva injectării de comenzi SQL. Se definește o matrice similară ca în cazul precedent. Aceasta se poate vedea în anexa 3.7.

if ( eregi ( "[a-zA-Z0-9]+", $cuvant ) )

{

$cuvant = trim ( str_replace( $banlist,'', strtolower ( $cuvant )));

}

else

{

$cuvant = NULL;

}

În cazul în care valoarea primită prin ID este un caracter alfanumeric, se elimină spațiile albe și toate posibilele comenzile SQL ce pot fi transmise prin ID, acesta fiind comparat cu comenzile memorate în matrice. Valoarea ID este apoi convertită în litere minuscule. În cazul în care valoarea primită prin ID nu este text, se salvează variabila ce primește valoarea ID ca NULL.

$querysearch = "select Latitudine,Longitudine,Status, MAX(DataTimp) from pozitii where ID=$cuvant";

$resultsearch = MYSQL_QUERY($querysearch);

$numbersearch = mysql_Numrows($resultsearch);

În continuare se generează o interogare a bazei de date unde se selectează pentru un ID din tabela poziții valorile latitudine, longitudine, status, dataTimp.

if ($numbersearch>0)

{

$x=0;

while ($x<$numbersearch)

{

$rom=mysql_result($resultsearch,$x,"Latitudine");

echo $rom; ?>,<?

$eng=mysql_result($resultsearch,$x,"Longitudine");

echo $eng; ?>,<?

$st=mysql_result($resultsearch,$x,"Status");

echo $st; ?>,<?

$dt=mysql_result($resultsearch,$x,3);

echo $dt;

$x++;

} // end while

$exista='D';

} // end if

else

{

$exista='N';

}

mysql_free_result($resultsearch);

Dacă interogarea a întors cel puțin o înregistrare, atunci se inițializează o variabilă x=0 ce contorizează câmpurile, urmând să se creeze o bucla while ce va lua fiecare câmp întors de BD și îl va salva într-o variabilă. Va afișa valorile câmpurilor separate printr-o virgulă. Când s-a terminat bucla, variabila exista va indica că s-a obținut o înregistrare. În cazul opus, această variabilă va indica că interogarea bazei de date nu a oferit nici o înregistrare ca răspuns. În final se eliberează variabila ce a conținut interogarea.

Fișierul GetIDs

Această funcție este apelată identic ca și cele prezentate precedent printr-un URL pentru a selecta din baza de date toate ID-urile și NickName-urile. Forma URL-ului este următoarea:

http:// xxx.xxx.xxx.xxx/FF/getIDs.php

Fișierul ,,getIDs.php” include ,,datacon.php” pentru a realiza conexiunea la baza de date.

$querysearch = "select distinct ID,NickName from pozitii";

$resultsearch = MYSQL_QUERY($querysearch);

$numbersearch = mysql_Numrows($resultsearch);

Se realizează creează o interogare a bazei de date unde se selectează câmpurile ID și NickName din tabela poziții.

if ($numbersearch>0)

{

$x=0;

while ($x<$numbersearch)

{

$rom=mysql_result($resultsearch,$x,"ID");

echo $rom; echo ", ";

$eng=mysql_result($resultsearch,$x,"NickName");

echo $eng;

$x++;

} // end while

$exista='D';

} // end if

else

{

$exista='N';

}

mysql_free_result($resultsearch);

Dacă interogarea a întors cel puțin o înregistrare, atunci se inițializează un contor x=0, urmând bucla while ce va lua fiecare pereche de câmpuri ID și NickName întors de BD și salvează fiecare într-o variabilă. Aceste valori vor fi afișate separate prin rânduri și virgule. Când s-a terminat bucla, variabila exista va indica că s-a obținut o înregistrare. În cazul opus, această variabilă va indica că interogarea bazei de date nu a oferit nici o înregistrare ca răspuns. În final se eliberează variabila ce a conținut interogarea.

Fișierul Login

Funcția ,,login.php” se ocupă cu cererea de autentificarea a unui utilizator și cu autorizarea acestuia. Este apelată printr-un URL ce conține ID-ul și Pass-ul ce corespund dispozitivului partener. De exemplu pentru următorul URL, valorile conținute de acesta sunt:

http:// xxx.xxx.xxx.xxx/FF/login.php?id=31&pass=qwe

ID=31

Pass= ,,qwe”

include("datacon.php");

$cuvant=$_GET['id'];

$pass=$_GET['pass'];

Fișierul include ,,datacon.php” pentru a realiza conexiunea la baza de date și preia din URL valorile menționate mai sus pe care le salvează în niște variabile.

Se creează o matrice cu toate comenzile SQL în vederea realizării unei testări împotriva injectării de comenzi SQL. Această matrice se găsește în anexa 3.3. Este important să nu se poată accesa baza de date prin această metodă deoarece se poate evita securitatea și accesa conturile tuturor utlizatorilor.

if ( eregi ( "[a-zA-Z0-9]+", $cuvant ) )

{

$cuvant = trim ( str_replace( $banlist,'', strtolower ( $cuvant )));

}

else

{

$cuvant = NULL;

}

Similar ca și în cazul funcției ,,putPosition.php”, dacă se primește un ID, de format text sau numeric, se elimină spațiile albe și toate eventualele comenzile SQL ce sunt memorate în matrice și care ar putea fi primite prin această valoare. Valoarea ID este apoi convertită în litere minuscule. În cazul în care valoarea primită prin ID nu este text, se setează implicit ca NULL.

$queryselect = "select * from utilizatori where ID=$cuvant AND pass='$pass'";

$resultselect = MYSQL_QUERY($queryselect);

$numbersearchselect = mysql_Numrows($resultselect);

În continuare se selectează din baza de date toate câmpurile din tabela utilizatori unde înregistrarea conține valorile ID și Pass primite prin intermediul URL.

if ($numbersearchselect>0)

{

$querysearch = "update utilizatori set login=1 where ID=$cuvant";

$resultsearch = MYSQL_QUERY($querysearch);

echo("1");

}

else

{

echo("0");

}

În cazul în care există cel puțin un câmp selectat, atunci se realizează o interogare în care se setează pentru această înregistrare câmpul Login cu ,,1” din tabela utilizatori și se întoarce o valoare ,,1” către aplicația Android ce semnifică o autentificare realizată cu succes. În cazul în care nu există o înregistrare cu ID și Pass introduse, atunci se întoarce valoarea ,,0”, autorizare eșuată.

Fișierul Logout

Această funcție se ocupă cu cererea de deconectare a unui utilizator. Similar ca la funcția ,,login.php” este apelată printr-un URL ce conține ID-ul și Pass-ul ce corespund dispozitivului partener. Forma URL este următoarea:

http://xxx.xxx.xxx.xxx/FF/logout.php?id=19&pass=rty

Informațiile ce sunt transmise prin intermediul acestui URL sunt:

ID=19

Pass= ,,rty”

include("datacon.php");

$cuvant=$_GET['id'];

$pass=$_GET['pass'];

Fișierul include ,,datacon.php” pentru a realiza conexiunea la baza de date și preia din URL valorile ID si Pass, pe care le salvează în niște variabile.

if ( eregi ( "[a-zA-Z0-9]+", $cuvant ) )

{

$cuvant = trim ( str_replace( $banlist,'', strtolower ( $cuvant )));

}

else

{

$cuvant = NULL;

}

Se creează matricea cu toate comenzile SQL împotriva injectării de comenzi SQL (anexa 3.4). Similar funcțiilor precedente, dacă se primește un ID, de format alfanumeric, se elimină spațiile albe și toate eventualele comenzile SQL memorate în matricea banlist. Valoarea ID este apoi convertită în litere minuscule. În cazul în care valoarea primită prin ID nu este text, se setează variabila utilizată pentru memorarea ID-ului ca NULL.

$queryselect = "select * from utilizatori where ID=$cuvant AND pass='$pass'";

$resultselect = MYSQL_QUERY($queryselect);

$numbersearchselect = mysql_Numrows($resultselect);

Se selectează din baza de date toate câmpurile din tabela utilizatori unde înregistrarea conține valorile ID și Pass primite prin intermediul URL.

if ($numbersearchselect>0)

{

$querysearch = "update utilizatori set login=0 where ID=$cuvant";

$resultsearch = MYSQL_QUERY($querysearch);

}

else

{}

Dacă există un câmp selectat, atunci se creează o cerere în care se setează pentru aceasta înregistrare câmpul Login cu ,,0” din tabela utilizatori ce semnifică o deconectare realizată cu succes. Spre deosebire de ,,login.php” nu este necesară transmiterea unui răspuns către aplicația Android dacă deconectarea s-a realizat cu succes sau nu. Utilizarea parolei pentru deconectarea clientului se face ca o măsura se securitate.

Fișierul Register

Această funcție este apelată din aplicația Android printr-un URL pentru a introduce în baza de date toate informațiile necesare atunci când un utilizator își creează un cont. De exemplu pentru următorul URL, valorile conținute de acesta sunt:

http://xxx.xxx.xxx.xxx/FF/register.php?id=92&n=Ana&pass=ghj

ID=92

Nickname= ,,Ana”

Pass= ,,ghj”

include("datacon.php");

$cuvant=$_GET['id'];

$nick=$_GET['n'];

$pass=$_GET['pass'];

Similar cazurilor precedente, fișierul include ,,datacon.php” pentru a realiza conexiunea la baza de date și preia din URL apelat din aplicație valorile menționate mai sus pe care le salvează în niște variabile.

banlist = array

(

"insert", "select", "update", "delete", "distinct", "having", "truncate", "replace", "handler", "like", "as", "or", "procedure", "limit", "order by", "group by", "asc", "desc"

);

Se creează matricea cu toate comenzile SQL necesară măsurilor de securitate (împotriva injectării de comenzi SQL).

if ( eregi ( "[a-zA-Z0-9]+", $cuvant ) )

{

$cuvant = trim ( str_replace( $banlist,'', strtolower ( $cuvant )));

}

else

{

$cuvant = NULL;

}

Ca și în cazul funcțiilor precedente, dacă se primește un ID, de format alfanumeric, se elimină spațiile albe și toate eventualele comenzile SQL memorate în matricea banlist. Valoarea ID este apoi convertită în litere minuscule. În cazul în care valoarea primită prin ID nu este text, se setează variabila utilizată pentru memorarea ID-ului ca NULL.

$queryselect = "select * from utilizatori where ID=$cuvant";

$resultselect = MYSQL_QUERY($queryselect);

$numbersearchselect = mysql_Numrows($resultselect);

În continuare se selectează din baza de date toate înregistrările din tabela utilizatori ce conține valoarea ID primite prin intermediul URL-ului.

if ($numbersearchselect>0)

{

echo("exista");

}

else

{

$querysearch = "insert into utilizatori (ID,NickName,pass,login) VALUES ($cuvant,'$nick', '$pass',0)";

$resultsearch = MYSQL_QUERY($querysearch);

}

Atunci când există cel puțin un câmp selectat, se întoarce textul ,,exista” către aplicația Android pentru a anunța clientul să aleagă alte date de autentificare. Atunci când nu există nici un câmp selectat, se realizează o cerere în care se introduce în tabela utilizatori valorile primite prin intermediul URL-ului, setând implicit utilizatorul ca neautentificat.

3.2 Aplicația Android

Aplicația Android reprezintă componenta software ce este instalată pe dispozitivul inteligent al clientului. Ea este formată din 9 activități:

Login

Logout

Register

Meniu

GetID

MainActivity

InsertCoord

FindLoc

MapsActivity

Activitățile principale ale sistemului de localizare sunt MainActivity, FindLoc și MapsActivity ce corespund celor 3 moduri de funcționare și sunt prezentate în continuare împreună cu controlul autentificării și autorizării.

Ca punct de pornire a fost o busolă, ce a furnizat funcțiile pentru interogarea senzorilor și afișarea pe interfața grafică a direcției către nordul magnetic. Această aplicație Android de tip ,,open source” a fost în continuare modificată pentru optimizare și pentru a integra toate componentele sistemului [16].

Figura 3.2: Ierarhia activităților

În figura 3.2 se prezintă ierarhia activităților pornind de la Login, prima activitate apelată în momentul pornirii aplicației. Se indică prin săgeți modul în care se realizează tranziția de la o activitate la alta. Fiecare dintre cele 9 activități prezentate are propriul fișier grafic ceea ce înseamnă că fiecare dintre ele reprezintă în același timp un ecran diferit al aplicației. Modul prin care aceste activități implementează interfețele sistemului este arătat în capitolul 2 al lucrării.

Se va prezenta alcătuirea claselor și metodele ce sunt conținute de acestea precum și modul de funcționare. Fiecare activitate este salvată sub un fișier Java sub aceeași nume, conține cel puțin o clasă și are atașat un fișier grafic prin intermediul căruia va afișa diferite informații și animații.

Activitatea Login

În momentul lansării aplicației, aceasta este prima activitate ce este încărcată urmând ca apoi să aștepte intervenția utilizatorului. Cele două clase componente ale activității ,,Login.java” sunt numite ,,Login” și ,,AttemptLogin”.

În clasa Login sunt inițializate butoanele, editoarele de text, variabila pass ce va fi utilizată pentru memorarea parolei, variabila m pentru răspunsul funcției ,,login.php” și variabila k ce numără de câte ori s-a realizat încercarea de autentificare. În continuare, metoda onCreate definește fișierul grafic XML numit activity_login și stabilește legătura între elementele grafice ale fișierului XML și variabilele din interiorul codului ce urmează să primească sau să furnizeze valori pentru afișare.

În momentul în care butonul este apăsat, atunci se salvează iD-ul și parola și se pornește firul de execuție AttemptLogin. Dacă funcția ,,login.php” a autorizat accesul, atunci prin variabila m va avea valoarea ,,1” și realizăm o accesarea a clasei Meniu, a activității cu același nume. Se oprește în acest caz activitatea Login. Dacă m are valoarea ,,0”, atunci apare afișat că informațiile de autentificare sunt greșite și se decrementează variabila k ce numără încercările nereușite. Atunci când variabila k atinge valoarea ,,0” se dezactivează butonul Login și nu se mai permite accesul.

Butonul Cancel oprește activitatea Login și închide aplicația atunci este apăsat. Butonul Register resetează variabila pass dintr-o posibilă valorare rămasă în editorul de text, în null, apoi el realizează apelul activității Register prin clasa ce îi poartă numele. Tot el oprește activitatea Login pentru a nu consuma resursele dispozitivului.

Această metodă suprascrie metoda implicită de revenire la ecranul precedent atunci când se apasă butonul Back al telefonului. În această configurație dacă se deconectează un utilizator și se dorește introducerea altor date de autentificare, pentru un cont diferit, o apăsare greșită pe butonul Back nu va retrimite la ecranul Meniu sau alt ecran ce a fost accesat înainte. Aceasta este una din măsurile de securitate și de bună funcționare a aplicației care asigură în același timp și ierarhia activităților prezentată la figura 3.2.

Clasa AttemptLogin extinde clasa AsyncTask, clasă ce este necesară pentru că ea rulează pe firul de execuție grafic și poate fi apelată din interiorul codului pentru butonul Login. Aceasta face posibil transferul de informație de la aplicație la server și primirea răspunsului referitor la autentificare.

Metoda doInBackground este specifică clasei AsyncTask și ea realizează conexiunea server și apelarea funcției ,,login.php”. Se declară USER_AGENT, variabilă ce este folosită pentru ca aplicația să fie văzută ca un browser de pe un calculator obișnuit și serverul astfel ne trimite versiunea normală a paginii web. În caz contrar ar trebui definită o versiune specifică telefoanelor sau dispozitivelor mobile. Se creează adresa ce trebuie apelată, se setează conexiunea HTTP și este setată transmiterea informației prin intermediul metodei GET. Valoarea ,,xxx.xxx.xxx.xxx” reprezintă adresa IP a unui server privat. Redirecționarea nu este dorită, deoarece ea este realizată atunci când clientul nu a completat toată cererea, în cazul nostru, sunt prezente toate informațiile necesare. În final se realizează conexiunea. Având în vedere că serverul are certificatele SSL expirate, este necesară o funcție care să permită validarea lor, pentru ca aplicația să funcționeze cu protocolul HTTP securizat. Metoda care realizează acest lucru este ,,trustAllCertificates” [17]. În cazul unui server web ce conține certificate valide, se poate folosi protocolul HTTPS și această metodă nu va fi necesară.

Se crează un buffer pentru a primi informația de la server urmând apoi ca ea să fie citită linie cu linie și să fie salvată în variabila line. Din cauza funcțiilor PHP care transmit informația cu linii goale și spații variabile, fiecare linie ce conține informație este reținută în variabila raspuns. Valoarea raspuns este apoi salvată pentru prelucrări ulterioare.

În final, răspunsul la apelul funcției PHP este salvat în variabila m și trimis către clasa Login prin intermediul metodei onPostExecute. În acest caz nu este necesară informarea utilizatorului de progresul pe care metoda doInBackground îl face așa că metoda onProgressUpdate va rămâne nefolosită.

Activitatea Logout

Similar activității precedente, Logout conține și ea două clase: Logout și AttemptLogout. Această activitate este apelată prin intermediul butonului aflat în activitatea Meniu.

În clasa Logout este inițializată variabila passLogout, ce primește în momentul autentificării parola introdusă în clasa Login urmat apoi de declararea metodei onCreate în care se setează fișierul grafic.

Se definesc două butoane, primul fiind butonul Cancel (anexa 1.2). Atunci când este apăsat trimite la activitatea Meniu prin apelarea clasei cu același nume, apoi închide și eliberează memoria ocupată de activitatea Logout. Al doilea buton este cel numit Logout în care se apelează clasa AttemptLogout, clasă ce lucrează pe firul de execuție al interfeței grafice la fel ca în cazul activității Login. Se afișează un mesaj pe ecran și se pornește clasa Login, urmând ca apoi activitatea Logout să se oprească. Este necesar ca butonul Back să fie dezactivat pentru a menține navigarea corectă a activităților ca și în cazul precedent.

Clasa AttemptLogout realizează deconectarea unui utilizator. Ea extinde clasa AsyncTask și conține aceleași metode care sunt implementate automat odată cu extinderea clasei AttemptLogin. Este pornită prin apelarea în cadrul butonului Logout și funcționează pe firul de execuție al interfeței grafice.

Metoda doInBackground conține conexiunea la baza de date și apelarea funcției ,,logout.php”. Se crează USER_AGENT ca și în cazul precedent. Se generează adresa ce trebuie apelată utilizând toate variabilele necesare transmiterii către server. Se seteză apoi conexiunea HTTP, ca și în cazul activității precedente și este verificată realizarea acesteia. În cazul unei excepții se creează o înregistrare. În cazul unei funcționări normale, clasa întoarce un mesaj ce arată că procesul s-a realizat cu succes.

Activitatea Register

Activitatea Register conține și ea două clase numite Register și AttemptRegister. Ea este apelată prin butonul Register existent în ecranul activității Login și este utilizată pentru crearea unui cont nou.

În clasa Register sunt declarate 2 variabile de tip șir de caractere împreună cu 4 editoare de text în care utilizatorul să își introducă datele personale.

În continuare este definită metoda onCreate, metodă care este implicit prima apelată atunci când s-a făcut trimiterea către o activitate.

Se definește fișierul grafic și se setează elementele grafice care urmează să preia informațiile introduse de client. Aceste elemente se pot vizualiza în anexa 1.3. Se setează butonul Register și atunci când este apăsat, valorile introduse în editoarele de text sunt salvate în variabile. În continuare se face o verificare ca cele 2 parole să fie identice și se pornește clasa AttemptLogin. Variabila val este întoarsă apoi pentru a face o ultimă decizie. Dacă ea este nulă, se afișează un mesaj pe ecran și se apelează clasa Login pentru autentificare după crearea contului, urmând ca activitatea curentă, și anume Register, să se închidă. În cazul contrar, se afișează pe ecran un mesaj ce indică existența unui cont cu același ID în baza de date (subcapitolul 3.1, fișierul Register) și se așteaptă introducerea unui ID diferit.

Clasa AttemptRegister extinde clasa AsyncTask și rulează pe firul de execuție al interfeței grafice. Aceasta întoarce prin intermediul funcțiilor specifice, valoarea ,,exista” sau null. Aceste valori depind de baza de date și mai exact, dacă există deja o înregistrare în DB cu același ID. Modul cum se face această verificare este prezentat în subcapitolul 3.2 fișierul Register.

Se declară variabila val ce va memora răspunsul serverului și va fi valoarea întoarsă de clasa doInBackground.

Similar se declară variabila USER_AGENT ce urmează a fi utilizată în realizarea conexiunii prin protocolul HTTP. Se generează URL-ul necesar introducerii în baza de date a valorilor introduse în editoarele de text, din clasa Register, urmând ca apoi să se realizeze conexiunea.

În cazul în care conexiunea s-a realizat corect, se creează un buffer pentru memorarea răspunsului primit de la server. Se realizează prelucrarea șirului de caractere primit, șir ce poate conține un număr de linii și spații albe. În final se salvează informația și este trimisă către onPostExecute pentru a putea să fie întoarsă firului de execuție principal.

Activitatea Meniu

Activitatea Meniu este cea care realizează legătura între cele 3 moduri de funcționare a sistemului și în același timp conține butonul pentru deconectarea utilizatorului. Ea conține o singură clasă spre deosebire de cele 3 activități precedente având numele Meniu.

În metoda onCreate sunt definite 4 butoane către activitățile principale ale sistemului, trecând în cazul lui MainActivity și FindLoc prin unele intermediare. Butonul prezentat mai sus este numit FF și trimite către clasa GetID, unde se poate alege un client al sistemului pentru a fi localizat. Se afișează un mesaj pe ecran și se oprește activitatea.

Similar se realizează și în cazul celorlalte 3 butoane. Trimiterea către clasa InsertCoord se face prin intermediul butonului FL pentru a accesa modul secundar de funcționare și anume obținerea direcției către o locație fixă. Apelarea hărților GoogleMaps se face prin butonul cu același nume și pentru deconectarea utilizatorului se apasă pe ultimul buton numit Logout ce trimite la clasa Logout.

Activitatea GetID

Această activitate este apelată prin apăsarea butonului FL din clasa Meniu. Ea are ca scop conexiunea la baza de date pentru a furniza o listă completă cu toate ID-urile și numele fiecărui utilizator. Prin aceasta se selectează persoana ce se dorește a fi localizată.

Clasa GetID declară un editor de text și 2 chenare text urmând ca metoda onCreate să le lege de elementele grafice propriu zise. Conținutul integral al metodei se poate găsi în anexa 1.5

Se apelează metoda getID și se creează în interfața grafică un buton care odată apăsat, salvează valoarea primită de la utilizator prin intermediul editorului de text în variabila parteneriD din activitatea MainActivity. Apoi se apelează activitatea principală pentru a începe localizarea.

Metoda getID crează adresa URL ce conține funcția ,,getID”, urmat apoi de setarea parametrilor și a metodei HTTP folosite pentru a deschide conexiunea și se afișează un mesaj pe ecran ce indică starea acesteia.

Se definește un buffer ce are ca scop preluarea informației de la server, urmând apoi ca prin metodele de prelucrare a șirurilor de caractere să se afișeze pe ecran pe linii, ID-urile și Nickname-urile respectivilor utilizatori pentru a putea selecta o persoană.

Activitatea MainActivity

MainActivity este modul principal de lucru al sistemului, el bazându-se pe ID-ul furnizat de activitatea GetID și alte clase proprii. Realizează localizarea unui client prin dispozitivul său inteligent indiferent dacă acesta este static sau în mișcare. El implementează interfața SensorEventListner, ce permite accesarea senzorilor dispozitivului mobil. ID-ul propriu este salvat și transmis către această clasă în timpul activității Login. Se dorește ca această activitate să arate direcția de urmat către găsirea telefonului partener și afișarea unor informații despre acesta. Ea conține 3 clase, în 3 fișiere diferite: MainActivity, GetPos și MyLocationListener.

Clasa MainActivity extinde clasa Activity și în același timp implementează interfața SensorEventListener (anexa 1.6). În realizarea acestei activități s-a plecat de la codul sursă a unei aplicații Android de tip ,,open-source” ce are ca scop implementarea un compas [16].

Următoarele variabile reprezintă disponibilitatea proprie care este setată implicit ca invizibil lăsând, clientul să o schimbe atunci când dorește să fie localizat. Valoarea iD este cea introdusă în timpul activității Login, în timp ce parteneriD este introdusă în timpul activității GetID. Numele este setat în momentul creării unui cont nou, iar variabila bearing este necesară calcului direcției.

Metoda onCreate începe prin stabilirea fișierul grafic. Se crează dependențele pentru senzorul magnetic și accelerometrul și se stabilește legătura cu imaginea numită ,,pointer” ce arată punctul cardinal nord [16].

S-a adăugat ulterior aplicației de compas încă o imagine având ca scop afișarea direcției de mers. Folosind valoarea calculată de aplicația inițială pentru a arăta nordul, această nouă imagine, va reprezenta direcția de mers.

Se definește un comutator pentru a seta dinamic variabila disponibilității myStatus. Se creează legătura cu interfața grafică și se setează implicit comutatorul ca oprit. În cazul în care el este apăsat, se verifică starea lui și dacă el este oprit disponibilitatea este setată în modul invizibil, respectiv dacă este pornit, disponibilitatea este setată în modul vizibil.

Se verifică dacă sistemul GPS este pornit sau nu și în funcție de acest lucru se afișează clientului un mesaj.

Se apelează firul de execuție runThread ce realizează actualizarea celor 2 clase care transmit către serverul web poziția proprie și interoghează DB pentru poziția geografică a partenerului. Se definesc clasele și interfețele ce au rolul de a furniza locația GPS a dispozitivului.

Se verifică dacă aplicația a primit permisiunea de a accesa locația dispozitivului. Este definit apoi ca accesarea sistemului GPS pentru furnizarea locației să se desfășoare o data la o secundă și să se salveze această valoare chiar dacă utilizatorul nu a parcurs nici un metru.

Metoda onResume este accesată atunci când activitatea interacționează cu utilizatorul și setează ce senzor și la ce frecvență să eșantioneze, în timp ce metoda onPause oprește senzorii atunci când activitatea nu mai este folosită. Metoda onPause este ultima metodă apelată înainte să se treacă la o altă activitate. Aceste 2 metode sunt metode ce au fost preluate din aplicația compas [16].

Metoda onSensorChanged este o metodă a interfeței SensorEventListener și este apelată atunci când se citește o valoare la unui dintre senzori.

În funcție de tipul de senzor matricea care salvează valorile primite are lungime și conținut diferit. Accelerometrul și senzorul magnetic oferă 3 valori măsurate pe axele de coordonate [9]. În situația în care valorile citite sunt de la accelerometru, ele sunt salvate într-o matrice. În situația ca valorile citite sunt de la senzorul magnetic, se salvează acestea în altă matrice [16].

În cazul în care atât senzorul magnetic cât și accelerometrul au furnizat valori, metoda getRotationMatrix calculează pe baza acestora, direcția nordului din sistemul de coordonate proprii telefonului, în sistemul de coordonate geografice. Metoda getOrientation calculează pe baza matrice mR primită ca parametru orientarea dispozitivului inteligent față de nordul magnetic, întorcând pe prima poziție a matrice mOrientation unghiul azimutal dintre nordul magnetic și axa ordonatelor a telefonului mobil. Valoarea este apoi modificată din radiani în grade și se fac prelucrări matematice pentru a limita intervalul de valori între 0 și 360 de grade [16].

Se creează o animație care rotește figura plecând de la valoarea calculată a unghiului azimutal și rotind în sensul invers trigonometric săgeata în jurul propriilor axe. Se setează durata de 250 de milisecunde și se setează ca animația să rămână schimbată după ce s-a executat. Se pornește animația și se actualizează noua poziție [16].

Se salvează valoarea calculată în interiorul clasei GetPos și se afișează pe ecran. Variabila heading este direcția de parcurs, fiind determinată pe baza unghiului azimutal calculat mai devreme și valoarea bearing, ce reprezintă unghiul între nordul magnetic și poziția telefonului partener.

Se prezintă decizia afișării distanței între cei 2 utilizatori, acest lucru fiind condiționat de disponibilitatea partenerului ce se dorește a fi localizat.

Se creează o a doua animație ce va arăta direcția către telefonul partenerului. Această animație este similară cu cea prezentată mai sus, cu diferența modificării valorii unghiului reprezentat de variabila heading [16].

Se suprascrie butonul Back al telefonului mobil, astfel încât atunci când este apăsat să pornească activitatea Meniu.

Apelul metodelor updateMyPos din clasa MyLocationListener și metoda updateHisPos din clasa GetPos se face odată la 2 secunde și pentru că acestea fac modificări pe interfața grafică, este necesar ca ele să fie apelate din firul de execuție al interfeței grafice.

În continuare se va prezenta clasa MyLocationListener, clasă ce implementează interfața LocationListener și care are rolul de a prelua poziția GPS a dispozitivului inteligent (anexa 1.6). Una din metodele conținute de această clasă este updateMyPos ce primește de la firul de execuție din MainActivity variabila loc și în care salvează locația. Este afișată pe ecran locația cu un număr redus de zecimale, calculele ce urmează însă vor folosi valoarea exactă.

Se formează adresa URL a sistemului introducând toate datele necesare și se afișează pe ecran un mesaj pentru o realizare corectă a conexiunii similar ca și în cazurile precedente (anexa 1.6).

În momentul schimbării poziției geografice se salvează această poziție și se apelează metoda updateMyPos pentru a fi transmisă către DB.

Clasa GetPos obține poziția geografică a dispozitivului inteligent partener prin interogarea DB. În continuare vom prezenta modul de funcționare a acestei clase începând cu metoda updateHisPos.

Metoda începe prin realizarea conexiunii HTTPS, prin formarea adresei URL a sistemului, introducând toate datele necesare și se afișează pe ecran un mesaj pentru o realizare corectă.

Se definește un buffer pentru preluarea datelor provenite de la server în scopul de a fi prelucrate. Se prelucrează șirul de caractere și se obțin toate valorile de interes despărțite prin virgulă.

Dacă șirul de caractere nu conține informație, înseamnă că ori a existat o problemă cu conexiunea HTTP, ori informația nu există pe server, ori a existat o eroare în apelarea funcției PHP și metoda trebuie să își încheie execuția. În caz contrar, în urma informației primite este necesar ca aceasta să fie descompusă în valorile ce o compun. În acest moment, în variabila coordonatePartener, există latitudinea, longitudinea, status, data și ora. Toate aceste valori despărțite prin virgulă.

Se selectează a treia valoare din șirul de caractere (numărătoarea începe de la 0) și este salvată în variabila hisStatus.

Dacă variabila hisStatus are valoarea diferită de ,,0”, atunci se salvează latitudinea și longitudinea în variabila loc2. Se prelucrează ultimul termen din șirul inițial pentru a se afișa ora ultimei înregistrări a dispozitivului partener. Se afișează trunchiat coordonatele și informațiile referitoare la iD-ul partener, disponibilitatea, data și ora ultimei înregistrări. Se realizează apoi calculul unghiului între nordul magnetic și poziția telefonului partener și distanța între cele 2 poziții.

În cazul în care hisStatus are valoarea ,,0” se apelează metoda onStatusChanged care maschează afișarea coordonatelor și setează valoarea distanței și a unghiului bearing cu ,,0”. Astfel imaginea va arăta nordul magnetic.

Metodele care întorc distanța, unghiul, data și ora, sunt utilizate pentru a face citirea codului mai ușoară.

Activitatea InsertCoord

Această activitate are rolul de oferi utilizatorului posibilitatea de a introduce coordonatele unei locații fixe pentru a realiza navigarea către aceasta.

În metoda onCreate se creează un buton și două editoare de text. În momentul apăsării pe buton, latitudinea și longitudinea sunt memorate și transmise către clasa FindLoc. Se pornește apoi activitatea FindLoc prin apelarea clasei cu același nume (anexa 1.7). De asemenea, butonul Back al dispozitivului inteligent, este suprascris să apeleze activitatea Meniu.

Activitatea FindLoc

Activitatea FindLoc funcționează similar ca și activitatea MainActivity. Diferențele între cele două sunt mici, una dintre ele fiind salvarea coordonatelor primite în activitatea InsertCoord. Această operație se realizează în metoda onCreate. O altă diferență este calculul distanței și a valorii bearing ce se calculează între poziția telefonului inteligent și coordonatele introduse în activitatea precedentă, calcule ce se realizează în interiorul metodei onSensorChanged (anexa 1.8). Se determină apoi variabila heading, care este utilizată în animația ce arată direcția către locația selectată. Valorile sunt apoi afișate pe ecran.

O altă diferență este dispariția variabilelor de disponibilitate, atât a telefonului curent cât și a telefonului partener, care în această activitate nu există. Tot din acest motiv, comutatorul nu mai este utilizat.

Diferența principală este conținutul firului de execuție care în acest caz apelează numai activitatea MyLocationListener de unde setează valoarea locației proprii, locație care este afișată și pe ecran. Clasa GetPos nu este apelată deoarece nu mai există telefon partener în această activitate.

Metoda onBackPressed suprascrie butonul Back al dispozitivului și trimite către clasa Meniu.

Activitatea MapsActivity

Această activitate este apelată din butonul numit GoogleMaps ce se găsește în Meniu. Această activitate folosește un API oferit de Google pentru a permite utilizarea hărților Google Maps [18] (anexa 1.9). După ce s-a rezervat un API și acesta este introdus în fișierul AndroidManifest.xml se poate vizualiza harta (anexa 1.10).â

Activitatea conține configurarea implicită, iar în metoda onMapReady s-au creat apoi 2 marcatori ce indică pozițiile celor două dispozitive inteligente. Valorile pentru locații sunt preluate din clasa MyLocationListener pentru poziția proprie și din clasa GetPos pentru poziția telefonului partener. Se setează numele celor 2 marcatori și se afișează pe hartă. Ca și în cazul activității precedente, apăsarea butonului Back a dispozitivului apelează clasa Meniu.

3.3 Interfața grafică

Interfața grafică este construită pe baza fișierelor XML asociate fiecărei activități prezentate anterior în subcapitolul 3.2.

În realizarea unui fișier XML se creează o ierarhie a obiectelor. Astfel se specifică atributele generale ale fișierului și apoi se introduc diferitele obiecte grafice, precum: editorul de text, chenarele text, butoanele, comutatorul și imagini cu atributele lor specifice.

De exemplu, pentru activitatea Login, atributele generale sunt următoarele:

Se definește eticheta rădăcină și anume RelativeLayout și se asigură că fișierul XML recunoaște etichetele și atributele folosite, ele fiind găsite la URL-ul specificat urmând ca apoi să se definească atributele generale ale fișierului [8]. Se specifică marginea ecranului și contextul în care acest fișier este apelat.

Modul prin care se specifică proprietățile fiecărui element grafic este prin atributul ce primește valoarea dorită. Fiecare tip de element grafic este asociat cu o etichetă unică și sub această etichetă sunt enumerate atributele. De exemplu, mai jos, se arată modul în care un chenar text este definit în fișierul XML al activității Login (anexa 2.1).

Pe lângă aceste atribute se mai pot adăuga și altele care ar schimba modul în care chenarul text este afișat. În cazul unui buton și anume în cazul butonului Register se procedează astfel (anexa 2.3):

Prin wrap_content se înțelege că dimensiunea este minimul necesar după ce a fost inclus conținutul în interiorul elementului grafic, în timp ce prin match_parent se dorește ca acel element să ia aceleași valori ca și părintele.

Se prezintă editorul de text unde se introduce parola din activitatea Login. Se alege tipul textului ca textPassword, ceea ce maschează caracterele ce sunt introduse. În figura 3.3 se prezintă interfața grafică pentru clasa Login unde se pot observa editoarele de text, chenarele text și butoanele.

Fișierele grafice XML se pot găsi integral în anexa 2.

Figura 3.3: Interfața grafică a activității Login

Prin apăsarea butonului Register, se apelează activitatea cu același nume și aceasta se poate observa în figura 3.4. În cazul în care contul deja există se poate observa mesajul apărut pe ecran.

Figura 3.4: Interfața grafică a activității Register

În figura 3.5 se poate observa interfața grafică a activității Meniu, ceea care face posibilă tranziția între cele 3 moduri de funcționare a sistemului de localizare.

Figura 3.5: Interfața grafică a activității Meniu

În cazul activității MapsActivity, a fost folosită interfața implicită oferită, unde au fost adăugați marcatorii pentru locațiile celor două poziții așa cum se observă în figura 3.6.

Figura 3.6: Interfața grafică a activității MapsActivity

În cazul activităților MainActivity și FindLoc este necesar să se introducă ID-ul partenerului, respectiv coordonatele locației căutate. În figura 3.7 sunt prezentate interfețele grafice pentru activitățile InsertCoord și GetID ce fac posibil acest lucru.

Figura 3.7: Interfața grafică a activităților InsertCoord și GetID

În interfața grafică a activității MainActivity, figura 3.8, se poate observa cele două direcții arătate de săgeți, una pentru nord și una pentru telefonul partener.

Figura 3.8: Interfața grafică a activității MainActivity

În figura 3.9 este prezentat un exemplu al activității FindLoc unde s-a setat latitudinea cu valoare ,,44.263” și longitudinea cu valoarea ,,26.325”.

Figura 3.9: Interfața grafică a activității FindLoc

3.4 Elemente de securitate

Prin crearea funcțiilor PHP clientului i se oferă anumite funcții și opțiuni de a selecta și de a actualiza informația în baza de date. El poate să acceseze și să modifice numai datele ce corespund contului său, cu excepția funcției ,,getIDs.php”, unde prin simpla accesare se furnizează o listă cu toți utilizatorii.

Informațiile de autentificare sunt trimise către server unde se face autorizarea către cont prin intermediul protocolului HTTPS. El oferă protecție suplimentară asupra informației ce este criptată și oferă garanția că nu există o terță entitate ce interceptează informațiile și le poate folosi. Acest lucru este făcut posibil de către certificatele SSL.

În acest moment, serverul web care conține baza de date și funcțiile PHP este utilizat de mult timp și are certificatul SSL expirat. Pentru realizarea conexiunii HTTPS din aplicația Android, este necesar în acest caz de o metodă care să accepte toate certificatele, indiferent de starea lor. Acest lucru oferă o slăbiciune în securitate deoarece deși se realizează criptarea datelor, clientul nu cunoaște dacă serverul web este cel corect. Există astfel posibilitatea unei intercepții a datelor. Cu toate acestea nivelul de securitate este mai ridicat decât dacă s-ar folosi protocolul HTTP. Aceasta este o soluție temporară și se dorește ca acea metodă să rămână în uz numai pentru a arăta funcționalitatea sistemului până în momentul reînnoirii certificatului SSL. În momentul reînnoirii certificatului SSL, sistemul va putea funcționa normal și cu toate beneficiile pe care protocolul HTTPS le oferă.

Sistemul de control al accesului utilizatorilor și autorizarea lor presupune implementarea funcțiilor ,,login.php”, ,,register.php” și ,,logout.php”, ce sunt salvate pe serverul web, dar și corespondentul lor în aplicația Android prin fișierele ,,Login.java”, ,,Register.java” și ,,Logout.java”. Acestea lucrează împreună în realizarea autentificării și autorizării, dar și a controlului informației ce este introdusă în baza de date.

Cu ajutorul funcției ,,register.php” se salvează toate informațiile necesare pentru crearea unui cont nou. Posesorul noului cont este definit implicit ca deconectat urmând să se autentifice pentru a folosi sistemul. Prin intermediul funcțiilor ,,login.php” și ,,logout.php” se stabilește activitatea unui client și anume dacă el este autentificat la un moment dat sau nu prin câmpul Login din DB.

Câmpul Login este urmărit ca o funcție de securitate ce va permite introducerea de coordonate în tabela poziții numai dacă el ne indică valoarea ,,1”. În caz contrar nu se realizează actualizarea. Acest lucru este necesar pentru protejarea integrității bazei de date, deoarece abia după apelul funcției ,,login.php”, utilizatorul este autentificat și se cunoaște înregistrarea ce trebuie actualizată cu poziția respectivului.

Una dintre cele mai uzuale metode prin care se încearcă să se obțină drepturi mai mari asupra bazelor de date este cea de injectare de comenzi SQL. Un atacator încearcă diferite combinații de comenzi inteligent alese pe care le introduce în căsuțele text destinate introducerii de informații în baza de date. Prin aceste comenzi se poate forța afișarea unui utilizator conținut, ce în mod normal ar fi setat ca nepermis de administratorul bazei de date. În funcțiile PHP prezentate anterior există o matrice ce conține comenzile SQL. Înainte de a se formula o cerere, variabila după care se face acea interogare, se supune unui test în care, dacă există comenzi ce se găsesc în matrice, acestea sunt eliminate.

În cazul funcției ,,register.php” selecția înregistrărilor se face după ID și nu este necesar să se testeze celelalte valori ce sunt transmise prin URL. Dacă se încearcă injectarea unor comenzi prin Nickname sau prin parola Pass¸ atunci acestea vor fi introduse ca atare în baza de date sau cel mai probabil vor furniza o eroare și funcția nu va funcționa.

Pentru funcția ,,logout.php” se utilizează atât ID cât și parola Pass. În cazul în care s-ar proceda diferit, un utilizator ar putea să utilizeze funcția ,,getIDs.php” și ,,logout.php” pentru a afla ID-ul tuturor și apoi să îi deconecteze pe toți. Utilizarea acestor două valori este ascunsă de utilizator.

Sistemul oferă posibilitatea clienților de a își exprima disponibilitatea prin valoarea Status, valoare ce se poate modifica din aplicația Android și care oferă două posibilități: disponibil prin valoarea ,,1” și indisponibil prin valoarea ,,0”. Prin disponibil, clientul lasă posibilitatea de a fi localizat de alți utilizatori, iar dacă selectează opțiunea de indisponibil, acesta va continua să transmită date către baza de date, dar ceilalți utilizatori nu vor putea să îi citească poziția. În cazuri de urgență este posibil ca utilizatorul sistemului să uite să activeze comutatorul Status și atunci dacă dispozitivul lui mobil nu ar trimite poziția către DB când modul indisponibil este selectat, ar putea exista implicații dezastruoase. Din acest motiv s-a decis transmisia a poziției indiferent de disponibilitatea clientului. Accesul la poziția unui utilizator ce are selectat modul indisponibil poate fi făcută numai de administratorul bazei de date, păstrând securitatea locației.

În cadrul aplicației Android, suprascrierea butonului Back, în unele cazuri poate fi o măsura de siguranță a datelor, deoarece în cazul în care un utilizator se deconectează și dorește să introducă alte informații de autentificare, o apăsare pe acest buton ar trimite la ecranul precedent sau alte activități ce au fost utilizate înainte existând cazul ca să se introducă în baza de date informații eronate.

Concluzii

S-a abordat această temă deoarece nu există implementat în momentul actual un sistem ce oferă aceleași funcționalităti. În acest moment există pe piață multe soluții pentru a localiza un telefon și de a șterge informațiile de pe el, în cazul unui furt/pierdere, însă există puține aplicații care urmăresc găsirea unui dispozitiv mobil cu ajutorul unui alt terminal. Un mare avantaj al acestui sistem este că nu necesită un alt dispozitiv ceea ce ar aduce costuri suplimentare (dispozitivul hardware și eventuale servicii, spre exemplu internet) pentru a localiza un alt utilizator. Atâta timp cât respectivul are aplicația pornită și dorește să fie localizat, acest lucru se poate realiza foarte ușor.

Tema elaborată poate să fie dezvoltată în continuare, prin implementarea unor algoritmi care să elimine zgomotul și valorilor eronate ce provin de la transmițătoarele GPS și de la senzori. Se dorește implementarea unor funcții ce afișează și diferența de altitudine. Se propune cartografierea obstacolelor dintre cele 2 locații ale dispozitivelor mobile și crearea unor funcții ce permit calculul unei rute optime evitând obstacolele între cele două terminale. Se dorește implementarea sistemului pe scară largă.

S-a proiectat și implementat o aplicație de monitorizare a poziției GPS pentru terminale mobile inteligente, cu sistem de operare Android, pe baza unei arhitecturi client-server. Aplicația permite monitorizarea poziției GPS a terminalului mobil cu ajutorul unui API HTTP securizat, precum și navigarea către alte dispozitive mobile aflate în sistem, dar și către destinații fixe prestabilite, respectând intimitatea utilizatorilor și a condițiilor de securitate a conturilor acestora.

S-a implementat modelul LAMP pe un server web prin instalarea componentelor acestuia. S-a realizat baza de date utilizând phpMyAdmin și s-au creat funcțiile PHP ce stau la baza serviciului web REST. S-au implementat elemente de control și securitate pentru protecția informațiilor și a conturilor utilizatorilor. S-a realizat sistemul de control al accesului utilizatorilor, autorizarea lor și deconectarea. S-a dezvoltat aplicația Android ce rulează pe terminalul clientului. Aplicația Android a fost implementată pornind de la o aplicație compas ce a fost modificată pentru a realiza achiziția locației de la sistemul GPS, comunicația între utilizatori prin recepționarea și transmiterea poziției GPS, prelucrarea informației recepționate de la serverul web, calculul direcției de mers și a distanței bazate pe pozițiile GPS ale celor două telefoane, implementarea elementelor de securitate pe dispozitivul clientului, localizarea pe hărțile GoogleMaps, interfețele grafice prin care se afișează elementele grafice de orientare și navigare a utilizatorului, interfețe grafice cu scopul de a introduce și afișa informații, interfețele grafice ale activităților de legătură și interfețele grafice pentru sistemul de control al accesului utilizatorilor.

Se va cerceta posibilitatea de implementare a sistemului în interiorul clădirilor și în spațiile unde semnalul GPS nu ajunge prin triangularea semnalului de la diferite puncte de acces Wi-FI, dar și prin utilizarea unor dispozitive Bluetooth ce vor interacționa cu dispozitivul mobil.

Se dorește dezvoltarea unui dispozitiv de dimensiuni reduse care să includă toate componentele hardware, ce ar face posibil rularea sistemului de localizare la capacități maxime. Dispozitiv poate fi atașat diverselor obiecte care se pot pierde ușor precum cheile și portofelul.

Se propune dezvoltarea în continuare a acestei aplicații pe sistemul de operare Android, dar și implementarea pe alte sisteme de operare ca IOS sau Windows Phone.

Sistemul asistă persoanele care doresc să se întâlnească și care nu cunosc locația în care se află, furnizând navigarea reciprocă a unuia către celălalt.

O altă utilizare a aplicației este atunci când cele două persoane se găsesc într-o zonă aglomerată, moment în care mișcarea continuă cât și lipsa unor repere relevante fac imposibilă întâlnirea.

În cazul unui accident, fie că se petrece în zone de șes sau în zone montane greu accesibile, în baza de date va fi memorată ultima locație a telefonului, locație ce va ajuta echipajele de salvare într-o situație extremă. De asemenea, în cazul unor activități periculoase precum: drumețiile, alpinismul, etc., sistemul poate fi utilizat ca metodă de precauție și prevenire. Se poate utiliza sistemul și în domeniul medical și social, pentru persoane bolnave de diabet, boli de inima, Alzheimer, etc ce necesită supraveghere permanentă, dar și în cazurile sociale ca: localizarea copiilor în diferite situații, dezorientarea bătrânilor etc, atâta timp cât presupune existența unui telefon mobil asupra lor.

O altă utilizare este atunci când se pleacă în grup spre o anumită destinație fie cu mașina sau pe jos. În cazul în care se folosesc mașinile, în zonele urbane, este dificil ca un sofer să se țină unul după altul. Astfel, șoferii și-ar dori să știe unde anume sunt restul persoanelor/mașinilor din grup, aplicația venind în ajutorul lor. Dacă un grup de oameni, de exemplu turiști, se plimbă într-o zonă aglomerată se pot pierde persoane de grup, situație în care utilizând sistemul de localizare, acestea se pot reîntâlni.

Sensibilitatea cu care se găsesc cele două telefoane pereche depinde de performanța sistemului de localizare a terminalelor (modului GPS) cât și a senzorului magnetic. Câmpurile magnetice perturbă puternic senzorul magnetic și în unele situații este necesară recalibrarea senzorului.

Sistemul GPS ajută la micșorarea distanței între cele două terminale, însă din cauza zgomotului, la distanțe mici, el este ineficient. În funcție de obstacolele din mediu, sistemul poate avea într-un caz favorabil o precizie de până la 2-10 metri. Într-un caz defavorabil precizia poate să scadă și până la 40-100 de metri. Se dorește creșterea în viitor a preciziei în proximitate prin tehnologia bluetooth.

Schimbul de informații cu serverul are dimensiuni reduse și astfel se utilizează trafic mobil puțin, consumând puțin din datele mobile. În utilizarea sistemului este necesar activarea sistemului GPS și a datelor mobile, amândouă funcțiile consumând multă putere. Din acest motiv sistemul nu poate funcționa pe perioade lungi de timp.

Se dorește optimizarea aplicației Android pentru a reduce și mai mult consumul de date mobile, schimbul de informații cu serverul, fiind făcut mai rar. Aplicația Android este încă în stadiu de dezvoltare și conține erori ce apar în momentul utilizării ei.

Bibliografie

[1] Documentația oficiala Android, accesat la data 15.03.2017

<< https://developer.android.com/about/android.html >>

[2] Bolcaș Radu Daniel, ”Sistem de localizare în timp real a dispozitivelor inteligente bazate pe platforma Android și asistență la navigare către destinații fixe sau în mișcare”, UPB, Sesiunea de Comunicări Științifice 2017 (uz intern).

[3] Documentația oficială Android, ”Introduction to Android”, accesat la data 15.06.2017

<< https://developer.android.com/guide/index.html >>

[4] Documentația oficială Android, ”Application Fundaments”, accesat la data 16.06.2017

<< https://developer.android.com/guide/components/fundamentals.html >>

[5] Documentația oficială Android, ”Platform Architecture”, accesat la data 15.06.2017

<< https://developer.android.com/guide/platform/index.html >>

[6] Reto Meier, ”Professional Android 4 Application Development”, John Wiley & Sons, Inc., Indianapolis, 2012, ISBN: 978-1-118-10227-5, pp. 481-483

[7] Kevin Grant, Chris Haseman, ”Beginning Android Programming: Develop and Design”, Peachpit Press, 2014, ISBN-13: 978-0321956569, pp. 89

[8] Wallace Jackson, ”Pro Android UI”, Apress, 2014, ISBN-13 (electronic): 978-1-4302-4987-0, pp.30-32

<< http://pdf.th7.cn/down/files/1508/Pro%20Android%20UI.pdf >> accesat la data 20.06.2017

[9] Documentația oficială Android, ”UI Overview”, accesat la data 20.06.2017

<< https://developer.android.com/guide/topics/ui/overview.html >>

[10] Wei-Meng Lee, ”Beginning Android 4 Application Development”, John Wiley & Sons, Inc., Indiana, 2012, ISBN: 978-1-118-19954-1, pp. 395

[11] Fielding Roy Thomas, Tim Berners-Lee, et al., ” HTTP/1.1, RFC 2616”, 1999, secțiunea 9.3-9.5

<< https://www.rfc-editor.org/rfc/rfc2616.txt >> accesat la data 21.06.2017

[12] Mark Massé, ”REST API Design Rulebook”, O’Reilly Media, Inc., 2012, ISBN: 978-1-449-31050-9, pp.2-6,11

[13] Documentația oficială PHP, ”Ce este PHP? ”, accesat la data 20.06.2017

<< http://php.net/manual/ro/intro-whatis.php >>

[14]Manualul oficial MySQL, ”MySQL and PHP”, accesat la data 09.04.2017, pp. 1-4

<< https://downloads.mysql.com/docs/apis-php-en.pdf >>

[15] Documentația oficială PHP, ” Injectarea SQL”, accesat la data 15.06.2017

<< http://php.net/manual/ro/security.database.sql-injection.php >>

[16] William J. Francis, ”Pro tip: Create your own magnetic compass using Android's internal sensors”, articol în Techrepublic, accesat la data: 02.11.2016

<<http://www.techrepublic.com/article/pro-tip-create-your-own-magnetic-compass-using-androids-internal-sensors/ >>

[17] Nilanchala, ”How to Trust All Certificates for HttpURLConnection in Android”, articol în Stacktips, accesat la data: 26.05.2017

<< https://stacktips.com/snippet/how-to-trust-all-certificates-for-httpurlconnection-in-android >>

[18] Documentația oficială GoogleMap, accesat la data 06.05.2017

<<https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap >>

Anexe 1: Activitățiile aplicației Android și AndroidManifest

În continuare fragmentele de cod ce sunt de culoare gri sunt preluate din aplicația compas ,,open source”[16], sau este cazul metodei trustAllCertificates() ce permite funcționarea protocolului HTTPS [17].

1.1 Activitatea Login

public class Login extends Activity {

Button bt1, bt2, bt3;
EditText edt1, edt2;
public static String pass;
public static int m;
static TextView txt1, txt2, txt3;
int k = 4; //numara incercarile de autentificare

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);

bt1 = (Button) findViewById(R.id.button); //Login button
edt1 = (EditText) findViewById(R.id.editText); ///username
edt2 = (EditText) findViewById(R.id.editText2); ///password

bt2 = (Button) findViewById(R.id.button2); //Cancel Button
bt3 = (Button) findViewById(R.id.button3); //Register button

txt1 = (TextView) findViewById(R.id.textView3);
txt2 = (TextView) findViewById(R.id.textView1);
txt3 = (TextView) findViewById(R.id.textView2);
txt1.setVisibility(View.GONE);

bt1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

MainActivity.iD = edt1.getText().toString();
pass = edt2.getText().toString();
Logout.passLogout=pass;

Log.i("Login", "inainte de async");
new AttemptLogin().execute();

Log.i("login", "Attempt login finished");
//int j = retRasp();
Log.i("login", "m " + m);

if (m == 1) {
Toast.makeText(getApplicationContext(), "Redirecting…", Toast.LENGTH_SHORT).show();
Intent i = new Intent(Login.this, Meniu.class);
startActivity(i);
finish();

} else {
Toast.makeText(getApplicationContext(), "Wrong ID/Password", Toast.LENGTH_SHORT).show();

txt1.setVisibility(View.VISIBLE);
txt1.setBackgroundColor(Color.RED);
k–;
txt1.setText(Integer.toString(k));

if (k == 0) {
bt1.setEnabled(false);
}
}
}
});

bt2.setOnClickListener(new View.OnClickListener() { //butonul Cancel
@Override
public void onClick(View v) {
finish();
}
});

bt3.setOnClickListener(new View.OnClickListener() { //butonul Register
public void onClick(View v) {
pass = null;
Intent n = new Intent(Login.this, Register.class);
startActivity(n);
finish();
}
});
}

@Override
public void onBackPressed()
{
}
}

class AttemptLogin extends AsyncTask<Object, Object, Integer>
{

protected Integer doInBackground(Object… urls) {
String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36";

try {
trustAllCertificates();
String str = "https://xxx.xxx.xxx.xxx/FF/login.php?id=" + MainActivity.iD + "&pass=" + Login.pass;
//MainActivity.t1.setText("connecting");
// MainActivity.t2.setText(st); //testare string st
Log.i("Login","str:"+ str);
URL obj = new URL(str);
Log.i("Login","obj: "+ obj);
HttpsURLConnection conn = (HttpsURLConnection) obj.openConnection();
Log.i("Login","con: "+ conn);
conn.setRequestMethod("GET");
Log.i("Login","get: ");
conn.setDoOutput(true);
Log.i("Login","doOutput: ");
conn.setRequestProperty("User-Agent", USER_AGENT);

Log.i("Login","req ");
conn.setInstanceFollowRedirects(false);
conn.connect();
Log.i("Login","connect: ");
Log.i("Login","ok? ");

int responseCode = conn.getResponseCode();
Log.i("Login","response code? "+responseCode);

BufferedReader inBuff = new BufferedReader( new InputStreamReader(conn.getInputStream()) );
Log.i("Login","in"+ inBuff);
StringBuilder raspuns = new StringBuilder();
String line;
while ((line = inBuff.readLine()) != null) {
raspuns.append(line).append('\n');
}
String valoare = raspuns.toString();
valoare =valoare.replaceAll("\\s","");
Login.m= Integer.parseInt(valoare);
Log.i("Login","valoare"+ Login.m);

//MainActivity.t4.setText("putPos: " + con.getResponseMessage()); ///verif cconexiunii

} catch (Exception e) {
// tx2.setText("err Login");
Log.i("Login", "exceptie: "+e.getCause());
//tx2.setText(e.getLocalizedMessage());
e.printStackTrace();
}

return Login.m;
}
protected void onProgressUpdate(Void… progress) {

}

protected int onPostExecute(String result) {
return Login.m;
}
public static void trustAllCertificates() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}

@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};

SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
}
}

}

1.2 Activitatea Logout

public class Logout extends Activity {

public static boolean connexOK;
public static String passLogout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logout);

final Button button = (Button) findViewById(R.id.buttonyy);////Cancel button trimite la Meniu
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {

Intent b = new Intent(Logout.this, Meniu.class);
startActivity(b);
finish();

}
});

final Button button2 = (Button) findViewById(R.id.buttonxx);////Logout button trimite la Login
button2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {

Log.i("Logout", "user");
Log.i("Logout", "pass");

new AttemptLogout().execute();
Toast.makeText(getApplicationContext(), "You succesfully logged out", Toast.LENGTH_SHORT).show();

Intent c = new Intent(Logout.this, Login.class);
startActivity(c);
finish();
}

});

}
@Override
public void onBackPressed()
{
}

}
class AttemptLogout extends AsyncTask<Object, Object, String>
{

protected String doInBackground(Object… urls) {
String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36";

try {
if(Login.pass!=null)
{Logout.passLogout=Login.pass;}
else{Logout.passLogout=Register.passRegister;}

trustAllCertificates();
String strg = "https://xxx.xxx.xxx.xxx/FF/logout.php?id=" + MainActivity.iD + "&pass=" + Logout.passLogout;

Log.i("Logout", "str:" + strg);
URL obj = new URL(strg);
Log.i("Logout", "obj: " + obj);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
Log.i("Logout", "con: " + con);
con.setRequestMethod("GET");
Log.i("Logout", "get: ");
con.setDoOutput(true);
Log.i("Logout", "doOutput: ");
con.setRequestProperty("User-Agent", USER_AGENT);
Log.i("Logout", "req ");
con.connect();
Log.i("Logout", "connect: ");
Log.i("Logout", "ok? " + con.getResponseMessage());
//Logout.connexOK=con.getResponseMessage().equals("OK");

} catch (Exception e) {
// tx2.setText("err Logout");
//tx2.setText(e.getLocalizedMessage());
e.printStackTrace();
Log.i("Logout","stacktrace"+ Arrays.toString(e.getStackTrace()));

}

return "ok";
}
protected void onProgressUpdate(Void… progress) {

}

protected String onPostExecute(Void result)
{
return "deconectare reusita";
}
public static void trustAllCertificates() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}

@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};

SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
}
}

}

1.3 Activitatea Register

public class Register extends Activity {
EditText edtxt1, edtxt2, edtxt3, edtxt4;
public static String passRegister, pass2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);

edtxt1 = (EditText) findViewById(R.id.editTexta);
edtxt2 = (EditText) findViewById(R.id.editTextb);
edtxt3 = (EditText) findViewById(R.id.editTextc);
edtxt4 = (EditText) findViewById(R.id.editTextd);

final Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
MainActivity.iD = edtxt1.getText().toString();
passRegister = edtxt2.getText().toString();
pass2 = edtxt3.getText().toString();
MainActivity.name = edtxt4.getText().toString();

Log.i("register", "user:" + edtxt1.getText().toString());//id
Log.i("register", "pass:" + passRegister);
Log.i("register", "pass2:" + pass2);

if (passRegister.equals(pass2) ) {
Logout.passLogout=passRegister;

Log.i("register", "inainte de async");
new AttemptRegister().execute();

Log.i("Register", "valoare dupa async" + AttemptRegister.val);/// nu raspunde nimic daca nu exista; raspunde cu string "exista" daca contul e in DB

if (AttemptRegister.val.equals( "" ))
{
Toast.makeText(getApplicationContext(), "You succesfully registered. Please Login", Toast.LENGTH_SHORT).show();
Intent a = new Intent(Register.this, Login.class);
startActivity(a);
finish();
}else{
Toast.makeText(getApplicationContext(), "The account exists already", Toast.LENGTH_SHORT).show();
}
}
}
});
}

}
class AttemptRegister extends AsyncTask<Object, Object, String>
{

public static String val;
public static boolean connexOK;

protected String doInBackground(Object… urls) {
String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36";

try {
trustAllCertificates();
String strg = "https://xxx.xxx.xxx.xxx/FF/register.php?id=" + MainActivity.iD +"&n="+ MainActivity.name+"&pass=" + Register.passRegister;
//MainActivity.t1.setText("connecting");
// MainActivity.t2.setText(st); //testare string st
Log.i("register", "str:" + strg);
URL obj = new URL(strg);
Log.i("register", "obj: " + obj);
HttpsURLConnection conn = (HttpsURLConnection) obj.openConnection();
Log.i("register", "con: " + conn);
conn.setRequestMethod("GET");
Log.i("register", "get: ");
conn.setDoOutput(true);
Log.i("register", "doOutput: ");
conn.setRequestProperty("User-Agent", USER_AGENT);
Log.i("register", "req ");
conn.connect();
Log.i("register", "connect: ");
Log.i("register", "ok? " + conn.getResponseMessage());
connexOK=conn.getResponseMessage().equals("OK");
//MainActivity.t4.setText("putPos: " + con.getResponseMessage()); ///verif cconexiunii

if (connexOK ) {
BufferedReader inBuff = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Log.i("Register", "in" + inBuff);
StringBuilder raspuns = new StringBuilder();
Log.i("Register", "in" + raspuns);/// nu raspunde nimic daca nu exista; raspunde cu string "exista" daca contul e in DB

String line;
while ((line = inBuff.readLine()) != null) {
raspuns.append(line).append('\n');
}
val = raspuns.toString();
val = val.replaceAll("\\s", "");
Log.i("Register", "valoare" + val);/// nu raspunde nimic daca nu exista; raspunde cu string "exista" daca contul e in DB

}
} catch (Exception e) {
// tx2.setText("err Logout");
//tx2.setText(e.getLocalizedMessage());
e.printStackTrace();
}

return val;
}
protected void onProgressUpdate(Void… progress) {

}

protected String onPostExecute(Void result)
{
return val;
}

public static void trustAllCertificates() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}

@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};

SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
}
}
}

1.4 Activitatea Meniu

public class Meniu extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meniu);

final Button buttonA = (Button) findViewById(R.id.buttonA); // FF
buttonA.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(getApplicationContext(),"FF…",Toast.LENGTH_SHORT).show();
Intent a=new Intent(Meniu.this, GetID.class);
startActivity(a);
finish();
}
});

final Button buttonB = (Button) findViewById(R.id.buttonB); //GoogleMaps
buttonB.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {

Toast.makeText(getApplicationContext(),"Maps…",Toast.LENGTH_SHORT).show();
Intent e=new Intent(Meniu.this, MapsActivity.class);
startActivity(e);
finish();
}
});

/*pt locatie fixaaaa*/
final Button buttonC = (Button) findViewById(R.id.buttonC); //FL
buttonC.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
Toast.makeText(getApplicationContext(),"FL…",Toast.LENGTH_SHORT).show();

Intent i=new Intent(Meniu.this, InsertCoord.class);
startActivity(i);
finish();

}
});
final Button buttonD = (Button) findViewById(R.id.buttonD); //Logout
buttonD.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click

Intent o=new Intent(Meniu.this, Logout.class);
startActivity(o);
finish();

}
});

}

@Override
public void onBackPressed()
{
Intent x=new Intent(Meniu.this, Logout.class);
startActivity(x);
finish();
return;
}
}

1.5 Activitatea GetID

public class GetID extends Activity {
EditText id;
public static TextView t1, t2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_get_id);
t1 = new TextView(this);
t1 = (TextView) findViewById(R.id.textView6);
t2 = new TextView(this);
t2 = (TextView) findViewById(R.id.textView7);

id = (EditText)findViewById(R.id.editTextid);
getID();

final Button buttonID = (Button) findViewById(R.id.buttonID);
buttonID.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
MainActivity.partneriD=id.getText().toString();
Intent i=new Intent(GetID.this, MainActivity.class);
startActivity(i);

finish();
}
});
}

public static void getID()
{
String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36";
Log.i("GetID","coord: 11");

try {
trustAllCertificates();

String st = "https://xxx.xxx.xxx.xxx/FF/getIDs.php";
Log.i("GetID","st: "+ st);

t1.setText("connecting");
t2.setText(st); //testare string st
URL obj = new URL(st);
Log.i("GetID","obj: "+ obj);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
Log.i("GetID","con: "+ con);
con.setRequestMethod("GET");
Log.i("GetID","get: ");
con.setDoOutput(true);
Log.i("GetID","doOutput: ");
con.setRequestProperty("User-Agent", USER_AGENT);
Log.i("GetID","req ");
con.connect();
Log.i("GetID","connect: ");
Log.i("GetID","ok? "+con.getResponseMessage());
t1.setText("GetID: " + con.getResponseMessage()); ///verif cconexiunii

BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream()) ); //buffer pt a salva stream-ul
Log.i("GetID","in: "+ in);

StringBuilder total = new StringBuilder();
String line;

while ((line = in.readLine()) != null) {
total.append(line).append('\n');
}
Log.i("GetID","total: "+ total);
String sirrr = total.toString();
sirrr =sirrr.replaceAll("\\n","&");
sirrr =sirrr.replaceAll("\\s","");
sirrr =sirrr.replaceAll("&&&&","\n");
sirrr =sirrr.replaceAll("&","");
Log.i("GetID","sirrr:"+ sirrr);

String s= sirrr.replaceAll(","," ") ;
t2.setText(s);
Log.i("GetID","s"+ s);

} catch (Exception e) {
t2.setText(e.getLocalizedMessage());
e.printStackTrace();
}
}

@Override
public void onBackPressed()
{
Intent y=new Intent(GetID.this, Meniu.class);
startActivity(y);
finish();
return;
}

public static void trustAllCertificates() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}

@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};

SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
}
}

}

1.6 Activitatea MainActivity

Clasa MainActivity:
public class MainActivity extends Activity implements SensorEventListener {

public static TextView t;
public static TextView t1;
public static TextView t2;
public static TextView t3;
public static TextView t4;
public static TextView t5;
public static TextView t6;

private ImageView mPointer;
private ImageView mPointer2;
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private Sensor mMagnetometer;
private float[] mLastAccelerometer = new float[3];
private float[] mLastMagnetometer = new float[3];
private boolean mLastAccelerometerSet = false;
private boolean mLastMagnetometerSet = false;
private float[] mR = new float[9];
private float[] mOrientation = new float[3];
private float mCurrentDegree = 0f;
private float mCurrentDegree2 = 0f;

public static Location loc = null;
public static int myStatus=0;
public static String iD ;
public static String partneriD;

public static String name ;
public static float bearing = 0; ///// metoda onSensorChanged – calculul rotatiei

public static Location loc2 = new Location(""); //loc2=locatie telefonul partener
public static Location loc1 = new Location(""); //loc1=locatie telefonul meu

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

setContentView(R.layout.activity_main);
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mPointer = (ImageView) findViewById(R.id.pointer);
mPointer2 = (ImageView) findViewById(R.id.pointer2);

Switch mainSwitch= (Switch) findViewById(R.id.switch1); // seteaza dinamic val status
mainSwitch.setChecked(false);
mainSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

if(isChecked){
myStatus=1;// Status is Visible
}else{
//Status is Invisible
myStatus=0;
}
}
});

t = new TextView(this); ///locatia mea
t = (TextView) findViewById(R.id.textView);
t1 = new TextView(this);//// bearing
t1 = (TextView) findViewById(R.id.textView1);
t2 = new TextView(this); // locatie partener
t2 = (TextView) findViewById(R.id.textView2);
t3 = new TextView(this); //// verif getPos
t3 = (TextView) findViewById(R.id.textView3);
t4 = new TextView(this);//// verif putPos
t4 = (TextView) findViewById(R.id.textView4);
t5 = new TextView(this); //// distanta
t5 = (TextView) findViewById(R.id.textView5);
t6 = new TextView(this); //// info
t6 = (TextView) findViewById(R.id.textView6);

////////////////////////////////////////// verif conexiune gps
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Toast.makeText(this, "GPS is Enabled in your device", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "GPS is Disabled in your device", Toast.LENGTH_LONG).show();
}
/////////////////////////////////////////////////////

loc1.setLatitude(2.0);
loc1.setLongitude(2.0);

runThread();/// thread pt actualizare GetPosition si PutPosition

LocationManager mlocManager = null;
LocationListener mlocListener;
mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener();

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

return;
}
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, mlocListener);

}

protected void onResume()
{
super.onResume();
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
}

protected void onPause()
{
super.onPause();
mSensorManager.unregisterListener(this, mAccelerometer);
mSensorManager.unregisterListener(this, mMagnetometer);
}

@Override
public void onSensorChanged(SensorEvent event)
{
if (event.sensor == mAccelerometer)
{
System.arraycopy(event.values, 0, mLastAccelerometer, 0, event.values.length);
mLastAccelerometerSet = true;
}
else if (event.sensor == mMagnetometer)
{
System.arraycopy(event.values, 0, mLastMagnetometer, 0, event.values.length);
mLastMagnetometerSet = true;
}

if (mLastAccelerometerSet && mLastMagnetometerSet)
{
SensorManager.getRotationMatrix(mR, null, mLastAccelerometer, mLastMagnetometer);
SensorManager.getOrientation(mR, mOrientation);
float azimuthInRadians = mOrientation[0];
float azimuthInDegrees = (float)(Math.toDegrees(azimuthInRadians)+360)%360; //limitează valoarea la intervalul [0,360]

Log.i("Main Activity","azimuth"+azimuthInDegrees);

//// aceasta animatie indica nordul
RotateAnimation ra1 = new RotateAnimation(
mCurrentDegree2,-azimuthInDegrees,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);

ra1.setDuration(250);
ra1.setFillAfter(true);

mPointer2.startAnimation(ra1);
mCurrentDegree2 = -azimuthInDegrees;
////////////////////////////////

bearing=GetPos.retBearing();
//bearing = GetPos.bearinggg(loc1, loc2); //calcul alternativ de bearing
MainActivity.t1.setText("bearing:"+String.valueOf(bearing));
Log.i("Main Activity","bearing"+bearing);
float heading = azimuthInDegrees – bearing; //directia de mers /// e necesar "-" pt corectia sensului de rotire

Log.i("Main Activity","heading"+heading);
if(GetPos.hisStatus!=0) {
if (GetPos.retDistance() < 1000) {
t5.setText("distanta:" + String.valueOf(GetPos.retDistance()) + "m");
} else {
t5.setText("distanta:" + String.valueOf(GetPos.retDistance() / 1000) + "km");
}
}else{
t5.setText("distanta:Invisible");
}
//animatia indica direactia de parcurs /// animatia se roteste trigonometric
RotateAnimation ra = new RotateAnimation(
mCurrentDegree,-heading,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);

ra.setDuration(250);
ra.setFillAfter(true);

mPointer.startAnimation(ra);
mCurrentDegree = -heading;
}
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}

@Override
public void onBackPressed()
{
Intent a=new Intent(MainActivity.this, Meniu.class);
startActivity(a);
finish();
return;
}

private void runThread() {

new Thread() {
public void run() {
while (true) {
try {
runOnUiThread(new Runnable() {

@Override
public void run() {
MyLocationListener.updateMyPos(loc1);
GetPos.updateHisPos(loc2);
}
});
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}

}

Clasa GetPos:

public class GetPos {

public static float x,y; // x-bearing//y-distanta
public static String dataOra;
public static int hisStatus;
public static double latit1, longit1;

public static void updateHisPos(Location loc){
loc1 = loc;

String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36";

try {
trustAllCertificates();

String st = "https://xxx.xxx.xxx.xxx/FF/getPosition.php?id="+ MainActivity.partneriD;
// MainActivity.t3.setText(st); //verif string
URL obj = new URL(st);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setDoOutput(true);
con.setRequestProperty("User-Agent", USER_AGENT);
con.connect();
MainActivity.t3.setText("getPos: " + con.getResponseMessage()); //verificarea conexiunii //functioneaza

BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream()) ); //buffer pt a salva stream-ul

StringBuilder sir = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
sir.append(line).append('\n');
}
String coordonatePartener = sir.toString(); // si se foloseste fara sa fie de tip String, dar coordonatePartener trebuie sa fie
Log.i("UpdateHisPosition","coordpartener1:"+ coordonatePartener);
coordonatePartener =coordonatePartener.replaceAll("\\s","");/// eliminare spatii albe din string, spatii ce provin de la functia php
//
Log.i("UpdateHisPosition","coordpartener2:"+ coordonatePartener);
// MainActivity.t2.setText(coordonatePartener);///coordonatePartener = tot ce s-a primit de la server prin putPosition – lati, long, dataOra

if (coordonatePartener != null)
{
hisStatus=Integer.parseInt(coordonatePartener.split(",")[2]); //selectie status partener
if (hisStatus!=0) {

Location loc2 = new Location(""); //loc2=locatie telefon partener

loc2.setLatitude(Double.parseDouble(coordonatePartener.split(",")[0]));//// incarca in loc2 coordonatele din stringul coordonatePartener
loc2.setLongitude(Double.parseDouble(coordonatePartener.split(",")[1]));//

latit1 = Double.parseDouble(coordonatePartener.split(",")[0]); ///pt google maps
longit1 = Double.parseDouble(coordonatePartener.split(",")[1]);///pt google maps

float lati = (float) Double.parseDouble(coordonatePartener.split(",")[0]); ///trunchiere latitudine partener
float longi = (float) Double.parseDouble(coordonatePartener.split(",")[1]); ///trunchiere longitudine partener

dataOra = coordonatePartener.split(",")[3];
Log.i("UpdateHisPosition", "coordpart split3 " + dataOra);
String data, ora;
data = dataOra.substring(0, 9);
ora = dataOra.substring(10);
dataOra = data + " " + ora;
Log.i("UpdateHisPosition", "dataOra" + dataOra);

//MainActivity.t2.setText(Double.parseDouble(coordonatePartener.split(",")[0])+ " " + Double.parseDouble(coordonatePartener.split(",")[1]));
MainActivity.t2.setText("El "+ lati + " " + longi);
MainActivity.t6.setText( "HisID: "+MainActivity.partneriD+ " st:"+ GetPos.hisStatus +" ActiveAt: "+ GetPos.getDataOra());
loc1.setLatitude(MyLocationListener.latitude);
loc1.setLongitude(MyLocationListener.longitude);
Log.i("UpdateHisPosition", "coord mele" + loc1);
x = loc1.bearingTo(loc2); //salvez bearingul ce ia val intre [-180,180]grade
Log.i("UpdateHisPosition", "coord mele" + MyLocationListener.latitude + " " + MyLocationListener.longitude);
Log.i("UpdateHisPosition", "coord lui" + loc2);
//MainActivity.t3.setText(String.valueOf(MyLocationListener.latitude+ " "+MyLocationListener.longitude));
////////////

if (x < 0) {
x = x + 360;
} // corectia valorii bearing
///////////////
y = MainActivity.loc.distanceTo(loc2);//distanta intre locatii
}else{
onStatusChanged();
}
}

} catch (Exception e) {
//e.printStackTrace();
//MainActivity.t2.setText(e.getLocalizedMessage());
MainActivity.t2.setText("err getPosition");
Log.d("UpdateHisPOsition","exceptie getPosition", e);
}
}

public static void onStatusChanged()
{
MainActivity.t6.setText( "HisID: "+MainActivity.partneriD+ " st:"+ hisStatus +" ActiveAt: Invisible");
MainActivity.t2.setText("Invisible");
x=0; //bearing
y=0; //distanta
}

public static float retBearing()
{return x;}

public static float retDistance()
{return y;}

public static String getDataOra()
{return dataOra;}

public static void trustAllCertificates() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}

@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};

SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
}
}

}

Clasa MyLocationListener:

public class MyLocationListener implements LocationListener {

public static double latitude;
public static double longitude;

public static void updateMyPos(Location loc){
MainActivity.loc = loc;

/// pt afisarea trunchiata a coordonatelor proprii
MainActivity.t.setText("Eu"+(float)loc.getLatitude() + " " + (float)loc.getLongitude());
String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.87 Safari/537.36";

try {
trustAllCertificates();
String st = "https://xxx.xxx.xxx.xxx/FF/putPosition.php?id=" + MainActivity.iD + "&n=" + MainActivity.name + "&La=" + loc.getLatitude() + "&Lg=" + loc.getLongitude()+"&st="+ MainActivity.myStatus;

URL obj = new URL(st);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setDoOutput(true);
con.setRequestProperty("User-Agent", USER_AGENT);
con.connect();

MainActivity.t4.setText("putPos: " + con.getResponseMessage()); ///verif cconexiunii

} catch (Exception e) {
MainActivity.t3.setText(e.getLocalizedMessage());
e.printStackTrace();
}
}

@Override
public void onLocationChanged(Location loc)
{
latitude = loc.getLatitude();
longitude = loc.getLongitude();
MyLocationListener.updateMyPos(loc);
}

@Override
public void onProviderDisabled(String provider)
{
//Toast.makeText(this, "Gps turned off ", Toast.LENGTH_LONG).show();
//print "Currently GPS is Disabled";
}
@Override
public void onProviderEnabled(String provider)
{
// Toast.makeText(this, "Gps turned on ", Toast.LENGTH_LONG).show();
//print "GPS got Enabled";
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
public static void trustAllCertificates() {
try {
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}

@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};

SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
}
}

}

1.7 Activitatea InsertCoord

public class InsertCoord extends Activity {

EditText edt1,edt2;
public static String LocLong1, LocLat1;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_insert_coord);

edt1 = (EditText)findViewById(R.id.editTextX);
edt2 = (EditText)findViewById(R.id.editTextY);

final Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
LocLat1=edt1.getText().toString();
LocLong1= edt2.getText().toString();
Log.i("Insert coord:", "LocLat"+LocLat1);
Log.i("Insert coord:", "LocLong"+LocLong1);

Toast.makeText(getApplicationContext(),"FindLoc",Toast.LENGTH_SHORT).show();

Intent m=new Intent(InsertCoord.this, FindLoc.class);
startActivity(m);
finish();
}
});
}

@Override
public void onBackPressed()
{
Intent a=new Intent(InsertCoord.this, Meniu.class);
startActivity(a);
finish();
return;
}

}

1.8 Activitatea FindLoc

public class FindLoc extends Activity implements SensorEventListener {
public static TextView t;
public static TextView t1;
public static TextView t2;
public static TextView t3;
public static TextView t4;
public static TextView t5;

private ImageView mPointer;
private ImageView mPointer2;
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private Sensor mMagnetometer;
private float[] mLastAccelerometer = new float[3];
private float[] mLastMagnetometer = new float[3];
private boolean mLastAccelerometerSet = false;
private boolean mLastMagnetometerSet = false;
private float[] mR = new float[9];
private float[] mOrientation = new float[3];
private float mCurrentDegree = 0f;
private float mCurrentDegree2 = 0f;
public static Location loc = null;

public static float bearingFL = 0; ///// e nevoie pt onSensorChanged pt calculul rotatiei pt cazul FL
public static float distanceFL;

public static Location locEu = new Location(""); //locEu=locatie telefonul meu
public static Location locDest = new Location(""); //locDest=destinatiee

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.activity_find_loc);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mPointer = (ImageView) findViewById(R.id.pointer);
mPointer2 = (ImageView) findViewById(R.id.pointer2);

t = new TextView(this);
t = (TextView) findViewById(R.id.textView);
t1 = new TextView(this);
t1 = (TextView) findViewById(R.id.textView1);
t2 = new TextView(this);
t2 = (TextView) findViewById(R.id.textView2);
t3 = new TextView(this);
t3 = (TextView) findViewById(R.id.textView3);
t4 = new TextView(this);
t4 = (TextView) findViewById(R.id.textView4);
t5 = new TextView(this);
t5 = (TextView) findViewById(R.id.textView5);

////////////////////////////////////////// verif conexiune gps
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Toast.makeText(this, "GPS is Enabled in your device", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "GPS is Disabled in your device", Toast.LENGTH_LONG).show();
}
/////////////////////////////////////////////////////

locEu.setLatitude(2.0);
locEu.setLongitude(2.0);

Log.i("FindLoc:", "LocLong"+InsertCoord.LocLong1);
Log.i("FindLoc", "LocLat"+InsertCoord.LocLat1);

runThread2();/// thread
locDest.setLongitude(Double.parseDouble(InsertCoord.LocLong1));
locDest.setLatitude(Double.parseDouble(InsertCoord.LocLat1));
FindLoc.t2.setText("Dest "+String.valueOf(locDest.getLatitude())+" "+String.valueOf(locDest.getLongitude()) );
Log.i("FindLoc:", "LocDest"+locDest.getLatitude()+" "+locDest.getLongitude());

LocationManager mlocManager = null;
LocationListener mlocListener;
mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener();

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

return;
}
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, mlocListener);

}

protected void onResume() {
super.onResume();
mSensorManager.registerListener( this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
}

protected void onPause() {
super.onPause();
mSensorManager.unregisterListener( this, mAccelerometer);
mSensorManager.unregisterListener(this, mMagnetometer);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor == mAccelerometer) {
System.arraycopy(event.values, 0, mLastAccelerometer, 0, event.values.length);
mLastAccelerometerSet = true;
} else if (event.sensor == mMagnetometer) {
System.arraycopy(event.values, 0, mLastMagnetometer, 0, event.values.length);
mLastMagnetometerSet = true;
}

if (mLastAccelerometerSet && mLastMagnetometerSet) {
SensorManager.getRotationMatrix(mR, null, mLastAccelerometer, mLastMagnetometer);
SensorManager.getOrientation(mR, mOrientation);
float azimuthInRadians = mOrientation[0];
float azimuthInDegrees = (float) (Math.toDegrees(azimuthInRadians) + 360) % 360;

RotateAnimation ra1 = new RotateAnimation(
mCurrentDegree2, -azimuthInDegrees,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);

ra1.setDuration(250);
ra1.setFillAfter(true);

mPointer2.startAnimation(ra1);
mCurrentDegree2 = -azimuthInDegrees;

bearingFL = locEu.bearingTo(locDest);
distanceFL = locEu.distanceTo(locDest);

if(bearingFL<0)
{bearingFL=bearingFL+360;}

t1.setText("bearing:" + String.valueOf(bearingFL) );

float heading = azimuthInDegrees – bearingFL; //directia de mers /// e necesar "-" pt corectia sensului de rotire

// t5.setText("distanta:" + String.valueOf(distanceFL) + "m");
if(distanceFL<1000) {
t3.setText("distanta:" + String.valueOf(distanceFL) + "m");
}else{t3.setText("distanta:" + String.valueOf(distanceFL/1000) + "km");}

//partea de animatie /// animatia se roteste trigonometric
RotateAnimation ra = new RotateAnimation(
mCurrentDegree, -heading,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);

ra.setDuration(250);
ra.setFillAfter(true);

mPointer.startAnimation(ra);
mCurrentDegree = -heading;
}

}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}

private void runThread2() {

new Thread() {
public void run() {
while (true) {
try {
runOnUiThread(new Runnable() {

@Override
public void run() {
locEu.setLatitude(MyLocationListener.latitude);
locEu.setLongitude(MyLocationListener.longitude);
//
FindLoc.t.setText("Eu"+String.valueOf((float)locEu.getLatitude())+" "+String.valueOf((float)locEu.getLongitude()));

}
});
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}

@Override
public void onBackPressed()
{
Intent a=new Intent(FindLoc.this, Meniu.class);
startActivity(a);
finish();
return;
}
}

1.9 Activitatea MapsActivity

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

private GoogleMap mMap;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}

@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;

LatLng Eu = new LatLng(MyLocationListener.latitude, MyLocationListener.longitude);
LatLng El = new LatLng(GetPos.longit1, GetPos.latit1);

mMap.addMarker(new MarkerOptions().position(Eu).title("Eu"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(Eu));

mMap.addMarker(new MarkerOptions().position(El).title("El"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(El));
}

@Override
public void onBackPressed()
{
Intent y=new Intent(MapsActivity.this, Meniu.class);
startActivity(y);
finish();
return;
}
}

1.10 Fișierul AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.radu.sistemgps">

<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="23" />
<!– android:versionCode="1" –>
<!– android:versionName="1.0" –>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.google.android.providers.gsf.permissions.READ_GSERVICES" />

<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />

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

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:screenOrientation="portrait" />

<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />

<activity
android:name=".MapsActivity"
android:label="@string/app_name" />
<activity
android:name=".Login"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".InsertCoord" />
<activity android:name=".Meniu"/>
<activity android:name=".FindLoc" />
<activity android:name=".GetID" />
<activity android:name=".Register" />
<activity android:name=".Logout"></activity>
</application>

</manifest>

Anexa 2: Interfața grafică

2.1 Activitatea Login

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:tools = "http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height = "match_parent"
android:paddingLeft= "@dimen/activity_horizontal_margin"
android:paddingRight = "@dimen/activity_horizontal_margin"
android:paddingTop = "@dimen/activity_vertical_margin"
android:paddingBottom = "@dimen/activity_vertical_margin"
tools:context = ".Login">

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:ems="10"
android:id="@+id/editText2"
android:layout_below="@+id/editText"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignRight="@+id/editText"
android:layout_alignEnd="@+id/editText"
android:textColorHint="#78b7ac"
android:hint="Enter Password" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView3"
android:layout_alignTop="@+id/textView2"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignBottom="@+id/textView2"
android:layout_toEndOf="@+id/textview"
android:textSize="24dp"
android:layout_toRightOf="@+id/textview" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"
android:id="@+id/button2"
android:layout_below="@+id/textView2"
android:layout_toLeftOf="@+id/button3"
android:layout_toStartOf="@+id/button3"
android:layout_marginRight="13dp"
android:layout_marginEnd="13dp"
android:layout_marginTop="56dp" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Login"
android:id="@+id/button"
android:textSize="20dp"
android:layout_alignBaseline="@+id/button2"
android:layout_alignBottom="@+id/button2"
android:layout_toRightOf="@+id/button3"
android:layout_toEndOf="@+id/button3"
android:layout_marginLeft="25dp"
android:layout_marginStart="25dp" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Register"
android:id="@+id/button3"
android:layout_marginTop="28dp"
android:layout_below="@+id/button"
android:layout_centerHorizontal="true" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Attempts Left:"
android:id="@+id/textView2"
android:textSize="24dp"
android:layout_marginTop="54dp"
android:layout_below="@+id/editText2"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />

<EditText
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:id = "@+id/editText"
android:hint = "Enter ID"
android:focusable = "true"
android:textColorHighlight = "#cb7c114c"
android:textColorHint = "#78b7ac"
android:layout_marginTop = "24dp"
android:layout_below="@+id/textview"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />

<TextView android:text = "Login"
android:layout_width="wrap_content"
android:layout_height = "wrap_content"
android:id = "@+id/textview"
android:textSize = "34dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />

</RelativeLayout>

2.2 Activitatea Logout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_logout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.radu.sistemgps.Logout">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Logout?"
android:id="@+id/buttonxx"
android:layout_marginTop="36dp"
android:layout_centerHorizontal="true" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cancel"
android:id="@+id/buttonyy"
android:layout_marginTop="61dp"
android:layout_below="@+id/buttonxx"
android:layout_centerHorizontal="true" />

</RelativeLayout>

2.3 Activitatea Register

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_register"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.radu.sistemgps.Register">

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="text"
android:ems="10"
android:id="@+id/editTexta"
android:hint="Enter username"
android:layout_below="@+id/editText"
android:layout_alignParentLeft="true"
android:layout_alignParentRight = "true"
android:layout_alignParentStart="true"
android:textColorHint="#78b7ac"
/>

<EditText
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:id = "@+id/editTextb"
android:hint = "Enter password"
android:focusable = "true"
android:textColorHighlight = "#cb7c114c"
android:textColorHint = "#78b7ac"
android:inputType="textPassword"
android:layout_marginTop = "46dp"
android:layout_alignParentLeft = "true"
android:layout_alignParentStart = "true"
android:layout_alignParentRight = "true"
android:layout_alignParentEnd = "true" />

<EditText
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:id = "@+id/editTextc"
android:hint = "Enter password again"
android:focusable = "true"
android:textColorHighlight = "#cb7c114c"
android:textColorHint = "#78b7ac"
android:inputType="textPassword"
android:layout_marginTop = "12dp"
android:layout_below="@+id/editTextb"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Create account"
android:id="@+id/button1"
android:layout_marginTop="149dp"
android:layout_below="@+id/editTextb"
android:layout_centerHorizontal="true" />

<EditText
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:id = "@+id/editTextd"
android:hint = "Enter name"
android:focusable = "true"
android:textColorHighlight = "#cb7c114c"
android:textColorHint = "#78b7ac"
android:inputType="text"
android:layout_marginTop = "17dp"
android:layout_below="@+id/editTextc"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />

</RelativeLayout>

2.4 Activitatea Meniu

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_meniu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.radu.sistemgps.Meniu">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="FF"
android:id="@+id/buttonA"
android:layout_centerHorizontal="true"
android:layout_marginBottom="51dp" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="FL"
android:id="@+id/buttonC"
android:layout_below="@+id/buttonA"
android:layout_alignLeft="@+id/buttonA"
android:layout_alignStart="@+id/buttonA" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Google maps"
android:id="@+id/buttonB"
android:layout_marginTop="56dp"
android:layout_below="@+id/buttonC"
android:layout_centerHorizontal="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Logout"
android:id="@+id/buttonD"
android:layout_marginTop="56dp"
android:layout_below="@+id/buttonB"
android:layout_centerHorizontal="true" />

</RelativeLayout>

2.5 Activitatea GetID

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_get_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.radu.sistemgps.GetID">

<TextView
android:text="TextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="57dp"
android:id="@+id/textView6" />

<TextView
android:text="TextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView6"
android:layout_alignRight="@+id/textView6"
android:layout_alignEnd="@+id/textView6"
android:layout_marginTop="43dp"
android:id="@+id/textView7" />

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal|numberSigned"
android:ems="10"
android:id="@+id/editTextid"
android:hint="partener ID:"
android:layout_below="@+id/editText"
android:layout_alignParentLeft="true"
android:layout_alignParentRight = "true"
android:layout_alignParentStart="true"
android:textColorHint="#78b7ac"
/>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go"
android:id="@+id/buttonID"
android:layout_marginBottom="48dp"
android:layout_alignParentBottom="true"
android:layout_toRightOf="@+id/textView7"
android:layout_toEndOf="@+id/textView7" />
</RelativeLayout>

2.6 Activitatea MainActivity

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.radu.sistemgps.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView1"
android:layout_alignParentBottom="true"
android:layout_marginBottom="28dp"
android:layout_alignLeft="@+id/switch1"
android:layout_alignStart="@+id/switch1" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView"
android:layout_alignBaseline="@+id/textView1"
android:layout_alignBottom="@+id/textView1"
android:layout_toRightOf="@+id/pointer"
android:layout_toEndOf="@+id/pointer" />

<ImageView
android:id="@+id/pointer"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="@drawable/pointer2"
android:layout_marginBottom="51dp"
android:layout_above="@+id/textView1"
android:layout_centerHorizontal="true" />

<ImageView
android:id="@+id/pointer2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/busola3"
android:layout_marginBottom="20dp"
android:layout_above="@+id/pointer"
android:layout_centerHorizontal="true" />

<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:id="@+id/textView2" />

<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView6"
android:layout_below="@+id/textView5"
android:layout_alignLeft="@+id/textView4"
android:layout_alignStart="@+id/textView4" />

<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView4"
android:layout_below="@+id/textView3"
android:layout_alignLeft="@+id/textView3"
/>

<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView5"
android:layout_below="@+id/textView4"
android:layout_alignLeft="@+id/textView4"
android:layout_alignStart="@+id/textView4" />

<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="47dp"
android:id="@+id/textView3"
android:layout_alignParentTop="true"
android:layout_alignLeft="@+id/switch1"
android:layout_alignStart="@+id/switch1" />

<Switch
android:text="Status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/switch1"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:textOn="Visible"
android:textOff="Invisible"/>

</RelativeLayout>

2.7 Activitatea InsertCoord

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_insert_coord"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.radu.sistemgps.InsertCoord">

<EditText
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:id = "@+id/editTextY"
android:hint = "Enter Long (+forE/-forW)"
android:focusable = "true"
android:textColorHighlight = "#cb7c114c"
android:textColorHint = "#78b7ac"
android:inputType="numberDecimal|numberSigned"
android:layout_marginTop = "46dp"
android:layout_alignParentLeft = "true"
android:layout_alignParentStart = "true"
android:layout_alignParentRight = "true"
android:layout_alignParentEnd = "true" />

<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="numberDecimal|numberSigned"
android:ems="10"
android:id="@+id/editTextX"
android:hint="Enter Lat (+forN/-forS)"
android:layout_below="@+id/editText"
android:layout_alignParentLeft="true"
android:layout_alignParentRight = "true"
android:layout_alignParentStart="true"
android:textColorHint="#78b7ac"
/>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="FindLocation"
android:id="@+id/button1"
android:layout_marginTop="36dp"
android:layout_below="@+id/editTextY"
android:layout_centerHorizontal="true" />

</RelativeLayout>

2.8 Activitatea FindLoc

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_find_loc"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.radu.sistemgps.FindLoc">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView1"
android:layout_alignParentBottom="true"
android:layout_alignLeft="@+id/pointer"
android:layout_alignStart="@+id/pointer"
android:layout_marginBottom="28dp" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/textView"
android:layout_alignBaseline="@+id/textView1"
android:layout_alignBottom="@+id/textView1"
android:layout_toRightOf="@+id/pointer"
android:layout_toEndOf="@+id/pointer" />

<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:id="@+id/textView2" />

<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:id="@+id/textView3" />

<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView3"
android:layout_alignLeft="@+id/textView3"
android:layout_marginTop="10dp"
android:id="@+id/textView4" />

<TextView
android:text=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView4"
android:layout_alignLeft="@+id/textView4"
android:layout_marginTop="10dp"
android:id="@+id/textView5" />

<ImageView
android:id="@+id/pointer"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="@drawable/pointer2"
android:layout_marginBottom="71dp"
android:layout_above="@+id/textView"
android:layout_centerHorizontal="true" />

<ImageView
android:id="@+id/pointer2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/busola3"
android:layout_below="@+id/textView5"
android:layout_centerHorizontal="true"
android:layout_marginTop="28dp" />

</RelativeLayout>

2.9 Activitatea MapsActivity

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.radu.sistemgps.MapsActivity"

/>

Anexa 3: Fișierele PHP

3.1 Fișierul datacon

<?

include("settings.php");

$dblink=MYSQL_CONNECT($MySqlHostname, $MySqlUsername, $MySqlPassword) OR DIE("Unable to connect to database");

@mysql_select_db("$db") or die( "Unable to select database");

?>

3.2 Fișierul settings

<?

$MySqlHostname = "localhost";

$MySqlUsername = "********";

$MySqlPassword = "********";

$db = "localizare";

// Row Colors

$row1BgColor = "#FFFFFF";

$row2BgColor = "#C0C0C0";

$dbConnectionFile = "include(\"datacon.php\");";

?>

3.3 Fișierul Login

<?

include("head.php");

include("datacon.php");

?>

<?

$cuvant=$_GET['id'];

$pass=$_GET['pass'];

// verificare impotriva SQL injection

$banlist = array

(

"insert", "select", "update", "delete", "distinct", "having", "truncate", "replace",

"handler", "like", "as", "or", "procedure", "limit", "order by", "group by", "asc", "desc"

);

if ( eregi ( "[a-zA-Z0-9]+", $cuvant ) )

{

$cuvant = trim ( str_replace ( $banlist, '', strtolower ( $cuvant ) ) );

}

else

{

$cuvant = NULL;

}

$queryselect = "select * from utilizatori where ID=$cuvant AND pass='$pass'";

$resultselect = MYSQL_QUERY($queryselect);

$numbersearchselect = mysql_Numrows($resultselect);

if ($numbersearchselect>0) {

$querysearch = "update utilizatori set login=1 where ID=$cuvant";

$resultsearch = MYSQL_QUERY($querysearch);

echo("1");

}

else

{

echo("0");

}

?>

3.4 Fișierul Logout

<?

include("head.php");

include("datacon.php");

?>

<?

$cuvant=$_GET['id'];

$pass=$_GET['pass'];

// verificare impotriva SQL injection

$banlist = array

(

"insert", "select", "update", "delete", "distinct", "having", "truncate", "replace",

"handler", "like", "as", "or", "procedure", "limit", "order by", "group by", "asc", "desc"

);

if ( eregi ( "[a-zA-Z0-9]+", $cuvant ) )

{

$cuvant = trim ( str_replace ( $banlist, '', strtolower ( $cuvant ) ) );

}

else

{

$cuvant = NULL;

}

$queryselect = "select * from utilizatori where ID=$cuvant AND pass='$pass'";

$resultselect = MYSQL_QUERY($queryselect);

$numbersearchselect = mysql_Numrows($resultselect);

if ($numbersearchselect>0) {

$querysearch = "update utilizatori set login=0 where ID=$cuvant";

$resultsearch = MYSQL_QUERY($querysearch);

}

else

{

}

?>

3.5 Fișierul Register

<?

include("head.php");

include("datacon.php");

?>

<?

$cuvant=$_GET['id'];

$nick=$_GET['n'];

$pass=$_GET['pass'];

// verificare impotriva SQL injection

$banlist = array

(

"insert", "select", "update", "delete", "distinct", "having", "truncate", "replace",

"handler", "like", "as", "or", "procedure", "limit", "order by", "group by", "asc", "desc"

);

if ( eregi ( "[a-zA-Z0-9]+", $cuvant ) )

{

$cuvant = trim ( str_replace ( $banlist, '', strtolower ( $cuvant ) ) );

}

else

{

$cuvant = NULL;

}

$queryselect = "select * from utilizatori where ID=$cuvant";

$resultselect = MYSQL_QUERY($queryselect);

$numbersearchselect = mysql_Numrows($resultselect);

if ($numbersearchselect>0) {

echo("exista");

}

else

{

$querysearch = "insert into utilizatori (ID,NickName,pass,login) VALUES ($cuvant,'$nick', '$pass',0)";

$resultsearch = MYSQL_QUERY($querysearch);

}

?>

3.6 Fișierul putPosition

<?

include("head.php");

include("datacon.php");

?>

<?

$cuvant=$_GET['id'];

$nick=$_GET['n'];

$lat=$_GET['La'];

$lon=$_GET['Lg'];

$st=$_GET['st'];

// verificare impotriva SQL injection

$banlist = array

(

"insert", "select", "update", "delete", "distinct", "having", "truncate", "replace",

"handler", "like", "as", "or", "procedure", "limit", "order by", "group by", "asc", "desc"

);

if ( eregi ( "[a-zA-Z0-9]+", $cuvant ) )

{

$cuvant = trim ( str_replace ( $banlist, '', strtolower ( $cuvant ) ) );

}

else

{

$cuvant = NULL;

}

$query = "select login from utilizatori where ID=$cuvant";

$result = MYSQL_QUERY($query);

if($result==1)

{

$queryselect = "select * from pozitii where ID=$cuvant";

$resultselect = MYSQL_QUERY($queryselect);

$numbersearchselect = mysql_Numrows($resultselect);

if ($numbersearchselect>0) {

$querysearch = "update pozitii set DataTimp=now(),Latitudine=$lat, Longitudine=$lon, Status=$st where ID=$cuvant";

$resultsearch = MYSQL_QUERY($querysearch);

}

else

{

$querysearch = "insert into pozitii (DataTimp,ID,NickName,Latitudine,Longitudine,Status) VALUES (now(),$cuvant,'$nick', $lat, $lon,$st)";

$resultsearch = MYSQL_QUERY($querysearch);

}

}

?>

3.7 Fișierul getPosition

<?

include("head.php");

include("datacon.php");

?>

<?

$cuvant=$_GET['id'];

// verificare impotriva SQL injection

$banlist = array

(

"insert", "select", "update", "delete", "distinct", "having", "truncate", "replace",

"handler", "like", "as", "or", "procedure", "limit", "order by", "group by", "asc", "desc"

);

if ( eregi ( "[a-zA-Z0-9]+", $cuvant ) )

{

$cuvant = trim ( str_replace ( $banlist, '', strtolower ( $cuvant ) ) );

}

else

{

$cuvant = NULL;

}

$querysearch = "select Latitudine,Longitudine,Status, MAX(DataTimp) from pozitii where ID=$cuvant";

$resultsearch = MYSQL_QUERY($querysearch);

$numbersearch = mysql_Numrows($resultsearch);

if ($numbersearch>0) {

$x=0;

?>

<?

while ($x<$numbersearch)

{

?> <? $rom=mysql_result($resultsearch,$x,"Latitudine");

?>

<? echo $rom; ?>,

<? $eng=mysql_result($resultsearch,$x,"Longitudine"); ?>

<? echo $eng; ?>,

<? $st=mysql_result($resultsearch,$x,"Status"); ?>

<? echo $st; ?>,

<? $dt=mysql_result($resultsearch,$x,3);

?>

<? echo $dt; ?>

<?

$x++;

} // end while

?>

<?

$exista='D';

} // end if

else

{

$exista='N';

}

mysql_free_result($resultsearch);

?>

3.8 Fișierul GetIDs

<?

include("head.php");

include("datacon.php");

?>

<?

$querysearch = "select distinct ID,NickName from pozitii";

$resultsearch = MYSQL_QUERY($querysearch);

$numbersearch = mysql_Numrows($resultsearch);

if ($numbersearch>0) {

$x=0;

?><?

while ($x<$numbersearch)

{

?>

<? $rom=mysql_result($resultsearch,$x,"ID"); ?>

<? echo $rom; echo ", "?>

<? $eng=mysql_result($resultsearch,$x,"NickName"); ?>

<? echo $eng; ?>

<?

$x++;

} // end while

?>

<?

$exista='D';

} // end if

else

{

$exista='N';

}

mysql_free_result($resultsearch);

?>

Anexa 4: Structura bazei de date

– phpMyAdmin SQL Dump

– version 3.1.0

– http://www.phpmyadmin.net

– Host: localhost

– Generation Time: Jun 22, 2017 at 11:08 AM

– Server version: 5.0.88

– PHP Version: 5.2.9

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";

– Database: `localizare`

4.1 Structura tabelei poziții

– Table structure for table `pozitii`

CREATE TABLE IF NOT EXISTS `pozitii` (

`DataTimp` datetime NOT NULL,

`ID` varchar(20) NOT NULL,

`NickName` varchar(30) NOT NULL,

`Latitudine` double NOT NULL,

`Longitudine` double NOT NULL,

`Status` int(11) NOT NULL,

FULLTEXT KEY `ID` (`ID`),

FULLTEXT KEY `ID_2` (`ID`)

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

4.2 Structura tabelei utilizatori

– Table structure for table `utilizatori`

CREATE TABLE IF NOT EXISTS `utilizatori` (

`ID` varchar(20) NOT NULL,

`NickName` varchar(30) NOT NULL,

`pass` varchar(30) NOT NULL,

`login` int(11) NOT NULL

) ENGINE=MyISAM DEFAULT CHARSET=latin1;

Similar Posts