Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android contacts Display Name and Phone Number(s) in single database query?

I'm trying to obtain a list of contacts from the native database with their Display Name and Phone Number (any or all). There are many methods for obtaining this information with several queries to the phone's database, but this introduces considerable overhead.

Here is the query I've been working on, but it results in

Uri uri                = ContactsContract.Contacts.CONTENT_URI;
String[] projection    = new String[] { ContactsContract.Contacts._ID,
                                        ContactsContract.Contacts.DISPLAY_NAME,
                                        ContactsContract.CommonDataKinds.Phone.NUMBER};
String selection       = ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '1'";
String[] selectionArgs = null;
String sortOrder       = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";

Cursor people          = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);

int index_id    = people.getColumnIndex(ContactsContract.Contacts._ID);
int indexName   = people.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
int indexNumber = people.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);

people.moveToFirst();
do {
    String _id    = people.getString(index_id);
    String name   = people.getString(indexName);
    String number = people.getString(indexNumber);
    // Do work...
} while (people.moveToNext());

And here's the resulting error.

E/AndroidRuntime(21549): Caused by: java.lang.IllegalArgumentException: Invalid column data1
E/AndroidRuntime(21549):    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:144)
E/AndroidRuntime(21549):    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:114)
E/AndroidRuntime(21549):    at android.content.ContentProviderProxy.bulkQueryInternal(ContentProviderNative.java:372)
E/AndroidRuntime(21549):    at android.content.ContentProviderProxy.query(ContentProviderNative.java:408)
E/AndroidRuntime(21549):    at android.content.ContentResolver.query(ContentResolver.java:264)

Thoughts? I believe a join may be needed to get all the columns in a single query.

like image 758
Derek Avatar asked Jul 05 '11 19:07

Derek


People also ask

How do I show contact names and numbers on Android?

Display Only Android Contacts with Phone Numbers. Open your Contacts app and tap the Options button (three dots), and select Contacts Manager. On the next screen, tap on Contacts to display from the menu.

How do I select a contact in Android Studio?

Create a new project in Android Studio. Select Phone and Tablet and choose Empty Activity from templates. In the next screen, you will be asked to provide details related to your project. You can name the application and package anything you want.


3 Answers

Try this code:

Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection    = new String[] {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER};

Cursor people = getContentResolver().query(uri, projection, null, null, null);

int indexName = people.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int indexNumber = people.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);

if(people.moveToFirst()) {
    do {
        String name   = people.getString(indexName);
        String number = people.getString(indexNumber);
        // Do work...
    } while (people.moveToNext());
}
like image 99
jamapag Avatar answered Oct 28 '22 04:10

jamapag


The contacts API is extremly tricky and has several implicit joins.

Read the ContactContract and ContactsProvider2 if you can afford the time.

What do you want? The tables are chained like this:

  • Contact 1--* Raw Contact
  • Raw Contact 1--* Phone Number (data table)

The API works like this: you select the bottom-most element (a phone number) and implicit join to the topmost element (contact).

You want to use the PHONE URI case (ContactsProvider2 / line 4377). This should select all phone numbers and join up to the contact.

Combine the PHONE uri with some UI magic (for grouping), request the DISPLAY_NAME and the PHONE number (DATA1?) and you should be able to solve the problem.

like image 22
treffer Avatar answered Oct 28 '22 05:10

treffer


Phone numbers are stored in their own table and need to be queried separately. To query the phone number table use the URI stored in the SDK variable ContactsContract.CommonDataKinds.Phone.CONTENT_URI. Use a WHERE conditional to get the phone numbers for the specified contact.

private String displayName(Uri contactUri) {
        HashSet detail = ContactDetail.getInstance().getContactArray();
        Log.d("ITEM", contactUri.toString());
        String[] projection = new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER};
        Cursor queryCursor = getActivity().getContentResolver()
                .query(contactUri, null, null, null, null);
        queryCursor.moveToFirst();
        String name = queryCursor.getString(queryCursor.getColumnIndex("display_name"));
        String id = queryCursor.getString(
                queryCursor.getColumnIndex(ContactsContract.Contacts._ID));

        if (Integer.parseInt(queryCursor.getString(queryCursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
            Cursor pCur = getActivity().getContentResolver().query(
                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    null,
                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
                    new String[]{id}, null);
            while (pCur.moveToNext()) {
                String number = pCur.getString(pCur.getColumnIndex("data1"));
                Log.d("Contact Name: ", number);
            }
            pCur.close();
        }


        return name;
    }

Perform a second query against the Android contacts SQLite database. The phone numbers are queried against the URI stored in ContactsContract.CommonDataKinds.Phone.CONTENT_URI. The contact ID is stored in the phone table as ContactsContract.CommonDataKinds.Phone.CONTACT_ID and the WHERE clause is used to limit the data returned.

like image 31
rinkesh Avatar answered Oct 28 '22 05:10

rinkesh