I'm trying to get the information of my contacts using ContactsContract and what I need to do, is to get only the first name of the contact. I used ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME but this get the name and the last name too, and I only want the name.
I tried using ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME but instead of getting the name, this get a number.
I have not found an exact way to get only the first name of the contact. Any idea?
You haven't shared your code, but it sounds like you're querying over table Phone.CONTENT_URI and trying to get a field via StructuredName.GIVEN_NAME.
That's not possible, as Phone.CONTENT_URI will only return phone rows, not StructuredName rows.
Here's code snippet to get all given-names from the Contacts DB:
String[] projection = new String[]{StructuredName.CONTACT_ID, StructuredName.GIVEN_NAME};
String selection = Data.MIMETYPE + "='" + StructuredName.CONTENT_ITEM_TYPE + "'";
Cursor c = getContentResolver().query(Data.CONTENT_URI, projection, selection, null, null);
DatabaseUtils.dumpCursor(c);
c.close();
UPDATE
Here's some sample code on how to query for multiple mimetypes in a single query.
In this example I created a mapping from to <given-name, phone> for each contact in the DB:
Map<Long, List<String>> contacts = new HashMap<Long, List<String>>();
String[] projection = {Data.CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, StructuredName.GIVEN_NAME, Phone.NUMBER };
// select all rows of type "name" or "phone"
String selection = Data.MIMETYPE + " IN ('" + Phone.CONTENT_ITEM_TYPE + "', '" + StructuredName.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 row: phone / name
// get the existing <Given-name, Phone> list from the Map, or create a new one
List<String> infos;
if (contacts.containsKey(id)) {
infos = contacts.get(id);
} else {
infos = new ArrayList<String>(2);
contacts.put(id, infos);
}
// add either given-name or phone to the infos list
switch (mime) {
case Phone.CONTENT_ITEM_TYPE:
infos.set(1, cur.getString(4));
break;
case StructuredName.CONTENT_ITEM_TYPE:
infos.set(0, cur.getString(3));
break;
}
}
Related
Is it possible to retrieve all data from contact book by one request (phone number, email, first name, last name, photo, thumbnail). Right now I am running a separate request for a first and last name, a separate request for a phone number and a separate request for an email, and so on. Is it possible to get all this data in one request? Please help me.
Yes, you can.
You're probably running your queries on Alias tables such as CommonDataKinds.Phone and CommonDataKinds.Email, but the actual data for all these tables is stored in a single table called Data.
So you should query directly on Data and use the MIMETYPE column to figure out the "type" of the current row you're iterating over.
Here's an example of getting name, email, phone.
You can add more mimetypes to the list to get more types of data.
I'm using a HashMap to keep a list of values for each contact-ID but you would probably want to create a custom Contact class and put that info in it.
Map<Long, List<String>> contacts = new HashMap<Long, List<String>>();
String[] projection = {Data.CONTACT_ID, Data.MIMETYPE, Data.DATA1, Data.DATA2, Data.DATA3};
// query only name/emails/phones
String selection = Data.MIMETYPE + " IN ('" + StructuredName.CONTENT_ITEM_TYPE + "', '" + 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 mime = cur.getString(1); // type of data (name / phone / email)
String data = cur.getString(2); // the actual info, e.g. +1-212-555-1234
String kind = "unknown";
switch (mime) {
case Phone.CONTENT_ITEM_TYPE:
kind = "phone";
break;
case StructuredName.CONTENT_ITEM_TYPE:
kind = "name";
break;
case Email.CONTENT_ITEM_TYPE:
kind = "email";
break;
}
Log.d(TAG, "got " + id + ", " + 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>();
contacts.put(id, infos);
}
infos.add(kind + " = " + data);
}
I am trying to get first name and last name in contact book by phone number.
Here is my code:
Uri contactUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Cursor cursor = cResolver.query(uri, null, null, null, null);
if(cursor != null && cursor.moveToFirst()) {
int idColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts._ID);
int firstNameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
int lastNameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
while (!cursor.isAfterLast()) {
long id = cursor.getLong(idColumnIndex);
contact = new MyContact();
contact.setId(id);
contact.setFirstName(cursor.getString(firstNameIndex));
contact.setLastName(cursor.getString(lastNameIndex));
}
cursor.close();
}
But firstNameIndex and lastNameIndex is always -1. What I am doing wrong ? Please help me.
PhoneLookup is a nice and quick way to get contact data by a phone number, but it returns a cursor limited to the columns mentioned in the docs.
You can see there's DISPLAY_NAME you can access, but not GIVEN_NAME, FAMILY_NAME.
GIVEN_NAME & FAMILY_NAME are fields stored in the Data table, which means you need to query that table separately to get to those fields.
So, you can just add another query using the contact ID you got from PhoneLookup (note that for each looked up phone there might be multiple contacts returned).
Here's a sample method to get first/last names from contact ID:
private void addNames(MyContact contact, long contactId) {
String[] projection = new String[] {StructuredName.GIVEN_NAME, StructuredName.FAMILY_NAME};
// filter to just StructuredName rows from the data table for the given contact
String selection = Data.CONTACT_ID + "=" + contactID + " AND " + Data.MIMETYPE + "=" + StructuredName.CONTENT_ITEM_TYPE;
Cursor cursor = getContentResolver().query(Data.CONTENT_URI, projection, selection, null, null);
if (cursor.next()) {
contact.setFirstName(cursor.getString(0));
contact.setLastName(cursor.getString(1));
}
cursor.close();
}
I can select all contacts using the query below
cr = mActivity.getContentResolver();
String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " > 0";
String orderBy = ContactsContract.Contacts.DISPLAY_NAME + " ASC ";
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, selection, null, orderBy);
However, I have a phone number list and I want to create this query like
String selection = ContactsContract.Contacts.PhoneNumber_or_something_else in (MyPhoneNumberArray)
Is that possible to do this?
A worst-case scenario, I can remove the related item using do while after I create my cursor, but, as far as I know, I cannot remove any record from the cursor.
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
All phone numbers in the Contacts DB are in the Data table, so that's what you need to query, you can get the list of CONTACT_IDs from that query and use it to get general info about contacts if you need.
String[] phonesList = new String[] { "+121212345" }; // will work better if all phones in this list are in e164 format
String[] projection = { Phone.CONTACT_ID, Phone.DISPLAY_NAME, Phone.NUMBER, Phone.NORMALIZED_NUMBER };
String selection = Phone.NUMBER + " IN ('" + TextUtils.join("','", phonesList) + "') OR " +
Phone.NORMALIZED_NUMBER + " IN ('" + TextUtils.join("','", phonesList) + "')";
Cursor cur = cr.query(Phone.CONTENT_URI, projection, selection, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1);
String phone = cur.getString(2);
Log.d(TAG, "got " + id + ", " + name + ", " + phone;
}
I'm new to android and i'm working with native contact.
So my app is let user put contact display name and their number for edit/delete.
In case the contact have more that one number.
I tried a lot but still have no luck, the app still doesn't update the number or it crashes.
What I'm going to do as my understanding is:
Find name in contact that matched name user inserted and use that to get contact_id that represent this contact datagroup.
Use contact_id in 1. and the number user input to find ._ID that represent the specific row id.
Do task with ._ID we get from 2.
This is 1. code to get contact_id:
public String getPeopleUniqueID(String name, Context context) {
String s = null;
String selection = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+" like'%" + name +"%'";
String[] projection = new String[] {ContactsContract.Data.CONTACT_ID};
Cursor c = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection, selection, null, null);
if(c.moveToFirst()) {
s = c.getString(c.getColumnIndex(ContactsContract.Data.CONTACT_ID));
}
c.close();
return s;
}
This is 2. code to get ._ID (num is number user inserted and name is from 1. > the contact_id)
public String checkPhoneNumber(String num, String name, Context context) {
String s = null;
String selection = ContactsContract.CommonDataKinds.Phone.NUMBER + "=?" + " AND "+ContactsContract.Data.CONTACT_ID+ "=?";
String[] projection = new String[] {ContactsContract.Data._ID};
Cursor c = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection, selection, new String[]{u,name}, null);
if(c.moveToFirst()) {
s=c.getString(c.getColumnIndex(ContactsContract.Data._ID));
}
c.close();
if (s==null){
s = "null";
}
return s;
}
To do something like editing (num is _.ID we get from 2. and newnum is new number user want to change into).
public void editNumber(String num , String newnum) {
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)
.withSelection(Data._ID + "=? AND " +
Data.MIMETYPE + "='" +
CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "'",
new String[]{num})
.withValue(Data.DATA1, newnum)
.build());
try{
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);}
catch (RemoteException e){e.printStackTrace();}catch (OperationApplicationException e) {e.printStackTrace();}
}
And well it crashes when I call editNumber().
Can you help me fix my code and my understanding?
And another question, can I edit/insert group for the contact programatically, like I want to add this contact to family friend or co-worker group (the default group that we can set at contact edit page)?
Use ContactsContract.Contacts.CONTENT_FILTER_URI for searching a contact based on name - to get Id or anything else. The like operator cannot handle all cases which the CONTENT_FILTER_URI does handle - For various languages, special characters etc.
http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html#CONTENT_FILTER_URI
Use following uri to lookup a contact from phone number - you can get person id or anything else :
Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phoneNumber));
In the set query you can also use contactId in the condition
For groups you can use custom mimetypes if the default one does not suit you (which is still very primitive for groups across different account types)
I need fetch information from all Android contacts:
First name
Last name
Cell Phone
Birth date
If the contact has two or more Cell phone numbers, it has to fit in the selection multiple times.
Now I use ContentResolver.Query() to get the required columns, but need more than once queries, rather than join tables.
How can I query multiple data fields from Android contacts?
I.e. i need execute something like SQL query:
SELECT
dName.Data2 as [firstName]
, dName.Data3 as [lastName]
, dPhone.Data1 as [cellPhone]
FROM
raw_contacts
INNER JOIN data as dName on dName.RAW_CONTACT_ID = Contacts._ID and dName.MIME_TYPE = ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
INNER JOIN data as dPhone on dName.RAW_CONTACT_ID = Contacts._ID and dName.MIME_TYPE = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
All the fields you've mentioned are eventually stored in the ContactsContract.Data table, so no need for joins.
You just need to query all the data in Data table, while selecting your specific mimetypes (phone and event, which is birthdays), the full contact-name and contact-id, are stored for each mimetype as well:
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 + "', '" + Event.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); // full name
String mime = cur.getString(2); // phone / birthday
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 Email.CONTENT_ITEM_TYPE:
Event = "birthday";
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);
}