Effective way to get contacts info with photo - android

I want to get some basic info of all contacts(I use api lvl 8). Currently i use this code snippet
private List<ContactInfo> readContacts() {
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null,
null, null, Phone.DISPLAY_NAME + " ASC");
for (int i = 0; i < cur.getColumnCount(); i++) {
Log.v("COlum", cur.getColumnName(i));
}
List<ContactInfo> temp = new ArrayList<ContactInfo>();
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
ContactInfo mContactInfo = new ContactInfo();
String id = cur.getString(cur
.getColumnIndex(ContactsContract.Contacts._ID));
mContactInfo.setId(Long.parseLong(id));
String name = cur
.getString(cur
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (Integer
.parseInt(cur.getString(cur
.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
mContactInfo.setmDisplayName(name);
// get the <span class="IL_AD" id="IL_AD7">phone
// number</span>
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ " = ?", new String[] { id }, null);
while (pCur.moveToNext()) {
String phone = pCur
.getString(pCur
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
mContactInfo.setmPhoneNumber(phone);
}
pCur.close();
// get email and type
Cursor emailCur = cr.query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID
+ " = ?", new String[] { id }, null);
while (emailCur.moveToNext()) {
// This would allow you get several email <span
// class="IL_AD" id="IL_AD9">addresses</span>
// if the email addresses were stored in an array
String email = emailCur
.getString(emailCur
.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
mContactInfo.setmEmail(email);
}
emailCur.close();
temp.add(mContactInfo);
}
}
}
return temp;
}
and pass to custom adapter (extended baseadapter). I get contact's photo using:
public static Bitmap loadContactPhoto(ContentResolver cr, long id) {
Uri uri = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI, id);
InputStream input = openContactPhotoInputStream1(cr, uri);
if (input == null) {
return null;
}
return BitmapFactory.decodeStream(input);
}
I tested on my phone with 2x contacts (had photo). I took ~ 10s to fetch all contact at 1st runtime. I try force close in application settings and run again. This time it took ~2s to get data.So i want to know the most effective way to get contacts info.
I found some similar SO questions but they dont need photo. contacts in android
I tried use cursor and cursor adapter but i dont know what query to get photo_uri + contact name at the same time.
Edit: i removed all getColumnIndex i can out of loop and project only column i want. The performance is better(10s => 5s).
What i want to know :
Better way to query info and set to my ContactInfo model or the query which get name, phone number, email, photo at the same time to pass to cursor adapter.
Thanks in advance

I changed to CusorAdapter and use ContactsPhotoLoader from Contacts app and performance is improved.

To get contact info you have to work with the Android Contact API. Also you have to keep in min that you have to handle this Api in a different way for android api below API 4 (1.6)and for the Android API 5 (2.0) and higher:
I will provide you some good links that will help you:
Working With Android Contacts
Handling Contact Photos (All API Levels)
Using the Contact Picker API 2.0 and above
Retrieving Contact Information (Name, Number, and Profile Picture)
API4 and lower
Thes also some SO thread similar to yours that must b helpful for you
get contact info from android contact picker
Getting a Photo from a Contact

Related

How to fetch all contacts from local phonebook and google contacts together?

