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;