This shows you the differences between two versions of the page.
pdm:laboratoare:05 [2016/03/21 00:00] alexandru.radovici |
pdm:laboratoare:05 [2016/03/22 12:22] (current) alexandru.radovici [Exerciții] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Laborator 05 - Intenții și Servicii ====== | + | ====== Laborator 5 - Intenții ====== |
- | ====== Intenții ====== | + | ===== Intenții ===== |
Conceptul de intenție în Android este destul de complex (și unic), putând fi definit ca o acțiune având asociată o serie de informații, transmisă sistemului de operare Android pentru a fi executată sub forma unui mesaj asincron. În acest fel, intenția asigură interacțiunea între toate aplicațiile instalate pe dispozitivul mobil, chiar dacă fiecare în parte are o existență autonomă. Din această perspectivă, sistemul de operare Android poate fi privit ca o colecție de componente funcționale, independente și interconectate. | Conceptul de intenție în Android este destul de complex (și unic), putând fi definit ca o acțiune având asociată o serie de informații, transmisă sistemului de operare Android pentru a fi executată sub forma unui mesaj asincron. În acest fel, intenția asigură interacțiunea între toate aplicațiile instalate pe dispozitivul mobil, chiar dacă fiecare în parte are o existență autonomă. Din această perspectivă, sistemul de operare Android poate fi privit ca o colecție de componente funcționale, independente și interconectate. | ||
De regulă, o intenție poate fi utilizată pentru: | De regulă, o intenție poate fi utilizată pentru: | ||
+ | * a invoca activități din cadrul aceleiași aplicații Android; | ||
+ | * a invoca alte activități, existente în contextul altor aplicații Android; | ||
+ | * a transmite mesaje cu difuzare (//eng.// broadcast messages), care sunt propagate la nivelul întregului sistem de operare Android și pe care unele aplicații Android le pot prelucra, prin definirea unor clase ascultător specifice; un astfel de comportament este util pentru a implementa aplicații bazate pe evenimente. | ||
- | ''%% * a invoca activități din cadrul aceleiași aplicații Android;%%''\\ | + | O intenție reprezintă o instanță a clasei ''android.content.Intent''. Aceasta este transmisă ca parametru unor metode (de tipul ''startActivity()'' sau ''startService()'', definite în clasa abstractă ''android.content.Context''), pentru a invoca anumite componente (activități sau servicii). Un astfel de obiect poate încapsula anumite date (împachetate sub forma unui ''android.os.Bundle''), care pot fi utilizate de componenta ce se dorește a fi executată prin intermediul intenției. |
- | ''%% * a invoca alte activități, existente în contextul altor aplicații Android;%%''\\ | + | |
- | ''%% * a transmite mesaje cu difuzare (//eng.// broadcast messages), care sunt propagate la nivelul întregului sistem de operare Android și pe care unele aplicații Android le pot prelucra, prin definirea unor clase ascultător specifice; un astfel de comportament este util pentru a implementa aplicații bazate pe evenimente.%%'' | + | |
- | + | ||
- | O intenție reprezintă o instanță a clasei //android.content.Intent//. Aceasta este transmisă ca parametru unor metode (de tipul //startActivity()// sau //startService()//, definite în clasa abstractă //android.content.Context//), pentru a invoca anumite componente (activități sau servicii). Un astfel de obiect poate încapsula anumite date (împachetate sub forma unui //android.os.Bundle//), care pot fi utilizate de componenta ce se dorește a fi executată prin intermediul intenției. | + | |
În programarea Android, un principiu de bază este de folosi intenții pentru a propaga acțiuni, chiar și în cadrul aceleiași aplicații, în detrimentul încărcării clasei corespunzătoare. În acest fel, se asigură cuplarea slabă a componentelor, oferind flexibilitate în cazul înlocuirii acestora, permițând totodată extinderea funcționalității cu ușurință. | În programarea Android, un principiu de bază este de folosi intenții pentru a propaga acțiuni, chiar și în cadrul aceleiași aplicații, în detrimentul încărcării clasei corespunzătoare. În acest fel, se asigură cuplarea slabă a componentelor, oferind flexibilitate în cazul înlocuirii acestora, permițând totodată extinderea funcționalității cu ușurință. | ||
Line 19: | Line 18: | ||
==== Intenții construite prin precizarea clasei încărcate ==== | ==== Intenții construite prin precizarea clasei încărcate ==== | ||
- | În fișierul //AndroidManifest.xml//, orice activitate definește în cadrul elementului //<html><intent-filter></html>//, denumirea unei acțiuni care va putea fi folosită de o intenție pentru a o invoca. | + | În fișierul ''AndroidManifest.xml'', orice activitate definește în cadrul elementului ''<intent-filter>'', denumirea unei acțiuni care va putea fi folosită de o intenție pentru a o invoca. |
- | <html><code xml></html> <html><activity | + | <code xml> |
+ | <activity | ||
android:name="org.rosedu.dandroid.lab05.MainActivity" | android:name="org.rosedu.dandroid.lab05.MainActivity" | ||
- | android:label="@string/app_name" ></html> | + | android:label="@string/app_name" > |
+ | <intent-filter> | ||
+ | <action android:name="org.rosedu.dandroid.lab05.intent.action.MainActivity" /> | ||
+ | <category android:name="android.intent.category.LAUNCHER" /> | ||
+ | </intent-filter> | ||
+ | </activity> | ||
+ | </code> | ||
- | ''%% %%''<html><intent-filter></html>\\ | + | <note important>Pentru ca o activitate să poată fi invocată, aceasta trebuie să specifice la elementul ''category'' din ''<intent-filter>'' valoarea ''android.intent.category.DEFAULT''.</note> |
- | ''%% %%''<html><action android:name="org.rosedu.dandroid.lab05.intent.action.MainActivity" /></html>\\ | + | |
- | ''%% %%''<html><category android:name="android.intent.category.LAUNCHER" /></html>\\ | + | |
- | ''%% %%''<html></intent-filter></html> | + | |
- | <html></activity></html> <html></code></html> | + | Pentru ca o funcționalitatea expusă de o activitate să poată fi invocată (în mod anonim) și din contextul altor componente ale sistemului de operare Android, pentru tipul de acțiune și pentru tipurile de date precizate, în cadrul secțiunii ''<intent-filter>'' trebuie precizat atributul ''android:label'' (șir de caractere care conține o descriere a funcționalității implementate), indicându-se ca tip de categorie valorile ''ALTERNATIVE'', ''SELECTED_ALTERNATIVE'' sau ambele. |
- | + | ||
- | <HTML> | + | |
- | <note important> | + | |
- | </HTML> | + | |
- | Pentru ca o activitate să poată fi invocată, aceasta trebuie să specifice la elementul //category// din //<html><intent-filter></html>// valoarea //android.intent.category.DEFAULT//. | + | |
- | + | ||
- | <HTML> | + | |
- | </note> | + | |
- | </HTML> | + | |
- | Pentru ca o funcționalitatea expusă de o activitate să poată fi invocată (în mod anonim) și din contextul altor componente ale sistemului de operare Android, pentru tipul de acțiune și pentru tipurile de date precizate, în cadrul secțiunii //<html><intent-filter></html>// trebuie precizat atributul //android:label// (șir de caractere care conține o descriere a funcționalității implementate), indicându-se ca tip de categorie valorile //ALTERNATIVE//, //SELECTED_ALTERNATIVE// sau ambele. | + | |
- | O activitate este în principiu invocată de o intenție care poate fi identificată prin apelul metodei //getIntent()//. Rezultatul acestei metode poate fi inclusiv //null//, în cazul în care activitatea nu a fost pornită prin intermediul unei intenții. | + | O activitate este în principiu invocată de o intenție care poate fi identificată prin apelul metodei ''getIntent()''. Rezultatul acestei metode poate fi inclusiv ''null'', în cazul în care activitatea nu a fost pornită prin intermediul unei intenții. |
Prin intermediul unei intenții, o aplicație poate invoca atât o activitate din cadrul său, cât și o activitate aparținând altei aplicații. | Prin intermediul unei intenții, o aplicație poate invoca atât o activitate din cadrul său, cât și o activitate aparținând altei aplicații. | ||
+ | * în situația în care se apelează o activitate din cadrul aceleiași aplicații, se poate folosi folosi metoda <code java> | ||
+ | startActivity(new Intent(this, AnotherActivity.class)); | ||
+ | </code> | ||
+ | * dacă se dorește rularea unei activități existente în cadrul altei aplicații, aceasta va trebui referită prin numele său complet, inclusiv denumirea pachetului care o identifică <code java> | ||
+ | startActivity(new Intent("org.rosedu.dandroid.lab05.AnotherActivity")); | ||
+ | </code> | ||
- | ''%% * în situația în care se apelează o activitate din cadrul aceleiași aplicații, se poate folosi folosi metoda startActivity(new%%'' ''%%Intent(this,%%'' ''%%AnotherActivity.class));%%''\\ | + | De remarcat faptul că în situația în care este pornită o activitate din cadrul aceleiași aplicații Android, obiectul de tip ''Intent'' primește ca parametru și contextul curent (''this''), în timp ce în cazul în care este lansată în execuție o activitate din cadrul altei aplicații Android acest parametru este omis. |
- | ''%% * dacă se dorește rularea unei activități existente în cadrul altei aplicații, aceasta va trebui referită prin numele său complet, inclusiv denumirea pachetului care o identifică startActivity(new%%'' ''%%Intent("org.rosedu.dandroid.lab05.AnotherActivity"));%%'' | + | |
- | De remarcat faptul că în situația în care este pornită o activitate din cadrul aceleiași aplicații Android, obiectul de tip //Intent// primește ca parametru și contextul curent (//this//), în timp ce în cazul în care este lansată în execuție o activitate din cadrul altei aplicații Android acest parametru este omis. | + | În momentul în care este invocată metoda ''startActivity()'', activitatea respectivă este lansată în execuție (prin apelul metodelor ''onCreate()'', ''onStart()'', ''onResume()'') și plasată în vârful stivei care conține toate componentele care au rulate anterior, fără a fi fost terminate. În momentul în care se apelează metoda ''finish()'' (sau se apasă butonul //Back//), activitatea este încheiată (prin apelul metodelor ''onPause()'', ''onStop()'', ''onDestroy()''), fiind scoasă din stivă, restaurându-se activitatea anterioară. |
- | + | ||
- | În momentul în care este invocată metoda //startActivity()//, activitatea respectivă este lansată în execuție (prin apelul metodelor //onCreate()//, //onStart()//, //onResume()//) și plasată în vârful stivei care conține toate componentele care au rulate anterior, fără a fi fost terminate. În momentul în care se apelează metoda //finish()// (sau se apasă butonul %%//%%Back%%//%%), activitatea este încheiată (prin apelul metodelor //onPause()//, //onStop()//, //onDestroy()//), fiind scoasă din stivă, restaurându-se activitatea anterioară. | + | |
==== Intenții construite prin precizarea acțiunii ==== | ==== Intenții construite prin precizarea acțiunii ==== | ||
Line 57: | Line 53: | ||
O intenție poate fi definită și prin intermediul unei acțiuni care se dorește a fi realizată, pentru care pot fi atașate opțional și anumite date. Utilizatorul care folosește un astfel de mecanism nu cunoaște activitatea (sau aplicația Android) care va fi lansată în execuție pentru realizarea acțiunii respective. Pentru a putea îndeplini o astfel de solicitare, sistemul de operare Android trebuie să identifice, la momentul rulării, activitatea care este cea mai adecvată pentru a rezolva acțiunea dorită. În acest fel, pot fi utilizate funcționalități deja implementate în cadrul sistemului de operare Android, fără a cunoaște în prealabil aplicația responsabilă de aceasta. | O intenție poate fi definită și prin intermediul unei acțiuni care se dorește a fi realizată, pentru care pot fi atașate opțional și anumite date. Utilizatorul care folosește un astfel de mecanism nu cunoaște activitatea (sau aplicația Android) care va fi lansată în execuție pentru realizarea acțiunii respective. Pentru a putea îndeplini o astfel de solicitare, sistemul de operare Android trebuie să identifice, la momentul rulării, activitatea care este cea mai adecvată pentru a rezolva acțiunea dorită. În acest fel, pot fi utilizate funcționalități deja implementate în cadrul sistemului de operare Android, fără a cunoaște în prealabil aplicația responsabilă de aceasta. | ||
- | <HTML> | + | <note>În cazul în care există mai multe activități care au specificat la elementul ''action'' din ''intent-category'' aceeași valoare care este transmisă ca parametru constructorului clasei ''Intent'', la execuția intenției în cauză utilizatorului i se va prezenta o listă de opțiuni dintre care poate alege. Dacă la realizarea selecției va fi precizată și opțiunea ''Use by default for this action'', preferințele vor fi salvate astfel încât în continuare vor fi utilizate fără a se mai solicita intervenția utilizatorului în acest sens.</note> |
- | <note> | + | |
- | </HTML> | + | |
- | În cazul în care există mai multe activități care au specificat la elementul //action// din //intent-category// aceeași valoare care este transmisă ca parametru constructorului clasei //Intent//, la execuția intenției în cauză utilizatorului i se va prezenta o listă de opțiuni dintre care poate alege. Dacă la realizarea selecției va fi precizată și opțiunea //Use by default for this action//, preferințele vor fi salvate astfel încât în continuare vor fi utilizate fără a se mai solicita intervenția utilizatorului în acest sens. | + | |
- | <HTML> | + | Procesul de rezolvare a unei intenții (//eng.// intent resolution) se face prin intermediul analizei tuturor ascultătorilor înregistrați pentru a procesa mesaje cu difuzare (//eng.// broascast receivers). |
- | </note> | + | |
- | </HTML> | + | |
- | Procesul de rezolvare a unei intenții (%%//%%eng.%%//%% intent resolution) se face prin intermediul analizei tuturor ascultătorilor înregistrați pentru a procesa mesaje cu difuzare (%%//%%eng.%%//%% broascast receivers). | + | |
- | Cele mai frecvent utilizate acțiuni implicite ale unui obiect de tip //Intent// sunt: | + | Cele mai frecvent utilizate acțiuni implicite ale unui obiect de tip ''Intent'' sunt: |
+ | * vizualizarea conținutului specificat în secțiunea ''data'' asociată intenției, sub forma unui URI, de către aplicații Android diferite, în funcție de schema (protocolul) utilizat (''http'' - navigator, ''tel'' - aplicația pentru formarea unui număr de telefon, ''geo'' - Google Maps, ''content'' - aplicația pentru gestiunea contactelor din agenda telefonică): <code java> | ||
+ | Intent intent = new Intent(Intent.ACTION_VIEW); | ||
+ | intent.setData(Uri.parse("http://android.rosedu.org")); | ||
+ | </code> | ||
+ | * căutarea unor informații pe Internet folosind un motor de căutare, termenul căutat fiind indicat în secțiunea ''extra'' asociată intenției, fiind identificată prin cheia ''SearchManager.QUERY'': <code java> | ||
+ | Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); | ||
+ | intent.setData(Uri.parse("http://www.google.ro")); | ||
+ | </code> | ||
+ | * invocarea aplicației Android pentru formarea unui număr de telefon (interfața grafică a aplicației Android poate fi populată deja cu numărul de telefon furnizat în secțiunea de date a intenției asociate, în cadrul unui URI); aplicația Android nativă poate normaliza majoritatea schemelor de numere de telefon (cod de țară, prefix, număr de telefon propriu-zis): <code java> | ||
+ | Intent intent = new Intent(Intent.ACTION_DIAL); | ||
+ | </code> | ||
+ | * invocarea aplicației pentru formarea unui număr de telefon și realizarea propriu-zisă a apelului telefonic, folosind valoarea furnizată în secțiunea de date a intenției asociate (în cadrul unui URI); se recomandă să fie folosită pentru activitățile care înlocuiesc aplicația Android nativă pentru formarea unui număr de telefon: <code java> | ||
+ | Intent intent = new Intent(Intent.ACTION_CALL); | ||
+ | intent.setData(Uri.parse("tel:0214029466")); | ||
+ | </code> | ||
- | ''%% * vizualizarea conținutului specificat în secțiunea %%''//''%%data%%''//''%% asociată intenției, sub forma unui URI, de către aplicații Android diferite, în funcție de schema (protocolul) utilizat (%%''//''%%http%%''//''%% - navigator, %%''//''%%tel%%''//''%% - aplicația pentru formarea unui număr de telefon, %%''//''%%geo%%''//''%% - Google Maps, %%''//''%%content%%''//''%% - aplicația pentru gestiunea contactelor din agenda telefonică): Intent%%'' ''%%intent%%'' ''%%=%%'' ''%%new%%'' ''%%Intent(Intent.ACTION_VIEW);%%'' ''%%intent.setData(Uri.parse("%%''[[http://android.rosedu.org|''%%http://android.rosedu.org%%'']]''%%"));%%''\\ | + | <note important>Pentru a fi posibil ca aplicația să realizeze un apel telefonic, în fișierul ''AndroidManifest.xml'' trebuie specificată explicit permisiunea pentru o astfel de acțiune\\ ''<uses-permission android:name="android.permission.CALL_PHONE">''. </note> |
- | ''%% * căutarea unor informații pe Internet folosind un motor de căutare, termenul căutat fiind indicat în secțiunea %%''//''%%extra%%''//''%% asociată intenției, fiind identificată prin cheia %%''//''%%SearchManager.QUERY%%''//''%%: Intent%%'' ''%%intent%%'' ''%%=%%'' ''%%new%%'' ''%%Intent(Intent.ACTION_WEB_SEARCH);%%'' ''%%intent.setData(Uri.parse("%%''[[http://www.google.ro|''%%http://www.google.ro%%'']]''%%"));%%''\\ | + | |
- | ''%% * invocarea aplicației Android pentru formarea unui număr de telefon (interfața grafică a aplicației Android poate fi populată deja cu numărul de telefon furnizat în secțiunea de date a intenției asociate, în cadrul unui URI); aplicația Android nativă poate normaliza majoritatea schemelor de numere de telefon (cod de țară, prefix, număr de telefon propriu-zis): Intent%%'' ''%%intent%%'' ''%%=%%'' ''%%new%%'' ''%%Intent(Intent.ACTION_DIAL);%%''\\ | + | |
- | ''%% * invocarea aplicației pentru formarea unui număr de telefon și realizarea propriu-zisă a apelului telefonic, folosind valoarea furnizată în secțiunea de date a intenției asociate (în cadrul unui URI); se recomandă să fie folosită pentru activitățile care înlocuiesc aplicația Android nativă pentru formarea unui număr de telefon: Intent%%'' ''%%intent%%'' ''%%=%%'' ''%%new%%'' ''%%Intent(Intent.ACTION_CALL);%%'' ''%%intent.setData(Uri.parse("%%''[[tel:0214029466|''%%tel:0214029466%%'']]''%%"));%%'' | + | |
- | <HTML> | + | * vizualizarea unei locații pe hartă pentru care s-au specificat coordonatele GPS <code java> |
- | <note important> | + | Intent intent = new Intent(Intent.ACTION_VIEW); |
- | </HTML> | + | intent.setData(Uri.parse("geo:44.436877,26.048029?z=100&q=Education")); |
- | Pentru a fi posibil ca aplicația să realizeze un apel telefonic, în fișierul //AndroidManifest.xml// trebuie specificată explicit permisiunea pentru o astfel de acțiune\\ //<html><uses-permission android:name="android.permission.CALL_PHONE"></html>//. | + | </code> |
- | + | * selectarea unei valori din cadrul furnizorului de conținut indicat în cadrul secțiunii de date asociate intenției, sub forma unui URI; de regulă, este lansată în execuție ca subacvititate, fiind necesar să furnizeze un URI către valoarea care a fost accesată, atunci când este terminată <code java> | |
- | <HTML> | + | Intent intent = new Intent(Intent.ACTION_PICK); |
- | </note> | + | intent.setData(Uri.parse("content://contacts/people")); |
- | </HTML> | + | </code> |
- | ''%% * vizualizarea unei locații pe hartă pentru care s-au specificat coordonatele GPS Intent%%'' ''%%intent%%'' ''%%=%%'' ''%%new%%'' ''%%Intent(Intent.ACTION_VIEW);%%'' ''%%intent.setData(Uri.parse("%%''[[geo:44.436877,26.048029?z=100&q=Education|''%%geo:44.436877,26.048029?z=100&q=Education%%'']]''%%"));%%''\\ | + | |
- | ''%% * selectarea unei valori din cadrul furnizorului de conținut indicat în cadrul secțiunii de date asociate intenției, sub forma unui URI; de regulă, este lansată în execuție ca subacvititate, fiind necesar să furnizeze un URI către valoarea care a fost accesată, atunci când este terminată Intent%%'' ''%%intent%%'' ''%%=%%'' ''%%new%%'' ''%%Intent(Intent.ACTION_PICK);%%'' ''%%intent.setData(Uri.parse("%%''[[content://contacts/people|''%%content://contacts/people%%'']]''%%"));%%'' | + | |
Alte acțiuni implicite utilizate sunt: | Alte acțiuni implicite utilizate sunt: | ||
+ | * ''ACTION_ALL_APPS'' - lansează în execuție o activitate care afișează toate aplicațiile Android instalate pe dispozitivul mobil; implicit, această acțiune este tratată de aplicația nativă care listează aplicațiile Android în meniul de aplicații din care pot fi rulate de utilizator prin accesarea pictogramei asociate; | ||
+ | * ''ACTION_ANSWER'' - lansează în execuție o activitate care gestionează apelurile primite; | ||
+ | * ''ACTION_BUG_REPORT'' - lansează în execuție o activitate prin intermediul căruia poate fi raportată funcționarea anormală a unei aplicații Android; | ||
+ | * ''ACTION_CALL_BUTTON'' - lansează în execuție o activitate responsabilă cu formarea numărului de telefon; de regulă, o astfel de acțiune este generată în momentul în care utilizatorul accesează un buton dedicat; | ||
+ | * ''ACTION_DELETE'' - lansează în execuție o activitate care permite ștergerea informațiilor specificate în secțiunea ''data'' asociată intenției, sub forma unui URI; | ||
+ | * ''ACTION_EDIT'' - lansează în execuție o activitate care permite modificarea informațiilor specificate în secțiunea ''data'' asociată intenției, sub forma unui URI; | ||
+ | * ''ACTION_INSERT'' - lansează în execuție o activitate care permite adăugarea unor informații în cursorul specificat în secțiunea de secțiunea ''data'' asociată intenției, sub forma unui URI (în cazul în care este rulată ca subactivitate, trebuie să furnizeze URI-ul informațiilor adăugate); | ||
+ | * ''ACTION_SEARCH'' - lansează în execuție o activitate care implementează o activitate de căutare; termenul care este căutat trebuie să fie specificat în secțiunea ''extra'' a activității, fiind identificat prin cheia ''SearchManager.QUERY''; | ||
+ | * ''ACTION_SEARCH_LONG_PRESS'' - lansează în execuție o activitate care implementează o activitate de căutare, fiind generată în momentul în care este detectat un eveniment de tip apăsare prelungită a unui buton dedicat (implicit, lansează în execuție o activitate pentru a realiza o căutare vocală); | ||
+ | * ''ACTION_SENDTO'' - lansează în execuție o activitate pentru a transmite anumite informații către un contact indicat în secțiunea ''data'' asociată intenției; | ||
+ | * ''ACTION_SEND'' - lansează în execuție o activitate care transmite informațiile conținute în cadrul intenției către un contact care va fi selectat ulterior (aflat pe un alt dispozitiv mobil): | ||
+ | * tipul MIME trebuie indicat prin intermediul metodei ''setType()''; | ||
+ | * informațiile propriu-zise trebnuie conținute în secțiunea ''extra'' asociată intenției, fiind identificate prin cheile ''EXTRA_TEXT'' sau ''EXTRA_STREAM'', în funcție de tipul respectiv (pentru aplicațiile de poștă electronică sunt suportate și cheile ''EXTRA_EMAIL'', ''EXTRA_CC'', ''EXTRA_BCC'', ''EXTRA_SUBJECT''). | ||
- | ''%% * %%''//''%%ACTION_ALL_APPS%%''//''%% - lansează în execuție o activitate care afișează toate aplicațiile Android instalate pe dispozitivul mobil; implicit, această acțiune este tratată de aplicația nativă care listează aplicațiile Android în meniul de aplicații din care pot fi rulate de utilizator prin accesarea pictogramei asociate;%%''\\ | + | Totuși, un utilizator nu poate avea garanția că acțiunea pe care o transmite ca parametru al unei intenții va putea fi rezolvată, întrucât există posibilitatea să nu existe nici o activitate asociată acesteia sau ca aplicația ce ar fi putut să o execute să nu fie instalată în contextul sistemului de operare Android. Din acest motiv, o practică curentă este de a verifica dacă o acțiune poate fi rezolvată **înainte** de a apela metoda ''startActivity()''. Astfel, procesul de gestiune a pachetelor poate fi interogat (prin intermediul metodei ''resolveActivity()'') dacă există o activitate ce poate executa o acțiune și în caz afirmativ, care este aceasta. |
- | ''%% * %%''//''%%ACTION_ANSWER%%''//''%% - lansează în execuție o activitate care gestionează apelurile primite;%%''\\ | + | |
- | ''%% * %%''//''%%ACTION_BUG_REPORT%%''//''%% - lansează în execuție o activitate prin intermediul căruia poate fi raportată funcționarea anormală a unei aplicații Android;%%''\\ | + | |
- | ''%% * %%''//''%%ACTION_CALL_BUTTON%%''//''%% - lansează în execuție o activitate responsabilă cu formarea numărului de telefon; de regulă, o astfel de acțiune este generată în momentul în care utilizatorul accesează un buton dedicat;%%''\\ | + | |
- | ''%% * %%''//''%%ACTION_DELETE%%''//''%% - lansează în execuție o activitate care permite ștergerea informațiilor specificate în secțiunea %%''//''%%data%%''//''%% asociată intenției, sub forma unui URI;%%''\\ | + | |
- | ''%% * %%''//''%%ACTION_EDIT%%''//''%% - lansează în execuție o activitate care permite modificarea informațiilor specificate în secțiunea %%''//''%%data%%''//''%% asociată intenției, sub forma unui URI;%%''\\ | + | |
- | ''%% * %%''//''%%ACTION_INSERT%%''//''%% - lansează în execuție o activitate care permite adăugarea unor informații în cursorul specificat în secțiunea de secțiunea %%''//''%%data%%''//''%% asociată intenției, sub forma unui URI (în cazul în care este rulată ca subactivitate, trebuie să furnizeze URI-ul informațiilor adăugate);%%''\\ | + | |
- | ''%% * %%''//''%%ACTION_SEARCH%%''//''%% - lansează în execuție o activitate care implementează o activitate de căutare; termenul care este căutat trebuie să fie specificat în secțiunea %%''//''%%extra%%''//''%% a activității, fiind identificat prin cheia %%''//''%%SearchManager.QUERY%%''//''%%;%%''\\ | + | |
- | ''%% * %%''//''%%ACTION_SEARCH_LONG_PRESS%%''//''%% - lansează în execuție o activitate care implementează o activitate de căutare, fiind generată în momentul în care este detectat un eveniment de tip apăsare prelungită a unui buton dedicat (implicit, lansează în execuție o activitate pentru a realiza o căutare vocală);%%''\\ | + | |
- | ''%% * %%''//''%%ACTION_SENDTO%%''//''%% - lansează în execuție o activitate pentru a transmite anumite informații către un contact indicat în secțiunea %%''//''%%data%%''//''%% asociată intenției;%%''\\ | + | |
- | ''%% * %%''//''%%ACTION_SEND%%''//''%% - lansează în execuție o activitate care transmite informațiile conținute în cadrul intenției către un contact care va fi selectat ulterior (aflat pe un alt dispozitiv mobil):%%''\\ | + | |
- | ''%% * tipul MIME trebuie indicat prin intermediul metodei %%''//''%%setType()%%''//''%%;%%''\\ | + | |
- | ''%% * informațiile propriu-zise trebnuie conținute în secțiunea %%''//''%%extra%%''//''%% asociată intenției, fiind identificate prin cheile %%''//''%%EXTRA_TEXT%%''//''%% sau %%''//''%%EXTRA_STREAM%%''//''%%, în funcție de tipul respectiv (pentru aplicațiile de poștă electronică sunt suportate și cheile %%''//''%%EXTRA_EMAIL%%''//''%%, %%''//''%%EXTRA_CC%%''//''%%, %%''//''%%EXTRA_BCC%%''//''%%, %%''//''%%EXTRA_SUBJECT%%''//''%%).%%'' | + | |
- | + | ||
- | Totuși, un utilizator nu poate avea garanția că acțiunea pe care o transmite ca parametru al unei intenții va putea fi rezolvată, întrucât există posibilitatea să nu existe nici o activitate asociată acesteia sau ca aplicația ce ar fi putut să o execute să nu fie instalată în contextul sistemului de operare Android. Din acest motiv, o practică curentă este de a verifica dacă o acțiune poate fi rezolvată %%**%%înainte%%**%% de a apela metoda //startActivity()//. Astfel, procesul de gestiune a pachetelor poate fi interogat (prin intermediul metodei //resolveActivity()//) dacă există o activitate ce poate executa o acțiune și în caz afirmativ, care este aceasta. | + | |
- | + | ||
- | <html><code java></html> Intent applicationIntent = new Intent(...); PackageManager packageManager = new PackageManager(); ComponentName componentName = applicationIntent .resolveActivity(packageManager); if (componentName == null) { | + | |
- | + | ||
- | ''%% Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("%%''[[market://search?q=pname|''%%market://search?q=pname%%'']]''%%:..."));%%''\\ | + | |
- | ''%% if (marketIntent.resolveActivity(packageManager) != null) {%%''\\ | + | |
- | ''%% startActivity(marketIntent);%%''\\ | + | |
- | ''%% } else {%%''\\ | + | |
- | ''%% Toast.makeText(getApplicationContext(), "Google Play Store is not available", Toast.LENGTH_LONG).show();%%''\\ | + | |
- | ''%% }%%'' | + | |
+ | <code java> | ||
+ | Intent applicationIntent = new Intent(...); | ||
+ | PackageManager packageManager = new PackageManager(); | ||
+ | ComponentName componentName = applicationIntent .resolveActivity(packageManager); | ||
+ | if (componentName == null) { | ||
+ | Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pname:...")); | ||
+ | if (marketIntent.resolveActivity(packageManager) != null) { | ||
+ | startActivity(marketIntent); | ||
+ | } else { | ||
+ | Toast.makeText(getApplicationContext(), "Google Play Store is not available", Toast.LENGTH_LONG).show(); | ||
+ | } | ||
} else { | } else { | ||
- | + | startActivity(intent); | |
- | ''%% startActivity(intent);%%'' | + | } |
- | + | </code> | |
- | } <html></code></html> | + | |
În situația în care nu este identificată nici o activitate asociată acțiunii respective, utilizatorul poate dezactiva componenta grafică asociată până în momentul în care aceasta devine disponibilă, prin descărcarea aplicației Android corespunzătoare din Google Play Store. | În situația în care nu este identificată nici o activitate asociată acțiunii respective, utilizatorul poate dezactiva componenta grafică asociată până în momentul în care aceasta devine disponibilă, prin descărcarea aplicației Android corespunzătoare din Google Play Store. | ||
- | Prin intermediul clasei //PackageManager// poate fi obținută lista tuturor acțiunilor care pot fi realizate pentru un set de date, atașat unei intenții, invocându-se metoda //queryIntentActivities()//. | + | Prin intermediul clasei ''PackageManager'' poate fi obținută lista tuturor acțiunilor care pot fi realizate pentru un set de date, atașat unei intenții, invocându-se metoda ''queryIntentActivities()''. |
Procesul de rezolvare a unei intenții pe baza unei acțiuni implică următoarele etape: | Procesul de rezolvare a unei intenții pe baza unei acțiuni implică următoarele etape: | ||
+ | - se construiește o listă cu toate filtrele de intenții asociate componentelor din aplicațiile Android existente; | ||
+ | - sunt eliminate toate filtrele de intenții care nu corespund acțiunii sau categoriei intenției care se dorește a fi rezolvată: | ||
+ | - verificările în privința acțiunii sunt realizate numai în situația în care filtrul de intenție specifică o acțiune; sunt eliminate acele filtre de intenții pentru care **nici una** dintre acțiunile pe care le include nu corespund acțiunii intenției care se dorește a fi rezolvată; | ||
+ | - verificările în privința categorie sunt realizate numai în situația în care filtrul de intenție specifică o categorie sau în cazul în care nu specifică nici o categorie, dacă nici intenția care se dorește a fi rezolvată nu include nici o categorie; sunt eliminate acele filtre de intenții care nu includ **toate** categoriile pe care le conține și intenția care se dorește a fi rezolvată (putând conține totuși și categorii suplimentare); | ||
+ | - fiecare parte a URI-ului datelor corespunzătoare intenției care se dorește a fi rezolvată este comparată cu secțiunea ''data'' din filtrul de intenție; gazda, autoritatea, tipul MIME, calea, portul, schema), orice neconcordanță conducând la eliminarea acestuia din listă (în situația în care filtrul de intenții nu specifică proprietăți în secțiunea ''data'', acesta va fi considerat compatibil cu intenția care se dorește a fi rezolvată; | ||
+ | - în situația în care, ca urmare a acestui proces, există mai multe componente rămase în listă, utilizatorul va trebui să aleagă dintre toate aceste posibilități. | ||
- | ''%% - se construiește o listă cu toate filtrele de intenții asociate componentelor din aplicațiile Android existente;%%''\\ | + | <note>Aplicațiile Android native sunt supuse aceluiași proces în momentul în care se realizează rezolvarea unei intenții ca și aplicațiile Android instalate din alte surse, având aceeiași prioritate și putând fi chiar înlocuite de acestea, dacă definesc filtre de intenții cu aceleași acțiuni / categorii.</note> |
- | ''%% - sunt eliminate toate filtrele de intenții care nu corespund acțiunii sau categoriei intenției care se dorește a fi rezolvată:%%''\\ | + | |
- | ''%% - verificările în privința acțiunii sunt realizate numai în situația în care filtrul de intenție specifică o acțiune; sunt eliminate acele filtre de intenții pentru care **nici una** dintre acțiunile pe care le include nu corespund acțiunii intenției care se dorește a fi rezolvată;%%''\\ | + | |
- | ''%% - verificările în privința categorie sunt realizate numai în situația în care filtrul de intenție specifică o categorie sau în cazul în care nu specifică nici o categorie, dacă nici intenția care se dorește a fi rezolvată nu include nici o categorie; sunt eliminate acele filtre de intenții care nu includ **toate** categoriile pe care le conține și intenția care se dorește a fi rezolvată (putând conține totuși și categorii suplimentare);%%''\\ | + | |
- | ''%% - fiecare parte a URI-ului datelor corespunzătoare intenției care se dorește a fi rezolvată este comparată cu secțiunea %%''//''%%data%%''//''%% din filtrul de intenție; gazda, autoritatea, tipul MIME, calea, portul, schema), orice neconcordanță conducând la eliminarea acestuia din listă (în situația în care filtrul de intenții nu specifică proprietăți în secțiunea %%''//''%%data%%''//''%%, acesta va fi considerat compatibil cu intenția care se dorește a fi rezolvată;%%''\\ | + | |
- | ''%% - în situația în care, ca urmare a acestui proces, există mai multe componente rămase în listă, utilizatorul va trebui să aleagă dintre toate aceste posibilități.%%'' | + | |
- | <HTML> | + | În cazul în care o componentă a unei activități este lansată în execuție prin intermediul unei intenții, aceasta trebuie să identifice acțiunea pe care trebuie să o realizeze și datele pe care trebuie sp le proceseze. În acest sens, clasa ''Intent'' pune la dispoziție metodele ''getAction()'', ''getData()'' și ''getExtras()''. |
- | <note> | + | |
- | </HTML> | + | |
- | Aplicațiile Android native sunt supuse aceluiași proces în momentul în care se realizează rezolvarea unei intenții ca și aplicațiile Android instalate din alte surse, având aceeiași prioritate și putând fi chiar înlocuite de acestea, dacă definesc filtre de intenții cu aceleași acțiuni / categorii. | + | |
- | <HTML> | + | <code java> |
+ | @Override | ||
+ | protected void onCreate(Bundle state) { | ||
+ | super.onCreate(state); | ||
+ | setContentView(R.layout.activity_main); | ||
+ | Intent intent = getIntent(); | ||
+ | if (intent != null) { | ||
+ | String action = intent.getAction(); | ||
+ | Uri data = intent.getData(); | ||
+ | Bundle extras = intent.getExtras(); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <note tip>În anumite situații, o componentă poate primi și alte intenții după ce a fost creată. De fiecare dată, va fi apelată în mod automat metoda ''onNewIntent()'': <code java> | ||
+ | @Override | ||
+ | public void onNewIntent(Intent newIntent) { | ||
+ | super.onNewIntent(newIntent); | ||
+ | // ... | ||
+ | } | ||
+ | </code> | ||
</note> | </note> | ||
- | </HTML> | ||
- | În cazul în care o componentă a unei activități este lansată în execuție prin intermediul unei intenții, aceasta trebuie să identifice acțiunea pe care trebuie să o realizeze și datele pe care trebuie sp le proceseze. În acest sens, clasa //Intent// pune la dispoziție metodele //getAction()//, //getData()// și //getExtras()//. | ||
- | <html><code java></html> @Override protected void onCreate(Bundle state) { | + | <note tip>O componentă are de asemenea posibilitatea de a transfera responsabilitatea cu privire la gestiunea unei intenții către altă componentă care corespunde criteriilor legate de acțiune și categorie, prin intermediul metodei ''startNextMatchingActivity()'': <code java> |
- | + | Intent intent = getIntent(); | |
- | ''%% super.onCreate(state);%%''\\ | + | if (intent != null) { |
- | ''%% setContentView(R.layout.activity_main);%%''\\ | + | startNextMatchingActivity(intent); |
- | ''%% Intent intent = getIntent();%%''\\ | + | } |
- | ''%% if (intent != null) {%%''\\ | + | </code> |
- | ''%% String action = intent.getAction();%%''\\ | + | În acest mod, o componentă poate indica condiții suplimentare cu privire la tratarea unei anumite acțiuni, în situația în care acestea nu pot fi exprimate în cadrul filtrului de intenții, pentru a putea fi luate în considerare în cadrul procesului automat de identificare a componentei care deservește o intenție. |
- | ''%% Uri data = intent.getData();%%''\\ | + | |
- | ''%% Bundle extras = intent.getExtras();%%''\\ | + | |
- | ''%% }%%'' | + | |
- | + | ||
- | } <html></code></html> | + | |
- | + | ||
- | <HTML> | + | |
- | <note tip> | + | |
- | </HTML> | + | |
- | În anumite situații, o componentă poate primi și alte intenții după ce a fost creată. De fiecare dată, va fi apelată în mod automat metoda //onNewIntent()//: <html><code java></html> @Override public void onNewIntent(Intent newIntent) { | + | |
- | + | ||
- | ''%% super.onNewIntent(newIntent);%%''\\ | + | |
- | ''%% // ...%%'' | + | |
- | + | ||
- | } <html></code></html> | + | |
- | + | ||
- | <HTML> | + | |
</note> | </note> | ||
- | <note tip> | ||
- | </HTML> | ||
- | O componentă are de asemenea posibilitatea de a transfera responsabilitatea cu privire la gestiunea unei intenții către altă componentă care corespunde criteriilor legate de acțiune și categorie, prin intermediul metodei //startNextMatchingActivity()//: <html><code java></html> Intent intent = getIntent(); if (intent != null) { | ||
- | ''%% startNextMatchingActivity(intent);%%'' | ||
- | |||
- | } <html></code></html> În acest mod, o componentă poate indica condiții suplimentare cu privire la tratarea unei anumite acțiuni, în situația în care acestea nu pot fi exprimate în cadrul filtrului de intenții, pentru a putea fi luate în considerare în cadrul procesului automat de identificare a componentei care deservește o intenție. | ||
- | |||
- | <HTML> | ||
- | </note> | ||
- | </HTML> | ||
==== Intenții construite prin intermediul unui URI ==== | ==== Intenții construite prin intermediul unui URI ==== | ||
- | De asemenea, un obiect de tip //Intent// poate fi creat și prin intermediul unui URI care identifică în mod unic o anumită activitate: | + | De asemenea, un obiect de tip ''Intent'' poate fi creat și prin intermediul unui URI care identifică în mod unic o anumită activitate: |
- | ''%%Uri%%'' ''%%uri%%'' ''%%=%%'' ''%%Uri.parse("myprotocol://mynamespace/myactivity");%%'' ''%%Intent%%'' ''%%intent%%'' ''%%=%%'' ''%%new%%'' ''%%Intent(Intent.ACTION_VIEW,%%'' ''%%uri);%%'' ''%%intent.putExtra("someKey",%%'' ''%%someValue);%%'' ''%%startActivity(intent);%%'' | + | <code java> |
+ | Uri uri = Uri.parse("myprotocol://mynamespace/myactivity"); | ||
+ | Intent intent = new Intent(Intent.ACTION_VIEW, uri); | ||
+ | intent.putExtra("someKey", someValue); | ||
+ | startActivity(intent); | ||
+ | </code> | ||
- | Pentru a putea fi apelată folosind acest mecanism, activitatea va trebui să definească elementul //data// în cadrul //<html><intent-filter></html>//: | + | Pentru a putea fi apelată folosind acest mecanism, activitatea va trebui să definească elementul ''data'' în cadrul ''<intent-filter>'': |
- | <html><code xml></html> <html><activity | + | <code xml> |
+ | <activity | ||
android:name="org.rosedu.dandroid.lab05.AnotherActivity" | android:name="org.rosedu.dandroid.lab05.AnotherActivity" | ||
- | android:label="@string/app_name" ></html> | + | android:label="@string/app_name" > |
- | + | <intent-filter> | |
- | ''%% %%''<html><intent-filter></html>\\ | + | <action android:name="org.rosedu.dandroid.lab05.intent.action.AnotherActivity" /> |
- | ''%% %%''<html><action android:name="org.rosedu.dandroid.lab05.intent.action.AnotherActivity" /></html>\\ | + | <category android:name="android.intent.category.DEFAULT" /> |
- | ''%% %%''<html><category android:name="android.intent.category.DEFAULT" /></html>\\ | + | <data |
- | ''%% %%''<html><data | + | |
android:scheme="myprotocol" | android:scheme="myprotocol" | ||
- | android:host="mynamespace" /></html>\\ | + | android:host="mynamespace" /> |
- | ''%% %%''<html></intent-filter></html> | + | </intent-filter> |
+ | </activity> | ||
+ | </code> | ||
- | <html></activity></html> <html></code></html> | + | De remarcat este faptul că în structura URI-ului, partea de după ''schemă:%%//%%protocol/'' poate conține orice șir de caractere, rolul său fiind strict acela de a respecta forma unui astfel de obiect (estetic), fără a influența în vreo formă funcționalitatea acestuia. |
- | + | ||
- | De remarcat este faptul că în structura URI-ului, partea de după //schemă:%%%%//%%%%protocol/// poate conține orice șir de caractere, rolul său fiind strict acela de a respecta forma unui astfel de obiect (estetic), fără a influența în vreo formă funcționalitatea acestuia. | + | |
===== Transmiterea de informații între componente prin intermediul intențiilor ===== | ===== Transmiterea de informații între componente prin intermediul intențiilor ===== | ||
- | Intențiile pot încapsula anumite informații care pot fi partajate de componentele între care fac legătura (însă unidirecțional, de la componenta care invocă spre componenta invocată!) prin intermediul secțiunii //extra// care conține un obiect de tip //Bundle//. Obținerea valorii secțiunii //extra// corespunzătoare unei intenții poate fi obținute folosind metoda //getExtras()//, în timp ce specificarea unor informații care vor fi asociate unei intenții poate fi realizată printr-un apel al metodei //putExtras()//. | + | Intențiile pot încapsula anumite informații care pot fi partajate de componentele între care fac legătura (însă unidirecțional, de la componenta care invocă spre componenta invocată!) prin intermediul secțiunii ''extra'' care conține un obiect de tip ''Bundle''. Obținerea valorii secțiunii ''extra'' corespunzătoare unei intenții poate fi obținute folosind metoda ''getExtras()'', în timp ce specificarea unor informații care vor fi asociate unei intenții poate fi realizată printr-un apel al metodei ''putExtras()''. |
- | <HTML> | + | <note>În cazul în care o intenție are deja atașat un obiect de tip ''Bundle'' în momentul în care se apelează metoda ''putExtras()'', perechile (cheie, valoare) vor fi transferate din cadrul parametrului metodei în obiectul deja existent.</note> |
- | <note> | + | |
- | </HTML> | + | |
- | În cazul în care o intenție are deja atașat un obiect de tip //Bundle// în momentul în care se apelează metoda //putExtras()//, perechile (cheie, valoare) vor fi transferate din cadrul parametrului metodei în obiectul deja existent. | + | |
- | <HTML> | + | Construirea unui obiect de tip ''Bundle'' care să fie transmis ca parametru al metodei ''putExtras()'' poate fi evitată prin utilizarea metodei ''putExtra()'' apelată pe obiectul ''Intent'', primind ca parametrii denumirea cheii prin care datele vor fi identificate și o valoare având un tip compatibil cu ''android.os.Parcelable''. Obținerea datelor se realizează apelând metoda pereche ''getExtra()'' căreia i se transmite denumirea cheii ce identifică în mod unic informațiile respective. De asemenea, sunt implementate și metode specifice pentru fiecare tip de dată (''put<type>Extra()'', respectiv ''get<type>Extra()''). |
- | </note> | + | |
- | </HTML> | + | |
- | Construirea unui obiect de tip //Bundle// care să fie transmis ca parametru al metodei //putExtras()// poate fi evitată prin utilizarea metodei //putExtra()// apelată pe obiectul //Intent//, primind ca parametrii denumirea cheii prin care datele vor fi identificate și o valoare având un tip compatibil cu //android.os.Parcelable//. Obținerea datelor se realizează apelând metoda pereche //getExtra()// căreia i se transmite denumirea cheii ce identifică în mod unic informațiile respective. De asemenea, sunt implementate și metode specifice pentru fiecare tip de dată (//put<html><type></html>Extra()//, respectiv //get<html><type></html>Extra()//). | + | |
- | <HTML> | + | <note tip>Se recomandă ca pentru cheie să se utilizeze o denumire prefixată de pachetul aplicației.</note> |
- | <note tip> | + | |
- | </HTML> | + | |
- | Se recomandă ca pentru cheie să se utilizeze o denumire prefixată de pachetul aplicației. | + | |
- | <HTML> | + | O activitate copil, lansată în execuție prin intermediul metodei ''startActivity()'', este independentă de activitatea părinte, astfel încât aceasta nu va fi notificată cu privire la terminarea sa. În situațiile în care un astfel de comportament este necesar, activitatea copil va fi pornită de activitatea părinte ca subactivitate care transmite înapoi un rezultat. Acest lucru se realizează prin lansarea în execuție a activității copil prin intermediul metodei ''startActivityForResult()''. În momentul în care este finalizată, va fi invocată automat metoda ''onActivityResult()'' de la nivelul activității părinte. |
- | </note> | + | |
- | </HTML> | + | |
- | O activitate copil, lansată în execuție prin intermediul metodei //startActivity()//, este independentă de activitatea părinte, astfel încât aceasta nu va fi notificată cu privire la terminarea sa. În situațiile în care un astfel de comportament este necesar, activitatea copil va fi pornită de activitatea părinte ca subactivitate care transmite înapoi un rezultat. Acest lucru se realizează prin lansarea în execuție a activității copil prin intermediul metodei //startActivityForResult()//. În momentul în care este finalizată, va fi invocată automat metoda //onActivityResult()// de la nivelul activității părinte. | + | |
- | La nivelul %%**%%activității părinte%%**%%, vor trebui implementate: | + | La nivelul **activității părinte**, vor trebui implementate: |
+ | * metoda ''startActivityForResult()'' va primi ca parametrii obiectul de tip ''Intent'' precum și un cod de cerere (de tip întreg), utilizat pentru a identifica în mod unic activitatea copil care a transmis un rezultat; | ||
+ | * metoda ''onActivityResult()'' care va fi apelată în mod automat în momentul în care activitatea copil a fost terminată; parametrii pe care îi furnizează aceasta sunt: | ||
+ | * codul de cerere (prin care se distinge între instanțe diferite ale activității copil); | ||
+ | * codul de rezultat transmis activității părinte (poate avea valorile ''RESULT_OK'' sau ''RESULT_CANCELED''); | ||
+ | * un obiect ''Intent'' prin intermediul căruia pot fi furnizate date suplimentare. | ||
- | ''%% * metoda %%''//''%%startActivityForResult()%%''//''%% va primi ca parametrii obiectul de tip %%''//''%%Intent%%''//''%% precum și un cod de cerere (de tip întreg), utilizat pentru a identifica în mod unic activitatea copil care a transmis un rezultat;%%''\\ | + | <code java> |
- | ''%% * metoda %%''//''%%onActivityResult()%%''//''%% care va fi apelată în mod automat în momentul în care activitatea copil a fost terminată; parametrii pe care îi furnizează aceasta sunt:%%''\\ | + | final private static int ANOTHER_ACTIVITY_REQUEST_CODE = 2015; |
- | ''%% * codul de cerere (prin care se distinge între instanțe diferite ale activității copil);%%''\\ | + | |
- | ''%% * codul de rezultat transmis activității părinte (poate avea valorile %%''//''%%RESULT_OK%%''//''%% sau %%''//''%%RESULT_CANCELED%%''//''%%);%%''\\ | + | |
- | ''%% * un obiect %%''//''%%Intent%%''//''%% prin intermediul căruia pot fi furnizate date suplimentare.%%'' | + | |
- | + | ||
- | <html><code java></html> final private static int ANOTHER_ACTIVITY_REQUEST_CODE = 2015; | + | |
- | + | ||
- | @Override protected void onCreate(Bundle state) { | + | |
- | + | ||
- | ''%% super.onCreate(state);%%''\\ | + | |
- | ''%% setContentView(R.layout.activity_main);%%''\\ | + | |
- | ''%% Intent intent = new Intent("org.rosedu.dandroid.lab05.AnotherActivity");%%''\\ | + | |
- | ''%% intent.putExtra("org.rosedu.dandroid.lab05.someKey", someValue);%%''\\ | + | |
- | ''%% startActivityForResult(intent, ANOTHER_ACTIVITY_REQUEST_CODE);%%''\\ | + | |
- | ''%% // start another activities with their own request codes%%'' | + | |
+ | @Override | ||
+ | protected void onCreate(Bundle state) { | ||
+ | super.onCreate(state); | ||
+ | setContentView(R.layout.activity_main); | ||
+ | Intent intent = new Intent("org.rosedu.dandroid.lab05.AnotherActivity"); | ||
+ | intent.putExtra("org.rosedu.dandroid.lab05.someKey", someValue); | ||
+ | startActivityForResult(intent, ANOTHER_ACTIVITY_REQUEST_CODE); | ||
+ | // start another activities with their own request codes | ||
} | } | ||
public void onActivityResult(int requestCode, int resultCode, Intent intent) { | public void onActivityResult(int requestCode, int resultCode, Intent intent) { | ||
+ | switch(requestCode) { | ||
+ | case ANOTHER_ACTIVITY_REQUEST_CODE: | ||
+ | if (resultCode == Activity.RESULT_OK) { | ||
+ | Bundle data = intent.getExtras(); | ||
+ | // process information from data ... | ||
+ | } | ||
+ | break; | ||
+ | | ||
+ | // process other request codes | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
- | ''%% switch(requestCode) {%%''\\ | + | În **activitatea copil**, înainte de apelul metodei ''finish()'', va trebui transmis activității părinte codul de rezultat (''Activity.RESULT_OK'', ''Activity.RESULT_CANCELED'' sau orice fel de rezultat de tip întreg) și obiectul de tip intenție care conține datele (opțional, în situația în care trebuie întoarse rezultate explicit), ca parametrii ai metodei ''setResult()''. |
- | ''%% case ANOTHER_ACTIVITY_REQUEST_CODE:%%''\\ | + | |
- | ''%% if (resultCode == Activity.RESULT_OK) {%%''\\ | + | |
- | ''%% Bundle data = intent.getExtras();%%''\\ | + | |
- | ''%% // process information from data ...%%''\\ | + | |
- | ''%% }%%''\\ | + | |
- | ''%% break;%%''\\ | + | |
- | ''%% %%''\\ | + | |
- | ''%% // process other request codes%%''\\ | + | |
- | ''%% }%%'' | + | |
- | } <html></code></html> | + | <code java> |
- | + | @Override | |
- | În %%**%%activitatea copil%%**%%, înainte de apelul metodei //finish()//, va trebui transmis activității părinte codul de rezultat (//Activity.RESULT_OK//, //Activity.RESULT_CANCELED// sau orice fel de rezultat de tip întreg) și obiectul de tip intenție care conține datele (opțional, în situația în care trebuie întoarse rezultate explicit), ca parametrii ai metodei //setResult()//. | + | protected void onCreate(Bundle state) { |
- | + | super.onCreate(state); | |
- | <html><code java></html> @Override protected void onCreate(Bundle state) { | + | setContentView(R.layout.activity_another); |
- | + | ||
- | ''%% super.onCreate(state);%%''\\ | + | // intent from parent |
- | ''%% setContentView(R.layout.activity_another);%%''\\ | + | Intent intentFromParent = getIntent(); |
- | ''%% %%''\\ | + | Bundle data = intentFromParent.getExtras(); |
- | ''%% // intent from parent%%''\\ | + | // process information from data ... |
- | ''%% Intent intentFromParent = getIntent();%%''\\ | + | |
- | ''%% Bundle data = intentFromParent.getExtras();%%''\\ | + | // intent to parent |
- | ''%% // process information from data ...%%''\\ | + | Intent intentToParent = new Intent(); |
- | ''%% %%''\\ | + | intent.putExtra("org.rosedu.dandroid.lab05.anotherKey", anotherValue); |
- | ''%% // intent to parent%%''\\ | + | setResult(RESULT_OK, intentToParent); |
- | ''%% Intent intentToParent = new Intent();%%''\\ | + | finish(); |
- | ''%% intent.putExtra("org.rosedu.dandroid.lab05.anotherKey", anotherValue);%%''\\ | + | } |
- | ''%% setResult(RESULT_OK, intentToParent);%%''\\ | + | </code> |
- | ''%% finish();%%'' | + | |
- | + | ||
- | } <html></code></html> | + | |
- | + | ||
- | În cazul folosirii unor intenții în care activitățile sunt invocate prin intermediul unor URI-uri, datele vor putea fi concatenate direct în cadrul acestuia (fără a utiliza un obiect de tip //Bundle//), restricția constând în faptul că pot fi utilizate numai șiruri de caractere: | + | |
- | ''%% * în activitatea părinte Uri%%'' ''%%uri%%'' ''%%=%%'' ''%%Uri.parse("myprotocol://mynamespace/myactivity?someKey=someValue&...");%%'' ''%%Intent%%'' ''%%intent%%'' ''%%=%%'' ''%%new%%'' ''%%Intent(Intent.ACTION_VIEW,%%'' ''%%uri);%%'' ''%%startActivity(intent);%%''\\ | + | În cazul folosirii unor intenții în care activitățile sunt invocate prin intermediul unor URI-uri, datele vor putea fi concatenate direct în cadrul acestuia (fără a utiliza un obiect de tip ''Bundle''), restricția constând în faptul că pot fi utilizate numai șiruri de caractere: |
- | ''%% * în activitatea copil Uri%%'' ''%%uri%%'' ''%%=%%'' ''%%getIntent().getData();%%'' ''%%String%%'' ''%%someValue%%'' ''%%=%%'' ''%%uri.getQueryParameter("someKey");%%'' | + | * în activitatea părinte <code java> |
+ | Uri uri = Uri.parse("myprotocol://mynamespace/myactivity?someKey=someValue&..."); | ||
+ | Intent intent = new Intent(Intent.ACTION_VIEW, uri); | ||
+ | startActivity(intent); | ||
+ | </code> | ||
+ | * în activitatea copil <code java> | ||
+ | Uri uri = getIntent().getData(); | ||
+ | String someValue = uri.getQueryParameter("someKey"); | ||
+ | </code> | ||
- | ===== Gestiunea evenimentelor cu difuzare prin intermediul intențiilor ===== | + | ==== Gestiunea evenimentelor cu difuzare prin intermediul intențiilor ===== |
Intențiile reprezintă și un mecanism de comunicație inter-proces, asigurând transferul unor mesaje structurate. Astfel, intențiile pot fi distribuite către toate componentele de la nivelul sistemului de operare Android, pentru a notifica producerea unui eveniment (legat de starea dispozitivului mobil sau a unor aplicații), fiind procesate în cadrul unor obiecte ascultător dedicate tipului de mesaj respectiv. | Intențiile reprezintă și un mecanism de comunicație inter-proces, asigurând transferul unor mesaje structurate. Astfel, intențiile pot fi distribuite către toate componentele de la nivelul sistemului de operare Android, pentru a notifica producerea unui eveniment (legat de starea dispozitivului mobil sau a unor aplicații), fiind procesate în cadrul unor obiecte ascultător dedicate tipului de mesaj respectiv. | ||
- | <HTML> | + | <note tip>Și sistemul de operare Android folosește acest mecanism pentru a notifica producerea unor modificări la nivelul stării curente (primirea unui apel telefonic / mesaj, schimbarea nivelului de încărcare al bateriei sau a conectivității).</note> |
- | <note tip> | + | |
- | </HTML> | + | |
- | Și sistemul de operare Android folosește acest mecanism pentru a notifica producerea unor modificări la nivelul stării curente (primirea unui apel telefonic / mesaj, schimbarea nivelului de încărcare al bateriei sau a conectivității). | + | |
- | <HTML> | + | <note>Trebuie realizată distincția între intențiile cu difuzare transmise la nivelul întregului sistem de operare Android și a celor transmise doar la nivelul aplicației, prin intermediul unui obiect de tipul ''LocalBroadcastManager'' (a cărui instanță se obține prin intermediul metodei statice ''getInstance()'' ce primește ca parametru contextul aplicației curente). Acesta operează într-un mod similar, implementând metodele ''sendBroadcast()'' și ''registerReceiver()''. În plus, dispune de o metodă ce permite trimiterea sincronă a notificărilor, apelul acesteia fiind blocant până la momentul în care toți ascultătorii le-au primit.</note> |
- | </note> | + | |
- | <note> | + | |
- | </HTML> | + | |
- | Trebuie realizată distincția între intențiile cu difuzare transmise la nivelul întregului sistem de operare Android și a celor transmise doar la nivelul aplicației, prin intermediul unui obiect de tipul //LocalBroadcastManager// (a cărui instanță se obține prin intermediul metodei statice //getInstance()// ce primește ca parametru contextul aplicației curente). Acesta operează într-un mod similar, implementând metodele //sendBroadcast()// și //registerReceiver()//. În plus, dispune de o metodă ce permite trimiterea sincronă a notificărilor, apelul acesteia fiind blocant până la momentul în care toți ascultătorii le-au primit. | + | |
- | <HTML> | + | Pentru o aplicație Android, în momentul rulării, pot fi activate / dezactivate oricare dintre componente (deci inclusiv ascultătorii pentru intențiile cu difuzare) prin intermediul metodei ''setComponentEnabledSetting()'' din cadrul clasei ''PackageManager''. Un astfel de comportament este util pentru a optimiza performanțele aplicației atunci când o anumită funcționalitate nu este necesară. |
- | </note> | + | |
- | </HTML> | + | |
- | Pentru o aplicație Android, în momentul rulării, pot fi activate / dezactivate oricare dintre componente (deci inclusiv ascultătorii pentru intențiile cu difuzare) prin intermediul metodei //setComponentEnabledSetting()// din cadrul clasei //PackageManager//. Un astfel de comportament este util pentru a optimiza performanțele aplicației atunci când o anumită funcționalitate nu este necesară. | + | |
- | <html><code java></html> PackageManager packageManager = getPackageManager(); | + | <code java> |
+ | PackageManager packageManager = getPackageManager(); | ||
ComponentName someEventBroadcastReceiver = new ComponentName(this, SomeEventBroadcastReceiver.class); | ComponentName someEventBroadcastReceiver = new ComponentName(this, SomeEventBroadcastReceiver.class); | ||
packageManager.setComponentEnabledSetting(someEventBroadcastReceiver , | packageManager.setComponentEnabledSetting(someEventBroadcastReceiver , | ||
- | + | PackageManager.COMPONENT_ENABLED_STATE_ENABLED, | |
- | ''%% PackageManager.COMPONENT_ENABLED_STATE_ENABLED,%%''\\ | + | PackageManager.DONT_KILL_APP); |
- | ''%% PackageManager.DONT_KILL_APP);%%'' | + | |
packageManager.setComponentEnabledSetting(someEventBroadcastReceiver , | packageManager.setComponentEnabledSetting(someEventBroadcastReceiver , | ||
- | + | PackageManager.COMPONENT_ENABLED_STATE_DISABLED, | |
- | ''%% PackageManager.COMPONENT_ENABLED_STATE_DISABLED,%%''\\ | + | PackageManager.DONT_KILL_APP); |
- | ''%% PackageManager.DONT_KILL_APP);%%'' | + | </code> |
- | + | ||
- | <html></code></html> | + | |
==== Trimiterea unei intenții cu difuzare ==== | ==== Trimiterea unei intenții cu difuzare ==== | ||
- | Construirea unei intenții care urmează să fie difuzată la nivelul sistemului de operare Android poate fi realizată prin definirea unui obiect de tipul //Intent//, pentru care se vor specifica acțiunea, datele și categoria, astfel încât obiectele de tip ascultător să îl poată identifica cât mai exact. Ulterior, acesta va fi trimis tuturor proceselor aferente aplicațiilor instalate pe dispozitivul mobil prin intermediul metodei //sendBroadcast()//, căreia îi este atașat ca parametru. | + | Construirea unei intenții care urmează să fie difuzată la nivelul sistemului de operare Android poate fi realizată prin definirea unui obiect de tipul ''Intent'', pentru care se vor specifica acțiunea, datele și categoria, astfel încât obiectele de tip ascultător să îl poată identifica cât mai exact. Ulterior, acesta va fi trimis tuturor proceselor aferente aplicațiilor instalate pe dispozitivul mobil prin intermediul metodei ''sendBroadcast()'', căreia îi este atașat ca parametru. |
- | <HTML> | + | <note tip>Pot fi utilizate atât acțiuni predefinite (care vor fi procesate atât de aplicațiile Android native cât și de eventuale aplicații instalate din alte surse) cât și acțiuni definite de utilizator, pentru care trebuie implementate aplicații dedicate, responsabile cu procesarea acestora.</note> |
- | <note tip> | + | |
- | </HTML> | + | |
- | Pot fi utilizate atât acțiuni predefinite (care vor fi procesate atât de aplicațiile Android native cât și de eventuale aplicații instalate din alte surse) cât și acțiuni definite de utilizator, pentru care trebuie implementate aplicații dedicate, responsabile cu procesarea acestora. | + | |
- | <HTML> | + | <code java> |
- | </note> | + | final public static String SOME_ACTION = "org.rosedu.dandroid.lab05.SomeAction.SOME_ACTION"; |
- | </HTML> | + | |
- | <html><code java></html> final public static String SOME_ACTION = "org.rosedu.dandroid.lab05.SomeAction.SOME_ACTION"; | + | |
- | Intent intent = new Intent(SOME_ACTION); intent.putExtra("org.rosedu.dandroid.lab05.someKey", someValue); sendBroadcast(intent); <html></code></html> | + | Intent intent = new Intent(SOME_ACTION); |
+ | intent.putExtra("org.rosedu.dandroid.lab05.someKey", someValue); | ||
+ | sendBroadcast(intent); | ||
+ | </code> | ||
==== Primirea unui intenții cu difuzare ==== | ==== Primirea unui intenții cu difuzare ==== | ||
- | Pentru a putea primi o intenție cu difuzare, o componentă trebuie să fie înregistrată în acest sens, definind un filtru de intenții pentru a specifica ce tipuri de acțiuni și ce tipuri de date asociate intenției poate procesa. | + | Pentru a putea primi o intenție cu difuzare, o componentă trebuie să fie înregistrată în acest sens, definind un filtru de intenții pentru a specifica ce tipuri de acțiuni și ce tipuri de date asociate intenției poate procesa. |
Acesta poate fi precizat: | Acesta poate fi precizat: | ||
+ | * în fișierul ''AndroidManifest.xml'' (caz în care nu este necesar ca aplicația să ruleze la momentul în care se produce evenimentul cu difuzare pentru a-l putea procesa); elementul ''<receiver>'' trebuie să conțină în mod obligatoriu filtrul de intenții prin care se indică acțiunea care poate fi procesată: <file xml AndroidManifest.xml> | ||
+ | <manifest ... > | ||
+ | <application ... > | ||
+ | <receiver | ||
+ | android:name=".SomeEventBroadcastReceiver"> | ||
+ | <intent-filter> | ||
+ | <action android:name="org.rosedu.dandroid.lab05.SomeAction.SOME_ACTION" /> | ||
+ | </intent-filter> | ||
+ | </receiver> | ||
+ | </application> | ||
+ | </manifest> | ||
+ | </file> | ||
+ | * programatic, în codul sursă (caz în care aplicația trebuie să fie în execuție la momentul în care se produce evenimentul cu difuzare pentru a-l putea procesa); o astfel de abordare este utilă când procesarea intenției cu difuzare implică actualizarea unor componente din cadrul interfeței grafice asociate activității: <code java> | ||
+ | private SomeEventBroadcastReceiver someEventBroadcastReceiver = new SomeEventBroadcastReceiver(); | ||
+ | private IntentFilter intentFilter = new IntentFilter(SOME_ACTION); | ||
- | ''%% * în fișierul %%''//''%%AndroidManifest.xml%%''//''%% (caz în care nu este necesar ca aplicația să ruleze la momentul în care se produce evenimentul cu difuzare pentru a-l putea procesa); elementul %%''//<html><receiver></html>//''%% trebuie să conțină în mod obligatoriu filtrul de intenții prin care se indică acțiunea care poate fi procesată: %%''<html><file xml AndroidManifest.xml></html> | + | @Override |
- | + | protected void onResume() { | |
- | <html><manifest ... ></html> | + | super.onResume(); |
- | + | ||
- | ''%% %%''<html><application ... ></html>\\ | + | registerReceiver(someEventBroadcastReceiver, intentFilter); |
- | ''%% %%''<html><receiver | + | } |
- | android:name=".SomeEventBroadcastReceiver"></html>\\ | + | |
- | ''%% %%''<html><intent-filter></html>\\ | + | |
- | ''%% %%''<html><action android:name="org.rosedu.dandroid.lab05.SomeAction.SOME_ACTION" /></html>\\ | + | |
- | ''%% %%''<html></intent-filter></html>''%% %%''\\ | + | |
- | ''%% %%''<html></receiver></html>\\ | + | |
- | ''%% %%''<html></application></html> | + | |
- | + | ||
- | <html></manifest></html> <html></file></html> | + | |
- | + | ||
- | ''%% * programatic, în codul sursă (caz în care aplicația trebuie să fie în execuție la momentul în care se produce evenimentul cu difuzare pentru a-l putea procesa); o astfel de abordare este utilă când procesarea intenției cu difuzare implică actualizarea unor componente din cadrul interfeței grafice asociate activității: %%''<html><code java></html> | + | |
- | + | ||
- | private SomeEventBroadcastReceiver someEventBroadcastReceiver = new SomeEventBroadcastReceiver(); private IntentFilter intentFilter = new IntentFilter(SOME_ACTION); | + | |
- | + | ||
- | @Override protected void onResume() { | + | |
- | + | ||
- | ''%% super.onResume();%%''\\ | + | |
- | ''%% %%''\\ | + | |
- | ''%% registerReceiver(someEventBroadcastReceiver, intentFilter);%%'' | + | |
+ | @Override | ||
+ | protected void onPause() { | ||
+ | super.onPause(); | ||
+ | | ||
+ | unregisterReceiver(someEventBroadcastReceiver); | ||
} | } | ||
+ | </code> | ||
- | @Override protected void onPause() { | + | <note tip>O regulă este de a înregistra obiectul ascultător pe metoda ''onResume()'' și de a-l deînregistra pe metoda ''onPause()'', astfel încât acesta să nu reacționeze decât atunci când activitatea este vizibilă.</note> |
- | ''%% super.onPause();%%''\\ | + | O clasă capabilă să proceseze intenții cu difuzare este derivată din ''android.content.BroadcastReceiver'', implementând metoda ''onReceive()'' pe care realizează rutina de tratare propriu-zisă: |
- | ''%% %%''\\ | + | |
- | ''%% unregisterReceiver(someEventBroadcastReceiver);%%'' | + | |
- | + | ||
- | } <html></code></html> | + | |
- | + | ||
- | <HTML> | + | |
- | <note tip> | + | |
- | </HTML> | + | |
- | O regulă este de a înregistra obiectul ascultător pe metoda //onResume()// și de a-l deînregistra pe metoda //onPause()//, astfel încât acesta să nu reacționeze decât atunci când activitatea este vizibilă. | + | |
- | + | ||
- | <HTML> | + | |
- | </note> | + | |
- | </HTML> | + | |
- | O clasă capabilă să proceseze intenții cu difuzare este derivată din //android.content.BroadcastReceiver//, implementând metoda //onReceive()// pe care realizează rutina de tratare propriu-zisă: | + | |
- | <html><file java SomeEventBroadcastReceiver.java></html> import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; | + | <file java SomeEventBroadcastReceiver.java> |
+ | import android.content.BroadcastReceiver; | ||
+ | import android.content.Context; | ||
+ | import android.content.Intent; | ||
public class SomeEventBroadcastReceiver extends BroadcastReceiver { | public class SomeEventBroadcastReceiver extends BroadcastReceiver { | ||
+ | @Override | ||
+ | public void onReceive(Context context, Intent intent) { | ||
+ | // ... | ||
+ | } | ||
+ | } | ||
+ | </file> | ||
- | ''%% @Override%%''\\ | + | Metoda ''onReceive()'' va fi invocată în mod automat în momentul în care este primită o intenție cu difuzare, fiind executată pe firul de execuție principal al aplicației. De regulă, în cadrul acestei metode utilizatorul este anunțat asupra producerii evenimentului prin intermediul serviciului de notificare (//Notification Manager//), este lansat în execuție un serviciu sau sunt actualizate componente din cadrul interfeței grafice. |
- | ''%% public void onReceive(Context context, Intent intent) {%%''\\ | + | |
- | ''%% // ...%%''\\ | + | |
- | ''%% }%%'' | + | |
- | } <html></file></html> | + | <note important>Este necesar ca metoda ''onReceive()'' să se termine în maximum 5 secunde, în caz contrar fiind afișată o fereastră de dialog pentru a determina oprirea sa forțată.</note> |
- | Metoda //onReceive()// va fi invocată în mod automat în momentul în care este primită o intenție cu difuzare, fiind executată pe firul de execuție principal al aplicației. De regulă, în cadrul acestei metode utilizatorul este anunțat asupra producerii evenimentului prin intermediul serviciului de notificare (%%//%%Notification Manager%%//%%), este lansat în execuție un serviciu sau sunt actualizate componente din cadrul interfeței grafice. | ||
- | |||
- | <HTML> | ||
- | <note important> | ||
- | </HTML> | ||
- | Este necesar ca metoda //onReceive()// să se termine în maximum 5 secunde, în caz contrar fiind afișată o fereastră de dialog pentru a determina oprirea sa forțată. | ||
- | |||
- | <HTML> | ||
- | </note> | ||
- | </HTML> | ||
==== Gestiunea intențiilor cu difuzare native ==== | ==== Gestiunea intențiilor cu difuzare native ==== | ||
Cele mai multe servicii de sistem transmit intenții cu difuzare pentru a semnala faptul că s-au produs anumite modificări la nivelul stării dispozitivului mobil sau al aplicațiilor (primirea unui apel telefonic / mesaj, schimbarea nivelului de încărcare al bateriei, conectivitatea la Internet). | Cele mai multe servicii de sistem transmit intenții cu difuzare pentru a semnala faptul că s-au produs anumite modificări la nivelul stării dispozitivului mobil sau al aplicațiilor (primirea unui apel telefonic / mesaj, schimbarea nivelului de încărcare al bateriei, conectivitatea la Internet). | ||
- | ^ %%**%%ACȚIUNE%%**%% ^ %%**%%DESCRIERE%%**%% ^ | //ACTION_BATTERY_CHANGED// | acțiune transmisă în momentul în care se modifică nivelul de încărcare al bateriei; starea bateriei este disponibilă în secțiunea //extra//, prin intermediul cheii //EXTRA_STATUS//, putând avea valorile:\\ ♦ //BatteryManager.BATTERY_STATUS_CHARGING//\\ ♦ //BatteryManager.BATTERY_STATUS_FULL// | | //ACTION_BATTERY_LOW// | acțiune transmisă în momentul în care nivelul de încărcare al bateriei este scăzut, impunându-se încărcarea acesteia | | //ACTION_BATTERY_OKAY// | acțiune transmisă în momentul în care nivelul de încărcare al bateriei este acceptabil | | //ACTION_BATTERY_CONNECTED// | acțiune transmisă în momentul în care bateria este conectată la o sursă de energie externă | | //ACTION_BATTERY_DISCONNECTED// | acțiune transmisă în momentul în care bateria este deconectată de la o sursă de energie externă | | //ACTION_BOOT_COMPLETED// | acțiune transmisă în momentul în care a fost realizată complet secvența de pornire a dispozitivului mobil (aplicația poate primi o astfel de intenție cu difuzare dacă deține permisiunea //RECEIVE_BOOT_COMPLETED//) | | //ACTION_CAMERA_BUTTON// | acțiune transmisă în momentul în momentul în care este accesat butonul pentru pornirea camerei foto | | //ACTION_DATE_CHANGED// / //ACTION_TIME_CHANGED// | acțiuni transmise în momentul în care data calendaristică sau timpul sunt modificate manual (nu datorită progresului său natural) | | //ACTION_DOCK_EVENT// | acțiune transmisă în momentul în care dispozitivul mobil este ancorat, printr-un dispozitiv de birou sau de mașină, stare plasată în secțiunea //extra// prin intermediul cheii //ETRA_DOCK_STATE// | | //ACTION_MEDIA_EJECT// | acțiune transmisă în momentul în care este îndepărtat un mediu de stocare extern (util în situația în care aplicația scrie / citește de pe acesta, pentru a salva conținutul și pentru a le închide) | | //ACTION_MEDIA_MOUNTED// / //ACTION_MEDIA_UNMOUNTED// | acțiuni transmise de fiecare dată când dispozitive de stocare externe sunt adăugate sau îndepărtate cu succes | | //ACTION_NEW_OUTGOING_CALL// | acțiune transmisă în momentul în care urmează să fie format un număr de telefon, a cărui valoare este plasată în secțiunea //extra//, prin intermediul cheii //EXTRA_PHONE_NUMBER// (aplicația poate primi o astfel de intenție cu difuzare dacă deține permisiunea //PROCESS_OUTGOING_CALLS// | | //ACTION_SCREEN_OFF// / //ACTION_SCREEN_ON// | acțiuni transmise în momentul în care ecranul este închis, respectiv este deschis | | //ACTION_TIMEZONE_CHANGED// | acțiune transmisă în momentul în care zona de timp a telefonului este modificată, a cărui valoare (identificator) este plasată în secțiunea //extra// prin intermediul cheii //time-zone// | | + | ^ **ACȚIUNE** ^ **DESCRIERE** ^ |
+ | | ''ACTION_BATTERY_CHANGED'' | acțiune transmisă în momentul în care se modifică nivelul de încărcare al bateriei; starea bateriei este disponibilă în secțiunea ''extra'', prin intermediul cheii ''EXTRA_STATUS'', putând avea valorile:\\ ♦ ''BatteryManager.BATTERY_STATUS_CHARGING''\\ ♦ ''BatteryManager.BATTERY_STATUS_FULL'' | | ||
+ | | ''ACTION_BATTERY_LOW'' | acțiune transmisă în momentul în care nivelul de încărcare al bateriei este scăzut, impunându-se încărcarea acesteia | | ||
+ | | ''ACTION_BATTERY_OKAY'' | acțiune transmisă în momentul în care nivelul de încărcare al bateriei este acceptabil | | ||
+ | | ''ACTION_BATTERY_CONNECTED'' | acțiune transmisă în momentul în care bateria este conectată la o sursă de energie externă | | ||
+ | | ''ACTION_BATTERY_DISCONNECTED'' | acțiune transmisă în momentul în care bateria este deconectată de la o sursă de energie externă | | ||
+ | | ''ACTION_BOOT_COMPLETED'' | acțiune transmisă în momentul în care a fost realizată complet secvența de pornire a dispozitivului mobil (aplicația poate primi o astfel de intenție cu difuzare dacă deține permisiunea ''RECEIVE_BOOT_COMPLETED'') | | ||
+ | | ''ACTION_CAMERA_BUTTON'' | acțiune transmisă în momentul în momentul în care este accesat butonul pentru pornirea camerei foto | | ||
+ | | ''ACTION_DATE_CHANGED'' / ''ACTION_TIME_CHANGED'' | acțiuni transmise în momentul în care data calendaristică sau timpul sunt modificate manual (nu datorită progresului său natural) | | ||
+ | | ''ACTION_DOCK_EVENT'' | acțiune transmisă în momentul în care dispozitivul mobil este ancorat, printr-un dispozitiv de birou sau de mașină, stare plasată în secțiunea ''extra'' prin intermediul cheii ''ETRA_DOCK_STATE'' | | ||
+ | | ''ACTION_MEDIA_EJECT'' | acțiune transmisă în momentul în care este îndepărtat un mediu de stocare extern (util în situația în care aplicația scrie / citește de pe acesta, pentru a salva conținutul și pentru a le închide) | | ||
+ | | ''ACTION_MEDIA_MOUNTED'' / ''ACTION_MEDIA_UNMOUNTED'' | acțiuni transmise de fiecare dată când dispozitive de stocare externe sunt adăugate sau îndepărtate cu succes | | ||
+ | | ''ACTION_NEW_OUTGOING_CALL'' | acțiune transmisă în momentul în care urmează să fie format un număr de telefon, a cărui valoare este plasată în secțiunea ''extra'', prin intermediul cheii ''EXTRA_PHONE_NUMBER'' (aplicația poate primi o astfel de intenție cu difuzare dacă deține permisiunea ''PROCESS_OUTGOING_CALLS'' | | ||
+ | | ''ACTION_SCREEN_OFF'' / ''ACTION_SCREEN_ON'' | acțiuni transmise în momentul în care ecranul este închis, respectiv este deschis | | ||
+ | | ''ACTION_TIMEZONE_CHANGED'' | acțiune transmisă în momentul în care zona de timp a telefonului este modificată, a cărui valoare (identificator) este plasată în secțiunea ''extra'' prin intermediul cheii ''time-zone'' | | ||
- | <HTML> | + | <note tip>Pentru aceste tipuri de intenții cu difuzare, înregistrarea și deînregistrarea unor obiecte de tip ascultător poate fi realizată numai programatic, în codul sursă.</note> |
- | <note tip> | + | |
- | </HTML> | + | |
- | Pentru aceste tipuri de intenții cu difuzare, înregistrarea și deînregistrarea unor obiecte de tip ascultător poate fi realizată numai programatic, în codul sursă. | + | |
- | <HTML> | + | În cazul unei aplicații Android, foarte importante sunt și modificările în privința conectivității la Internet (inclusiv parametrii precum lățimea de bandă, latența) întrucât acestea pot fi semnificative în privința luării unor decizii legate de realizarea anumitor actualizări sau de descărcarea unor fișiere având dimensiuni mari. O astfel de funcționalitate poate fi definită prin implementarea unui obiect ascultător, care procesează acțiunea ''android.net.conn.CONNECTIVITY_CHANGE'' (''ConnectivityManager.CONNECTIVITY_ACTION''). Se transmise o intenție cu difuzie nepersistentă care nu conține informații suplimentare cu privire la schimbarea stării. |
- | </note> | + | |
- | </HTML> | + | |
- | În cazul unei aplicații Android, foarte importante sunt și modificările în privința conectivității la Internet (inclusiv parametrii precum lățimea de bandă, latența) întrucât acestea pot fi semnificative în privința luării unor decizii legate de realizarea anumitor actualizări sau de descărcarea unor fișiere având dimensiuni mari. O astfel de funcționalitate poate fi definită prin implementarea unui obiect ascultător, care procesează acțiunea //android.net.conn.CONNECTIVITY_CHANGE// (//ConnectivityManager.CONNECTIVITY_ACTION//). Se transmise o intenție cu difuzie nepersistentă care nu conține informații suplimentare cu privire la schimbarea stării. | + | |
- | ''%%ConnectivityManager%%'' ''%%connectivityManager%%'' ''%%=%%'' ''%%(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);%%'' ''%%NetworkInfo%%'' ''%%networkInfo%%'' ''%%=%%'' ''%%connectivityManager.getActiveNetworkInfo();%%'' ''%%boolean%%'' ''%%isConnected%%'' ''%%=%%'' ''%%networkInfo.isConnectedOrConnecting();%%'' ''%%boolean%%'' ''%%isMobile%%'' ''%%=%%'' ''%%(networkInfo.getType()%%'' ''%%==%%'' ''%%ConnectivityManager.TYPE_MOBILE);%%'' | + | <code java> |
+ | ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); | ||
+ | NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); | ||
+ | boolean isConnected = networkInfo.isConnectedOrConnecting(); | ||
+ | boolean isMobile = (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE); | ||
+ | </code> | ||
- | ====== Exerciții ====== | + | ===== Exerciții ===== |
- | [%%**%%0%%**%%]. Să se cloneze în directorul de pe discul local conținutul depozitului la distanță de la [[https://www.github.com/andreirosucojocaru/DAndroid2015_Laborator05.git|%%//%%www.github.com/andreirosucojocaru/DAndroid2015_Laborator05.git]]. În urma acestei operații, directorul //Laborator05// va trebui să conțină subdirectorul //labtasks// (cu proiectele Android Studio //MessageMe// si //DateAndTime//), fișierele //README.md// și //LICENSE//. ''%%student@dandroid2015:~$%%'' ''%%git%%'' ''%%clone%%'' [[https://www.github.com/andreirosucojocaru/DAndroid2015_Laborator05.git|''%%https://www.github.com/andreirosucojocaru/DAndroid2015_Laborator05.git%%'']] Să se importe în mediul integrat de dezvoltare Android Studio proiectele //MessageMe// si //DateAndTime//. | + | - Realizati o aplicatie Android care permite utiliztaorului sa introduca un numar de telefon si sa il apeleze. Folositi ACTION_DIAL si ACTION_CALL. Incercati si pe simulator si pe telefon. Pe simulator va trebui sa cereti permisiunea PHONE_CALL (requestPermission). |
+ | - Adaugati in aplicatia posibilitate de a trimite un SMS acelui numar. Folositi ACTION_VIEW si SmsManager. Incercati si pe simulator si pe telefon. | ||
+ | - Adaugati aplicatiei anterioare posibilitatea de a pune o semnatura pentru utiliztaor. Adaugati un buton care deschide o alta activitate unde utilizatorul isi poate scrie o semnatura. Acesa semantura este adaugata la SMS-urile trimise. | ||
+ | - Realizati o aplicatie care scrie afiseaza in logcat (System.out Sau Log) sms-urile primite. (BroadcastReceiver) | ||
+ | - Realizati o aplicatie care afiseaza SMS-urile primite (porniti o activitate la primirea unui SMS) | ||
+ | - Inregistrati o activitate care poate afisa fisiere de tip text (Activitatea este pronita de actiunea VIEW si categoria DEFAULT si are in data textul) | ||
+ | - Să se implementeze un ascultător pentru mesaje cu difuzare în aplicația ''MessageMe'', care interceptează mesajele trimise de sistemul de operare Android cu privire la schimbările legate de conectivitatea la Internet. Acesta va jurnaliza toate operațiile care au fost detectate, cu ajutorul ''Logcat''. Acțiunea care este transmisă în acest caz este ''android.net.conn.CONNECTIVITY_CHANGE''. Astfel înregistrat, un obiect de acest tip va fi invocat în mod automat, furnizând informații legate de existența unei conexiuni precum și a unei rețele fără fir. | ||
- | [%%**%%1%%**%%]. Să se adauge o acțiune asociată evenimentului de apăsare a butonului //notYetRegisteredButton//, astfel încât să se lanseze în execuție activitatea //RegisterActivity//. În cadrul acesteia, un utilizator are posibilitatea de a-și crea un cont, prin completarea unor câmpuri. Pentru ca operația să fie realizată cu succes, este necesar ca toate atributele să fie specificate, iar valorile indicate în cadrul parolelor să corespundă. Rezultatul va fi transmis înapoi activității //LoginActivity// care îl va afișa pe ecran. | + | <code java> |
- | + | ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); | |
- | * * a)%%**%% În activitatea //LoginActivity// se va asocia butonului //notRegisteredYetButton// un obiect ascultător pentru evenimentele de tip apăsare (//View.OnClickListener//) care implementează metoda de callback //onClick(View)//. În cadrul acesteia, se va constui o %%**%%intenție implicită%%**%% (definită pe baza acțiunii - //Constants.REGISTER_ACTIVITY_INTENT_ACTION//), după care se va lansa în execuție activitatea corespunzătoare în așteptarea unui rezultat (metoda //setActivityForResult()// primește ca parametri intenția și codul de cerere - //Constants.REGISTER_ACTIVITY_REQUEST_CODE//). | + | NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo(); |
- | + | boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); | |
- | * * b)%%**%% În activitatea //RegisterActivity// se va proceda similar pentru butoanele //registerButton//, respectiv //cancelButton//: | + | boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI; |
- | + | </code> | |
- | ''%% * în cazul %%''//''%%registerButton%%''//''%% se verifică ca toate câmpurile să fi fost completate și ca parolele să corespundă, situație în care se transmite activității părinte rezultatul %%''//''%%Activity.RESULT_OK%%''//''%%, activitatea încheindu-și execuția (se apelează metoda %%''//''%%finish()%%''//''%%).%%''\\ | + | |
- | ''%% * în cazul %%''//''%%cancelButton%%''//''%% se transmite activității părinte rezultatul %%''//''%%Activity.RESULT_CANCELED%%''//''%%, activitatea încheindu-și execuția (se apelează metoda %%''//''%%finish()%%''//''%%).%%'' | + | |
- | + | ||
- | * * c)%%**%% În clasa //LoginActivity// se va implementa metoda //onActivityResult()// ce verifică rezultatul cu care s-a terminat activitatea invocată, afișându-l în cadrul interfeței grafice. | + | |
- | + | ||
- | ''%%@Override%%'' ''%%public%%'' ''%%void%%'' ''%%onActivityResult(int%%'' ''%%requestCode,%%'' ''%%int%%'' ''%%resultCode,%%'' ''%%Intent%%'' ''%%intent);%%'' | + | |
- | + | ||
- | Metoda primește ca parametri: | + | |
- | + | ||
- | ''%% * %%''//''%%requestCode%%''//''%% - codul de cerere transmis ca parametru în metoda %%''//''%%startActivityForResult()%%''//''%%, în funcție de care se identifică eventualele răspunsuri primite de la invocări diferite;%%''\\ | + | |
- | ''%% * %%''//''%%resultCode%%''//''%% - codul de răspuns (rezultatul);%%''\\ | + | |
- | ''%% * %%''//''%%Intent%%''//''%% - obiect prin intermediul căruia pot fi furnizate informații suplimentare.%%'' | + | |
- | + | ||
- | <HTML> | + | |
- | <note tip> | + | |
- | </HTML> | + | |
- | Pentru afișarea unui mesaj se poate utiliza următorul cod sursă: ''%%Snackbar.make(notRegisteredYetButton,%%'' ''%%getResources().getString(R.string.activity_returned_with_result)%%'' ''%%+%%'' ''%%"%%'' ''%%"%%'' ''%%+%%'' ''%%resultCode,%%'' ''%%Snackbar.LENGTH_LONG).show();%%'' | + | |
- | + | ||
- | <HTML> | + | |
- | </note> | + | |
- | </HTML> | + | |
- | [%%**%%2%%**%%]. Să se adauge o acțiune asociată evenimentului de apăsare a butonului //loginButton//, astfel încât să se lanseze în execuție activitatea //MainActivity//. În acest scop, este necesar să se verifice faptul că numele de utilizator și parola au fost completate corespunzător. Pentru invocarea componentei, se va folosi o %%**%%intenție explicită%%**%% (indicată prin denumirea clasei care o implementează). Informațiile nume de utilizator și parolă trebuie incluse în câmpul //extra// al intenției (folosindu-se cheile //Constants.USERNAME//, respectiv //Constants.PASSWORD//). | + | |
- | + | ||
- | [%%**%%3%%**%%]. În fragmentul //ProfileFragment//, să se obțină valorile corespunzătoare numelui de utilizator și parolei provenite de la activitatea care l-a invocat, prin intermediul intenției corespunzătoare. Să se afișeze aceste valori în câmpurile text //usernameTextView//, respectiv //passwordTextView//. | + | |
- | + | ||
- | <HTML> | + | |
- | <note tip> | + | |
- | </HTML> | + | |
- | Toate aceste operații trebuie să fie realizate în cadrul metodei //onActivityCreated()// pentru că numai în acest moment se garantează faptul că activitatea din care face parte fragmentul poate fi accesată. | + | |
- | + | ||
- | <HTML> | + | |
- | </note> | + | |
- | </HTML> | + | |
- | [%%**%%4%%**%%]. În fragmentul //ProfileFragment//, să se implementeze trei butoane prin care să se invoce, folosind mecanisme diferite, activitatea //DateAndTimeActivity// din contextul altei aplicații Android. Această activitate afișează data și ora curente, folosind un calendar și un ceas analogic. | + | |
- | + | ||
- | * * a)%%**%% Se va folosi %%**%%o intenție%%**%% calificată prin intermediul acțiunii //Constants.DATE_AND_TIME_INTENT_ACTION//. Această valoare trebuie inclusă și în fișierul //AndroidManifest.xml// al proiectului //DateAndTime//, în cadrul unui alt filtru de intenție, ce va avea categoria //android.intent.category.DEFAULT//. | + | |
- | + | ||
- | <html><code xml></html> <html><intent-filter></html> | + | |
- | + | ||
- | ''%% %%''<html><action android:name="org.rosedu.dandroid.dateandtime.intent.action.DateAndTimeActivity" /></html>\\ | + | |
- | ''%% %%''<html><category android:name="android.intent.category.DEFAULT" /></html> | + | |
- | + | ||
- | <html></intent-filter></html> <html></code></html> | + | |
- | + | ||
- | * * b)%%**%% Se va folosi %%**%%un ascultător de mesaje cu difuzare%%**%%. Tipul de acțiune utilizat va fi //Constants.DATE_AND_TIME_BROADCAST_RECEIVER_ACTION//. Este necesar să se utilizeze metoda //sendBroadcast()//. În fișierul //AndroidManifest.xml// al proiectului //DateAndTime//, este necesar să se defineacă un element //<html><receiver></html>// care va specifica clasa ce implementează obiectul ascultător pentru mesaje cu difuzare și acțiunea în cadrul unui filtru de intenții. | + | |
- | + | ||
- | <html><code xml></html> <html><receiver android:name=".controller.DateAndTimeBroadcastReceiver"></html> | + | |
- | + | ||
- | ''%% %%''<html><intent-filter></html>\\ | + | |
- | ''%% %%''<html><action android:name="org.rosedu.dandroid.dateandtime.broadcastreceiver.action.DateAndTimeActivity"/></html>\\ | + | |
- | ''%% %%''<html></intent-filter></html> | + | |
- | + | ||
- | <html></receiver></html> <html></code></html> | + | |
- | + | ||
- | Clasa //DateAndTimeBroadcastReceiver// (derivată din //BroadcastReceiver//) prelucrează mesajele cu difuzare care respectă anumite criterii, metoda //onReceive()// fiind apelată în mod automat. În cadrul acestei metode, trebuie să se invoce mai departe, tot prin intermediul unei intenții, activitatea //DateAndTimeActivity//. Fiind vorba de invocarea unei activități din cadrul aceleiași clase, se va utiliza o intenție explicită (definită prin denumirea clasei). | + | |
- | + | ||
- | <HTML> | + | |
- | <note important> | + | |
- | </HTML> | + | |
- | Este necesar să se indice flag-ul //Intent.FLAG_ACTIVITY_NEW_TASK//, în caz contrar activitatea neputând fi lansată în execuție. | + | |
- | + | ||
- | <HTML> | + | |
- | </note> | + | |
- | </HTML> | + | |
- | <html><file java DateAndTimeBroadcastReceiver.java></html> public class DateAndTimeBroadcastReceiver extends BroadcastReceiver { | + | |
- | + | ||
- | ''%% @Override%%''\\ | + | |
- | ''%% public void onReceive(Context context, Intent intent) {%%''\\ | + | |
- | ''%% Intent mainActivityIntent = new Intent(context.getApplicationContext(), DateAndTimeActivity.class);%%''\\ | + | |
- | ''%% mainActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);%%''\\ | + | |
- | ''%% context.getApplicationContext().startActivity(mainActivityIntent);%%''\\ | + | |
- | ''%% }%%'' | + | |
- | + | ||
- | } <html></file></html> | + | |
- | + | ||
- | * * c)%%**%% Se va folosi %%**%%un URI%%**%% (Uniform Resource Identifier). Invocarea se face prin intermediul unui identificator de resurse (conținut de obiectul //Constants.DATE_AND_TIME_URI_ACTION//), pe care se aplică acțiunea //Intent.ACTION_VIEW//. URI-ul conține același protocol și aceeași gazdă ca cele definite în secțiunea de date a fișierului //AndroidManifest.xml// din cadrul proiectului //DateAndTime//. | + | |
- | + | ||
- | <html><code xml></html> <html><intent-filter></html> | + | |
- | + | ||
- | ''%% %%''<html><action android:name="android.intent.action.VIEW" /></html>\\ | + | |
- | ''%% %%''<html><category android:name="android.intent.category.DEFAULT" /></html>\\ | + | |
- | ''%% %%''<html><data | + | |
- | android:scheme="dateandtimeprotocol" | + | |
- | android:host="dandroid.rosedu.org" /></html> | + | |
- | + | ||
- | <html></intent-filter></html> <html></code></html> | + | |
- | + | ||
- | <HTML> | + | |
- | <note tip> | + | |
- | </HTML> | + | |
- | De remarcat este faptul că pentru aceeași activitate pot fi definite mai multe filtre de intenții având un conținut diferit. | + | |
- | + | ||
- | <HTML> | + | |
- | </note> | + | |
- | <note tip> | + | |
- | </HTML> | + | |
- | Aplicația //DateAndTime// trebuie să fie instalată înainte de a se face invocările din aplicația //MessageMe//, în caz contrar fiind generată o excepție. | + | |
- | + | ||
- | <HTML> | + | |
- | </note> | + | |
- | </HTML> | + | |
- | [%%**%%BONUS%%**%%]. Să se implementeze un ascultător pentru mesaje cu difuzare în aplicația //MessageMe//, care interceptează mesajele trimise de sistemul de operare Android cu privire la schimbările legate de conectivitatea la Internet. Acesta va jurnaliza toate operațiile care au fost detectate, cu ajutorul //Logcat//. Acțiunea care este transmisă în acest caz este //android.net.conn.CONNECTIVITY_CHANGE//. Astfel înregistrat, un obiect de acest tip va fi invocat în mod automat, furnizând informații legate de existența unei conexiuni precum și a unei rețele fără fir. | + | |
- | + | ||
- | ''%%ConnectivityManager%%'' ''%%connectivityManager%%'' ''%%=%%'' ''%%(ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);%%'' ''%%NetworkInfo%%'' ''%%activeNetwork%%'' ''%%=%%'' ''%%connectivityManager.getActiveNetworkInfo();%%'' ''%%boolean%%'' ''%%isConnected%%'' ''%%=%%'' ''%%activeNetwork%%'' ''%%!=%%'' ''%%null%%'' ''%%&&%%'' ''%%activeNetwork.isConnectedOrConnecting();%%'' ''%%boolean%%'' ''%%isWiFi%%'' ''%%=%%'' ''%%activeNetwork.getType()%%'' ''%%==%%'' ''%%ConnectivityManager.TYPE_WIFI;%%'' | + | |
- | + | ||
- | <HTML> | + | |
- | <note important> | + | |
- | </HTML> | + | |
- | Informațiile cu privire la starea conectivității nu pot fi accesate decât în situația în care sunt acordate drepturile de acces corespunzătoare: <html><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /></html> | + | |
- | + | ||
- | <HTML> | + | |
- | </note> | + | |
- | </HTML> | + | |
+ | <note important>Informațiile cu privire la starea conectivității nu pot fi accesate decât în situația în care sunt acordate drepturile de acces corespunzătoare: <code xml> | ||
+ | <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||
+ | </code></note> |