I'm new to android dev, so I may get the whole concept totally wrong. I want to delete a specific entry from RawContact directory entry. Here is code that I have:
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
Uri entityUri = Uri.withAppendedPath(rawContactUri, Entity.CONTENT_DIRECTORY);
Cursor c = getContentResolver().query(entityUri,
new String[]{RawContacts._ID, Entity.DATA_ID, Entity.MIMETYPE,CommonDataKinds.GroupMembership.GROUP_SOURCE_ID},
null, null, null);
using cursor c I get appropriate Entity.DATA_ID. After that I try to delete an entry:
getContentResolver().delete(entityUri,Entity.DATA_ID+"=?",
new String[]{id});
and get an error:
java.lang.UnsupportedOperationException: URI:
content://com.android.contacts/raw_contacts/2709/entity
What am I doing wrong?
UPD 1
I am trying to remove group membership entry.
Please give a more complete explanation of what you're trying to do. You say that you want to "delete a specific entry from RawContact directory entry.", which is confusing? Do you want to
a) delete a raw contact?
b) delete a set of raw contacts?
c) delete all of the data rows for a single raw contact?
d) delete all of the data rows for a set of raw contacts?
or do you want to do something with group membership?
In any event, I think you've constructed the URI backwards. Try appending Entity.CONTENT_DIRECTORY before the rawContactId. I know that the documentation doesn't say this, but the documentation is not well-written.
A better alternative would be to use the ContactsContract.RawContactEntity table.
Looks like I was using the wrong URI. Also I switched to a "new" way of modifying the table:
ArrayList<ContentProviderOperation> ops =
new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI)
.withSelection(Data._ID + "=?", new String[]{i})
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
Related
i use the following the code to update the number:
ContentValues mobilePhoneValues = new ContentValues();
mobilePhoneValues.put(ContactsContract.CommonDataKinds.Phone.TYPE, typePhone);
mobilePhoneValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, binding.numberEdit.getText().toString());
getContentResolver().update(ContactsContract.Data.CONTENT_URI, mobilePhoneValues,
ContactsContract.CommonDataKinds.Phone.NUMBER + "=?", new String[]{mobilePhoneNumbers.get(0)});
It works perfectly but when i try to update the email using same logic it fails to update it.
Code:
ContentValues contentValues1 = new ContentValues();
contentValues1.put(ContactsContract.CommonDataKinds.Email.TYPE, typeEmail);
contentValues1.put(ContactsContract.CommonDataKinds.Email.DATA, binding.emailEdit.getText().toString());
getContentResolver().update(ContactsContract.Data.CONTENT_URI, contentValues1,
ContactsContract.CommonDataKinds.Email.DATA + "=?", new String[]{homeEmailNumbers.get(0)});
Why is it the same logic updates the number but fails to update the email ?
Please help
There's a big problem in both examples.
You are telling the API - change any occurrence of phone (or email) "X" to "Y" across all contacts.
It depends on your use case, but I'm assuming you want to let users edit contact information.
For that use case that's not what you intend to be doing. instead, you should tell the API - take row with ID "12345" and change its value to "Y".
Adding the contact-id to the WHERE clause will also have unintended consequences when you consider a case where a certain contact has 2 duplicate phone numbers, and the user wants to edit one of them - you don't want to modify both numbers in this case.
You should first change the way you read and present the data, so every data row for every contact also holds the specific Data table row ID (Data._ID)
and then the code is:
batch update approach (preferred):
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)
.withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)})
.withValue(CommonColumns.TYPE, newType)
.withValue(CommonColumns.DATA, newData)
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
single change approach:
ContentValues values = new ContentValues();
values.put(CommonColumns.TYPE, newType);
values.put(CommonColumns.DATA, newData);
getContentResolver().update(Data.CONTENT_URI, values,
Data._ID + "=?", new String[]{String.valueOf(dataId)});
The use of CommonColumns and Data._ID allows for the same code to work for both phones, emails, and some other common types.
I am working on a requirement, where I need to identify all Google's contact saved/synced with Android device's phonebook. Then I have to fetch unique contact Id (Google's unique contact id)of each contact which will be same on other devices and other platform.
I have read Android developer's documentation regarding RAW_CONTACT_ID. Also, tried to get raw contact id, but I am getting different value of raw contact id on other devices.
If anyone can put me on right direction, it will really helpful.
If require more information, please ask.
Try using ContactsContract.PhoneLookup
A table that represents the result of looking up a phone number, for example for caller ID. To perform a lookup you must append the number you want to find to CONTENT_FILTER_URI. This query is highly optimized.
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
resolver.query(uri, new String[]{PhoneLookup.DISPLAY_NAME,...
where
PhoneLookup._ID
is what you're looking for.
You may also try the solution provided in this post:
public static int getContactIDFromNumber(String contactNumber,Context context)
{
contactNumber = Uri.encode(contactNumber);
int phoneContactID = new Random().nextInt();
Cursor contactLookupCursor = context.getContentResolver().query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,contactNumber),new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup._ID}, null, null, null);
while(contactLookupCursor.moveToNext()){
phoneContactID = contactLookupCursor.getInt(contactLookupCursor.getColumnIndexOrThrow(PhoneLookup._ID));
}
contactLookupCursor.close();
return phoneContactID;
}
All _ID values in Android's Contacts are local, they are usually incremental, and are not synced between devices.
The values that might get synced by the app's SyncAdapter (in this case Google's SyncAdapter) are SYNC1, SYNC2, SYNC3, SYNC4.
However, note that these fields are not guaranteed to do anything, and the SyncAdapter may use them for whatever purpose it needs, usually, one of them is used as a "server identifier" you just need to print them, and check manually which one.
If a SyncAdapter A for Account A creates a raw contact in the ContactsContract.RawContacts table, can SyncAdapter B for Account B update the RawContact added by SyncAdapter A.
Of particular interest is the sync1 or any of the sync fields in the raw contacts table?
If this is possible what are the possible issues that might arise as a result.
Can anyone show a sample of how this should be done?
There's no per-contact-permission-model on the Contacts DB, every app and every SyncAdapter with the Contacts permission can read/write to any field in any contact.
However, the syncX fields under RawContact are used for proprietary purposes by the owning SyncAdapter (e.g. to keep track on what contact requires syncing, which one is dirty, when was it last synced, the backend-contact-id value, etc.), so make sure you don't touch anything you don't know what it's for, or you might risk corrupting some contacts.
To modify the Sync1 value on RawContact with id 1234, do:
ContentResolver cr = context.getContentResolver();
ContentValues values = new ContentValues(2);
values.put(RawContacts.SYNC1, "Hello World");
cr.update(RawContacts.CONTENT_URI, values, RawContacts._ID + "=" + 1234, null);
UPDATE - batch updates
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
.withSelection(RawContacts._ID + "=" + 1234, null)
.withValue(RawContacts.SYNC1, "Hello")
.build());
ops.add(ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
.withSelection(RawContacts._ID + "=" + 5678, null)
.withValue(RawContacts.SYNC1, "World")
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
I am using the generic columns DATA1 to Data15 to store some data. My question is whether it is safe to assume that these columns are not being used by other android applications to store their own data. IF not how would I make sure that a particular column is not being used by any other application?
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withValue(Data.DATA10,"Data")
Retrive data:
ContentResolver cr=context.getContentResolver();
Cursor emailCur = cr.query(
ContactsContract.Data.CONTENT_URI,
null,
ContactsContract.Data._ID + " = ?",
new String[]{str_id}, null);
while (emailCur.moveToNext())
{
String name=emailCur.getString(
emailCur.getColumnIndex(Data.DATA10));
}
It will be safe, if you use your own MIME type value for the MIMETYPE column. When querying the data table, a MIME is specified to query for specific results (Phone numbers, names, addresses and so on), so if you use a value special for your application, other applications will probably not use it/change it.
Read more about the data table here.
EDIT: Append this call to the ContentProviderOperation creation chain:
.withValue(Data.MIMETYPE, "yourCustomMimeType")
I have two contacts group on my device like Work, Home. I have to add contact on that particular group. Like Add john(Contacts name0) to Work group.
I have used following Code:
ContentValues values = new ContentValues();
values.put(ContactsContract.CommonDataKinds.GroupMembership.RAW_CONTACT_ID,
Integer.parseInt(contactId));
values.put(
ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID,
"3");
values
.put(
ContactsContract.CommonDataKinds.GroupMembership.MIMETYPE,
ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE);
context.getContentResolver().insert(
ContactsContract.Data.CONTENT_URI, values);
But I get the following output: content://com.android.contacts/data/714
Please guide me, what am I doing wrong?
Thanks in advance!
I don't see anything wrong! What makes you think something is wrong?
Looks like you're trying to add the group identified by "3" for the raw contact identified by contactId. The result is contactId now belongs to group "3" (You have to look up "3" in ContactsContract.Groups).
What this does is add a GroupMembership row to the Data table. Group membership is an attribute of the raw contact contactId. So you've done what you set out to do. The result is an Uri that points to the data row you added.
I figure you were expecting something else. Can you elaborate?