I've searched the internet for this problem but couldn't get any working response.
I believe it's from the selection but I don't know what is wrong with it.
I get this error :
android.database.sqlite.SQLiteException: no such column: data1 (Sqlite code 1): , while compiling: SELECT sort_key, photo_uri ...
after executing this code to retrieve the phone contacts:
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String no07 = "%07";
String no407 = "%+407";
String selection = "((" + ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY + " NOTNULL) AND ("
+ ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY + " != '' ) AND (("
+ ContactsContract.CommonDataKinds.Phone.NUMBER + " LIKE '" + no07 + "' ) OR ("
+ ContactsContract.CommonDataKinds.Phone.NUMBER + " LIKE '" + no407 + "' )))";
Cursor phones = getActivity()
.getContentResolver()
.query(uri, null, selection, null, null);
I would appreciate any help.
According to your error there is no such a column data1 from the URI you are querying. The ContactsContract.CommonDataKinds.Phone.NUMBER column included in your selection should be causing the exception.
You might want to query a different table from the ContactsContract which is ContactsContract.Data that as stated at the overview from the ContactsContract
A row in the ContactsContract.Data table can store any kind of personal data, such as a phone number or email addresses.
Change Your Query URI.
You are using a URI that is not meant for searching/filtering Contacts and does not have access to those columns:
Uri uri = ContactsContract.Contacts.CONTENT_URI;
You need to use a URI that has access to the columns you're trying to filter on, like this:
Uri uri = ContactsContract.Data.CONTENT_URI;
There's a decent breakdown of what URIs to use and when on the Android SDK Documentation:
If you need to read an individual contact, consider using CONTENT_LOOKUP_URI instead of CONTENT_URI.
If you need to look up a contact by the phone number, use PhoneLookup.CONTENT_FILTER_URI, which is optimized for this purpose.
If you need to look up a contact by partial name, e.g. to produce filter-as-you-type suggestions, use the CONTENT_FILTER_URI URI.
If you need to look up a contact by some data element like email address, nickname, etc, use a query against the ContactsContract.Data table. The result will contain contact ID, name etc.
Related
I need a Cursor selecting contacts belonging to specific groups ordered by their family names (not display_names).
It is easy to get a cursor returning the contacts belonging to the requested groups, and another one returning the contacts sorted by family names.
However the family name belongs to DATA records with ContactsContract.Data.MIMETYPE = ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE while contacts belonging to specific groups are to be found in records with ContactsContract.Data.MIMETYPE = ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE.
How can I join records with different CONTENT_ITEM_TYPE but that share a common field, namely RAW_CONTACT_ID?
You said you need to select contacts, if so you shouldn't use RAW_CONTACT_ID, but instead CONTACT_ID to join your contacts data.
A single Contact may be an aggregate of multiple RawContacts and in that case I assume you want all the details of that single contacts as one row.
Now to get what you want, you can't use a Cursor to iterate through the contacts, instead you should load all the data you need to memory (e.g. HashMap) and run through that.
BTW, if you prefer to query over the Contacts/RawContacts tables instead of the Data table, you can utilise DISPLAY_NAME_ALTERNATIVE column to get your sort, see: https://developer.android.com/reference/android/provider/ContactsContract.ContactNameColumns.html#DISPLAY_NAME_ALTERNATIVE
Example code:
int selectedGroupId = 12345;
HashSet<Long> ids = new HashSet<>();
// get all CONTACT_IDs belonging to some GROUP_ID
String[] projection = new String[]{Data.CONTACT_ID};
String selection = Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE + "' AND " + GroupMembership.GROUP_ROW_ID + "=" + selectedGroupId;
Cursor c = getContentResolver().query(Data.CONTENT_URI, projection, selection, null, null);
while (c.moveToNext()) {
ids.add(c.getLong(0));
}
c.close();
String[] projection = new String[]{Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1};
// you can add more MIMETYPES to the selection here to get phones, emails, etc. for each contact
String selection = Data.CONTACT_ID + " IN (" + TextUtils.join(",", ids) + ") AND " + Data.MIMETYPE + "='" + StructuredName.CONTENT_ITEM_TYPE + "'";
c = getContentResolver().query(Data.CONTENT_URI, projection, selection, null, StructuredName.FAMILY_NAME + " ASC");
DatabaseUtils.dumpCursor(c);
c.close();
I've been working on a block of code to let the user search (character by character using an AutoCompleteTextView) contacts by name, email or phone number. I've worked out the below code:
// General contact data, so we have to get the DATA1 attribute and use MIMETYPE
// to figure out what it is. Usually we'd query, say, ContactsContract.CommonDataKinds.Email.CONTENT_URI
Uri uri = ContactsContract.Data.CONTENT_URI;
// Limit the query results to only the columns we need for faster operations.
// Using a projection also seems to make the query DISTINCT
String[] projection = new String[] {ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Data.DATA1,
ContactsContract.Data.MIMETYPE};
// Find contact records with an email address or phone number
// Search the name and data1 field (which may contain an email or phone number)
// for user-entered search phrase
String filter = "(" + ContactsContract.Data.MIMETYPE + "=? OR " + ContactsContract.Data.MIMETYPE + "=?)"
+ " AND (" + ContactsContract.Data.DATA1 + " LIKE ? OR " + ContactsContract.Data.DISPLAY_NAME + " LIKE ?)";
String wildcardedConstraint = "%" + constraintString + "%";
String[] filterParams = new String[]{ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE, wildcardedConstraint, wildcardedConstraint};
// Sort contacts with the most recently contacted ones first. That's often 0 (unset)
// so do a sub-sort by last updated date, most recent contacts first
String orderBy = ContactsContract.Contacts.LAST_TIME_CONTACTED + " DESC, " + ContactsContract.Contacts.CONTACT_LAST_UPDATED_TIMESTAMP + " DESC";
Cursor cursor = getContext().getContentResolver().query(uri, projection, filter, filterParams, orderBy);
if (cursor != null) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
String data1 = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DATA1));
String mimetype = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.MIMETYPE));
String number = null;
String email = null;
if (mimetype.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
email = data1;
} else if (mimetype.equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
number = data1;
}
items.add(new Person(name, number, email));
Log.e("temp", name + " " + data1 + " " + mimetype);
}
cursor.close();
}
There is a problem with the phone number search, however. In contacts, phone numbers are in many different formats:
+101234567890
(123) 456-7890
1234567890
123-456-7890
And so on.
How can I adapt my Contacts query filter so the user's input will find phone numbers in any format--preferably without making the entire query extremely slow?
Some solutions I've found rely on editing table data to standardize the phone numbers, which isn't an option with contacts. Maybe that normalized number field would work... if I could find a way to easily build it into this query on the Contacts Data table. I know I could do extra phone number searches for each record, or use Java to make the checks, but I think that would make it very slow. Perhaps a regexp SQL operator in the query--but I don't know how I could make it work for the user's character-by-character search where they may have only entered part of the phone number.
Any ideas?
You can do this with Android's built-in SQLite function PHONE_NUMBERS_EQUAL, which compares two numbers and will return 1 if they're identical enough for caller ID purposes.
You simply need to change your filter as follows:
String filter = "(" + ContactsContract.Data.MIMETYPE + "=? OR "
+ ContactsContract.Data.MIMETYPE + "=?) AND "
+ "(PHONE_NUMBERS_EQUAL(" + ContactsContract.Data.DATA1 + ", ?, 0) OR "
+ ContactsContract.Data.DATA1 + " LIKE ? OR "
+ ContactsContract.Data.DISPLAY_NAME + " LIKE ?)";
And add another wildcardedConstraint to your filterParams:
String[] filterParams = new String[] { ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
wildcardedConstraint,
wildcardedConstraint,
wildcardedConstraint };
The final INTEGER parameter in the PHONE_NUMBERS_EQUAL function indicates whether to use strict number comparation; 1 meaning do use strict, 0 meaning non-strict. Apparently this is a system-wide setting that can be retrieved from the system Resources, but I am uncertain as to what factors dictate how this is determined for a particular environment. The example above just uses non-strict comparation. However, if it is a concern, the actual resource value can be obtained like so:
private static final String STRICT_COMPARE = "config_use_strict_phone_number_comparation";
...
int strictResId = Resources.getSystem().getIdentifier(STRICT_COMPARE, "bool", "android");
boolean useStrict = Resources.getSystem().getBoolean(strictResId);
I'm attempting to retrieve both email and phone via a single cursor described below. I'm using the Email.CONTENT_URI, hence I don't retrieve the phone number, so my phoneColumn is returning email. I tried using Phone.CONTENT_URI but it only returns a smaller subset of contacts (possibly because it only fetches ones that have phone numbers). Is there a way to get both email and phone with a specific Uri or how can I do it with two cursors?
Cursor cursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,
projection, null, null, order);
int idColumn = cursor.getColumnIndex(ContactsContract.Data._ID);
int nameColumn = cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME);
int emailColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA);
int phoneColumn = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA);
where projection is:
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Data.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Email.DATA,
ContactsContract.CommonDataKinds.Phone.DATA, }
Please have a look here. You should find all the necessary examples for such kind of querying.
For an example, you can fetch all information of a contactId in this way:
Cursor data = context.getContentResolver().query(
Data.CONTENT_URI, new String[] { Data._ID,Data.MIMETYPE,
Email.ADDRESS, Photo.PHOTO},Data.CONTACT_ID
+ "=?" + " AND " + "(" + Data.MIMETYPE + "='"
+ Photo.CONTENT_ITEM_TYPE + "' OR " + Data.MIMETYPE
+ "='" + Email.CONTENT_ITEM_TYPE +"')",
new String[] {String.valueOf(contactId)}, null);
You can fetch info for all contacts in this way and then probably sort it according to your criteria. You can build queries like this based on your need.
I have created this library to solve all your queries. It will only save contacts with at least one email or phone number. Also it will remove duplicates from emails and phone numbers from same contacts (created by 3rd party apps like whatsapp).
Please have a look at it.
Link : https://github.com/raghavsatyadev/ContactFetcher/
I Have tied to get all contacts by using following code
getContentResolver().query(uri, null, null, null, null)
But it doesn't return all contacts. It seems that it returns only that contacts which have in column "single_is_restricted" value "1", but this column cannot be asseccable from aplication, I found it when I was viewing table "contacts" directly through sqlite.
How I can get all contacts?
Thanks.
Check the create statement for the table/view.
For example in ContactManager example you will see this code block;
private Cursor getContacts()
{
// Run query
Uri uri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME
};
String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" +
(mShowInvisible ? "0" : "1") + "'";
String[] selectionArgs = null;
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
return managedQuery(uri, projection, selection, selectionArgs, sortOrder);
}
If you can get an exception (for example you can change selection...), you can get view/table name from log cat, like this (you can see "ASDF" in log cat, just get an exception);
04-28 12:16:34.682: E/AndroidRuntime(466): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.contactmanager/com.example.android.contactmanager.ContactManager}: android.database.sqlite.SQLiteException: near "'1'": syntax error: , while compiling: SELECT _id, display_name FROM view_contacts_restricted WHERE (in_visible_group =ASDF '1') ORDER BY display_name COLLATE LOCALIZED ASC
Point is; FROM view_contacts_restricted
And now you can check this view's create statement. You can install a root browser app. And copy sqlite file to SDCARD or install sqlite3 to Android Device. then open database from command line;
sqlite3 '/home/semeteycoskun/Desktop/contacts2.db'
Check view;
.schema view_contacts_restricted
Result is;
CREATE VIEW view_contacts_restricted
AS SELECT contacts._id AS _id
, contacts.custom_ringtone AS custom_ringtone
, name_raw_contact.display_name_source AS display_name_source
, name_raw_contact.display_name AS display_name
, name_raw_contact.display_name_alt AS display_name_alt
, name_raw_contact.phonetic_name AS phonetic_name
, name_raw_contact.phonetic_name_style AS phonetic_name_style
, name_raw_contact.sort_key AS sort_key
, name_raw_contact.sort_key_alt AS sort_key_alt
, name_raw_contact.sort_priority AS sort_priority
, name_raw_contact.sort_priority_alt AS sort_priority_alt
, name_raw_contact.sort_locale AS sort_locale
, name_raw_contact.sort_locale_alt AS sort_locale_alt
, name_raw_contact.contact_in_visible_group AS in_visible_group
, has_phone_number, lookup, photo_id
, contacts.last_time_contacted AS last_time_contacted
, contacts.send_to_voicemail AS send_to_voicemail
, contacts.starred AS starred
, contacts.times_contacted AS times_contacted
, status_update_id
, dirty_contact
, has_email
, link_count
, raw_contact_linkpriority1
, link_type1
, raw_contact_linkpriority2
, link_type2
, raw_contact_linkpriority3
, link_type3
, raw_contact_linkpriority4
, link_type4
, raw_contact_linkpriority5
, link_type5
FROM contacts
JOIN raw_contacts AS name_raw_contact ON(name_raw_contact_id=name_raw_contact._id)
WHERE single_is_restricted=0;
If create statements include single_is_restricted=0 you can not access the rows that single_is_restricted=1.
[sorry for my english]
Some manufacturers like Samsung have deals with Facebook in which Facebook syncs to the device contacts with names, phones, pics, etc. but those contacts can't be accessed via the Contacts APIs.
This is the reason some contacts can't be accessed by your app, but are visible in the stock contacts app.
How can we fetch displayname and organization.data through ContactsContract APIs using impicit joins so that I can both these values in a single cursor?
You can use this code to get the organization name and display name:
Cursor organizationNameCursor = cr.query(ContactsContract.Data.CONTENT_URI,new String[] {Organization.TITLE,Organization.DISPLAY_NAME}, ContactsContract.Data.CONTACT_ID + " = " + contactId + " AND ContactsContract.Data.MIMETYPE = '"
+ ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE
+ "'",null,null);
organizationNameCursor.moveToNext();
organizationName.setText(organizationNameCursor.getString(organizationNameCursor.getColumnIndex(Organization.TITLE))+" "+organizationNameCursor.getString(organizationNameCursor.getColumnIndex(Organization.DISPLAY_NAME)));
The ContactsContact data can only be fetched by using content providers which does not allow us to have explicit joins in the query.
You can however have both the values using a single query on Data database as follows:
Cursor c = getContentResolver().query(Data.CONTENT_URI,new String[] {StructuredName.DISPLAY_NAME,Organization.COMPANY}, Data..CONTACT_ID + " = " + contactId,null,null)
In that case you wont be able to get the values directly.
You can very well fetch all the details using a single query by adding a parameter
Data.MIMETYPE IN (StructuredName,CONTENT_ITEM_TYPE, Organization.CONTENT_ITEM_TYPE)
however you need to have that logic in your code which would reorder your data.
Each MIMETYPE will fetch a separate record.
Similarly you can use RawContactsEntity for the same. It provides a join between Contacts and Data database internally.