I am trying to fetch contacts from the phonebook in my Android application. But it fetches the contacts that are present only in the local phone storage. I need to fetch all the contacts including the ones synced to the device using various accounts like Google. That is currently not happening. I am using a RecyclerView to display the contacts fetched.
I have tried using https://github.com/mirrajabi/rx-contacts2 library for fetching asynchronously. But that doesn't include Google contacts as well. Then I tried using Android's built-in CotentResolver
Contact contact;
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
if (cursor != null) {
if (cursor.getCount() > 0) {
while (cursor.moveToNext()) {
int hasPhoneNumber = Integer.parseInt(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)));
if (hasPhoneNumber > 0) {
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
contact = new Contact(Long.parseLong(id));
contact.setDisplayName(name);
Cursor phoneCursor = contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[]{id},
null);
if (phoneCursor != null) {
if (phoneCursor.moveToNext()) {
String phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Set<String> phoneNumbers = new HashSet<>();
phoneNumbers.add(phoneNumber);
contact.setPhoneNumbers(phoneNumbers);
}
phoneCursor.close();
}
Cursor emailCursor = contentResolver.query(
ContactsContract.CommonDataKinds.Email.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?",
new String[]{id}, null);
if (emailCursor != null) {
while (emailCursor.moveToNext()) {
String emailId = emailCursor.getString(emailCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
}
emailCursor.close();
}
listContacts.add(contact);
}
}
}
cursor.close();
}
Currently, I am trying to fetch the contacts synchronously and it hangs up the main thread. It would be really helpful if you could suggest some ways to do that asynchronously. When doing so I also require a trigger to know when the task is completed.
Your code should work on all contacts synced to the device, including Google contacts (assuming the Google account is installed, and the contacts sync is enabled).
However, your code has some bugs, and can be greatly improved, currently for a device with 500 contacts, you are doing ~1000 queries.
All the data you need is on a single table called Data so you can get everything in a single quick query, see here:
Map<Long, Contact> contacts = new HashMap<>();
String[] projection = {Data.CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1};
String selection = Data.MIMETYPE + " IN ('" + Phone.CONTENT_ITEM_TYPE + "', '" + Email.CONTENT_ITEM_TYPE + "')";
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);
while (cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1);
String mime = cur.getString(2); // email / phone
String data = cur.getString(3); // the actual info, e.g. +1-212-555-1234
// get the Contact class from the HashMap, or create a new one and add it to the Hash
Contact contact;
if (contacts.containsKey(id)) {
contact = contacts.get(id);
} else {
contact = new Contact(id);
contact.setDisplayName(name);
// start with empty Sets for phones and emails
contact.setPhoneNumbers(new HashSet<>());
contact.setEmails(new HashSet<>());
contacts.put(id, contact);
}
switch (mime) {
case Phone.CONTENT_ITEM_TYPE:
contact.getPhoneNumbers().add(data);
break;
case Email.CONTENT_ITEM_TYPE:
contact.getEmails().add(data);
break;
}
}
cur.close();
Notes:
I've changed your listContacts to a HashMap called contacts so we can quickly find an existing contact
I've added setEmails, getPhoneNumbers and getEmails to your Contact class

Fetching more than 10000 contacts from android device

I want to retrieve >10000 contacts from the android device. To fetch that much contact it takes about 8-10 min. Is there any other possible way to do this. I have implemented a method its working fine but when it comes to large number of contacts it taking it time to fetch the contacts.
ContentResolver cr = getActivity().getApplication().getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(
ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME));
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()) {
int phoneType = pCur.getInt(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.TYPE));
String phoneNumber = pCur.getString(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneNumber = phoneNumber.replace(" ","");
phoneNumber = phoneNumber.replace("-","");
boolean addNumber = stringCheck(phoneNumber,symbols);
if (!addNumber){
if (phoneNumber.length() == 10){
addContact(phoneNumber,phoneType,name);
}else if (phoneNumber.length() == 11){
phoneNumber = phoneNumber.substring(1);
addContact(phoneNumber,phoneType,name);
}else if (phoneNumber.length() == 12){
phoneNumber = phoneNumber.substring(2);
addContact(phoneNumber,phoneType,name);
}else if (phoneNumber.length() == 13){
phoneNumber = phoneNumber.substring(3);
addContact(phoneNumber,phoneType,name);
}
}
}
pCur.close();
}
}
}
If 900 out of the 1000 contacts have phone numbers, you're currently querying the DB 901 times, you can reduce it to only two queries:
Give me all contacts information
Give me all phone numbers
Then you use the contact-id field on both to match the phone to the right contacts.
Also, as noted in other answers, you really should add projection to all your queries to improve performance.
Another improvement you can make is to avoid runtime cur.getColumnIndex() calls, if you have a projection, you should already know the index - so use it hard-coded
Map<Long, List<String>> phones = new HashMap<>();
ContentResolver cr = getActivity().getApplication().getContentResolver();
// First build a mapping: contact-id > list of phones
Cursor cur = cr.query(Phone.CONTENT_URI, new String[] { Phone.CONTACT_ID, Phone.Number }, null, null, null);
while (cur != null && cur.moveToNext()) {
long contactId = cur.getLong(0);
String phone = cur.getString(1);
List list;
if (phones.contains(contactId)) {
list = phones.get(contactId);
} else {
list = new ArrayList<String>();
phones.put(contactId, list);
}
list.add(phone);
}
cur.close();
// Next query for all contacts, and use the phones mapping
cur = cr.query(Contacts.CONTENT_URI, new String[] { Contacts._ID, Contacts.DISPLAY_NAME }, null, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1);
List<String> contactPhones = phones.get(id);
addContact(id, name, contactPhones);
}
Keep your fetching process in doInBackground method of AyncTask and then display it. And get only those info which is required first, eg, Contact Name and ID.
refer this ans for more clarification:
Fetching a large number of contacts
In order to fetch large number of contacts you must be fetching the contacts in the form of pages by using rest API.
For example page size of contacts is 100.
One possible approach:
If you are showing the contacts in the listview then you can fetch the data while user is scrolling the list. For that You have to set the threshold position of the list i.e. 80, So when user reaches at 80th position while scrolling you can hit your rest API for next page to fetch the new contacts and add those contacts in the listview.
From your comments i can see you want all the contacts in order to move forward.For this you can start an intent service when app is launched. This service will fetch all the contacts and store them. You can use them as per your needs
Here some optimization for speed up
String[] select = new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER};
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, select, null, null, null);
String[] selectOnly = new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.TYPE};
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
selectOnly,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
Do your number check, length check in server side if possible. Do it in Async task.

