I want to fetch id,name,birthday,addess from android contacts. I changed the uri (ContactsContract.CommonDataKinds, ContactsContract.Contacts etc.) and was able to fetch the address, but then the birthday disappeared. Anyway I tried, I can not find a solution to fetch both at once.
public void getBirthdays() {
// get data from contacts
Uri uri = ContactsContract.Data.CONTENT_URI;
String[] projection = new String[]{
ContactsContract.CommonDataKinds.Event.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Event.START_DATE,
ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS};
String selection =
ContactsContract.Data.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY;
String[] selectionArgs = new String[]{ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE};
Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, null);
int columnCount = cursor.getColumnCount();
cursor.moveToFirst();
for (int i = 0; i < columnCount; i++) {
Common.echo(cursor.getColumnName(i) + ", " + cursor.getString(i));
}
cursor.close();
}
the output of the above code is:
I: contact_id, 14046
I: display_name, Magret XXXX
I: data1, XXXX-05-31
I: data1, XXXX-05-31
The "data1"-field is listed twice, because START_DATE (birthday) and FORMATTED_ADDRESS are both stored in same virtual column "data1".
Is there a way to define a virtual column-names in a resolver like the SQL-equivalent "SELECT col1 AS name1, col2 AS name2, col3,col4 WHERE..."?
two issues: you're limiting your query to EVENTs only & you're only logging the first row found in the query.
Try this:
private class Contact {
public Long contactId;
public String name;
public String birthday;
public String address;
}
public void getBirthdaysAndAddress() {
// mapping from contactId to a contact object
Map<Long, Contact> contacts = new HashMap<>();
Uri uri = Data.CONTENT_URI;
String[] projection = new String[]{
Data.CONTACT_ID,
Data.DISPLAY_NAME,
Data.MIMETYPE,
Data.DATA1,
Event.TYPE};
// get ALL rows that represent either a birthday or a postal address
String selection = Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=?";
String[] selectionArgs = new String[]{Event.CONTENT_ITEM_TYPE, StructuredPostal.CONTENT_ITEM_TYPE};
Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, null);
while (cursor.moveToNext()) {
Long id = cursor.getLong(0);
// get an existing contact object, or create a new one
Contact contact = contacts.get(id);
if (contact == null) {
contact = new Contact();
contact.contactId = id;
contact.name = cursor.getString(1);
contacts.put(id, contact);
}
String mimetype = cursor.getString(2);
if (mimetype.equals(Event.CONTENT_ITEM_TYPE)) {
// this is an event row, check that it is a birthday
int type = cursor.getInt(4);
if (type == Event.TYPE_BIRTHDAY) {
contact.birthday = cursor.getString(3);
}
} else {
// this is an address row
contact.address = cursor.getString(3);
}
}
cursor.close();
// print all contact objects containing a birthday
Iterator it = mp.values().iterator();
while (it.hasNext()) {
Contact contact = (Contact) it.next();
if (!TextUtils.isEmpty(contact.birthday)) {
Log.i("Birthday contacts", contact.contactId + " - " + contact.name + " - " + contact.birthday + " - " + contact.address);
}
}
}
Related
I want to fetch only the first contact number from a list of contact numbers of a particular user, with the help of cursor. Here is my code:
private ArrayList<ArrayList<String>> getAllContacts() {
ArrayList<ArrayList<String>> nameList = new ArrayList<ArrayList<String>>();
ArrayList<String> person=new ArrayList<>();
ArrayList<String> number=new ArrayList<>();
ArrayList<String> temp=new ArrayList<>();
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
null, null, null, null);
if ((cur!=null ? cur.getCount() : 0) > 0) {
while (cur!=null && cur.moveToNext()) {
String id = cur.getString(
cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME));
person.add(name);
if (cur.getInt(cur.getColumnIndex( ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) {
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[]{id}, null);
if(pCur.getCount()==1) {
while (pCur.moveToNext()) {
String phoneNo = pCur.getString(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER));
number.add(phoneNo);
}
}
else{
while (pCur.moveToNext()) {
String phoneNo = pCur.getString(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER));
temp.add(phoneNo);
}
number.add(temp.get(0));
temp.clear();
}
pCur.close();
}
}
}
if (cur!=null) {
cur.close();
}
Log.d("contacts",String.valueOf(number.size())+" "+String.valueOf(person.size())); //the lists aren't of equal size
if(person.size()==number.size()){
nameList.add(person);
nameList.add(number);
}
else{
//don't know what to do here
}
return nameList;
}
But, the code still fetches multiple contact numbers saved for a single user, in other words person.size() is not equal to number.size(). What do I do?
The array sizes are not the same because not all contacts have phone-numbers, you are correctly checking for HAS_PHONE_NUMBER and only if true, getting that contact's phone numbers - which means number.size() would be < person.size() on most phones.
I would suggest instead of keeping separate Arrays for names and phones, having a single Array with a simple java class that represents a person.
Other than that, your code is very inefficient, as you're doing a ton of queries, while you can do just one.
Here's an example with the two suggestions above:
class Person {
long id,
String name,
String firstPhone;
public Person(id, name, firstPhone) {
this.id = id;
this.name = name;
this.firstPhone = firstPhone;
}
}
Map<Long, Person> mapping = new HashMap<>(); // mapping between a contact-id to a Person object
String[] projection = {Data.CONTACT_ID, Data.DISPLAY_NAME, Phone.NUMBER};
// query phones only
String selection = Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'";
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1); // full name
String phone = cur.getString(2); // phone
Log.d(TAG, "got " + id + ", " + name + " - " + data);
// only add a new object if we haven't seen this person before
if (!mapping.containsKey(id)) {
Person person = new Person(id, name, phone);
mapping.put(id, person);
}
}
cur.close();
Array<Person> people = mapping.values();
EDIT
Set<Long> ids = new HashSet<Long>();
Array<String> names = new ArrayList<String>();
Array<String> numbers = new ArrayList<String>();
String[] projection = {Data.CONTACT_ID, Data.DISPLAY_NAME, Phone.NUMBER};
// query phones only
String selection = Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'";
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1); // full name
String phone = cur.getString(2); // phone
Log.d(TAG, "got " + id + ", " + name + " - " + data);
// only add a new object if we haven't seen this person before
if (ids.add(id)) {
names.add(name);
numbers.add(phone);
}
}
cur.close();
This code is working fine for fetching name and phone but i don't know how to get email from this code. Here is my code :
public static ArrayList<ContentValues> getContactDetails(final Context mContext){
ArrayList<ContentValues> contactList = new ArrayList<ContentValues>();
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor managedCursor = mContext.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null,
null, order);
int _number = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int _name = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int _id = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
while (managedCursor.moveToNext()) {
ContentValues values = new ContentValues();
Contact mContact = new Contact();
values.put(ContactClass.CONTACT_NAME, managedCursor.getString(_name));
values.put(ContactClass.CONTACT_MOBILE_NUMBER, managedCursor.getString(_number).replaceAll("\\s+",""));
mContact.setPhNo(managedCursor.getString(_number).replaceAll("\\s+",""));
mContact.setName(managedCursor.getString(_name));
contactList.add(values);
serverContactList.add(mContact);
}
}
return contactList;
}
here i want to get email and add to serverContactList list.
I edited your code, add rest of your code in 2 todos.
public static ArrayList<ContentValues> getContactDetails(final Context mContext) {
// todo rest of things
int _id = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
while (managedCursor.moveToNext()) {
// we will get emails for a contact id
String id = managedCursor.getString(_id);
Cursor cur1 = mContext.getContentResolver().query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?",
new String[]{id}, null);
if (cur1 != null) {
while (cur1.moveToNext()) {
//to get the contact names
String name = cur1.getString(cur1.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
Log.e("Name :", name);
String email = cur1.getString(cur1.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
Log.e("Email", email);
}
}
cur1.close();
// todo rest of things
}
return contactList;
}
Don't use managedCursor, ever.
Query over Data.CONTENT_URI instead of Phone.CONTENT_URI to get access to all Data items (including Phone and Email and others if needed)
Limit the query by MIMETYPE to just the items you need
Map<Long, Contact> contacts = new HashMap<>();
String[] projection = {Data.CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3};
// query only emails/phones/events
String selection = Data.MIMETYPE + " IN ('" + Phone.CONTENT_ITEM_TYPE + "', '" + Email.CONTENT_ITEM_TYPE + "')";
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1); // full name
String mime = cur.getString(2); // type of data (phone / email)
String data = cur.getString(3); // the actual info, e.g. +1-212-555-1234
Log.d(TAG, "got " + id + ", " + name + " - " + data);
// add info to existing list if this contact-id was already found, or create a new list in case it's new
Contact contact;
if (contacts.containsKey(id)) {
contact = contacts.get(id);
} else {
contact = new Contact();
contacts.put(id, contact);
contact.setName(name);
}
if (mime == Phone.CONTENT_ITEM_TYPE) {
contact.setPhNo(data);
} else {
contact.setEmail(data);
}
}
I am trying to get all contacts which have mobile numbers.
I am able to fetch the contacts.But the problem is it gives me duplicate contacts.same phone number comes two times.
I used the following code to get contacts.
public static List<RawContact> getAllContacts(Context context,Account account){
Log.d(TAG, "*** Looking for local contacts with mobile number!!");
String phoneNumber = null;
String email = null;
int numberOfContacts = 0;
List<RawContact> newContacts = new ArrayList<RawContact>();
Uri CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
String _ID = ContactsContract.Contacts._ID;
String DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME;
String HAS_PHONE_NUMBER = ContactsContract.Contacts.HAS_PHONE_NUMBER;
Uri PhoneCONTENT_URI = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String Phone_CONTACT_ID = ContactsContract.CommonDataKinds.Phone.CONTACT_ID;
String NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER;
List<RawContact> localNewContacts = new ArrayList<RawContact>();
final ContentResolver contentResolver = context.getContentResolver();
final Cursor cursor = contentResolver.query(CONTENT_URI,
null,
null,
null,
null);
if(cursor.getCount()>0){
numberOfContacts = 0;
Log.d(TAG, "*** Looking for local contacts "+cursor.getCount());
while(cursor.moveToNext()){
String contact_id = cursor.getString(cursor.getColumnIndex(_ID));
String name = cursor.getString(cursor.getColumnIndex(DISPLAY_NAME));
int hasPhoneNumber = Integer.parseInt(cursor.getString(cursor.getColumnIndex(HAS_PHONE_NUMBER)));
final long rawContactId = cursor.getLong(DirtyQuery.COLUMN_RAW_CONTACT_ID);
if (hasPhoneNumber > 0) {
//This is to read multiple phone numbers associated with the same contact
Cursor phoneCursor = contentResolver.query(PhoneCONTENT_URI, null, ContactsContract.RawContacts.ACCOUNT_TYPE + " <> 'google' "+" AND "+ Phone_CONTACT_ID + " = ?", new String[]{contact_id}, null);
while (phoneCursor.moveToNext()) {
phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER));
Log.d(TAG,"Phone number is: "+phoneNumber);
RawContact rawContact = getRawContact(context, rawContactId);
Log.d(TAG, "Contact Name: " + rawContact.getBestName());
localNewContacts.add(rawContact);
}phoneCursor.close();
}
numberOfContacts++;
Log.d(TAG, "numberOfContacts updated: "+numberOfContacts);
}
}
return localNewContacts;
}
How to solve this issue
You're getting duplicate contacts because you're actually reading RawContacts, not contacts. Multiple RawContacts can and will contain info about a single person represented by a single Contact.
You need a single query over the Phones table, and organize the data using a HashMap from CONTACT_ID to Contact info, so you won't get duplicates.
The Contacts DB is organized in three main tables:
Contacts - each entry represents one contact, and groups together one or more RawContacts
RawContacts - each entry represents data about a contact that was synced in by some SyncAdapter (e.g. Whatsapp, Google, Facebook, Viber), this groups multiple Data entries
Data - The actual data about a contact, emails, phones, etc. each line is a single piece of data that belongs to a single RawContact
You're trying to make a query on the Contacts table, with projection of fields from the Data table, you can't do that.
You can use something like the following code, just convert the HashMap to work with your ContactModel object:
Map<Long, List<String>> contacts = new HashMap<Long, List<String>>();
String[] projection = { Data.CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3 };
String selection = Data.MIMETYPE + " IN ('" + Phone.CONTENT_ITEM_TYPE + "')";
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1);
String mime = cur.getString(2); // type of data (e.g. "phone")
String data = cur.getString(3); // the actual info, e.g. +1-212-555-1234
int type = cur.getInt(4); // a numeric value representing type: e.g. home / office / personal
String label = cur.getString(5); // a custom label in case type is "TYPE_CUSTOM"
String labelStr = Phone.getTypeLabel(getResources(), type, label);
Log.d(TAG, "got " + id + ", " + name + ", " + kind + " - " + data + " (" + labelStr + ")");
// add info to existing list if this contact-id was already found, or create a new list in case it's new
List<String> infos;
if (contacts.containsKey(id)) {
infos = contacts.get(id);
} else {
infos = new ArrayList<String>();
infos.add("name = " + name);
contacts.put(id, infos);
}
infos.add(kind + " = " + data + " (" + labelStr + ")");
}
Here is quick solution i came up with
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
null,
null,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC ");
contactArray = new ArrayList<>();
String tempId = "";
if(cursor != null && cursor.getCount() > 0){
while(cursor.moveToNext())
{
String contact_id = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
if(!tempId.equals(contact_id)){
String contact_name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String contact_number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String result = contact_id+"\n"+contact_name+"\n"+contact_number;
contactArray.add(result);
}
tempId = contact_id;
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, contactArray);
listView.setAdapter(adapter);
cursor.close();
I am getting only name & birthday using the code below. But I need phone number & email also. It would be great if anyone can help me out. Thanks.
private void getContacts() {
Uri uri = ContactsContract.Data.CONTENT_URI;
String[] projection = new String[]{
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Event.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Email.DATA,
ContactsContract.CommonDataKinds.Event.START_DATE
};
String where = ContactsContract.Data.MIMETYPE + "= ? AND " +
ContactsContract.CommonDataKinds.Event.TYPE + "=" +
ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY;
String[] selectionArgs = new String[]{
ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE
};
String sortOrder = null;
ContentResolver contentResolver = this.getActivity().getContentResolver();
Cursor cursor = contentResolver.query(uri, projection, where, selectionArgs, sortOrder);
int nameColumn = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
int numberColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int emailColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA);
int bithDayColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.START_DATE);
while (cursor.moveToNext()) {
String name = cursor.getString(nameColumn);
String number = cursor.getString(numberColumn);
String email = cursor.getString(emailColumn);
String birthDay = cursor.getString(bithDayColumn);
Log.d(TAG, "Birthday: " + birthDay);
}
}
In your projection you're limiting your query to rows of MIMETYPE CommonDataKinds.Event.CONTENT_ITEM_TYPE only, so you'll only get birthdays.
You need to ask for emails and phones mimetypes, but note that these additional information will come in separate rows for the same contact.
For example, for contact A that has 2 phones, 3 emails and a birthday, you'll get 6 results in your cursor. So you need to group them all together using the CONTACT_ID field.
Here's simple code to get you started, print the resulting HashMap and you'll get for each contact all his/hers name, emails, phones and birthday:
Map<Long, List<String>> contacts = new HashMap<Long, List<String>>();
String[] projection = {Data.CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3};
// query only emails/phones/events
String selection = Data.MIMETYPE + " IN ('" + Phone.CONTENT_ITEM_TYPE + "', '" + Event.CONTENT_ITEM_TYPE"', '" + Email.CONTENT_ITEM_TYPE + "')";
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1); // full name
String mime = cur.getString(2); // type of data (phone / birthday / email)
String data = cur.getString(3); // the actual info, e.g. +1-212-555-1234
String kind = "unknown";
switch (mime) {
case Phone.CONTENT_ITEM_TYPE:
kind = "phone";
break;
case Event.CONTENT_ITEM_TYPE:
kind = "birthday";
break;
case Email.CONTENT_ITEM_TYPE:
kind = "email";
break;
}
Log.d(TAG, "got " + id + ", " + name + ", " + kind + " - " + data);
// add info to existing list if this contact-id was already found, or create a new list in case it's new
List<String> infos;
if (contacts.containsKey(id)) {
infos = contacts.get(id);
} else {
infos = new ArrayList<String>();
infos.add("name = " + name);
contacts.put(id, infos);
}
infos.add(kind + " = " + data);
}
I want to fetch all contact data including all raw contacts.
I referred this link
and this is the code that i am using :
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, Long.valueOf(raw_contact_id));
Uri entityUri = Uri.withAppendedPath(rawContactUri, Entity.CONTENT_DIRECTORY);
Cursor c = getContentResolver().query(entityUri,
new String[] { RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE, Entity.DATA1,
Entity.DATA2, Entity.DATA3, Entity.DATA4, Entity.DATA5, Entity.DATA6, Entity.DATA7,
Entity.DATA8, Entity.DATA9, Entity.DATA10, Entity.DATA11, Entity.DATA12, Entity.DATA13,
Entity.DATA14/* , Entity.DATA15 */ },
null, null, null);
try {
while (c.moveToNext()) {
String sourceId = c.getString(0);
if (!c.isNull(1)) {
String mimeType = c.getString(2);
// if (!mimeType.contains("photo")) {
String data1 = c.getString(3);
String data2 = c.getString(4);
String data3 = c.getString(5);
String data4 = c.getString(6);
}
}
} finally {
c.close();
}
The problem is that the implementation of this code takes a lot of time to fetch all contacts-data.
Is there any other way to get the contacts-data in under 5 seconds.
This is how I am getting the name & email Address, you can retrieve the other data also
ArrayList<String> emailAddressList = new ArrayList<String>();
ArrayList<String> contactNameList = new ArrayList<String>();
HashSet<String> emlRecsHS = new HashSet<String>();
ContentResolver cr = getContentResolver();
String[] PROJECTION = new String[] {ContactsContract.CommonDataKinds.Email.DATA, ContactsContract.Contacts.DISPLAY_NAME};
String order = "CASE WHEN "
+ ContactsContract.Contacts.DISPLAY_NAME
+ " NOT LIKE '%#%' THEN 1 ELSE 2 END, "
+ ContactsContract.Contacts.DISPLAY_NAME
+ ", "
+ ContactsContract.CommonDataKinds.Email.DATA
+ " COLLATE NOCASE";
String filter = ContactsContract.CommonDataKinds.Email.DATA + " NOT LIKE ''";
Cursor cur = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, PROJECTION, filter, null, order);
if (cur.moveToFirst())
{
do
{
// names comes in hand sometimes
String emlAddress = cur.getString(0);
String contactName = cur.getString(1);
// keep unique only
if (emlRecsHS.add(emlAddress.toLowerCase(Locale.US)))
{
emailAddressList.add(emlAddress);
contactNameList.add(contactName);
}
} while (cur.moveToNext());
}
cur.close();