I'm trying to modify the value of SEND_TO_VOICEMAIL from 0 to 1 and vice versa.
I succeed to modify the others contact's details, such as name, number, nickname, email, ecc... but I need to change SEND_TO_VOICEMAIL.
I tried many possibility, but this should work... i guess:
String rawContactId = "1";
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(
ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection( Data.RAW_CONTACT_ID + "=?" , new String[] { rawContactId })
.withValue(ContactsContract.RawContacts.SEND_TO_VOICEMAIL , 1)
.build()
);
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
but the logcat says:
ERROR/AndroidRuntime(822): android.database.sqlite.SQLiteException: no
such column: send_to_voicemail: , while compiling: UPDATE data SET
send_to_voicemail=? WHERE _id =?
I really don't know what to try anymore. Any help would be really appreciated.
Thanks.
According to the[manual, the SEND_TO_VOICEMAIL field you're looking for isn't in the ContactsContract.Data table but in the ContactsContract.Contacts table. It seems like you're trying to modify the wrong table.
See ContactsContract.Data and ContactsContract.Contacts for the fields in each table.
It is better modify through ContentProvider Contacts.CONTENT_URI:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newUpdate(Contacts.CONTENT_URI)
.withSelection(Contacts._ID + "=?", new String[]{hmout.get("cid").toString()})
.withValue(Contacts.SEND_TO_VOICEMAIL, 1)
.build());
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
Log.e("Exception: ", e.getMessage());
}
Related
I am trying to Edit Specific Contact's display name, but whatever I do, display name is not getting edited. I have looked all related questions, but I did not find any solution regarding this issue.
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=? AND " +
ContactsContract.CommonDataKinds.Phone.MIMETYPE + "='" +
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "' AND "+ContactsContract.CommonDataKinds.Phone.RAW_CONTACT_ID +"=?",
new String[]{id,raw})
//.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "B "+name)
//.withValue(ContactsContract.CommonDataKinds.Phone.PHONETIC_NAME, "B "+name)
//.withValue(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY, "B "+name)
//.withValue(ContactsContract.Data.DISPLAY_NAME, "B "+name)
.withValue(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, "B "+name)
.build());
try {
ContentProviderResult[] result =HomeActivity.this.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
Log.e("Edit Result",result.toString());
} catch (RemoteException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
I have tried all option which are written in comments, but with ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME. It edits contact No. instead of contact name. I am trying to do this for the last 3 days, but not getting success. Please tell me what I'm doing wrong or show me the right way of editing contact name.
The name is stored in contacts database with STRUCTURED_NAME mime type. More information here
You should modify your code like this
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=? AND " +
ContactsContract.CommonDataKinds.Phone.MIMETYPE + "='" +
ContactsContract.CommonDataKinds.StructuredName + "' AND "+ContactsContract.CommonDataKinds.Phone.RAW_CONTACT_ID +"=?",
new String[]{id,raw})
.withValue(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, "B "+name)
.build());
try {
ContentProviderResult[] result =HomeActivity.this.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
Log.e("Edit Result",result.toString());
} catch (RemoteException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
I would suggest that you pull out the contacts database from an emulator or a rooted phone to get a better understanding.
I'm new in Android and O'm trying to understand how the contacts is working on Android so please bear with me.
I implemented an Observer to observe this URI, ContactsContract.Contacts.CONTENT_URI or ContactsContract.RawContacts.CONTENT_URI.
I am getting notified, and then I query the RawContact like below to get the dirty fields,
Cursor cursor = contResv.query(ContactsContract.RawContacts.CONTENT_URI,
null, ContactsContract.RawContacts.DIRTY + " = ?", new String[] { "1" }, null);
and I do get the accounts that have been changed (Version changed) or deleted. But what I have noticed is that after few seconds I'm getting notified again but this time the dirty rows that I have been notified about in the first time are removed, the DIRTY seems to be cleared after some Sync or something.
How can I guarantee that I will get the dirty rows before it's getting updated?
Because I'm afraid that if my app restarted for some reason and then came back up and then got notified, it won't get the dirty rows as it got cleared during the restart, or any other race condition scenario.
Edit 1
After digging for few hours I think I will need to create a raw contact with the same display name. The reason for this is that I think if I do this Android will think that I'm a sync adapter and will make this raw contact entry dirty and it want be cleaned unless I do so.
I'm trying this but it's not working, taken from here
private void addContact(String accountName, String accountType,
String name, String username) {
Log.i(Commons.TAG, "Adding contact: " + name);
ArrayList operationList = new ArrayList();
ContentProviderOperation.Builder builder = ContentProviderOperation .newInsert(RawContacts.CONTENT_URI);
builder.withValue(RawContacts.ACCOUNT_NAME, null);
builder.withValue(RawContacts.ACCOUNT_TYPE, null);
//builder.withValue(RawContacts.SYNC1, username);
operationList.add(builder.build());
builder = ContentProviderOperation .newInsert(ContactsContract.Data.CONTENT_URI);
builder.withValueBackReference( ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID, 0);
builder.withValue( ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
builder.withValue( ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
operationList.add(builder.build());
try {
ContentResolver mContentResolver = ContactsUpdateService.this.getContentResolver();
mContentResolver.applyBatch(ContactsContract.AUTHORITY, operationList);
} catch (Exception e) {
Log.e(Commons.TAG, "Something went wrong during creation! " + e);
e.printStackTrace();
}
}
This one didn't help also
private void addContact(String accountName, String accountType,
String name, String username) {
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
int rawContactInsertIndex = ops.size();
ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
.withValue(RawContacts.ACCOUNT_TYPE, accountType)
.withValue(RawContacts.ACCOUNT_NAME, accountName).build());
ops.add(ContentProviderOperation
.newInsert(Data.CONTENT_URI)
.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
.withValue(StructuredName.DISPLAY_NAME, name)
.withValue(Phone.NUMBER, "09876543")
.build());
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OperationApplicationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.clear();
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(Data._ID + "=?", new String[]{String.valueOf(id)})
.withValue(Email.DATA, "somebody1#android.com")
.build());
try
{
context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
}
The logs don't show me anything. But the email is not updated. Does anyone know why?
The ops converted to string is as follows:
[mType: 2, mUri: content://com.android.contacts/data, mSelection: _id=?, mExpectedCount: null, mYieldAllowed: false, mValues: data1=somebody1#android.com, mValuesBackReferences: null, mSelectionArgsBackReferences: null]
First, you have a try without a catch, which may explain why you don't see any error in the logs.
Second, from what I can see in the documentation, I think you should better write it this way:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.clear();
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(ContactsContract.Data.CONTACT_ID + "=?",
new String[] {String.valueOf(id)})
.withValue(ContactsContract.CommonDataKinds.Email.DATA, "somebody1#android.com")
.build());
try {
context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
e.printStackTrace();
}
Try use inside withValue not string, but array of strings.
.withValue(ContactsContract.CommonDataKinds.Email.DATA, emails)
where
String[] emails = {"Email Name<somebody1#android.com>"};
I am working on Unit Tests for my Android app, and am doing a lot with Contacts. I have to insert contacts into the Android Content Providers, and delete them after running my tests. Trouble is, they do not get actually deleted:
Insertion:
ArrayList<ContentProviderOperation> contactOps = new ArrayList<ContentProviderOperation>();
int backRefIndex = 0;
Random r = new Random();
contactOps.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.build());
contactOps.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, backRefIndex)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "Sample Name" + r.nextInt())
.build());
contactOps.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, backRefIndex)
.withValue(ContactsContract.CommonDataKinds.Phone.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "020" + r.nextInt())
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, r.nextInt(20)
.build());
try {
ContentProviderResult[] result = context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, contactOps);
} catch (Exception e) {
e.printStackTrace();
}
Deletion method 1 (returns number of raw contacts, but they do not actually get deleted):
int deletedRawContacts = context.getContentResolver().delete(ContactsContract.RawContacts.CONTENT_URI, ContactsContract.RawContacts._ID + " >= ?", new String[]{"0"});
Deletion method 2 (same result as deletion method 1, but different approach):
private static int deleteAllRawContacts(Context context) {
ContentResolver cr = context.getContentResolver();
Cursor cur = cr.query(ContactsContract.RawContacts.CONTENT_URI, null, null, null, null);
int count = 0;
while (cur.moveToNext()) {
try {
String contactId = cur.getString(cur.getColumnIndex(ContactsContract.RawContacts._ID));
count += cr.delete(ContactsContract.RawContacts.CONTENT_URI, ContactsContract.RawContacts._ID + " = ?", new String[]{contactId});
} catch (Exception e) {
System.out.println(e.getStackTrace());
}
}
return count;
}
The deletion method for Contacts works, but the deletion method for Raw Contacts will return a false value. It will "tell" me, that it deleted all contacts, but when I run my next test case, the old Raw Contacts can still be found (i.e. the count of inserted contacts vs. present contacts is wrong). Note: All testing is done on the Android emulator.
Any ideas how to solve this?
I saw a similar question here: How to delete a contact? - but the solution does not seem to solve the given problem either.
As wiseideal already mentioned the way you delete your rawcontacts will only set the "deleted"-flag to 1.
What you need to do is to set the caller_is_syncadapter-flag in your URI to true like this:
RawContacts.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build()
And then use this new URI to call the delete-method:
int deletedRawContacts = context.getContentResolver().delete(RawContacts.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").build(), ContactsContract.RawContacts._ID + " >= ?", new String[]{"0"});
The corresponding part in the documentation is here (Operations->delete).
Hope this helps and happy coding :)
I am working on the same issue.I found the delete column is setted to 1 once I "delete" it.So I think contentresolver doesnt delete the rawcontact data physically,it just set a delete flag.Maybe we should avoid these tag.
I want to create a new contact group. I can query the group and display all the group names but I can't create a group in android I tried as creating contacts method but not created...
ContentResolver cr = this.getContentResolver();
groupValues = new ContentValues();
Log.e("Group","start");
groupValues.put(android.provider.Contacts.GroupMembership.GROUP_ID, 4);
groupValues.put(android.provider.Contacts.GroupMembership.NAME, "Sriseshaa");
groupValues.put(android.provider.Contacts.GroupMembership.PERSON_ID, 1);
cr.insert(android.provider.Contacts.GroupMembership.CONTENT_URI, groupValues);
i found the answer.i found in two ways but i dont know which is correct or best way to use.i am sharing those here..
its simple way like adding contact,
ContentValues groupValues;
create group()
{
ContentResolver cr = this.getContentResolver();
groupValues = new ContentValues();
groupValues.put(ContactsContract.Groups.TITLE, "MyContactGroup");
cr.insert(ContactsContract.Groups.CONTENT_URI, groupValues);
}
Another method using ContentProviderOperation
private void createGroup() {
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation
.newInsert(ContactsContract.Groups.CONTENT_URI)
.withValue(ContactsContract.Groups.TITLE, "SRI").build());
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
Log.e("Error", e.toString());
}
}
Thanks
adithi's answer is enough for Android 4.2.2, in which the name of Contacts manager application is "Contacts" , but the group created by that code will not show on Android 4.4,6 in which the name of Contacts manager application is "People".
The group would show up after adding the account type/name information while insertion happens.
private void createGroup() {
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation
.newInsert(ContactsContract.Groups.CONTENT_URI)
.withValue(
ContactsContract.Groups.TITLE,
Constants.CC_CONTACT_GROUP_TITLE)
.withValue(
ContactsContract.Groups.ACCOUNT_TYPE,
Constants.CC_CONTACT_GROUP_ACCOUNT_TYPE)
.withValue(
ContactsContract.Groups.ACCOUNT_NAME,
Constants.CC_CONTACT_GROUP_ACCOUNT_NAME)
.build());
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
Log.e("Error", e.toString());
}
}
Why are you specifying group ID with groupValues.put(android.provider.Contacts.GroupMembership.GROUP_ID, 4); Its androids job to determined the group ID, you cant specify it because you don't know whether this id is already taken or not.