ContactsContract.Data.CONTENT_URI getting deleted contacts - android

** Edit**
This is the URI in question: ContactsContract.Data.CONTENT_URI
Is there any way of knowing if a contact is marked for deletion from this URI?
I already tried querying for the DELETED column, but it crashes with an SQL exception
Thanks for your help
** Attached code **
ContentQuery contentQuery = new ContentQuery(ContactsContract.Data.CONTENT_URI)
.column(ContactsContract.CommonDataKinds.Phone.CONTACT_ID)
.column(ContactsContract.CommonDataKinds.Phone.NUMBER)
.column(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)
.column(ContactsContract.CommonDataKinds.Phone.LOOKUP_KEY)
.column(CommonDataKinds.Note.NOTE)
.column(Data.MIMETYPE)
.column(ContactsContract.CommonDataKinds.Phone.STARRED)
.where(ContactsContract.CommonDataKinds.Phone.DELETED, "=", "1");
Where ContentQuery is a query builder interface

I haven't tried it, but to get the implicit join of the DELETED field from RawContacts as mentioned in the docs, you need to add RawContacts.DELETED to your projection.
Check the following code, it should print data belonging to deleted contacts:
String[] projection = new String[] { Phone.CONTACT_ID, Phone.DISPLAY_NAME, Phone.NUMBER, RawContact.DELETED };
Cursor cur = contentResolver.query(ContactsContract.Data.CONTENT_URI, projection, null ,null, null);
while (cur.moveToNext()) {
if (cur.getInt(3) == 1) {
Log.i("TAG", "found a deleted data row: " + cur.getLong(0) + ", " + cur.getString(1) + ", " + cur.getString(2));
}
}
cur.close();

Related

How to get the first name of a contact in Android?

I'm trying to get the information of my contacts using ContactsContract and what I need to do, is to get only the first name of the contact. I used ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME but this get the name and the last name too, and I only want the name.
I tried using ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME but instead of getting the name, this get a number.
I have not found an exact way to get only the first name of the contact. Any idea?
You haven't shared your code, but it sounds like you're querying over table Phone.CONTENT_URI and trying to get a field via StructuredName.GIVEN_NAME.
That's not possible, as Phone.CONTENT_URI will only return phone rows, not StructuredName rows.
Here's code snippet to get all given-names from the Contacts DB:
String[] projection = new String[]{StructuredName.CONTACT_ID, StructuredName.GIVEN_NAME};
String selection = Data.MIMETYPE + "='" + StructuredName.CONTENT_ITEM_TYPE + "'";
Cursor c = getContentResolver().query(Data.CONTENT_URI, projection, selection, null, null);
DatabaseUtils.dumpCursor(c);
c.close();
UPDATE
Here's some sample code on how to query for multiple mimetypes in a single query.
In this example I created a mapping from to <given-name, phone> for each contact in the DB:
Map<Long, List<String>> contacts = new HashMap<Long, List<String>>();
String[] projection = {Data.CONTACT_ID, Data.DISPLAY_NAME, Data.MIMETYPE, StructuredName.GIVEN_NAME, Phone.NUMBER };
// select all rows of type "name" or "phone"
String selection = Data.MIMETYPE + " IN ('" + Phone.CONTENT_ITEM_TYPE + "', '" + StructuredName.CONTENT_ITEM_TYPE + "')";
Cursor cur = cr.query(Data.CONTENT_URI, projection, selection, null, null);
while (cur != null && cur.moveToNext()) {
long id = cur.getLong(0);
String name = cur.getString(1);
String mime = cur.getString(2); // type of row: phone / name
// get the existing <Given-name, Phone> list from the Map, or create a new one
List<String> infos;
if (contacts.containsKey(id)) {
infos = contacts.get(id);
} else {
infos = new ArrayList<String>(2);
contacts.put(id, infos);
}
// add either given-name or phone to the infos list
switch (mime) {
case Phone.CONTENT_ITEM_TYPE:
infos.set(1, cur.getString(4));
break;
case StructuredName.CONTENT_ITEM_TYPE:
infos.set(0, cur.getString(3));
break;
}
}

Get the Max _id from ContentResolver from Contacts.CONTENT_URI

