4

I wrote the following function in order to retrieve one single phone number that belongs to the contact with id "contactID".

The function which is to retrieve the phone number:

private String getContactPhone(String contactID) {
    Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    String[] projection = null;
    String where = ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?";
    String[] selectionArgs = new String[] { contactID };
    String sortOrder = null;
    Cursor result = managedQuery(uri, projection, where, selectionArgs, sortOrder);
    if (result.moveToFirst()) {
        String phone = result.getString(result.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
        if (phone == null) {
            result.close();
            return null;
        }
        result.close();
        return phone;
    }
    result.close();
    return null;
}

How this function is called:

ArrayList<Contact> resultContacts = new ArrayList<Contact>();
Cursor result = null;
Uri uri = ContactsContract.Data.CONTENT_URI;
String[] projection = new String[] {
        ContactsContract.Contacts._ID,
        ContactsContract.Contacts.DISPLAY_NAME,
        ContactsContract.CommonDataKinds.Event.CONTACT_ID,
        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;
result = managedQuery(uri, projection, where, selectionArgs, sortOrder);
while (result.moveToNext()) {
    Long id = result.getLong(result.getColumnIndex(ContactsContract.Contacts._ID));
    String phone = getContactPhone(String.valueOf(id));
    ...
}
...

Unfortunately, it doesn't work. I get null if I call this function with the value that I got from "ContactsContract.Contacts._ID". Why is this so? What is wrong?

Edit: I used to map Contacts._ID to CommonDataKinds.Phone.CONTACT_ID - which didn't work. But now I map Contacts.DISPLAY_NAME to CommonDataKinds.Phone.DISPLAY_NAME and it works suddenly - strange, isn't it? But I would rather like to map the IDs instead of the display names. So the question is still topical. Could this be due to different IDs in those tables? Isn't this why there are lookup IDs?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
caw
  • 30,999
  • 61
  • 181
  • 291
  • Have you confirmed that you only get one contact? – tidbeck Jan 09 '12 at 23:58
  • Yes, as I try to get the phone numer for every contact while iterating through the resulting cursor of the first query. And if I got two contacts, this wouldn't work with the display name, either, would it? – caw Jan 10 '12 at 17:23
  • Is it possible that you could show how you get the `contactId` so I might be able to try this my self? – tidbeck Jan 10 '12 at 17:31
  • Of course, I can. I added details to the question above. Thank you for your effort! – caw Jan 10 '12 at 22:15

3 Answers3

12

To get the contact id in the first part, you should use:

ContactsContract.Data.CONTACT_ID

instead of:

ContactsContract.Contacts._ID

So the projection should be:

String[] projection = new String[] {
         ContactsContract.Data.CONTACT_ID,
         ContactsContract.CommonDataKinds.Event.CONTACT_ID,
         ContactsContract.CommonDataKinds.Event.START_DATE,
 };

And then of course get the correct row:

Long id = result.getLong(result.getColumnIndex(ContactsContract.Data.CONTACT_ID));
tidbeck
  • 2,363
  • 24
  • 35
  • No, please see my edit in the question. But thanks for the answer so far :) – caw Jan 09 '12 at 22:44
  • @MarcoW. I have updated the answer now when you provided more details in the question. This worked for me. – tidbeck Jan 11 '12 at 01:07
  • It works, thank you very much! Why is Contacts._ID the wrong field? What is in that field? – caw Jan 11 '12 at 14:08
  • 2
    With `Contacts._ID` you will actually get the `Data._ID` column as both is `"_id"`. The column you want is `"contact_id"` as you are pulling data from uri `ContactsContract.Data.CONTENT_URI`. – tidbeck Jan 11 '12 at 14:43
2

You are getting null because you have set your projection to null. The projection is basically the list of columns that you want returned e.g.

String[] projection = {ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER};

Usually, when you find the contact, they may have a list of phone numbers, so you have to use another cursor to iterate through the phone numbers, e.g.

Cursor phones = mContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId, null, null);    
while (phones.moveToNext()) 
{    
     phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA));
}

Hope this helps.

John J Smith
  • 11,435
  • 9
  • 53
  • 72
  • Thanks for the answer! You set the projection to null in your example as well, don't you? I thought the when the projection is null then the cursor returns ALL columns. Is this wrong? – caw Jan 07 '12 at 18:25
  • Yeah, you're right. Sorry I missed the null. The only thing I can suggest is to check that the contactID is valid and debug through the method. Perhaps get all contacts first and check you have one with the contactID which is being passed. – John J Smith Jan 08 '12 at 18:15
  • I did check if it is valid. And the ID always seemed to be valid. I just had to make a conversion from long to String. But please see my edit in the question, maybe that helps. – caw Jan 09 '12 at 22:47
1

Your code for getContactPhone() works fine on my end. I tested by launching a contact picker, selecting a contact, then using the ID that was returned and passed that into your method.

So I suspect you are indeed passing in an invalid ID. Can you post the full stack trace for the null pointer exception?

Yes, lookup keys are available because _IDs are not guaranteed to stay the same since syncs and contact aggregation changes them.

robertly
  • 2,132
  • 14
  • 9
  • Thanks for the answer! There's no null pointer exception, the managedQuery just can't find any rows. Please see the full code in the question :) – caw Jan 10 '12 at 23:29