Get only numbers shown in the android contactbook

I want to filter what numbers I am getting from Android based on which contacts the user chose to display in his contact book. (For example only contacts saved on the device when all other contacts are excluded)
I read here that you can do this by using
Uri queryUri = ContactsContract.Contacts.CONTENT_URI;
I use following code to read the contacts and I allways get every contact, phone, SIM, etc..
//https://stackoverflow.com/questions/16651609/how-to-display-phone-contacts-only-exclude-sim-contacts
// http://www.higherpass.com/Android/Tutorials/Working-With-Android-Contacts/1/
ContentResolver cr = currentActivity.getContentResolver();
Uri queryUri = ContactsContract.Contacts.CONTENT_URI;
Cursor cur = cr.query(queryUri,
null, null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) { //Are there still contacts?
//See if the contact has at least one number
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
String id = cur.getString( cur.getColumnIndex(ContactsContract.Contacts._ID) );
String name = cur.getString( cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME) );
ArrayList<String> numbers = new ArrayList<String>();
//Read numbers:
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
numbers.add( pCur.getString(
pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)) );
Log.e("Contactbook", "The latest added number is: " + numbers.get(numbers.size()-1) );
}
pCur.close();
}
}
}
What am I missing? This code still gives me both SIM and phone contacts to the log.
Edit: To clarifify, in the contactbook you got the "Display options". In there ist the "select contacts to display"-option, and I want to read the contacts that are shown based on the users choice there. So if a user choses to show only SIM-contacts, read only SIM-contacts, if he choses to only show Phone-Contacts, show onyl phone contacts etc...
Try with following "selection".
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = ?";
From Android docs:
public static final String IN_VISIBLE_GROUP: An indicator of whether this contact is supposed to be visible in the UI. "1" if the contact has at least one raw contact that belongs to a visible group; "0" otherwise.
This should be your "selection" argument in query API.
Update: I tried below code on Android-2.3(I know it is old device, but right now Don't have newer device with me).
final ContentResolver cr = getContentResolver();
String[] projection = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME };
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = ?" ;
String[] Args = { "1" };
final Cursor contacts = cr.query(
ContactsContract.Contacts.CONTENT_URI, projection,
selection,Args ,
null);
This could be a long operation (depending on no. of contacts), hence you should use CursorLoader class (A loader that queries the ContentResolver and returns a Cursor) for this.
cursorLoader.loadInBackground();
This will be called on a worker thread to perform the actual load and to return the result of the load operation.
You can easily create two Arrays for each kind of contacts
ArrayList<String> simContacts = new ArrayList<>();
//get all sim contacts
Uri simUri = Uri.parse("content://icc/adn");
Cursor cursorSim = getContext().getContentResolver().query(simUri, null, null, null, null);
while (cursorSim.moveToNext()) {
simContacts.add(cursorSim.getString(cursorSim.getColumnIndex("name")));
}
}
ArrayList<String> allContacts = new ArrayList<>();
//get all contacts
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,
null, null, null, null);
if (cursor != null && cursor.getCount() > 0) {
while (!cursor.isAfterLast()) {
String phoneNumber = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER));
String displayNameColumn = Utils.hasHoneycomb() ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME;
String displayName = cursor.getString(cursor.getColumnIndexOrThrow(displayNameColumn));
//check if simContacts Array contains this particular name
if (!simContacts.contains(displayNameColumn){
allContacts.add(displayNameColumn);
}
}
}
This is just a working example,of course you can modify to your needs.You can parse more contact fields and make more complication queries.

Wrong reference to Contacts table from sms inbox

