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:
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 structura unei intenții pot fi identificate mai multe elemente, precizate în cadrul secțiunii <intent-filter>
, prin intermediul cărora se declară faptul că o componentă a unei aplicații poate realiza o anumită acțiune pentru un anumit set de date (sau pe care un ascultător al unei intenții cu difuzare îl poate procesa):
action
) care trebuie executată este indicată prin proprietatea android:name
, cele mai frecvent utilizate valori fiind: MAIN
, VIEW
, DIAL
, CALL
, ANSWER
, SEND
, SENDTO
, INSERT
, EDIT
, DELETE
, SEARCH
, WEB_SEARCH
; fiecare filtru de intenție trebuie să indice cel puțin o acțiune; este recomandat să se utilizeze convențiile folosite în Java pentru identificarea pachetelor pentru denumirile acțiunilor;
data
din <intent-filter>
informații legate de categoria MIME ale datelor procesate (mimeType
), de locația la care se găsesc (path
, host
, port
), de schema utilizată (scheme
).
category
), indicată tot prin proprietatea android:name
oferă informații suplimentare cu privire la acțiunea care trebuie realizată; fiecare filtru de intenție poate specifica mai multe categorii, putând fi utilizate valori definite de utilizator sau valori preexistente în sistemul de operare Android:ALTERNATIVE
- acțiunea ar trebui să fie disponibilă ca o alternativă la activitatea implicită pentru tipul de date respectiv;SELECTED_ALTERNATIVE
- acțiunea poate fi selectată, dintr-o listă, ca o alternativă la activitatea implicită pentru tipul de date respectiv;BROWSABLE
- indică o acțiune disponibilă din cadrul navigatorului; pentru ca o activitate sau un serviciu să poată fi invocate din cadrul navigatorului trebuie să specifice în mod obligatoriu această categorie;DEFAULT
- utilizat pentru ca activitatea sau serviciul să fie utilizate în mod implicit pentru tipul de date specificat în filtrul de intenții; de asemenea, este necesar pentru activitățile sau serviciile care se doresc a fi lansate în execuție prin intermediul unor intenții explicite;HOME
- este folosit pentru a indica o alternativă la ecranul principal, dacă nu este indicată nici o acțiune;LAUNCHER
- atunci când este specificat, face ca activitatea să fie inclusă în meniul de aplicații care pot fi lansate în execuție direct de către utilizator, prin accesarea lor;INFO
, PREFERENCE
, CAR_DOCK
, DESK_DOCK
, CAR_MODE
, APP_MAKET
.data
) reprezință informațiile care vor fi procesate, fiind exprimate de obicei sub forma unui URI, fie că este vorba despre un număr de telefon (prefixat de tel:
), despre datele unei persoane din lista de contacte (prefixate de content://contacts/people
), despre coordonate geografice (prefixate de geo:
) sau o adresă Internet (prefixată de http://www.
); pot fi specificate o serie de proprietăți (în orice combinație) pentru a indica datele suportate de componenta respectivă:android:host
- o adresă (accesibilă prin rețea - poate fi indicată denumirea sau adresa IP a gazdei) la care se găsesc datele ce pot fi procesate de componentă;android:mimeType
- tipul de date;android:path
- locația la care se găsesc datele;android:port
- portul pe care se permite conexiunea pentru accesarea datelor;android:scheme
- un protocol prin intermediul căruia pot fi accesate datele (spre exemplu, file
, http
, mailto
, content
, tel
).type
) referă în mod explicit clasificarea MIME al datelor (deși aceasta poate fi dedus în mod automat din conținutul propriu-zis al datelor respective);component
) specifică în mod explicit denumirea unei clase care va fi invocată de intenție (deși aceasta putea fi dedusă în mod automat din denumirea acțiunii și categoria ei, datele și tipul lor);
extra
) este un obiect de tip Bundle
care conține informații suplimentare cu privire la componenta respectivă; informațiile conținute într-o intenție pot fi obținute folosind intent.getExtras()
, în timp ce specificarea unor informații care vor fi atașate la o intenție va fi realizată printr-un apel al metodei intent.putExtras(Bundle)
.Dintre aceste componente, esențiale sunt acțiunea și datele:
Intent
;setData()
(pentru acțiunile care necesită date); fiind vorba despre un URI, acesta va fi construit ca rezultat al Uri.parse(…)
.
După ce a fost construit obiectul de tip Intent
prin specificarea acestor parametri, acțiunea poate fi executată prin transmiterea acestuia ca parametru al metodei startActivity()
sau startService()
, disponibile în clasa android.content.Context
.
startActivity(intent); |
startService(intent); |
Terminarea unei activități (moment în care se realizează revenirea la activitatea părinte) este realizată prin apelul metodei finish()
.
Î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.
<activity android:name="ro.pub.cs.systems.eim.lab04.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="ro.pub.cs.systems.eim.lab04.intent.action.MainActivity" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
<pachet-aplicație>.intent.action.ACȚIUNE
.
<activity>
în fișierul AndroidManifest.xml
.
category
din <intent-filter>
valoarea android.intent.category.DEFAULT
.
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>
se poate specifica 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.
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.
startActivity(new Intent(this, AnotherActivity.class));
startActivity(new Intent("ro.pub.cs.systems.eim.lab04.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ă.
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.
action
din intent-filter
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.
Procesul de rezolvare a unei intenții (eng. intent resolution) se face prin intermediul analizei tuturor ascultătorilor înregistrați.
Cele mai frecvent utilizate acțiuni implicite ale unui obiect de tip Intent
sunt:
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://ocw.cs.pub.ro/eim"));
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"));
Intent intent = new Intent(Intent.ACTION_DIAL);
Intent intent = new Intent(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:0214029466"));
AndroidManifest.xml
trebuie specificată explicit permisiunea pentru o astfel de acțiune<uses-permission android:name=“android.permission.CALL_PHONE”>
.
Intent intent = new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("geo:44.436877,26.048029?z=100&q=Education"));
Intent intent = new Intent(Intent.ACTION_PICK); intent.setData(Uri.parse("content://contacts/people"));
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):setType()
;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.
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 { startActivity(intent); }
Î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()
:
Intent applicationIntent = new Intent(); intent.setData(...); intent.addCategory(Intent.CATEGORY_SELECTED_ALTERNATIVE); PackageManager packageManager = new PackageManager(); int flags = PackageManager.MATCH_DEFAULT_ONLY; List<ResolveInfo> availableActions = packageManager.queryIntentActivities(applicationIntent, flags); for (ResolveInfo availableAction: availableActions) { Log.d(Constants.TAG, "An available action for the data is "+getResources().getString(availableAction.labelRes)); }
Procesul de rezolvare a unei intenții pe baza unei acțiuni implică următoarele etape:
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 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()
.
@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(); } }
onNewIntent()
:
@Override public void onNewIntent(Intent newIntent) { super.onNewIntent(newIntent); // ... }
startNextMatchingActivity()
:
Intent intent = getIntent(); if (intent != null) { startNextMatchingActivity(intent); }
Î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.
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()
.
Bundle
în momentul în care se apelează metoda putExtras()
, perechile (cheie, valoare) vor fi transferate din cadrul parametrului metodei în obiectul deja existent.
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()
).
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:
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;onActivityResult()
care va fi apelată în mod automat în momentul în care activitatea copil a fost terminată; parametrii pe care îi furnizează aceasta sunt:RESULT_OK
sau RESULT_CANCELED
);Intent
prin intermediul căruia pot fi furnizate date suplimentare.final private static int ANOTHER_ACTIVITY_REQUEST_CODE = 2017; @Override protected void onCreate(Bundle state) { super.onCreate(state); setContentView(R.layout.activity_main); Intent intent = new Intent("ro.pub.cs.systems.eim.lab04.AnotherActivity"); intent.putExtra("ro.pub.cs.systems.eim.eim.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) { 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 } }
Î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()
.
@Override protected void onCreate(Bundle state) { super.onCreate(state); setContentView(R.layout.activity_another); // intent from parent Intent intentFromParent = getIntent(); Bundle data = intentFromParent.getExtras(); // process information from data ... // intent to parent Intent intentToParent = new Intent(); intent.putExtra("ro.pub.cs.systems.eim.lab04.anotherKey", anotherValue); setResult(RESULT_OK, intentToParent); finish(); }
Î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:
Uri uri = Uri.parse("myprotocol://mynamespace/myactivity?someKey=someValue&..."); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent);
Uri uri = getIntent().getData(); String someValue = uri.getQueryParameter("someKey");
</spoiler>
Se dorește implementarea unei aplicații Android, conținând o activitate care să ofere utilizatorilor funcționalitatea necesară pentru a stoca un număr de telefon în agenda de contacte, specificând pentru acesta mai multe informații.
1. În contul Github personal, să se creeze un depozit denumit 'Laborator04'. Acesta trebuie să conțină unui fișier README.md
, un fișier .gitignore
specific unei aplicații Android și un fișier LICENSE
care să descrie condițiile pentru utilizarea aplicației.
2. Să se cloneze într-un director de pe discul local conținutul depozitului la distanță astfel creat. În urma acestei operații, directorul Laborator04 va trebui să se conțină fișierele README.md
, .gitignore
care indică tipurile de fișiere (extensiile) ignorate și LICENSE
.
student@eim-lab:~$ git clone https://www.github.com/perfectstudent/Laborator04.git
3. În directorul Laborator04 de pe discul local, să se creeze un proiect Android Studio denumit ContactsManager (se selectează Start a new Android Studio project).
Se indică detaliile proiectului:
Se indică platforma pentru care se dezvoltă aplicația Android (se bifează doar Phone and Tablet), iar SDK-ul Android (minim) pentru care se garantează funcționarea este API 24 (Nougat).
Se creează o activitate care inițial nu va conține nimic (Empty Activity):
pentru care se precizează:
ContactsManagerActivity
;res/layout
în care va fi construită interfața grafică) - activity_contacts_manager.xml
.De asemenea:
4. În fișierul activity_contacts_manager
din directorul res/layout
să se construiască interfața grafică folosind:
Acesta va fi format din două containere după cum urmează:
Button
) având mesajul Show Additional Fields în cazul în care celălalt container nu este afișat, respectiv mesajul Hide Additional Fields în cazul în care celălalt container este afișat, determinând atașarea / detașarea acestuia la activitate;EditText
) prin care se introduc:android:enabled=“false”
), urmând ca valoarea sa să fie preluată din câmpul extra
al unei intenții;
Fiecare container poate fi inclus într-un mecanism de dispunere a conținutului de tip LinearLayout
cu dispunere verticală. Acestea vor fi incluse într-un container de tip ScrollView
, pentru a preîntâmpina situația în care interfața grafică nu poate fi afișată pe ecranul dispozitivului mobil.
Să se implementeaze interacțiunea cu utilizatorul a aplicației.
onCreate()
a activității se obțin referințe către butoanele Show Additional Details / Hide Additional Details, respectiv Save și Cancel prin intermediul metodei findViewById(R.id….)
;View.OnClickListener
și implementează metoda onClick(View v)
; în funcție de id-ul butonului care este transmis argument metodei, sunt realizate următoarele acțiuni:visibility
al containerului, resepctiv metoda setVisibility()
a clasei Java împreună cu constantele View.VISIBLE
, View.GONE
).Intent intent = new Intent(ContactsContract.Intents.Insert.ACTION); intent.setType(ContactsContract.RawContacts.CONTENT_TYPE); if (name != null) { intent.putExtra(ContactsContract.Intents.Insert.NAME, name); } if (phone != null) { intent.putExtra(ContactsContract.Intents.Insert.PHONE, phone); } if (email != null) { intent.putExtra(ContactsContract.Intents.Insert.EMAIL, email); } if (address != null) { intent.putExtra(ContactsContract.Intents.Insert.POSTAL, address); } if (jobTitle != null) { intent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobTitle); } if (company != null) { intent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); } ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); if (website != null) { ContentValues websiteRow = new ContentValues(); websiteRow.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE); websiteRow.put(ContactsContract.CommonDataKinds.Website.URL, website); contactData.add(websiteRow); } if (im != null) { ContentValues imRow = new ContentValues(); imRow.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE); imRow.put(ContactsContract.CommonDataKinds.Im.DATA, im); contactData.add(imRow); } intent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); startActivity(intent);
Intenția pentru realizarea acestei operații are asociată acțiunea ContactsContract.Intents.Insert.ACTION
și tipul ContactsContract.RawContacts.CONTENT_TYPE
. Informațiile care se doresc a fi completate sunt atașate în câmpul extra
al acesteia, având cheile:
✔ ContactsContract.Intents.Insert.NAME
;
✔ ContactsContract.Intents.Insert.PHONE
;
✔ ContactsContract.Intents.Insert.EMAIL
;
✔ ContactsContract.Intents.Insert.POSTAL
;
✔ ContactsContract.Intents.Insert.JOB_TITLE
;
✔ ContactsContract.Intents.Insert.COMPANY
;
Pentru site-ul web și identificatorul de mesagerie instantanee, se folosește un tablou de elemente ContentValues
în care se specifică înregistrări de tipul CommonDataKinds.Website.URL
, respectiv CommonDataKinds.Im.DATA
;
Pentru a putea gestiona agenda telefonică, este necesar ca în fișierul AndroidManifest.xml
să fie specificate următoarele permisiuni:
<uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" />
finish();
setOnClickListener()
.5. Să se modifice aplicația Android Phone Dialer astfel încât să conțină un buton suplimentar prin care este invocată aplicația Contacts Manager căreia îi transmite numărul de telefon format și așteptând un rezultat cu privire la stocarea contactului în agenda telefonică.
Ca imagine pentru butonul care invocă aplicația Contacts Manager se poate folosi această resursă.
Metoda de tratare a evenimentului de tip accesare a butonului de stocare a numărului de telefon în agenda telefonică invocă o intenție asociată aplicației Contacts Manager, transmițând și numărul de telefon în câmpul extra
asociat acesteia, identificabil prin intermediul unei chei.
String phoneNumber = phoneNumberEditText.getText().toString(); if (phoneNumber.length() > 0) { Intent intent = new Intent("ro.pub.cs.systems.eim.lab04.contactsmanager.intent.action.ContactsManagerActivity"); intent.putExtra("ro.pub.cs.systems.eim.lab04.contactsmanager.PHONE_NUMBER_KEY", phoneNumber); startActivityForResult(intent, Constants.CONTACTS_MANAGER_REQUEST_CODE); } else { Toast.makeText(getApplication(), getResources().getString(R.string.phone_error), Toast.LENGTH_LONG).show(); }
Definiți în prealabil constanta CONTACTS_MANAGER_REQUEST_CODE
și valoarea string phone_error
în fișierele corespunzătoare din folderul de resurse statice res.
6. Să se modifice aplicația Android Contacts Manager astfel încât să poată fi lansată în execuție doar din contextul altei activități, prin intermediul unei intenții care conține în câmpul extra
un număr de telefon, identificabil prin cheia ro.pub.cs.systems.eim.lab04.contactsmanager.PHONE_NUMBER_KEY
, acesta fiind plasat în câmpul text needitabil corespunzător. Totodată, va transmite înapoi rezultatul operației de stocare (Activity.RESULT_OK
sau Activity.RESULT_CANCELED
).
AndroidManifest.xml
se modifică filtrul de intenții (acțiunea și categoria), astfel încât activitatea să poată fi rulată doar prin intermediul unei intenții <manifest ...> <application ...> <activity android:name=".graphicuserinterface.ContactsManagerActivity" android:label="@string/app_name" > <intent-filter> <action android:name="ro.pub.cs.systems.eim.lab04.contactsmanager.intent.action.ContactsManagerActivity" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>
onCreate()
a activității aplicației ContactsManager
este verificată intenția cu care este pornită, și în cazul în care aceasta nu este nulă, este preluată informația din secțiunea extra
, identificată prin cheia ro.pub.cs.systems.eim.lab04.contactsmanager.PHONE_NUMBER_KEY
, conținutul său fiind plasat în cadrul câmpului text corespunzător: Intent intent = getIntent(); if (intent != null) { String phone = intent.getStringExtra("ro.pub.cs.systems.eim.lab04.contactsmanager.PHONE_NUMBER_KEY"); if (phone != null) { phoneEditText.setText(phone); } else { Toast.makeText(this, getResources().getString(R.string.phone_error), Toast.LENGTH_LONG).show(); } }
startActivityForResult(intent, Constants.CONTACTS_MANAGER_REQUEST_CODE);
setResult(Activity.RESULT_CANCELED, new Intent());
onActivityResult()
asociată activității aplicației ContactsManager, în momentul în care s-a părăsit aplicația nativă pentru gestiunea agendei telefonice, se verifică codul de cerere și se transmite înapoi un rezultat: public void onActivityResult(int requestCode, int resultCode, Intent intent) { switch(requestCode) { case Constants.CONTACTS_MANAGER_REQUEST_CODE: setResult(resultCode, new Intent()); finish(); break; } }
Datorită faptului că aplicația Android Contacts Manager nu dispune de o activitate principală (implicită), aceasta nu va mai putea fi lansată în execuție folosind mediul integrat de dezvoltare Android Studio. Pentru ca aceasta să fie doar instalată pe dispozitivul mobil, se accesează meniul Run → Edit Configurations…, iar în secțiunea Launch Options de pe panoul General, se selectează opțiunea Launch: Nothing.
student@eg106:~$ adb shell vbox86p:/ # pm list packages -f
7. Să se încarce modificările realizate în cadrul depozitului 'Laborator04' de pe contul Github personal, folosind un mesaj sugestiv.
student@eim-lab:~/Laborator04$ git add * student@eim-lab:~/Laborator04$ git commit -m "implemented taks for laboratory 04" student@eim-lab:~/Laborator04$ git push origin master
Intents and Intent Filters(android.com)
Joseph ANNUZZI, Jr, Lauren DARCEY, Shane CONDER, Introduction to Android Application Development - Developer's Library, 4th Edition, Addison-Wesley, 2013 - capitolul 4, subcapitolele Organizing Activity Components with Fragments, Managing Activity Transition with Intents, Working with Services, Receiving and Broadcasting Intents
Bill PHILLIPS, Brian HARDY, Android Programming. The Big Nerd Ranch Guide, Pearson Technology Group, 2013 - capitolele 5, 7, 10, 21, 23, 29, 30
Reto MEIER, Professional Android for Application Development, John Wiley & Sons, 2012 - capitolul 4 (Introducing Fragments), 5 (Introducing Intents)
Ronan SCHWARZ, Phil DUTSON, James STEELE, Nelson TO, Android Developer's Cookbook, Building Applications with the Android SDK, 2nd Edition, Addison Wesley, 2013 - capitolele 2, 7
Wei Meng LEE, Beginning Android 4 Application Development, Wiley, 2012
Satya KOMATINENI, Dave MACLEAN, Pro Android 4, Apress, 2012
Dezvoltarea aplicațiilor pentru Android
Android Programming Tutorials - Core Servlets - secțiunile Intents - part I, II & III
Android Intents - Tutorial