How can I choose a phone number with Android's contacts dialog
Asked Answered
M

4

25

I'm using the old Contacts API to choose a contact with a phone number. I want to use the newer ContactsContracts API. I want...

  1. ...a dialog shown with all contacts that have phone numbers.
  2. ...the user to choose a contact AND one of their phone numbers.
  3. ...access to the chosen phone number.

The ContactsContracts is very complicated. I found many examples, but none that fit my needs. I don't want to choose a contact and then query for the contact's details because this will give me a list of their phone numbers. I need the user to choose ONE of the contact's phone numbers. I don't want to have to write my own dialogs to display the contacts or to have the user pick a phone number. Is there any simple way to get what I want?

Here is the old API code I'm using:

static public final int CONTACT = 0;
...
Intent intent = new Intent(Intent.ACTION_PICK, Contacts.Phones.CONTENT_URI);
startActivityForResult(intent, CONTACT);
...
public void onActivityResult (int requestCode, int resultCode, Intent intent) {
  if (resultCode != Activity.RESULT_OK || requestCode != CONTACT) return;
  Cursor c = managedQuery(intent.getData(), null, null, null, null);
  if (c.moveToFirst()) {
     String phone = c.getString(c.getColumnIndexOrThrow(Contacts.Phones.NUMBER));
     // yay
  }
}      
Mezzanine answered 23/12, 2011 at 5:23 Comment(4)
there are enough question on SO for the same.Caballero
possible duplicate of How to call Android contacts list?Caballero
The other questions pick a contact, they don't pick a phone number.Mezzanine
Check unselected answer's link #4224678Obsess
M
37
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
startActivityForResult(intent, PICK_CONTACT); 

This code might help you. I think the PICK action only returns the ID of the contact picked. From that you could query the Contact provider and if there are multiple phone numbers, prompt the user to select one of them.

You can use this too (updated):

public void readcontact(){
    try {
        Intent intent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts/people"));
        startActivityForResult(intent, PICK_CONTACT);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void onActivityResult(int reqCode, int resultCode, Intent data) {
      super.onActivityResult(reqCode, resultCode, data);

      switch (reqCode) {
        case (PICK_CONTACT) :
          if (resultCode == Activity.RESULT_OK) {
              Uri contactData = data.getData();
                Cursor c =  managedQuery(contactData, null, null, null, null);
                startManagingCursor(c);
                if (c.moveToFirst()) {
                    String name = c.getString(c.getColumnIndexOrThrow(People.NAME));    
                    String number = c.getString(c.getColumnIndexOrThrow(People.NUMBER));
                    personname.setText(name);
                    Toast.makeText(this,  name + " has number " + number, Toast.LENGTH_LONG).show();
                 }
           }
         break;
      }

}

Updated 28/12 -2011

You can use this:

@Override  
protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
    if (resultCode == RESULT_OK) {  
        switch (requestCode) {  
        case CONTACT_PICKER_RESULT:
            final EditText phoneInput = (EditText) findViewById(R.id.phoneNumberInput);
            Cursor cursor = null;  
            String phoneNumber = "";
            List<String> allNumbers = new ArrayList<String>();
            int phoneIdx = 0;
            try {  
                Uri result = data.getData();  
                String id = result.getLastPathSegment();  
                cursor = getContentResolver().query(Phone.CONTENT_URI, null, Phone.CONTACT_ID + "=?", new String[] { id }, null);  
                phoneIdx = cursor.getColumnIndex(Phone.DATA);
                if (cursor.moveToFirst()) {
                    while (cursor.isAfterLast() == false) {
                        phoneNumber = cursor.getString(phoneIdx);
                        allNumbers.add(phoneNumber);
                        cursor.moveToNext();
                    }
                } else {
                    //no results actions
                }  
            } catch (Exception e) {  
               //error actions
            } finally {  
                if (cursor != null) {  
                    cursor.close();
                }

                final CharSequence[] items = allNumbers.toArray(new String[allNumbers.size()]);
                AlertDialog.Builder builder = new AlertDialog.Builder(your_class.this);
                builder.setTitle("Choose a number");
                builder.setItems(items, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int item) {
                        String selectedNumber = items[item].toString();
                        selectedNumber = selectedNumber.replace("-", "");
                        phoneInput.setText(selectedNumber);
                    }
                });
                AlertDialog alert = builder.create();
                if(allNumbers.size() > 1) {
                    alert.show();
                } else {
                    String selectedNumber = phoneNumber.toString();
                    selectedNumber = selectedNumber.replace("-", "");
                    phoneInput.setText(selectedNumber);
                }

                if (phoneNumber.length() == 0) {  
                    //no numbers found actions  
                }  
            }  
            break;  
        }  
    } else {
       //activity result error actions
    }  
}

You need to adapt this to work with your app.

Mckamey answered 23/12, 2011 at 6:6 Comment(7)
Are you saying there is no built in way to pick a phone number?Mezzanine
Just picking a contact is nice, but I need to pick one of the contact's phone numbers. The code in the question using the old API shows a contact picker, when a contact is shown, if it has multiple phone numbers, a little dialog is shown to pick a phone number (at least on my HTC Thunderbolt). This is what I would like to do but with the new API. I don't know if this functionality is built-in or if a custom dialog is needed to choose a phone number.Mezzanine
developer.android.com/resources/samples/BusinessCard/src/com/… Use this link for Contacts pick n even for number n i trying to do code for it .HopefullyMckamey
Intent intent = new Intent(Intent.ACTION_PICK, Contacts.Phones.CONTENT_URI); startActivityForResult(intent, PICK_CONTACT_RQCODE_OLD); Shows the Phone Numbers aswell as the Contacts... :)Mckamey
what is People.Name and People.Number, where is it defined?Orbital
I have three accounts on my phone . X@gmail Y@gmail and Z@gmail. I can get the contact ID for all of the contacts that belong to all of these contacts. But i can only get the number of contacts that belong to X@gmail. What is the solution ?Clamber
@Rizvan: your solution works great on my phone wich runs Android 4.4.4. But when I tried to use this solution on my gf's phone (Android 4.1.2) it showed no contacts at all. I think it is because several methods are deprecated.Pupa
O
12

