Pe măsură ce tehnologia avansează, așteptările utilizatorilor de vehicule moderne s-au schimbat dramatic. Nu mai este suficient ca un sistem de infotainment auto să ofere doar funcționalități de bază. În zilele noastre, interfețele HMI (Human-Machine Interface) trebuie să fie intuitive, rapide și să ofere o experiență de utilizare fluidă. Acesta este contextul în care Android Automotive OS (AAOS) joacă un rol esențial.
AAOS reprezintă sistemul de operare Android pentru vehicule și oferă dezvoltatorilor posibilitatea de a crea experiențe HMI personalizate și eficiente, unde producătorii pot integra funcții avansate precum navigația, controlul media și conectivitatea, funcții care prioritizează siguranța și ușurința în utilizare.
Un HMI impecabil pentru noi reprezintă o experiență optimă pentru utilizator, cât și pentru dezvoltator, concentrându-ne astfel pe două aspecte importante: performanța sistemului (aplicații pre-integrate/de platformă) și calitatea codului (arhitectura de bază).
În acest articol, vom explora cei mai ușori pași pe care îi putem face pentru un impact maximal asupra performanței și a experienței utilizatorului, atunci când vine vorba despre funcționalități HMI.
În cazul aplicațiilor pre-integrate, Google ne pune la dispoziție un plugin relativ nou care ne oferă o modalitate simplă pentru a optimiza fluxurile aplicațiilor, astfel încât utilizatorul să se poată bucura de o experiență cât mai fluidă.
Plugin-ul se numește Baseline Profile (profil de bază) și are un set predefinit de reguli, pe baza execuției codului pentru cazurile esențiale. Aceste fluxuri critice sunt fundamentale pentru utilizator, precum este cazul afișării programelor într-o aplicație radio.
Cum funcționează? Când o aplicație care are integrat un profil de bază este instalată pe dispozitiv, Android Runtime va folosi profilul de bază pentru a compila în avans (Ahead-of-Time compilation) clasele și metodele folosite în dezvoltarea codului ce acoperă fluxurile principale sau clasele și metodele ce vin cu dependințele aplicației.
În continuare, vom explora cum să configurăm, să generăm și să măsurăm timpii de execuție. E important să parcurgem secțiunea următoare cu un set de recomandări în minte.
TTFD (Time to Full Display) și TTID (Time to Interactive Display) sunt metrici esențiale pentru performanța aplicațiilor Android. Ideal, TTFD ar trebui să fie sub 2 secunde, pentru a oferi utilizatorului o interfață rapidă și complet afișată, iar TTID ar trebui să fie sub 3-4 secunde, pentru ca aplicația să fie interactivă cât mai repede. Aceste recomandări provin din cercetări de UX și practici din industrie, care subliniază importanța unui timp de răspuns rapid pentru a menține utilizatorii angajați și pentru a evita abandonul aplicației din cauza întârzierilor.
Configurare pentru baseline profile
Folosește un șablon. Din Android Studio, se poate selecta adăugarea unui nou modul de tip baseline profile, această opțiune fiind disponibilă începând cu Android Studio Iguana și Android Gradle Plugin (AGP) 8.2. Modulul și clasele de sub android test vor fi generate automat.
Creează totul manual
Creează un nou modul com.android.test—de exemplu, :baseline-profile.
Configurează fișierul build.gradle.kts pentru :baseline-profile:
Aplică plugin-ul androidx.baselineprofile
.
Asigură-te că targetProjectPath
indică spre modulul :app
.
Opțional, adaugă un dispozitiv gestionat de Gradle.
Aplică configurația dorită.
includeInStartupProfile = true
în clasa generatorului tău de profil de bază. Acest lucru va activa, de asemenea, profilurile de startup.Generarea profilului
Pentru mediul AAOS trebuie să comutăm la utilizatorul 0 înainte de a genera profilul. Altfel, pentru ceilalți utilizatori, vom obține erori de permisiune. Se poate folosi comanda: adb shell am switch-user 0.
Pentru a rula generatorul de profil din IDE, fă click dreapta pe clasa BaselineProfileGenerator
și selectează 'Run BaselineProfileGenerator`.
Pentru a rula generatorul de profil din linia de comandă: ./gradlew :modules:yourappmodule:generateVariantBaselineProfile
.
Trecem la aplicațiile de platformă, integrate cu Soong și fișiere blueprint (.bp), pentru care Perfetto este recomandat în special pentru măsurarea performanței. Perfetto, un instrument esențial în AOSP, ajută la identificarea rapidă a problemelor de performanță și ne oferă o interfață prietenoasă unde să putem inspecta resursele folosite de aplicația noastră.
Configurare pentru Perfetto
Asigură-te că ai instalat Perfetto și că acesta este configurat corect în mediul tău de dezvoltare. Perfetto vine integrat în AOSP, dar este important să ai o versiune recentă pentru cele mai noi funcționalități.
Pornește un dispozitiv emulator sau fizic cu o versiune compatibilă de Android (în mod ideal, una dintre cele mai recente pentru a evita incompatibilități).
Configurează fișierul trace_config.pbtxt
pentru a specifica evenimentele pe care vrei să le monitorizezi (de exemplu, CPU, memorie, activități HMI).
Rularea Perfetto
Deschide terminalul și conectează-te la dispozitiv folosind adb
(Android Debug Bridge).
Rulează următoarea comandă pentru a porni captura datelor: adb shell perfetto -c /data/local/tmp/trace_config.pbtxt -o /data/local/tmp/trace_file.perfetto-trace
. -c
specifică fișierul de configurare, iar -o
indică locația unde va fi salvat fișierul cu rezultatele capturate.
adb pull /data/local/tmp/trace_file.perfetto-trace
.Analiza datelor capturate
Deschide Perfetto UI în browser și încarcă fișierul capturat (trace_file.perfetto-trace
).
Analizează secțiunile specifice (de exemplu, timpii de răspuns ai interfeței HMI, utilizarea CPU și memorie) pentru a identifica potențialele optimizări.
Arhitectura Clean într-o aplicație Android Automotive
Arhitectura Clean se bazează pe separarea responsabilităților în straturi distincte, fiecare având propriul model de date. Într-o aplicație Android Automotive, arhitectura poate fi organizată în următoarele straturi:
Acest strat este responsabil pentru interacțiunea utilizatorului cu aplicația. Este compus din activități, fragmente sau componente specifice sistemului automotive, cum ar fi serviciile care gestionează interfața cu utilizatorul. Stratul de prezentare nu ar trebui să conțină logică de business, ci să se bazeze pe cazurile de utilizare pentru a obține datele necesare. Stratul de prezentare se ocupă strict de ceea ce ține de interfața grafică sau decomponentele de acces principale ale sistemului de operare Android. Stratul de prezentare permite testarea prin component tests, cu librării specifice simulării concrete a interacțiunii, precum Espresso, UI Automator, Apium sau Kakao pentru Kotlin.
Acest strat include logica specifică aplicației și definește ce trebuie să se întâmple ca răspuns la acțiunile utilizatorului. De exemplu, într-o aplicație Android Automotive, cazurile de utilizare pot gestiona scenarii precum reglarea volumului sau gestionarea unei sesiuni de navigație. Acest strat nu depinde de interfața utilizator sau de metoda de stocare a datelor, oferind o flexibilitate mare. Stratul de use case permite încadrarea în întregime a logicii de business, putând fi testată prin unit tests bucată cu bucată, indiferent de aplicația în cadrul căreia sunt scrise aceste logici de business sau de sursele de date puse la dispoziție.
Stratul de date gestionează sursa efectivă a datelor, fie că acestea provin de la API-uri externe, baze de date locale sau senzorii interni ai mașinii. Acest strat implementează concret contractele definite de cazurile de utilizare și de entități. Stratul de date permite accesarea surselor de date fără a ține cont de ce cazuri de utilizare sunt folosite și, cu atât mai mult, fără a necesita cunoștințe despre felul prezentărilor datelor către utilizator. Acest strat poate fi testat atât prin component tests, cât și prin unit tests, însă, de cele mai multe ori, nu este nevoie, deoarece stratul doar preia date din surse deja testate de către dezvoltatorii surselor de date.
Separarea clară a responsabilităților: Fiecare strat are o responsabilitate bine definită, ușor de înțeles și de întreținut.
Flexibilitate și extensibilitate: Arhitectura permite adăugarea de noi funcționalități fără a afecta straturile deja existente.
Testabilitate crescută: Datorită separării stricte a straturilor, este ușor să testezi fiecare componentă în mod izolat. De exemplu, fiecare dezvoltator specializat pe o anumită funcționalitate își poate testa independent munca sau poate chiar ruga testerii să o facă într-un mod ce nu necesită deloc cunoștințe despre tehnologiile sau funcționalitățile din alte straturi, respectiv componente / cerințe funcționale.
Complexitatea inițială: Aplicarea principiilor Clean Architecture necesită o înțelegere profundă a acestei abordări și poate adăuga complexitate suplimentară la început. În special pentru aplicațiile Android Automotive, care deja au o serie de constrângeri tehnice, această complexitate poate deveni o provocare. Complexitatea survine din înțelegerea profundă a tuturor cerințelor funcționale și a interfațării minime necesare între componente, satisfăcând cerințele non-funcționale, precum utilizabilitatea, extensibilitatea, mentenabilitatea, etc.
Gestionarea dependințelor de platformă: Automotive include componente și servicii specifice care pot fi dificil de abstractizat. De exemplu, integrarea cu sistemele vehiculului poate introduce interdependințe greu de izolat în anumite straturi. De asemenea, fluxul de date trebuie să fie analizat cu atenție pentru a satisface corect cerințele de securitate.
În concluzie, crearea unui HMI impecabil bazat pe AAOS necesită o atenție deosebită asupra performanței aplicațiilor și a calității codului. Utilizarea unor instrumente precum Baseline Profiles și Perfetto permite optimizarea experienței utilizatorului prin timpi de răspuns rapizi și o interfață fluidă. Arhitectura Clean oferă o separare clară a responsabilităților și flexibilitate în dezvoltare. Astfel, aplicarea acestor bune practici ajută la dezvoltarea unor interfețe performante și eficiente, esențiale pentru experiența utilizatorului.
de Ovidiu Mățan
de Diana Gabor
de Ovidiu Popa