0

I'm trying to retrieve data from the Contact provider but the data shows seems not query correctly. The code I use is just below:

mCursor = mContext.getContentResolver().query(
        ContactsContract.Data.CONTENT_URI, null, null, null, null);



if(mCursor == null){
    mListener.onRetrieveError();
    return;
}

for (mCursor.moveToFirst(); !mCursor.isAfterLast(); mCursor.moveToNext()) {
    String contact_f = mCursor.getString(mCursor
            .getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
    String contact_m = mCursor.getString(mCursor
            .getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME));
    String contact_l = mCursor.getString(mCursor
            .getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
    String phone_type = mCursor.getString(mCursor
            .getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
    String email_type = mCursor.getString(mCursor
            .getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));

    Log.d(TAG,  "|" + contact_l + ", " + contact_f + " " + contact_m + " | " + phone_type + " | " + email_type);
}

The Log shows for example :

Log: |LastName, FirstName  | FirstName  | FirstName  
Log: |null, 3 null | 3 | 3

I was expecting :

Log: |LastName, FirstName MiddleName | PhoneType| EmailType

I want to be able to get the firstname, lastname, middle name, email type (home/work...) - and all email types listed and also the phone type.

The goal is to for example get for a contact his lastname, firstname middle name and also saying that we got is home and work phone or email

The result I got seems a mix.

Any ideas.

Regards

Seb
  • 2,929
  • 4
  • 30
  • 73
  • Have you tried this tutorial: http://developer.android.com/training/contacts-provider/retrieve-details.html – T D Nguyen Apr 14 '16 at 22:50

3 Answers3

2

That's not how it works. The Data table contains one row per contact value field (phone number, email address, structured name ...). Each row has a mimetype value that tells you how to interpret the columns of that row.

For example, if the mimetype column has the value Phone.CONTENT_ITEM_TYPE you must use the Phone column mapping to access the data.

So if a contact has one phone number and one email address there are at least 3 rows for this contact in the Data table. One for the StructuredName (this one is required exactly once for each RawContact), one for the Phone number and one for the Email address.

Each row also has a RAW_CONTACT_ID that contains the row id of the RawContact the value belongs to.

When you query the Data table, you actually read from a view that joins the real Data table with the RawContacts table, so each row also contains the CONTACT_ID of the contact the row belongs to. That means if two rows have the same CONTACT_ID they belong to the same contact.

I hope that explains it. I don't really know what you're trying to achieve in the end, so I can't give any helpful code snippets.

Update

The key to this is to check the mimetype of each row before you decide how to interpret the values. Also you need to read the CONTACT_ID or RAW_CONTACT_ID to be able to aggregate the data correctly. If you order the result by CONTACT_ID you can assume that all rows belonging to a contact have been read when the CONTACT_ID value changes.

The (untested) code snippet below should point you to the right direction. The point is, you can not get all the data of a contact in a single row. You always need to read multiple rows and aggregate them in some way.

mCursor = mContext.getContentResolver().query(
        ContactsContract.Data.CONTENT_URI, null, null, null, ContactsContract.Data.CONTACT_ID);

if(mCursor == null){
    mListener.onRetrieveError();
    return;
}

colIdxContactId = mCursor.getColumnIndex(ContactsContract.Data.CONTACT_ID);
colIdxMimetype = mCursor.getColumnIndex(ContactsContract.Data.MIMETYPE);

long lastContactId = -1L;

for (mCursor.moveToFirst(); !mCursor.isAfterLast(); mCursor.moveToNext())

  // this is the contact Id the current row belongs to
  long contactId = mCursor.getLong(colIdxContactId);

  if (lastContactId != contactId) {
    // the previous contact is complete, the following data belong to a new contact
    // handle this case ...

    lastContactId = contactId;
  }

  // the mimetype column tells us how to interpret the current row:
  switch(mCursor.getString(colIdxMimetype)) {
    case ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE: {
      // this row is a structured name
      String contact_f = mCursor.getString(mCursor
        .getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
      String contact_m = mCursor.getString(mCursor
        .getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME));
      String contact_l = mCursor.getString(mCursor
        .getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
      // store names somewhere ...

      break;
    }
    case ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE: {
      // this row represents a phone number
      int phone_type = mCursor.getInt(mCursor
        .getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
      // store phone_type somewhere ...

      break;
    }
    case ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE: {
      // this row represents an email address
      int email_type = mCursor.getInt(mCursor
        .getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));
      // store email_type somewhere ...

      break;
    }
  }
}
Marten
  • 3,802
  • 1
  • 17
  • 26
  • Thanks. What I'm trying to achieve is to extract something like – Seb Apr 15 '16 at 19:57
  • Lastname, Firstname, Middle name and also phone numbers + type(home, work, custom..) and same for emails but email data is not where phone data are and where name are (Structured name) – Seb Apr 15 '16 at 19:58
  • of all contacts. I do not want the displayed name because I can't make difference between first last and middle name. – Seb Apr 15 '16 at 20:54
  • I've added simple example based on your code. It's probably not ideal, but it should give you an idea of how it works. – Marten Apr 15 '16 at 21:31
0

You can use this

 public void getAllContacts(){


        Cursor cursor = null;
        ContactPerson contact;
        try {
            cursor = getActivity().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
            int nameIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
            int phoneNumberIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
            int emailAddressIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA);
            cursor.moveToFirst();
            do {
                contact = new ContactPerson(cursor.getString(nameIdx),cursor.getString(phoneNumberIdx),cursor.getString(emailAddressIdx));
                cpList.add(contact);
                                    //  Toast.makeText(getActivity(),cursor.getString(nameIdx)+" "+ cursor.getString(phoneNumberIdx),Toast.LENGTH_SHORT).show();

            } while (cursor.moveToNext());
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(getActivity(),e.getMessage(), Toast.LENGTH_LONG).show();
            Log.d("Error",e.getMessage());

        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }

   }
Usman
  • 87
  • 1
  • 13
  • this code seems not working. First I need to get First name, last and middle name from the StructuredName and you are querying ContactsContract.CommonDataKinds.Phone.CONTENT_URI but email is pointed to CommonDataKinds.Email – Seb Apr 15 '16 at 02:07
  • it will give you display name, phone number and email – Usman Apr 15 '16 at 13:10
0

I think the URI you are using is wrong. Try using ContactsContract.Contacts.CONTENT_URI instead of ContactsContract.Data.CONTENT_URI (this is what I use).

Lior A
  • 1
  • 1
  • The issue is that the different info are located at different place. Contacts.CONTENT_URI will give me the Display Name" but the First name, lastname and middle name is located the NamedStructures and you are not using the same query. – Seb Apr 15 '16 at 01:42
  • The best for me should be to list all contacts id and be able to send a query with this ID to get details info from this particular ID – Seb Apr 15 '16 at 01:43