I am making a autocomplete Field that queries contacts by Display name and Email. When someone clicks on the desired contact after the filtering that contact is added to a list with his email, display name and Picture if he has any.
So so far i have managed to do everything except to make the Photo appear. Here is how i run the query to get the email, display name, ID , and Photo ID.
return mContent.query(Email.CONTENT_URI,
PROJECTION, filter, null, null);
where projection is:
PROJECTION = new String[] {ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.PHOTO_ID,
Email.DATA
};
This one does what i need and returns all the data. But one thing i noticed during debugging this issue is that the contact id is different than if you run the query against ContactsContract.Contacts.CONTENT_URI for a specific display name for example.
For example the tests i have run where i get all the contacts by running the Contacts.CONTENT_URI gave me a contact with an image and Id of 152. However the query against the Email.CONTENT_URI gives me an id of 452 for the same contact (With same display name and email address). so when i try to get the Photo for a content uri containing the Id 452 it returns that the photo doesnt exist, but if i try to get the photo for 152 it works perfectly.
What is causing this issue? how do i get the correct User ID? Is there any relational query that i can maybe run to get a contact ID, or maybe a correct way to get it with the help of this one.
Thank you.
EDIT
I found this digging around old code. Might be helpful to anyone.
So the full query:
String[] PROJECTION = new String[] { ContactsContract.RawContacts._ID,
ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.PHOTO_ID,
Email.DATA, ContactsContract.CommonDataKinds.Photo.CONTACT_ID };
String order = " CASE WHEN " + ContactsContract.Contacts.DISPLAY_NAME
+ " NOT LIKE '%#%' THEN 1" + " ELSE 2 END, "
+ ContactsContract.Contacts.DISPLAY_NAME + " COLLATE NOCASE";
String filter = Email.DATA + " NOT LIKE '' ) GROUP BY ( " + Email.DATA;
then its
getContentResolver().query( Email.CONTENT_URI, PROJECTION, filter, null, order);
When you want to access the photo of a contact, you need to specify the contact photo URI, for example using this method:
public Uri getContactPhotoUri(long contactId) {
Uri photoUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
photoUri = Uri.withAppendedPath(photoUri, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
return photoUri;
}
But for contactId you must use:
String id = ContactsContract.CommonDataKinds.Photo.CONTACT_ID;
long contactId = Long.parseLong(id);
Please note that a common error is to use ContactsContract.Contacts._ID instead ContactsContract.CommonDataKinds.Photo.CONTACT_ID
I hope that can help you.
You should use RAW_CONTACT_ID in the query. For ex, there can be two different contacts i.e. different RAW_CONTACT_ID for a single CONTACT_ID.
maybe you can take a look at this blog post in the example there they query all contacts, email addresses and the contact photo
http://blog.app-solut.com/2011/03/working-with-the-contactscontract-to-query-contacts-in-android/
best code will be
Uri photoUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, Id);
Bitmap photoBitmap;
ContentResolver cr = getContentResolver();
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(cr, photoUri);
photoBitmap = BitmapFactory.decodeStream(is);
it works for all
Related
I'm working on an application in which I should be able to access all the contacts, able to update or delete the numbers in any contact.
I want to delete few numbers in a contact. I'm using batchOperations to perform delete operation.
phone = ContactsContract.Data.RAW_CONTACT_ID + " = ? AND " +
ContactsContract.Data.MIMETYPE + " = ? AND " +
ContactsContract.CommonDataKinds.Phone._ID + " = ?";
String[] phoneArgs = new String[]{Integer.toString(rawContactId), ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE, String.valueOf(id)};
batchOperations.add(ContentProviderOperation.newDelete(Data.CONTENT_URI).withSelection(phone, phoneArgs).build());
this.mContext.getContentResolver().applyBatch("com.android.contacts", batchOperations);
batchOperations.clear();
I'm using this part of code to delete a specific number from the Contact. Using debugger, for a sample delete operation, I found the values as:
raw_contact_id = 4093
id = 21579
These values correspond to specific number("+814444444444") in a group of numbers in a sample contact.(Please refer image below)
But still the number is not getting deleted. I've been trying to figure it out for the last couple of hours but couldn't solve it. Please help.
Instead of supplying selection + selectionArgs, you can build a uri of the specific item you want to delete, like so:
Uri phoneUri = ContentUris.withAppendedId(Data.CONTENT_URI, phoneId);
batchOperations.add(ContentProviderOperation.newDelete(phoneUri).build());
A couple of other notes:
Always check the return value of applyBatch, if it's false, there's some issue with your code / permissions.
Use the constant ContactsContract.AUTHORITY instead of the hard-coded string "com.android.contacts".
Another reason for the observed behavior is that the phone "+814444444444" is stored on multiple RawContacts aggregated into a single contact.
In which case even when you properly delete the row from RawContact A, the contact profile would still get the number from RawContact B.
This is especially true for phone numbers when certain apps such as Whatsapp are installed which tend to copy over contacts' phone numbers to a separate RawContact under their own account.
If that's the issue you'll need to delete the phone number from ALL the contact's RawContacts holding that phone.
EDIT
Here's how to dump all phone numbers that belong to a specific contact, along with the raw-contact that holds them:
String selection = Data.CONTACT_ID + "=? AND " + Data.MIMETYPE + "=?";
String[] selectionArgs = new String[] { contactId.toString(), Phone.CONTENT_ITEM_TYPE };
String[] projection = new String[] { Data.CONTACT_ID, Data.RAW_CONTACT_ID, Data.DATA1 };
Cursor cur = getContentResolver().query(Data.CONTENT_URI, projection, selection, selectionArgs, projection);
DatabaseUtils.dumpCursor(cur);
Also, note that a rawContactId is not an integer, it's a long.
I am very new to app development. I am trying to read contact info without having to request permission to contacts (so I am using intents).
I get a URI with the following code in my main activity:
Intent selectContactIntent = new Intent(Intent.ACTION_PICK);
selectContactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);
if (selectContactIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(selectContactIntent, REQUEST_CODE_SELECT_CONTACT);
}
else {
showContactRequiredMessage(view);
}
In another (sub)activity, I do the following:
contactUri = intent.getParcelableExtra(MainActivity.CONTACT_URI);
String[] projection = new String[] {
ContactsContract.Contacts.Data._ID,
ContactsContract.Contacts.Data.MIMETYPE,
ContactsContract.Contacts.Data.DATA1,
ContactsContract.Contacts.Data.DATA2,
ContactsContract.Contacts.Data.DATA3,
ContactsContract.Contacts.Data.DATA4,
ContactsContract.Contacts.Data.DATA5,
ContactsContract.Contacts.Data.DATA6,
ContactsContract.Contacts.Data.DATA7,
ContactsContract.Contacts.Data.DATA8,
ContactsContract.Contacts.Data.DATA9,
ContactsContract.Contacts.Data.DATA10,
ContactsContract.Contacts.Data.DATA11,
ContactsContract.Contacts.Data.DATA12,
ContactsContract.Contacts.Data.DATA13,
ContactsContract.Contacts.Data.DATA14,
ContactsContract.Contacts.Data.DATA15
};
Cursor contactResults = getContentResolver().query(contactUri, projection, null, null, null);
The last line throws the exception java.lang.IllegalArgumentException: Invalid column <any column after _ID>
My app doesn't require all of the data in reality I just want to see what is available, I will most likely need first name, last name, phone, and email.
My issue is the MIME type that I set on the intent when I request the contact info. The documentation states ContactsContract.Contacts.CONTENT_TYPE should be used. However, if I use, something like ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE, I can get display name and phone number. I am not sure if this means I will need to make multiple queries to get everything (the information shown in the contact picker changes when changing the type requested).
TL;DR: Used the "wrong" content type when creating the intent to select a contact.
As mentioned in my comment to your answer, you should be able to get the information expected without using a specific CONTENT_TYPE like CommonDataKinds.Phone.CONTENT_TYPE.
The problem I see in your code is that you're trying to access Data table info from a Contacts table uri.
The ContactsContract api stored info on 3 main tables: Contacts, RawContacts and Data.
You were given a contactUri which points to an entry in the Contacts table, use the following code to read Data entries related to that contact:
long contactId = ContentUris.parseId(contactUri);
String projection = String[] { Data.MIMETYPE, Data.DISPLAY_NAME, Data.DATA1 };
String selection = Data.CONTACT_ID + " = " + contactId;
Cursor cursor = getContentResolver().query(Data.CONTENT_URI, projection, selection, null, null);
while (cursor != null && cursor.moveToNext()) {
String mime = cursor.getString(0);
String name = cursor.getString(1);
String info = cursor.getString(2);
if (mime.equals(CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
Log.d(TAG, name + ": email = " + info;
}
if (mime.equals(CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
Log.d(TAG, name + ": phone = " + info;
}
// Add more mimetypes here if needed...
}
if (cursor != null) {
cursor.close();
}
I have inserted some raw contacts (given account type and name null). the native contact app of android shows all contacts are sorted ( merged previews and newly given). But in my app (a listview for displaying contacts), it shows first the previous contatcs (sorted by display name) and then newly inserted contacs (also sorted). I have tried whatever combination possible , but no luck. please help any one.
Query Code
String PROJECTION[] = new String[] { ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME};
private final String SORT_ORDER = ContactsContract.Contacts.DISPLAY_NAME + " ASC";
Uri uri = ContactsContract.Contacts.CONTENT_URI;
Cursor contacts = cr.query(uri, PROJECTION, null ,null, SORT_ORDER);
Update*strong text*
however , i was using handler , and now after converting to cusorloadr with loader manager. problem solved
Use getShort() method of Cursor to sort on the bases of a particular column.
try this as query :
Cursor cursor = getContentResolver.query(ContactsContract.Contacts.CONTENT_URI, PROJECTION, null ,null, Phone.DISPLAY_NAME + " ASC");
I am developing a phonebook app. I am trying to retrieve contact picture. At first I retrieved all the contacts and then took each contact_id and did a query on the photo table to get the picture. However, it is taking forever to query all the contacts for pics. As in my emulator there are more than 1000 contacts, so, more than 1000 hits on the photo table is being fired. So, is there a way to join the two tables and get the data in a single query?
Below is my code to do it. But I know its wrong. Just gave it a shot. Please someone correct it.
String[] projection = new String[]{Contacts._ID, Contacts.DISPLAY_NAME};
String joinCondition = "ContactsContract.Contacts._ID=ContactsContract.CommonDataKinds.Photo.CONTACT_ID";
ContentResolver cr = context.getContentResolver();
Uri contactUri = ContactsContract.Contacts.CONTENT_URI;
Uri fillUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY);
Cursor cur = cr.query(contactUri, projection,
joinCondition, null, Contacts.DISPLAY_NAME);
Thx!
Rahul.
You should be retrieving the photo thumbnail in the list adapter's getView method. This is already optimized so that you only have to process the records which need to be shown on the screen. So at most you'll have to query a handful at a time, even if you have thousands of contacts.
you can try the following:
public final String[] columns = {ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.PHOTO_THUMBNAIL_URI};
Cursor c = contentResolver.query(Contacts.CONTENT_URI, columns, where, args, ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
this should return you a cursor with all contacts and their pictures
I faced with problem while fetching phone numbers for linked contacts on HTC phone.
The problem only with contacts that have phone numbers in invisible group.
E.g. I have contact in addressbook that linked from Google and Facebook accounts.
Contact1 - Google account (contact name, email)
Contact1 - Facebook account (contact name, phone number)
In the Contacts settings Google group is active and Facebook group is hidden.
Here what I am doing in the code.
Preparing cursor for ListView that shows only contacts with phone numbers and in visible group.
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.LOOKUP_KEY
};
String[] selectionArgs = null;
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
CursorLoader cursorLoader = new CursorLoader(AllContactsNewActivity.this,
uri, projection, ContactsContract.Contacts.HAS_PHONE_NUMBER +" = 1 " +
" AND " + ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '1'",
selectionArgs, sortOrder);
The Contact1 is presented in the list.
When user click on this contact I am fetching phone numbers from selected contact, but get empty list.
CursorLoader cursorLoader = new CursorLoader(
AllContactsNewActivity.this,
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
projection,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?",
new String[] { String.valueOf(contactId) }, null);
I have already tried to use RAW_CONTACT_ID, _ID, LOOKUP_KEY for fetching numbers but w/o luck.
Could some one give me piece of advice how I can fetch phone numbers for these contacts or just not show such contacts in the ListView.
I had this exact same problem and searched for hours to find a solution. This is probably too late for you, but if you use the following code the facebook contacts are not included in the listing.
Please note that this uses deprecated code. I suspect, however, that we are stuck using it until facebook gets their act together and stops violating every rule Google ever made regarding contacts.
Calling code:
Intent intent = new Intent(Intent.ACTION_PICK, Contacts.Phones.CONTENT_URI);
startActivityForResult(intent, SELECT_CONTACT);
Later in onActivityResult
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));
Toast.makeText(this, name + " has number " + number, Toast.LENGTH_LONG).show();
}