It's supposed to be a common problem but I don't know what is the right word to look for solution.
In my app, I user can key in a number, and I need to search if the contact exist in database. Also, given a contact ID and number, I want to find the phone label of the number..
The problem is, if I have a number in phone as "8710 2863" and my query arg is "87102863", I won't be able to get the contact and phone label... There must be a way to standardize the format.. But I can't find the way :(
Here is my code:
Cursor cursor = MyApp.getContext().getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[] {
ContactsContract.CommonDataKinds.Phone.TYPE,
ContactsContract.CommonDataKinds.Phone.LABEL
},
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ? AND "
+ ContactsContract.CommonDataKinds.Phone.NUMBER + " = ? ",
new String[] { Long.toString(contactId), number },
ContactsContract.Data.IS_SUPER_PRIMARY + " DESC");
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
int type = cursor.getInt(0);
String label = cursor.getString(1);
String phoneLabel = (String) ContactsContract.CommonDataKinds.Phone
.getTypeLabel(MyApp.getContext().getResources(), type, label);
hashBuilder.put(Defs.ARG_PHONE_TYPE, phoneLabel);
}
} finally {
cursor.close();
}
}
Have you tried PhoneNumberUtils.formatNumber(String)?
Related
I have developed a program that shows a list of contacts from my phone book.
For this I use the following code:
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI,
null,
ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '1'",
null,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
if (cursor != null && cursor.getCount() > 0) {
while (cursor.moveToNext()) {
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, String.valueOf(id));
Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id,
null,
null);
if (phones != null) {
while (phones.moveToNext()) {
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactList.add(new Contact(name, phoneNumber, id));
}
phones.close();
}
}
cursor.close();
}
adapter = new ContactAdapter(contactList, R.layout.contacts_list_item, getApplicationContext());
recyclerView.setAdapter(adapter);
Everything works, and the program displays all contacts from my phone book, but I want a certain number of contacts to be displayed. For example:
I open the program and load the first 50 contacts from the phone book, after scrolling, the next 50 contacts are loaded to the end of the list. and so on
Use below code that has limit cause. Replace your code with below
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI,
null,
ContactsContract.Contacts.HAS_PHONE_NUMBER + " = '1' ",
null,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " COLLATE LOCALIZED ASC LIMIT 10");
It will get first 10 records. And in pull to refresh implementation, get more records on call back event of pull to refresh. Hope this will help you
I assume the reason you want this is because loading all contacts is very slow.
The reason it's very slow is because you currently have 1 query per contact, so if a user has 500 contacts, you'll need to run 500 queries.
You can reduce the number of queries to just one, then I assume you won't need the limit thing.
String[] projection = { Phone.CONTACT_ID, Phone.DISPLAY_NAME, Phone.NUMBER };
Cursor phones = getContentResolver().query(Phone.CONTENT_URI, projection, null, null, Phone.DISPLAY_NAME + " ASC");
while (phones.moveToNext()) {
String name = phones.getString(1);
String phone = phones.getString(2);
Long id = phones.getLong(0);
contactList.add(new Contact(name, phone, id));
}
phones.close();
If you want to display only one item per contact, and not per phone, you can change your contactList field to be a HashMap<Long, Contact> instead of a List, and add newly found phones to an existing Contact object if it already exists in the Map.
Something like:
Contact contact = allContacts.get(id);
if (contact == null) {
contact = new Contact(name, phone, id);
allContacts.put(id, contact);
} else {
contact.addPhone(phone); // you'll need to implement this
}
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 am trying to get the contact's phone number after I have retrieved their ID number from the built-in activity. However, whenever I query the database using the cursor in my code below -- I get zero rows returned even though there is a mobile number for the contact I have selected.
Can anyone point me in a better direction or show an example of how to get the contact's phone number AFTER getting their userID?
My code:
private Runnable getSMSRunnable() {
return new Runnable() {
public void run() {
Intent i = new Intent(Intent.ACTION_PICK,
ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
startActivityForResult(i, CONTACTS_REQUEST_CODE);
}
};
}
Returns the Log output
content://com.android.contacts/data/6802
From which i pass the ID (6802) into a method which is designed to return the phone number from the ID with the given type (in this case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
public static String getContactPhoneNumberByPhoneType(Context context, long contactId, int type) {
String phoneNumber = null;
String[] whereArgs = new String[] { String.valueOf(contactId), String.valueOf(type) };
Log.d(TAG, String.valueOf(contactId));
Cursor cursor = context.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ? and "
+ ContactsContract.CommonDataKinds.Phone.TYPE + " = ?", whereArgs, null);
int phoneNumberIndex = cursor
.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER);
Log.d(TAG, String.valueOf(cursor.getCount()));
if (cursor != null) {
Log.v(TAG, "Cursor Not null");
try {
if (cursor.moveToNext()) {
Log.v(TAG, "Moved to first");
Log.v(TAG, "Cursor Moved to first and checking");
phoneNumber = cursor.getString(phoneNumberIndex);
}
} finally {
Log.v(TAG, "In finally");
cursor.close();
}
}
Log.v(TAG, "Returning phone number");
return phoneNumber;
}
Which returns null for a phone number -- which means it cannot find the row that I am trying to access -- which means that something is wrong with my query -- however if I check a contact that has a mobile phone number -- how could I get a 0 row query?
Any help would be greatly appreciated. Thank you so much!
I found the answer.
The reason I was not getting any rows from the cursor was because I was using the line
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
"The id of the row in the Contacts table that this data belongs to."
Since I was getting the URI from contacts table anyways -- this was not needed and the following should have been substituted. The ID was the one corresponding to the contact in the phone table not the raw contact.
ContactsContract.CommonDataKinds.Phone._ID
Exchanging the lines returned the correct results in the query. Everything seems to be working well at the moment.
This should work, (maybe try losing the type)
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.
if (Integer.parseInt(cur.getString(
cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
// Do something with phones
}
pCur.close();
}
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.
I am trying to get the contact's phone number after I have retrieved their ID number from the built-in activity. However, whenever I query the database using the cursor in my code below -- I get zero rows returned even though there is a mobile number for the contact I have selected.
Can anyone point me in a better direction or show an example of how to get the contact's phone number AFTER getting their userID?
My code:
private Runnable getSMSRunnable() {
return new Runnable() {
public void run() {
Intent i = new Intent(Intent.ACTION_PICK,
ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
startActivityForResult(i, CONTACTS_REQUEST_CODE);
}
};
}
Returns the Log output
content://com.android.contacts/data/6802
From which i pass the ID (6802) into a method which is designed to return the phone number from the ID with the given type (in this case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
public static String getContactPhoneNumberByPhoneType(Context context, long contactId, int type) {
String phoneNumber = null;
String[] whereArgs = new String[] { String.valueOf(contactId), String.valueOf(type) };
Log.d(TAG, String.valueOf(contactId));
Cursor cursor = context.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ? and "
+ ContactsContract.CommonDataKinds.Phone.TYPE + " = ?", whereArgs, null);
int phoneNumberIndex = cursor
.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER);
Log.d(TAG, String.valueOf(cursor.getCount()));
if (cursor != null) {
Log.v(TAG, "Cursor Not null");
try {
if (cursor.moveToNext()) {
Log.v(TAG, "Moved to first");
Log.v(TAG, "Cursor Moved to first and checking");
phoneNumber = cursor.getString(phoneNumberIndex);
}
} finally {
Log.v(TAG, "In finally");
cursor.close();
}
}
Log.v(TAG, "Returning phone number");
return phoneNumber;
}
Which returns null for a phone number -- which means it cannot find the row that I am trying to access -- which means that something is wrong with my query -- however if I check a contact that has a mobile phone number -- how could I get a 0 row query?
Any help would be greatly appreciated. Thank you so much!
I found the answer.
The reason I was not getting any rows from the cursor was because I was using the line
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
"The id of the row in the Contacts table that this data belongs to."
Since I was getting the URI from contacts table anyways -- this was not needed and the following should have been substituted. The ID was the one corresponding to the contact in the phone table not the raw contact.
ContactsContract.CommonDataKinds.Phone._ID
Exchanging the lines returned the correct results in the query. Everything seems to be working well at the moment.
This should work, (maybe try losing the type)
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.
if (Integer.parseInt(cur.getString(
cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
// Do something with phones
}
pCur.close();
}
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.
I want to get the nickname of a contact from addressbook. I start with his phone number, query it and want the nickname (aka alias) as a result.
Cursor cur = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.NUMBER + " = " + incomingNumber, null, null);
if (cur.moveToFirst()) {
Log.e("saymyname", cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Nickname.NAME)));
Log.e("saymyname", cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Nickname.LABEL)));
}
Output of the logs is the incomingNumber (first Log.e() ) and null (second Log.e() ), but I want to get the contact's nickname!
Thanks
Tom
Nickname is held in a different table than the phone numbers, you have to query ContactsContract.Data.CONTENT_URI
Check my answer on this question
(I don't have necessary reputation to comment so I have to add answer)
TomTasche's answer is misleading and it got me to waste a lot of time trying to figure out why I couldn't get the proper nickname on a contact I knew had one.
I found the answer by myself but got the confirmation from this post that I was now doing it properly.
Basically when you read the ContactsContract.Data documentation you read:
Each row of the data table is typically used to store a single piece of contact information (such as a phone number) and its associated metadata (such as whether it is a work or home number).
That explains the shady part of TomTasche's code :
if (nickname.equals(incomingNumber)) {
return name;
}
Since doing a search with just the CONTACT_ID can return multiple rows (one for each information type), it's not guaranteed that the first one contains the nickname. When there is a nickname it will be in DATA1, but the phone number is also found in DATA1.
The example part in the documentation of ContactsContract.Data makes it clear that rows must be selected based on their MIME_TYPE, only when the MIME_TYPE is selected, can we start making sense of the content in the row itself.
A proper query would therefore be:
cursor = getContentResolver().query(
ContactsContract.Data.CONTENT_URI,
new String[]{Nickname.NAME},
ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + "= ?",
new String[]{contactID, Nickname.CONTENT_ITEM_TYPE},
null);
(where Nickname is ContactsContract.CommonDataKinds.Nickname)
I felt I had to say something on this topic to prevent other people wasting as much time as I did based on this sole topic (first one I found with my Google friend).
The answer from Pentium10 was very helpful! Thanks!
If anybody needs a sample, look at the following code:
public String accessContact(String incomingNumber) {
if (incomingNumber == null || "".equals(incomingNumber)) {
return "unknown";
}
try {
Cursor cur = context.getContentResolver().query(Phone.CONTENT_URI, new String[] {Phone.DISPLAY_NAME, Phone.TYPE, Phone.CONTACT_ID}, Phone.NUMBER + " = " + incomingNumber, null, null);
int nameIndex = cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int typeIndex = cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
int idIndex = cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID);
String name;
String type;
String id;
if (cur.moveToFirst()) {
name = cur.getString(nameIndex);
type = cur.getString(typeIndex);
id = cur.getString(idIndex);
} else {
return "unknown";
}
cur = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, new String[] {ContactsContract.Data.DATA1}, ContactsContract.Data.CONTACT_ID + " = " + id, null, null);
int nicknameIndex = cur.getColumnIndex(ContactsContract.Data.DATA1);
String nickname;
if (cur.moveToFirst()) {
nickname = cur.getString(nicknameIndex);
if (nickname.equals(incomingNumber)) {
return name;
}
return nickname;
} else {
return name;
}
} catch (Exception e) {
e.printStackTrace();
return "unknown";
}