Kontakty Omówienie: http://saigeethamn.blogspot.in/2011/05/contacts-api-20-and-above-android.html All data related to a contact is stored in this generic data table with each row telling what is the data it stores through its MIME type. So we could have a Phone.CONTENT_ITEM_TYPE as the MIME type of the data row, it contains Phone data. Similarly, if we have Email.CONTENT_ITEM_TYPE as the row’s MIME type, then it stores email data. Like this lot of data rows are associated with a single Raw Contact Więcej szczegółów: http://www.higherpass.com/Android/Tutorials/Working-With-Android-Contacts/ ----------------------------------------- Lista kontaktów 1. Tworzymy projekt aplikacji Android Application Project o nazwie Kontakty. Wybieramy API 7. To ważne, bo od wersji 2.0 Androida (API Level 7) są duże zmiany. Będziemy używać Contacts API 2.0. 2. Przechodzimy do pliku res/layout/activity_main.xml 3. Następnie modyfikujemy plik res/values/strings.xml Kontakty Kontakty Settings Kontakty 4. W katalogu src/pl.umk.fizyka.kontakty tworzymy plik klasy Kontakt.java zawierajacy klase z na razie jedna statyczna metodą: package pl.umk.fizyka.kontakty; import ... public class Kontakt { //pozniej bedziemy czytali liste rekordów z większą ilością szczegółów public static ArrayList listaNazwWszystkichKontaktow(ContentResolver contentResolver) { ArrayList lista = new ArrayList(); Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); if (cursor.getCount() > 0) { while (cursor.moveToNext()) { String nazwa = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); // lista.add("["+id+"] "+nazwa); } } else { lista=null; } cursor.close(); return lista; } } 5. Mając taką metodę możemy zapełnić listView łańcuchami z nazwami kontaktów. W tym celu w klasie KontaktyActivity: public class KontaktyActivity extends Activity { ListView listView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ContentResolver contentResolver=this.getContentResolver(); //dane dla listy ArrayList lista = Kontakt.listaNazwWszystkichKontaktow(contentResolver); if (lista==null) { TextView naglowek=(TextView)findViewById(R.id.naglowek); naglowek.setText("Brak zdefiniowanych kontaktów"); } ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1, lista); // kontrolka listView = (ListView)findViewById(R.id.listView); listView.setAdapter(adapter); } ... } 6. Uruchomienie aplikacji skończy się błęd. Aby odczytać listę kontaktów, aplikacja musi mieć odpowiednie uprawnienia. Do pliku manifestu należy dodać: ... Lista kontaktów może być pusta. Można utworzyć przykładowe kontakty korzystając z interfejsu androida, ale można też stworzyć kontakty z poziomu aplikacji (poniżej). --------------- Zapis nowego kontaktu do bazy danych i usunięcie wszystkich istniejących 7. Rozbudujmy klasę Kontakt z pliku Kontakt.java czyniąc z niej klasę encji (nadal niekompletną): package pl.umk.fizyka.kontakty; import ...; public class Kontakt { public String nazwaWyswietlana; public String telefonKomorkowy; public String telefonDomowy; public String telefonWPracy; public String emailWPracy; public String firma; public String tytul; //mozna uzupelnic m.in. o zdjecie public Kontakt( String nazwaWyswietlana, String telefonKomorkowy, String telefonDomowy, String telefonWPracy, String emailWPracy, String firma, String tytul) { this.nazwaWyswietlana=nazwaWyswietlana; this.telefonKomorkowy=telefonKomorkowy; this.telefonDomowy=telefonDomowy; this.telefonWPracy=telefonWPracy; this.emailWPracy=emailWPracy; this.firma=firma; this.tytul=tytul; } public static ArrayList listaNazwWszystkichKontaktow(ContentResolver contentResolver) { ArrayList lista = new ArrayList(); Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); if (cursor.getCount() > 0) { while (cursor.moveToNext()) { String nazwa = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); // lista.add("["+id+"] "+nazwa); } } else { lista=null; } cursor.close(); return lista; } public static void usunWszystkieKontakty(ContentResolver contentResolver) { Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); while(cursor.moveToNext()) { String klucz = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY)); Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI,klucz); contentResolver.delete(uri, null, null); } cursor.close(); } //Zrodlo: http://stackoverflow.com/questions/4744187/how-to-add-new-contacts-in-android private static void dodajNowyKontaktDoBazy(ContentResolver contentResolver, Kontakt kontakt) throws RemoteException, OperationApplicationException { ArrayList dodawanyKontakt=new ArrayList(); dodawanyKontakt.add(ContentProviderOperation.newInsert( ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null) .build()); if (kontakt.nazwaWyswietlana != null) { dodawanyKontakt.add(ContentProviderOperation.newInsert( ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,kontakt.nazwaWyswietlana) .build()); } if (kontakt.telefonKomorkowy != null) { dodawanyKontakt.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, kontakt.telefonKomorkowy) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE,ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) .build()); } if (kontakt.telefonDomowy != null) { dodawanyKontakt.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, kontakt.telefonDomowy) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE,ContactsContract.CommonDataKinds.Phone.TYPE_HOME) .build()); } if (kontakt.telefonWPracy != null) { dodawanyKontakt.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, kontakt.telefonWPracy) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE,ContactsContract.CommonDataKinds.Phone.TYPE_WORK) .build()); } if (kontakt.emailWPracy != null) { dodawanyKontakt.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Email.DATA, kontakt.emailWPracy) .withValue(ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.TYPE_WORK) .build()); } if (kontakt.firma!=null & !kontakt.firma.equals("") && kontakt.tytul!=null && !kontakt.tytul.equals("")) { dodawanyKontakt.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) .withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, kontakt.firma) .withValue(ContactsContract.CommonDataKinds.Organization.TYPE, ContactsContract.CommonDataKinds.Organization.TYPE_WORK) .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, kontakt.tytul) .withValue(ContactsContract.CommonDataKinds.Organization.TYPE, ContactsContract.CommonDataKinds.Organization.TYPE_WORK) .build()); } //prosba do dostawcy kontaktaktow o utworzenie nowego kontaktu //try //{ contentResolver.applyBatch(ContactsContract.AUTHORITY, dodawanyKontakt); //return true; //} //catch (Exception e) //{ //e.printStackTrace(); //return false; //} } public void zapisz(ContentResolver contentResolver) throws RemoteException, OperationApplicationException { dodajNowyKontaktDoBazy(contentResolver, this); } } 8. W klasie aktywności dodajemy kod usuwający wszystkie istniejące kontakty i dodające dwa nowe. public class KontaktyActivity extends Activity { ListView listView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ContentResolver contentResolver=this.getContentResolver(); Kontakt.usunWszystkieKontakty(contentResolver); try { new Kontakt( "Jacek Matulewski", "+48600123456", null, "+48(56)6113310", "jacek@fizyka.umk.pl", "UMK", "Dr").zapisz(contentResolver); new Kontakt( "Jan Kowalski", "+48600987654", "11111111", "+48(56)1111111", "jankowalski@firma.pl", "AAAAA", null).zapisz(contentResolver); } catch (Exception exc) { Toast.makeText(getApplicationContext(), "Nie udało się dodać kontaktu (" + exc.getMessage() + ")", Toast.LENGTH_LONG).show(); } //dane dla listy ArrayList lista = Kontakt.listaNazwWszystkichKontaktow(contentResolver); ... 9. Do tego potrzebne jest uprawnienie, które dodajemy do manifestu: ---------------------- Odczyt kompletnych kontaktów 10. Do klasy Kontakt dodajmy jeszcze jedną statyczną metodę pozwalającą na odczyt pełnej listy kontaktów oraz alternatywny kontruktor wspomagający tworzenie instancji kontaktów na podstawie danych z rekordu bazy danych: public class Kontakt { ... private Kontakt(ContentResolver contentResolver,Cursor cursor) { this.nazwaWyswietlana=""; this.telefonKomorkowy=""; this.telefonDomowy=""; this.telefonWPracy=""; this.emailWPracy=""; this.firma=""; this.tytul=""; String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); this.nazwaWyswietlana = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); if(Integer.parseInt(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)))>0) { Cursor numeryTelefonow = contentResolver.query(Phone.CONTENT_URI, null,Phone.CONTACT_ID+" = "+id,null,null); while(numeryTelefonow.moveToNext()) { String numer = numeryTelefonow.getString(numeryTelefonow.getColumnIndex(Phone.NUMBER)); int typNumeru = numeryTelefonow.getInt(numeryTelefonow.getColumnIndex(Phone.TYPE)); switch(typNumeru) { case Phone.TYPE_MOBILE: this.telefonKomorkowy = numer; break; case Phone.TYPE_HOME: this.telefonDomowy = numer; break; case Phone.TYPE_WORK: this.telefonWPracy = numer; break; } } numeryTelefonow.close(); } Cursor adresyEmail = contentResolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,null,ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = " + id,null,null); while(adresyEmail.moveToNext()) { String adresEmail = adresyEmail.getString(adresyEmail.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)); int typAdresu = adresyEmail.getInt(adresyEmail.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE)); if(typAdresu==ContactsContract.CommonDataKinds.Email.TYPE_WORK) { emailWPracy=adresEmail; break; //przerwanie petli while } } adresyEmail.close(); //organizacja String where = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?"; String[] whereParams = new String[] { id, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE }; Cursor organizacje = contentResolver.query(ContactsContract.Data.CONTENT_URI, null, where, whereParams, null); if (organizacje.moveToFirst()) { firma = organizacje.getString(organizacje.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DATA)); tytul = organizacje.getString(organizacje.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE)); } organizacje.close(); } public static ArrayList listaWszystkichKontaktow(ContentResolver contentResolver) { ArrayList lista = new ArrayList(); Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); if (cursor.getCount() > 0) { while (cursor.moveToNext()) { lista.add(new Kontakt(contentResolver,cursor)); } } else { lista=null; } return lista; } public static ArrayList listaOpisowWszystkichKontaktow(ContentResolver contentResolver) { ArrayList listaKontaktow = Kontakt.listaWszystkichKontaktow(contentResolver); ArrayList lista = new ArrayList(); for(Kontakt kontakt : listaKontaktow) { String opis = kontakt.tytul+" "+kontakt.nazwaWyswietlana+ "\ntel. kom.:"+kontakt.telefonKomorkowy+ "\ne-mail:"+kontakt.emailWPracy; lista.add(opis.trim()); } return lista; } 11. Metoda listaOpisowWszystkichKontaktow służy jedynie do testowania metody listaWszystkichKontaktow. Korzystając z tej nowej statycznej metody Kontakt.listaOpisowWszystkichKontaktow wyświetlmy w liście więcej informacji o kontaktach. Wystarczy podmienić metodę listaOpisowNazwKontaktow: public class KontaktyActivity extends Activity { ListView listView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ContentResolver contentResolver=this.getContentResolver(); //dane dla listy //ArrayList lista = Kontakt.listaNazwWszystkichKontaktow(contentResolver); ArrayList lista = Kontakt.listaOpisowWszystkichKontaktow(contentResolver); if (lista==null) { TextView naglowek=(TextView)findViewById(R.id.naglowek); naglowek.setText("Brak zdefiniowanych kontaktów"); } ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1, lista); // kontrolka listView = (ListView)findViewById(R.id.listView); listView.setAdapter(adapter); ---------------------- Użycie danych z kontaktów do inicjacji połączenia wychodzącego 12. Zaczniemy od przygotowania menu podręcznego inicjowanego dłuższym przytrzymaniem pozycji w liście. W metodzie KontaktyActivity.onCreate dodajemy: ... // kontrolka listView = (ListView)findViewById(R.id.listView); listView.setAdapter(adapter); final ArrayList listaKontaktow = Kontakt.listaWszystkichKontaktow(contentResolver); listView.setOnItemLongClickListener(new OnItemLongClickListener() { public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { Kontakt kontakt=listaKontaktow.get(position); AlertDialog.Builder adb = new AlertDialog.Builder(parent.getContext()); adb.setTitle(kontakt.nazwaWyswietlana); String[] etykiety = {"Zadzwoń (tel. kom.)", "Wyślij SMS", "Napisz e-mail", "Anuluj"}; adb.setItems( etykiety, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { switch(which) { case 0: break; case 1: break; case 2: break; default: case 3: break; } return; } }); AlertDialog ad = adb.create(); ad.show(); return true; } }); 13. Wystarczy teraz tylko uzupełnić instrukcję switch case 0 o odpowiednią intencję: switch(which) { case 0: { Intent intencja = new Intent(Intent.ACTION_CALL); intencja.setData(Uri.parse("tel:"+kontakt.telefonKomorkowy)); //finish(); startActivity(intencja); } break; 14. Przed uruchomieniem dodajemy do manifestu uprawnienie do dzwonienia: --------------------------- Wysyłanie SMSów 15. Można to zrobić na dwa sposoby. Albo, tak jak w przypadku inicjacji połączeń użyć systemowej aktywności, albo skorzystać z niskopoziomowego API android.telephony: case 1: { String tekst="Przykładowa treść"; Intent intencja = new Intent(Intent.ACTION_SENDTO,Uri.parse("smsto:"+kontakt.telefonKomorkowy)); intencja.putExtra("sms_body", tekst); startActivity(intencja); /* SmsManager sms = SmsManager.getDefault(); PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, new Intent(getBaseContext(),KontaktyActivity.class), 0); sms.sendTextMessage(kontakt.telefonKomorkowy, null, tekst, null, null); Toast.makeText(getBaseContext(), "Wyslanie SMSa powiodło się", Toast.LENGTH_LONG).show(); */ } break; W tym drugim (zakomentowanym) przypadku potrzebne jest uprawnienie: --------------------------- Wysyłanie listów e-mail 16. W przypadku listów e-mail dwie wariacje metody (plain i z formatowaniem): case 2: { String tekst="Przykładowa treść"; Intent intencja = new Intent(Intent.ACTION_SEND); intencja.setType("message/rfc822"); intencja.putExtra(Intent.EXTRA_EMAIL , new String[]{kontakt.emailWPracy}); //tu moze byc wielu odbiorcow intencja.putExtra(Intent.EXTRA_SUBJECT, "Temat listu"); intencja.putExtra(Intent.EXTRA_TEXT , tekst); try { startActivity(Intent.createChooser(intencja, "Wyślij e-mail...")); } catch (android.content.ActivityNotFoundException ex) { Toast.makeText(KontaktyActivity.this, "Brak zainstalowanych aplikacji do wysyłania listów e-mail", Toast.LENGTH_SHORT).show(); } /* Intent intencja = new Intent(Intent.ACTION_SENDTO); // it's not ACTION_SEND intencja.setType("text/plain"); intencja.putExtra(Intent.EXTRA_SUBJECT, "Temat listu"); intencja.putExtra(Intent.EXTRA_TEXT, tekst); intencja.setData(Uri.parse("mailto:"+kontakt.emailWPracy)); // or just "mailto:" for blank intencja.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // this will make such that when user returns to your app, your app is displayed, instead of the email app. startActivity(intencja); */ } break;