Here you can find a great code from : http://developer.android.com/training/basics/intents/result.html

static final int PICK_CONTACT_REQUEST = 1;  // The request code
...
private void pickContact() {
    Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
    pickContactIntent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
    startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Check which request it is that we're responding to
    if (requestCode == PICK_CONTACT_REQUEST) {
        // Make sure the request was successful
        if (resultCode == RESULT_OK) {
            // Get the URI that points to the selected contact
            Uri contactUri = data.getData();
            // We only need the NUMBER column, because there will be only one row in the result
            String[] projection = {Phone.NUMBER};

            // Perform the query on the contact to get the NUMBER column
            // We don't need a selection or sort order (there's only one result for the given URI)
            // CAUTION: The query() method should be called from a separate thread to avoid blocking
            // your app's UI thread. (For simplicity of the sample, this code doesn't do that.)
            // Consider using CursorLoader to perform the query.
            Cursor cursor = getContentResolver()
                    .query(contactUri, projection, null, null, null);
            cursor.moveToFirst();

            // Retrieve the phone number from the NUMBER column
            int column = cursor.getColumnIndex(Phone.NUMBER);
            String number = cursor.getString(column);

            // Do something with the phone number...
        }
    }
}
Overbold answered 25/12, 2014 at 13:24 Comment(0)
M
10

From the older answers and my own tests I ended using this:

launching contact list:

import android.content.Intent;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;

...

public static final int PICK_CONTACT = 100;

...

Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
intent.setType(Phone.CONTENT_TYPE);  //should filter only contacts with phone numbers
startActivityForResult(intent, PICK_CONTACT);

onActivityResult handler:

private static final String[] phoneProjection = new String[] { Phone.DATA };

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (PICK_CONTACT != requestCode || RESULT_OK != resultCode) return;
    Uri contactUri = data.getData();
    if (null == contactUri) return;
    //no tampering with Uri makes this to work without READ_CONTACTS permission
    Cursor cursor = getContentResolver().query(contactUri, phoneProjection, null, null, null);
    if (null == cursor) return;
    try {
        while (cursor.moveToNext()) {
            String number = cursor.getString(0);
            // ... use "number" as you wish
        }
    } finally {
        cursor.close();
    }
    // "cursor" is closed here already
}

So what are the differences from Rizvan answer?

On my testing device (Samsung S3):

  • the app does NOT need READ_CONTACS permission (because I use the returned uri as is, when I use only the "id" of it and create select ID=? query type, the permission crash happens)
  • when contact has multiple phone numbers, the picker itself does show dialog to select only one of them, then it returns uri which leads directly to that single selected number
  • even if some phone would return uri to multiple numbers, the proposed onActivityResult handler can be extended to read them all and you can do your own selection dialog.

So this looks to me like perfect fit for what OP asked.

Now I just wonder:

  1. on which phones this will require the READ_CONTACTS permission (it should not, according to http://developer.android.com/guide/topics/providers/content-provider-basics.html#Intents )
  2. on which phones it will return multiple numbers instead of doing the selection dialog

Let me know if you have real world experience with it, thanks.

Update: HTC Desire S, custom rom with android 4.0.3 -> has both problems, requires READ_CONTACTS permission to work, and will return multiple numbers without additional selection dialog.

Mcghee answered 24/11, 2014 at 3:8 Comment(3)
HTC M8 requires READ_CONTACTS with this code, but they seem to provided the phone number in an intent extra with key Intent.EXTRA_PHONE_NUMBERReceivership
I get IllegalArgumentException: Invalid column data1 on the query lineEffulgent
About IllegalArgumentException - it's probably from the Phone.DATA, being not available in content resolver... I would need your particular phone model to see what is then available, and how to detect. I'm quite irritated by the general low quality of Android implementations, not following the API, like in this example the phones which make this fail without the READ_CONTACTS permission, etc... The code as is should be correct on correct Android, you can fortify it more by enclosing it into try-catch and even try to find some workaround for your particular phone, but I didn't had one.Mcghee
D
0

I find one way to pick exactly the phone number from contact list. Below is the snippet.

1.Launch contacts to select phone numbers in fragment.

Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);        
// filter the contacts with phone number only
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE); 
startActivityForResult(intent, PICK_CONTACT);

2.Pick the selected phone numbers in fragment.

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case (PICK_CONTACT):
            if (resultCode == Activity.RESULT_OK) {
                Uri contactData = data.getData();
                Cursor cur =  getActivity().getContentResolver().query(contactData, null, null, null, null);
                if (cur == null) return;
                try {
                    if (cur.moveToFirst()) {
                        int phoneIndex = cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
                        mobileNoEditText.setText(cur.getString(phoneIndex));
                    }
                }
                finally {
                    cur.close();
                }
            }
    }
}

P.S. private final int PICK_CONTACT = 666;

Distraught answered 26/4, 2018 at 7:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.