private Cursor getContacts(CharSequence constraint) {
boolean hasConstrains = constraint != null && constraint.length() != 0;
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME };
String selection = hasConstrains ? projection[1] + " LIKE '"+constraint+"%'" : null;
String[] selectionArgs = null;
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " ASC";
return managedQuery(uri, projection, selection, selectionArgs, sortOrder);
}
The first time issue it I give null as parameter to the function to the selection parameter is empty, meaning i don't filter any rows.
The problem is i get only contacts i created myself using no syncAdapter.
I used Facebook app to sync my Facebook contacts, but this query doesn't return them.
I extracted the contacts2.db from the emulator and the view_contacts view shows me all the contacts, so the DB is updated.
What should I do to get all the contacts regardless of how they were created (with which sync adapter).
i've run a search on the subject in google, it seems like facebook chose to have the contacts as 'restricted' though i must say they are not in the table view, of course i can't be sure to which table the contcats.CONTENT_URI will refer to...
Could it be that i can't but for example i will be able to view google synched contacts ?
Related
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 am create an application which use contact to display. My problem is that i can show all conacts (from my email accounts,skype and other), but i want show only contacts from my device (with images like i am getting now), like when open native contacts app and go to Contacts->Menu->Settings->Contacts->Contact to display->Device contacts. I am not very well understand Contact content provider and need a help. There a lot of posts on stackoverflow, bu t i cant find post for my requirements.
For retreive all contact i am using this CursorLoader
CursorLoader cL = new CursorLoader(getActivity(),
contentUri,
ContactsQuery.PROJECTION,
ContactsQuery.SELECTION,
null,
ContactsQuery.SORT_ORDER
);
This is my criteria and projections:
final static int QUERY_ID = 1;
// A content URI for the Contacts table
final static Uri CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
// The search/filter query Uri
final static Uri FILTER_URI = ContactsContract.Contacts.CONTENT_FILTER_URI;
// The selection clause for the CursorLoader query. The search criteria defined here
// restrict results to contacts that have a display name and are linked to visible groups.
// Notice that the search on the string provided by the user is implemented by appending
// the search string to CONTENT_FILTER_URI.
#SuppressLint("InlinedApi")
final static String SELECTION =
(Utils.hasHoneycomb() ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME) +
"<>''" + " AND " + ContactsContract.Contacts.IN_VISIBLE_GROUP + "= 1 AND "+ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1";
// The desired sort order for the returned Cursor. In Android 3.0 and later, the primary
// sort key allows for localization. In earlier versions. use the display name as the sort
// key.
#SuppressLint("InlinedApi")
final static String SORT_ORDER =
Utils.hasHoneycomb() ? ContactsContract.Contacts.SORT_KEY_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME;
// The projection for the CursorLoader query. This is a list of columns that the Contacts
// Provider should return in the Cursor.
#SuppressLint("InlinedApi")
final static String[] PROJECTION = {
// The contact's row id
ContactsContract.Contacts._ID,
// A pointer to the contact that is guaranteed to be more permanent than _ID. Given
// a contact's current _ID value and LOOKUP_KEY, the Contacts Provider can generate
// a "permanent" contact URI.
ContactsContract.Contacts.LOOKUP_KEY,
// In platform version 3.0 and later, the Contacts table contains
// DISPLAY_NAME_PRIMARY, which either contains the contact's displayable name or
// some other useful identifier such as an email address. This column isn't
// available in earlier versions of Android, so you must use Contacts.DISPLAY_NAME
// instead.
Utils.hasHoneycomb() ? ContactsContract.Contacts.DISPLAY_NAME_PRIMARY : ContactsContract.Contacts.DISPLAY_NAME,
// In Android 3.0 and later, the thumbnail image is pointed to by
// PHOTO_THUMBNAIL_URI. In earlier versions, there is no direct pointer; instead,
// you generate the pointer from the contact's ID value and constants defined in
// android.provider.ContactsContract.Contacts.
Utils.hasHoneycomb() ? ContactsContract.Contacts.PHOTO_THUMBNAIL_URI : ContactsContract.Contacts._ID,
// The sort order column for the returned Cursor, used by the AlphabetIndexer
SORT_ORDER,
ContactsContract.Contacts.HAS_PHONE_NUMBER
};
After some time , i am return to search answer to thisquestion.
the answer maybe is not correct byt it helps me.
public static boolean getConnections(Context context, String contactId) {
// Read all data for contactId
String selection = ContactsContract.RawContacts.CONTACT_ID + " = ?";
String[] selectionArgs = new String[]{contactId};
Cursor c = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, selection, selectionArgs, null);
String accountType = null;
while (c.moveToNext()) {
accountType = c.getString(c.getColumnIndexOrThrow(ContactsContract.RawContacts.ACCOUNT_TYPE));
}
Log.e("getConnections", accountType + "");
c.close();
if (accountType.equals("SIM Account") || accountType.equals("vnd.sec.contact.phone"))
return true;
else
return false;
}
After my query posted in question i am filter contacts by contactId and check their ACCOUNT_TYPE , in my logs i see on samsung vnd.sec.contact.phone(means that is phone contact) and on my lg with 2 sim i found this SIM Account.
Perhaps there is better solution, but i figure it out this way.
I'm using the following code segment to get phone numbers of a contact by contact ID
private static ArrayList<PhoneName> getPhonesFromID(Context context,
String contactID, String column) {
// Run query
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.CommonDataKinds.Phone._ID,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.STARRED,
ContactsContract.CommonDataKinds.Phone.TYPE };
String selection = column + " = '" + contactID + "'";
String[] selectionArgs = null;
String sortOrder = ContactsContract.CommonDataKinds.Phone.NUMBER
+ " COLLATE LOCALIZED ASC";
Cursor cursor = context.getContentResolver().query(uri, projection,
selection, selectionArgs, sortOrder);
if (cursor == null)
return null;
int numberIndex = cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int nameIndex = cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int typeIndex = cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
int favIndex = cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.STARRED);
ArrayList<PhoneName> phones = new ArrayList<PhoneName>();
while (cursor.moveToNext()) {
PhoneName pn = new PhoneName();
pn.name = cursor.getString(nameIndex);
pn.number = cursor.getString(numberIndex);
pn.starred = cursor.getString(favIndex);
pn.state = DataHelper.getInstance(context)
.getSubscriptionStateByNumber(pn.number);
Log.d("Number", pn.number);
int type = cursor.getInt(typeIndex);
if (type == ContactsContract.CommonDataKinds.Phone.TYPE_HOME) {
pn.type = "Home";
} else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) {
pn.type = "Mobile";
} else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_WORK) {
pn.type = "work";
} else {
pn.type = "other";
}
phones.add(pn);
}
cursor.close();
return phones;
}
Here's PhoneName is my self-defined class to store contact information of that specific contact. This function is called like:
getPhonesFromID(context, _id,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID);
I'm getting the contact information correctly but here's the problem, sometimes this function returns null when I make frequent queries. When this problem occurs, default people application of my android don't show any contact too. All contacts are like vanished. Then if I close my application and restart then it shows all contacts like before. Then again when I go to the contact details of a contact from my application it works fine several times and then all contacts are gone again.
This is a weird problem and I don't know actually what is happening here. I double checked my queries and couldn't figure out what's wrong in here.
Finally, this problem got solved.
Like I said, my application is like Phonebook and I had to show a favourite icon for each contact in the list which is my favourite contact. In my case, I had a function like isFavourite() to determine if a contact is in my favourite list or not and this is called in every single time when a contact row is loading.
Each time I open a cursor to get the query result and it was found that the cursor was not closed anywhere. So basically, closing the cursor properly solved the problem! Cheers!
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'm trying to fetch all the Phone numbers and Emails in Android.by using this code.
enter code here
String KEY_NAME = "Name";
String KEY_NO = "No";
String selection = ContactsContract.CommonDataKinds.Phone.IN_VISIBLE_GROUP + " = 1";
String sortOrder = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
String data="";
String name="";
ContactEntry contactObj;
String id;
List<String> temp = new ArrayList<String>();
final String[] projection = new String[]{ContactsContract.Contacts._ID , ContactsContract.Contacts.DISPLAY_NAME , ContactsContract.Contacts.HAS_PHONE_NUMBER};
final String[] email_projection = new String[] {ContactsContract.CommonDataKinds.Email.DATA , ContactsContract.CommonDataKinds.Email.TYPE};
final String[] phone_projection = new String[] {ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.TYPE};
ContentResolver cr = context.getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI , projection , selection , null , sortOrder);
if(cur.getCount()>0){
while(cur.moveToNext()){
id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
// get the phone number
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI , phone_projection ,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",new String[]{id}, null);
while (pCur.moveToNext()){
data = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
if(!temp.contains(data) && !data.equals(null)){
}
}
pCur.close();
}
Cursor emailCur = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, email_projection,
ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", new String[]{id}, null);
while (emailCur.moveToNext()){
data = emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
if(!temp.contains(data) && !data.equals(null)){
}
}
emailCur.close();
}
}
This code is working fine. but for the large number number of contacts let's say 5000 contacts then it blocks the UI thread.how to create a ListAdapter for displaying all these contacts.If i fetch all the contacts in background user will see the empty list for a long time.please suggest some solution
I had very similar problem some time ago even with significantly lower number of contacts.
I needed to populate all contacts in list view and allow the user to select from them. Initially I was loading all the contact information in the list view. However this required really a lot of queries, which is what actually is slow.
So I changed my design: I selected only the Contact name and the Contact id and recorded it in an object. Afterwards when the user of my app selected any contact I loaded only his data. This turned to be drastically faster (as expected). And in my case it worked perfectly, because I was querying a lot of information which I actually never needed (that is phone numbers and emails of all not-selected contacts).
Hopefully you will be able to redesign your app in similar way. However if you need to display the contents of the data variable in the listview right away, you really might turn to need lazy-loading list view with adapter (lets just hope it will perform smoothly even on fast scroll).