I am trying to find the contact details corresponding to an sms from the phone's sms inbox. From my understanding the person column is a foreign key to the _id column of ContactsContract.Contacts.
My problem is that I am getting wrong values for the person value from the sms query. Some person ids don't exist in the contact table and some are pointing to totally different contact.
Below is the code that I use for fetching the list of person values, Can anyone tell me if I missed something or faced a similar problem.
Tested with Nexus S running Android 4.1.2
Uri parsedUri = Uri.parse("content://sms/inbox");
String[] projection = new String[] { "_id", "address", "person" };
Cursor cursor = contentResolver.query(parsedUri, projection, null, null, null);
Log.d(TAG, "Total Count " + cursor.getCount());
if (cursor.getCount() > 0) {
// String address;
int person;
int personIndex = cursor.getColumnIndex("person");
if (cursor.moveToFirst())
do {
person = cursor.getInt(personIndex);
if (person > 0) {
// Add this id to a list
}
} while (cursor.moveToNext());
}
cursor.close();
Update: I was looking at some documentation from the Android Developer Portal (http://developer.android.com/guide/topics/providers/contacts-provider.html), Is it possible that the person id that is retrieved from the sms inbox is referring to the ContactsContract.RawContacts instead of ContactsContract.Contacts as I have done.
Indeed the person column in the sms inbox refers to a RawContacts entry's id. By querying the RawContacts table you can find the contact_id for the Contacts table for the specific user.
You can try this code to get the contact id from the RawContacts table..
long contactId = 0;
Uri uri = ContactsContract.RawContacts.CONTENT_URI;
String[] projection = new String[] { ContactsContract.RawContacts._ID, ContactsContract.RawContacts.CONTACT_ID };
Cursor cursor = contentResolver.query(uri, projection,
ContactsContract.RawContacts._ID + " = ?",
new String[] { rawContactId }, null);
if (cursor.moveToFirst()) {
int contactIdIndex = cursor.getColumnIndex(ContactsContract.RawContacts.CONTACT_ID);
contactId = cursor.getLong(contactIdIndex);
}
cursor.close();
This should solve your problem for fetching the correct contact details by reading an sms row in Android. However as the sms data provider is not documented and phone manufacturers may use them differently, there is chance that this approach may not work on phones other than pure android.
You first check that person number is exits in contact list or not.if yes then match both id.
Cursor cursor=managedQuery(uri, null, null, null, null);
while (cursor.moveToNext()) {
String contactId = cursor.getString(cursor.getColumnIndex(
ContactsContract.Contacts._ID));
String hasPhone = cursor.getString(cursor.getColumnIndex(
ContactsContract.Contacts.HAS_PHONE_NUMBER));
if (Boolean.parseBoolean(hasPhone)) {
// You know have the number so now query it like this
Cursor phones = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId,
null, null);
while (phones.moveToNext()) {
String phoneNumber = phones.getString(
phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
phones.close();
}
}

Android: strange thing about loading contact info

I created an app. It is working on htc desire hd, but when i tested it on ZTE Blade, a strange problem appeared. In my app when user selects a contact name from a spinner a menu appears. In the menu the user can send sms to the user, call him/her or just look at his/her contact info. On HTC Desire HD, everything is working fine. On ZTE there seems to be an exasperating problem with the contact info button: In certain cases when user selects a contact and wants to see his contact info, some other contact's info is shown. So I select Pete from my spinner but I get Dave's contact info. In other cases I select Tom from the spinner and I get Tom's contact info. The problem is not existing on my HTC. I couldn't figure out what causes the problem. By the way, my contact list on HTC is populated also from gmail and facebook and the app still working fine, while the contact list of the ZTE has never seen any gmail or facebook accounts (i am not entirely sure about this).
This is the code i am using to get to the contact info:
infobtn.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur.getCount() > 0)
{
while (cur.moveToNext()) {
id_contact = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
name_contact = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (name_contact.equals(name1))
{
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new String[]{id_contact}, null);
id_contact2 = id_contact;
while (pCur.moveToNext()){
}
pCur.close();
}
}
Intent intent_contacts = new Intent(Intent.ACTION_VIEW, Uri.parse("content://contacts/people/" + id_contact2));
startActivity(intent_contacts);
}
}
});
I have similar problems in my application. The app is a widget that give possibility to use favorites contacts in fast way. User creates new widget and assigns contact to it. When he clicks on widget he is able to make common contact actions - call, sms, edit, etc.
Some users send report like this one:
"I select about 4 contacts and the app shows 4 but only one of them right 3 others is same contact which I didnt even picked".
"Why does the wrong contact show when picked? On my droid incredible"
I can't reproduce the problem on my side. I have tried several different devices, tried to make import/export contacts - no results.
Anyway, i have some ideas about source of the problem.
My application uses lookup keys to store contacts, according to sdk. So, when user picks up a contact, application stores contact lookup key. Then it uses this lookup key to get Contact ID for this contact. After that, it uses ONLY received Contact ID in all other functions. So does your function - it uses only Contact ID in sub-query.
The question is: is it possible that different contacts (with different lookup keys) have same Contact ID? It looks like it's possible on some devices in rare cases... If so, we need to use Contact ID + lookup key always together to identify contact. (update: the suggestion was incorrect. Lookup key can be changed after contact info modification, you won't find contact).
As I understand, you are able to reproduce the problem on your side. I would suggest to change your code in such way:
infobtn.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur.getCount() > 0)
{
while (cur.moveToNext()) {
id_contact = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
name_contact = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
String lookup_key = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
if (name_contact.equals(name1))
{
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ? AND " + ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY + " = ?", new String[]{id_contact, lookup_key}, null);
id_contact2 = id_contact;
while (pCur.moveToNext()){
}
pCur.close();
}
}
Intent intent_contacts = new Intent(Intent.ACTION_VIEW, Uri.parse("content://contacts/people/" + id_contact2));
startActivity(intent_contacts);
}
}
});
and try to reproduce the problem again.
You can see this link, It's very good: http://www.vtutorials.info/2014/08/working-with-android-contacts-how-to.html
private Map<Long, ArrayList<LocalContactInfo>> queryAllPhones(ContentResolver contentresolver)
{
HashMap<Long, ArrayList<LocalContactInfo>> hashmap = new HashMap<Long, ArrayList<LocalContactInfo>>();
Uri PhoneCONTENT_URI = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String Phone_CONTACT_ID = ContactsContract.CommonDataKinds.Phone.CONTACT_ID;
String NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER;
Cursor cursor = contentresolver.query(PhoneCONTENT_URI, null, null, null, null);
do
{
if (!cursor.moveToNext())
{
cursor.close();
return hashmap;
}
long l = cursor.getLong(cursor.getColumnIndex(Phone_CONTACT_ID));
String s = cursor.getString(cursor.getColumnIndex(NUMBER));
LocalContactInfo temp = new LocalContactInfo(String.valueOf(l), "", s, "", 1);
if (hashmap.containsKey(Long.valueOf(l))){
((List<LocalContactInfo>)hashmap.get(Long.valueOf(l))).add(temp);
} else{
ArrayList<LocalContactInfo> arraylist = new ArrayList<LocalContactInfo>();
arraylist.add(temp);
hashmap.put(Long.valueOf(l), arraylist);
}
} while (true);
}
And:
public List<LocalContactInfo> doloadContacts() {
List<LocalContactInfo> _return = new ArrayList<LocalContactInfo>();
Uri CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
String _ID = ContactsContract.Contacts._ID;
String DISPLAY_NAME = ContactsContract.Contacts.DISPLAY_NAME;
String HAS_PHONE_NUMBER = ContactsContract.Contacts.HAS_PHONE_NUMBER;
ContentResolver contentResolver = mContext.getContentResolver();
Map<Long, ArrayList<LocalContactInfo>> map = queryAllPhones(contentResolver);
Cursor cursor = contentResolver.query(CONTENT_URI, null,null, null, null);
if(cursor == null || cursor.getCount()==0){
return _return;
}
if (cursor.getCount() > 0) {
while (cursor.moveToNext()) {
Long contact_id = cursor.getLong(cursor.getColumnIndex( _ID ));
String fullname = cursor.getString(cursor.getColumnIndex( DISPLAY_NAME )).trim();
int hasPhoneNumber = Integer.parseInt(cursor.getString(cursor.getColumnIndex( HAS_PHONE_NUMBER )));
if (hasPhoneNumber > 0 && map.get(contact_id) != null){
Object obj = ((List<LocalContactInfo>)map.get(contact_id)).get(0);
if(obj instanceof LocalContactInfo){
LocalContactInfo _temp = (LocalContactInfo)obj;
_return.add(new LocalContactInfo(String.valueOf(contact_id), fullname, _temp.getNumberPhone(), "",hasPhoneNumber));
}
}
}
}
return _return;
}
instead of using "contacts/people/xxx", try using contactsContract.Contacts.CONTENT_URI.
basically, you want to replace.
Uri contactUri = Uri.parse("content://contacts/people/" + id_contact2));
with
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI,
id_contact2);
Another thing to note is that "id_contact2" may be changed if a sync occurs before you use it (like when google sync merges a contact). To prevent this, it might be better to use a LookupKey instead.
ContactsContract.Contacts.LOOKUP_KEY
and retrieve using
Uri contactUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI,
yourContactLookupKey);

Categories

Resources