I want to get the last added contact in the contacts and for getting that i want to pull the max _id of the contact. So here is my query that i want to realise:
AppMain.applicationContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
new String[]{
"MAX(" + ContactsContract.Contacts._ID + ") as max_id",
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.HAS_PHONE_NUMBER
},
null, null, null);
But unfortunately i am getting this error:
Invalid column MAX(contact_id) as max_id
I tried removing the 'as max_id' but no luck.
Does any one know how to get the last added contact or get the max _id of the contact.
This is not officially supported by Android's ContentProvider framework, especially if the Provider set the strictProjectionMap flag.
But this should work instead, it asks for all contacts sorted by contact-id, and limits the results to 1:
Cursor c = cr.query(Contacts.CONTENT_URI, new String[] { Contacts._ID }, null, null, Contacts._ID + "DESC LIMIT 1");
if (c != null && c.moveToNext()) {
Log.d(TAG, "id is: " + c.getLong(0));
}

SQLite Android query returns no results with where

I have an issue where when I execute my query with a WHERE clause it returns no results but if I leave the WHERE as null it will execute through all of my records and find the match. Can anyone tell me what is wrong with my query?
in my code lets say that contactURI is equal to "content://com.android.contacts/contacts/lookup/953i7d73a639091bc5b6/164" and contactUriId is equal to "164"
// Put data in the contactURI
contactURI = data.getData();
// get the contact id from the URI
contactUriId = contactURI.getLastPathSegment();
//TEST TODO Fix URI Issue
String [] PROJECTION = new String [] { Data.CONTACT_ID, Data.LOOKUP_KEY };
Cursor cursor = this.managedQuery(Data.CONTENT_URI, PROJECTION, Data.CONTACT_ID + "=?" + " AND "
+ Data.MIMETYPE + "='*'",
new String[] { String.valueOf(contactUriId) }, null);
Log.e(DEBUG_TAG, contactUriId+"-164-");
for(cursor.moveToFirst(); cursor.moveToNext(); cursor.isAfterLast()) {
Log.v(DEBUG_TAG, "lookupKey for contact: " + cursor.getString(1) + " is: -" + cursor.getString(0) + "-");
if(cursor.getString(0).equals("164")){
Log.e(DEBUG_TAG, "WE HAVE A MATCH");
}
}
This is my log...
05-14 19:08:40.764: D/OpenGLRenderer(21559): Flushing caches (mode 0)
05-14 19:08:46.944: E/MyDebug(22269): 164-164-
The problem is with this:
Data.MIMETYPE + "='*'"
That is searching for MIMETYPEs literally named *. If you want to select all MIMETYPEs, don't do anything. A query returns all of these rows by default.
Also, this loop seems to execute, but it is not quite right:
for(cursor.moveToFirst(); cursor.moveToNext(); cursor.isAfterLast()) {
Since cursor has not been move from index -1. This will safely start at the beginning and iterate until the last row:
while(cursor.moveToNext()) {
If you have moved cursor and want to start from the beginning again you can use:
for(cursor.moveToFirst(); cursor.moveToNext(); ) {
Detailed Explanation Why: cursor.isAfterLast() does not move the cursor, it simply checks if the cursor is still referring to valid data. cursor.moveToNext() moves the cursor to the next row and returns true if the cursor is still in bounds. (In other words if cursor.isAfterLast() is true then cursor.moveToNext() returns false.)

Android - New Data record is added to the wrong contact

I'm trying to add Data record to an already exist contact, I find the contact using phone lookup, i take the contact _id field, and add a new data with raw_contact_id set to the _id field.
on some contacts it just doesn't work, it match the data to different contact.
(I think it relates to contacts that are stored on the sim card)
Please advice, maybe you have a different way to add the data
code sample:
LinkedList<Long> lcv = new LinkedList<Long>();
ContentResolver cr = getContentResolver();
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
Cursor c = cr.query(uri, null, null, null, null);
try {
while (c.moveToNext()) {
Uri lookupUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI,
c.getString(c.getColumnIndex(PhoneLookup.LOOKUP_KEY)));
Cursor c2 = getContentResolver().query(lookupUri, new String[] { Contacts._ID, Contacts.DISPLAY_NAME },
null, null, null);
try {
if (c2.moveToNext()) {
Log.i(TAG, "found: " + c2.getLong(c2.getColumnIndex(Contacts._ID)) + ", " + c2.getString(c2.getColumnIndex(Contacts.DISPLAY_NAME)));
lcv.add(c2.getLong(c2.getColumnIndex(Contacts._ID)));
} else {
Log.e(TAG, "failed to lookup");
}
} finally {
c2.close();
}
}
} finally {
c.close();
}
for (Long rawid : lcv) {
Cursor c3 = cr.query(RawContacts.CONTENT_URI, null, RawContacts.CONTACT_ID + "=?", new String[] {rawid+""}, null);
if (c3.moveToNext()) {
Log.e(TAG,"aaaa: " + c3.getString(c3.getColumnIndex(Contacts.DISPLAY_NAME)));
} else {
Log.e(TAG,"errrrror");
}
ContentValues cv = new ContentValues();
cv.put(Data.RAW_CONTACT_ID, rawid + "");
cv.put(Data.MIMETYPE, MyMime.MIMETYPE);
cv.put(Data.DATA1, "mydata");
cv.put(Data.SYNC1, syncvalue);
Uri newIns = cr.insert(ContactsContract.Data.CONTENT_URI, cv);
Log.i(TAG, "insert: " + newIns + ", " + name);
}
The problem lies when you select the Contacts._ID and use this id to populate the data in the LinkedList lcv .
Cursor c2 = getContentResolver().query(lookupUri, new String[] { Contacts._ID, Contacts.DISPLAY_NAME },
null, null, null);
You actually need a RAW_CONTACT_ID here.
The DISPLAY_NAME can be fetched either from Contacts database/ContactsContract.Data' OR 'database/ContactsContract.CommonDataKinds.StructuredName' OR 'database/RawContactsEntity. In the later 2 cases you will be able to fetch the DISPLAY_NAME using RAW_CONTACT_ID
Couple of Key pointers:
Contacts._ID = Data.CONTACT_ID
RawContacts._ID = Data.RAW_CONTACT_ID
RawContacts.CONTACT_ID = Contacts._ID
RawContactsEntity._ID = RawContacts._ID
Sounds confusing?? Let me try...
The Contacts database is divided into 3 tables contacts, raw contacts, and data.
Each table contains column (_ID) which is an auto incremented primary key.
data table contains all the contact info like phone number, mail id, address etc.
The raw contacts points to the actual contact created. Hence we use the raw contacts while adding a contact.
The user cannot add any data in the contacts table. The data in this table is populated internally due to aggregation of contacts.
The reason your logic worked for some of the contacts is: _ID for contacts, raw contacts remains same until there is any contact aggregation taking place. Lets say you add two contacts with same name abc. Here the _ID for raw contacts increments twice while _ID for contacts increments only once as these two contacts gets merged due to the aggregation of contacts
Refer this for more details.
The best approach to fetch the info in your case is by using ContactsContract.RawContactsEntity ( an outer join of the raw_contacts table with the data table)
Reference: http://developer.android.com/reference/android/provider/ContactsContract.RawContactsEntity.html

Android; I only have 2 contacts, yet I can obtain 5 from a query, why?

I have setup 2 test contacts in my emulator.
I'm running the following query, it should pick them both out, populate my domain object, and add to a list. The output at the bottom should therefore be 2, but it is 5, why is this? (cursor.getCount() is 5 instead of 2)
I have stepped through each iteration of the while loop and it is retreving the same contact multiple times, but with different values for POSTCODE, such as the phone number
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.Data.CONTENT_URI,
null, null, null, null);
List<MeCercanaContact> contacts = new ArrayList<MeCercanaContact>();
if (cursor.getCount() > 0)
{
while (cursor.moveToNext())
{
MyContact myContact = new MyContact();
String givenName = cursor.getString(cursor.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME));
String postcode = cursor.getString(cursor.getColumnIndex(
ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE));
myContact.setFirstName(givenName);
myContact.setLastName(postcode);
contacts.add(myContact);
}
}
System.out.println(contacts.size());
After API 21 We Write this Query for remove contact duplicacy.
String select = ContactsContract.Data.HAS_PHONE_NUMBER + " != 0 AND " +
ContactsContract.Data.MIMETYPE
+ " = " + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "
AND "+ ContactsContract.Data.RAW_CONTACT_ID + " = " +
ContactsContract.Data.NAME_RAW_CONTACT_ID;
Cursor cursor = mContent.query(ContactsContract.Data.CONTENT_URI, null, select,
null, null);
You are querying ContactsContract.Data, which is a generic container that holds a list of various contact details, such as phone numbers, postal codes etc.. You must filter the results for the rows whose ContactsContract.Data.MIMETYPE column equals StructuredPostal.CONTENT_ITEM_TYPE:
So change the query to:
Cursor cursor = cr.query(ContactsContract.Data.CONTENT_URI,
null, null, ContacsContract.Data.MIMETYPE + "='" +
ContactsContract.StructuredPostal.CONTENT_ITEM_TYPE + "'", null);
See ContactsContract.Data
a contact that is registered to multiple groups will show up multiple times
if you query the Uri CONTENT_URI = ContactsContract.Data.CONTENT_URI
Add this to your SELECTION:
+ ContactsContract.Data.DATA1 + " = 1 " ; //show only contacts in group 1

Categories

Resources