I have an app that can add and delete contacts just fine. And if there is an existing value in an existing contact, it can be modified just fine. But I can't seem to be able to insert new values into existing contacts. For example, if there is an existing value for a home phone number, but not for the work phone number, I tried using the fillowing to add the value (cintact idValue and workNumber are passed in):
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.CONTACT_ID, idValue)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_WORK)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, workNumber)
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
But I get a NullPointerException:
java.lang.NullPointerException
at com.android.providers.contacts.ContactsProvider2.insertData(ContactsProvider2.java:2604)
at com.android.providers.contacts.ContactsProvider2.insertInTransaction(ContactsProvider2.java:2452)
at com.android.providers.contacts.SQLiteContentProvider.insert(SQLiteContentProvider.java:106)
at com.android.providers.contacts.ContactsProvider2.insert(ContactsProvider2.java:2256)
at android.content.ContentProviderOperation.apply(ContentProviderOperation.java:214)
at com.android.providers.contacts.SQLiteContentProvider.applyBatch(SQLiteContentProvider.java:216)
at com.android.providers.contacts.ContactsProvider2.applyBatch(ContactsProvider2.java:2290)
at android.content.ContentProvider$Transport.applyBatch(ContentProvider.java:217)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:194)
at android.os.Binder.execTransact(Binder.java:336)
at dalvik.system.NativeStart.run(Native Method)
Can someone please tell me what I'm doing wrong?
You are missing withValue(Phone.TYPE, Phone.TYPE_WORK)
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, idValue)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, workNumber).
withValue(Phone.TYPE, Phone.TYPE_WORK)
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
Edits
You are correct I checked the schema for the data table and it is as follow it is only using raw contacts id and not contact id
CREATE TABLE data (_id INTEGER PRIMARY KEY AUTOINCREMENT,
package_id INTEGER REFERENCES package(_id),
mimetype_id INTEGER REFERENCES mimetype(_id) NOT NULL,
raw_contact_id INTEGER REFERENCES raw_contacts(_id) NOT NULL,
is_primary INTEGER NOT NULL DEFAULT 0,
is_super_primary INTEGER NOT NULL DEFAULT 0,
data_version INTEGER NOT NULL DEFAULT 0,
data1 TEXT,
data2 TEXT,
data3 TEXT,
data4 TEXT,
data5 TEXT,
data6 TEXT,
data7 TEXT,
data8 TEXT,
data9 TEXT,
data10 TEXT,
data11 TEXT,
data12 TEXT,
data13 TEXT,
data14 TEXT,
data15 TEXT,
data_sync1 TEXT,
data_sync2 TEXT,
data_sync3 TEXT,
data_sync4 TEXT );
You were getting error because Android doesn't give you access to add a contact directly to you Contact table. Rather you need to modify or add a raw Contact and Android will automatically create a Contact for you.
Related
I don't know what I am doing wrong while inserting contact into phonebook.
here is the code to insert.
public static void AddMultipleContact(Context context, String name , String numbers, String Data4){
ContentResolver resolver = context.getContentResolver();
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
int rawContactInsertIndex = ops.size();
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(ContactsContract.RawContacts.CONTENT_URI, true))
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, AccountGeneral.ACCOUNT_NAME)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, AccountGeneral.ACCOUNT_TYPE)
.withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
.withValue(ContactsContract.RawContacts.SOURCE_ID, sourceId)
.build());
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(ContactsContract.Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
.withValue(RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, numbers) // Number of the person
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
.build()); // Type of mobile number
android.util.Log.e(TAG, "AddMultipleContact:-------------- NAME = " + name);
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(ContactsContract.Data.CONTENT_URI, true))
.withValueBackReference(ContactsContract.RawContacts.Data.RAW_CONTACT_ID, rawContactInsertIndex)
.withValue(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)
.build());
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(ContactsContract.Data.CONTENT_URI, true))
.withValueBackReference(ContactsContract.RawContacts.Data.RAW_CONTACT_ID, rawContactInsertIndex)
.withValue(ContactsContract.RawContacts.Data.MIMETYPE,MIMETYPE)
.withValue(Data.DATA1, sourceId)
.withValue(Data.DATA3, Data4)
.build());
try {
ContentProviderResult[] results = resolver.applyBatch(ContactsContract.AUTHORITY, ops);
}
catch (Exception e) {
e.printStackTrace();
}
}
As you can see i am also printing log for name.
android.util.Log.e(TAG, "AddMultipleContact:-------------- NAME = " + name);
Here i am sending contactName and contactNumber to this method.
the name what I am passing is suppose ex: "A.Bcdef"
but the name what I am seeing in the phonebook is "A. Bcdef"
It is adding extra space after period(.).
Please help me. I am not getting any solution on google, or not able to search exactly what I want to search.
Thanks in advance.
I SOLVED THIS BY Changing this line
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)
to
.withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name)
GIVEN_NAME is taking the same name what we passed as value
There are other parameters like
DISPLAY_NAME, GIVEN_NAME, FAMILY_NAME, PREFIX, MIDDLE_NAME, SUFFIX, PHONETIC_GIVEN_NAME, PHONETIC_MIDDLE_NAME, PHONETIC_FAMILY_NAME, FULL_NAME_STYLE, PHONETIC_NAME_STYLE
I really don't know what actually these all means.
But when i added name as 'Testing,123' while creating a contact, then the name appears to be like '123 Testing'.
So I thought it is automatically thinking like what is 'middleName' and 'lastName' based on SpecialCharacters.
I have a problem when try to update existing contact with field which is not exist.
Example:
I successfully create new contact which contain name and email address fields. During create action I use ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) only for fields which are not empty.
Code for inserting phone field during contact creation (works fine):
if (isNewContact){
if (!phone.equals("")){
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, id)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, type)
.build());
}
}
So, now I try to run update process and append to my contact the phone number:
if (isUpdateContact){
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND "
+ ContactsContract.CommonDataKinds.Phone.TYPE
+ "=? AND " + ContactsContract.Data.MIMETYPE
+ "=?",
new String[] {"" + id, "" + type,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE })
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, type)
.build());
}
In case if during contact creation the phone field was inserted, then update works fine. In case if phone was not inserted, then update does nothing - the field will not be updated. No warnings neither errors in LogCat.
The reason why I do not want to create empty fields on contact creation is because of empty fields crashes Phone application in Samsung Nexus device when I switch to contacts tab with null pointer exception in com.android.contacts.list.ContactListItemView.onMeasure(ContactListItemView.java:350).
So, my question is:
How during update process to insert a new field if not exist (and how to detect it) OR delete the field if exist but new update value is empty? Is it possible at all or there is another solution to avoid crash of Nexus phone app if fields are empty?
P.S. tried to run newInsert during for already created contact, getting:
mType: 1, mUri: content://com.android.contacts/data, mSelection: null, mExpectedCount: null, mYieldAllowed: false, mValues: data1= mimetype=vnd.android.cursor.item/phone_v2 data2=1, mValuesBackReferences: raw_contact_id=2962, mSelectionArgsBackReferences: null
java.lang.ArrayIndexOutOfBoundsException: asked for back ref 2962 but there are only 1 back refs
at android.content.ContentProviderOperation.backRefToValue(ContentProviderOperation.java:362)
Ok, I found the fix:
(this will do right update operation - in case if not found, create; in case if new value empty, just remove the field; in case if exists, do update.)
if (isUpdateContact){
ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
.withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND "
+ ContactsContract.CommonDataKinds.Phone.TYPE
+ "=? AND " + ContactsContract.Data.MIMETYPE
+ "=?",
new String[] {"" + id, "" + type,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE })
.build());
if (!phone.equals("")){
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.RAW_CONTACT_ID, id)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, type)
.build());
}
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to add new contacts in android
how can i add a name to the contacts?
I have two spinners, one for the firstname and one for the lastname. The assigned variables are linkname1 and linkname2. When user pushes the OK button (these are all in a dialog), the name (linkname1 + " " + linkname2) should be added to the contacts. I can read the contacts but how do i write it?
Thanks
Update:
I also tried this:
newname = linkname1 + " " + linkname2;
ContentValues values = new ContentValues();
vales.put(ContactsContract.Contacts.DISPLAY_NAME, newname);
and this:
StringBuffer strBuf = new StringBuffer();
strBuf.append(linkname1);
strBuf.append(" ");
strBuf.append(linkname2);
ContentValues values = new ContentValues();
values.put(ContactsContract.Contacts.DISPLAY_NAME, strBuf.toString());
But the new name is not appearing in the contact list.
That content provider although will still work was replaced with Contacts Contracts in 2.2. The following code will work with new contacts contracts providers:
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.GIVEN_NAME, linkname1)
.withValue(StructuredName.FAMILY_NAME, linkname2)
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
The Account Name and Type you will have to query from the AccountManager service. Either by choosing the an account (e.g. Local or Google) or prompting the user.
Android how-to (create a new contact):
http://www.lacherstorfer.at/haris_blog/2008/03/android-howto-create-a-new-con.html
Be sure to look at the code edit in the comments, may help fix depending on version.
I'm using the following piece of codes to create a new contact. It follow closely the ContactManager example provided by Android.
The problem is, the created contacts do not appear in the Contacts app that shipped with Android. Nevertheless, when I load all the contacts from the phonebook, I can see the newly created contacts.
private void insertPBEntry()
throws RemoteException, OperationApplicationException
{
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, "Account type")
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, "Account name")
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "TOTAL_NEW")
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "9090")
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE,Phone.TYPE_MOBILE)
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
}
I've searched hard but have yet to find the answer. I found one answer suggesting that the problem might have (sth) to do with my strings "Account type" and "Account name". For my case, I do not need to create any account whatsoever. All I want is to add a new contact with a name, email/mail address, phones.
Thanks, guys!
The sample codes provided by Google work. Just that when it's run on the emulator, no account or group can be found to attach the created contact to. And by default, this newly created contact is not visible.
Using the actual phone (for my case, HTC Dream), after detecting the account name and type to feed in the codes, it works. Alternatively, we can get the visible group ids available and attach the new contact to one of those groups.
To get the available accounts:
//accounts
Account[] accounts = AccountManager.get(act).getAccounts();
for (Account acc : accounts){
Log.d(TAG, "account name = " + acc.name + ", type = " + acc.type);
}
To get the list of groups:
//group membership info
String[] tempFields = new String[] {
GroupMembership.GROUP_ROW_ID, GroupMembership.GROUP_SOURCE_ID};
Cursor tempCur = act.managedQuery(Data.CONTENT_URI, tempFields,
Data.MIMETYPE + "='" + GroupMembership.CONTENT_ITEM_TYPE + "'",
null, null);
Now, if we want to associate the new contact to a group instead of an account:
ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE)
.withValue(GroupMembership.GROUP_SOURCE_ID, *<THE_IDENTIFIED_GROUP_ID>*)
.build());
Hope it helps.
To add an account in emulator that has no groups or accounts, just put "null" as your account or group id, replace the line of code like this
ops.add(ContentProviderOperation
.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.build());
Did you try to set the visibility of your group to true?
In Contacts Tab press the menu button, than "Display options" > your Account and than check the boxes and "Done".
HTC Sense and MOTOBLUR can be problematic with contacts. I don't know if any of the information here (http://stackoverflow.com/questions/4431101/created-contacts-not-showing-up-on-htc-evo) is useful.
I am trying to display the name, phone number and email of a contact and letting the user update any of the values. For some reason, the value of email is overwritten on all three fields when my code is executed. There's got to be a glitch in the logic here, but I cannot figure it out.
Here's my method which updates the Contacts URI.
private void updateContact() {
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newUpdate(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, name)
.build());
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.build());
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.build());
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Email.DATA, email)
.build());
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
// Display update
Context ctx = getApplicationContext();
CharSequence txt = "Contact Updated";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(ctx, txt, duration);
toast.show();
} catch (Exception e) {
// Display warning
Context ctx = getApplicationContext();
CharSequence txt = "Update Failed";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(ctx, txt, duration);
toast.show();
}
}
see this link:
http://comments.gmane.org/gmane.comp.handhelds.android.devel/92848
" you shouldn't specify the mime type in an update statement - it is not updatable."
"Your query says: "update all data rows for this contact, setting one of the fields to "John" and another to "Abraham". Data rows include phone numbers, emails, photos, you-name-it. What you need to do is find a specific data row you want to update and then use its _id in the selection (or, more commonly, in the URI itself)."
"The data structure for contacts is based on three separate tables: Contacts, RawContacts and Data. A Contact can have multiple RawContacts, which can have multiple Data rows. Each data row has a mime type that specifies what kind of data is stored in that row. Contact name is stored in a row with the mime type StructuredName.CONTENT_TYPE.
So, in order to change the contact name you first need to find the Data row that contains the name and then update that Data row. The provider will take care of the rest (e.g. promoting the name to the level of RawContact and then Contact)."
Also see
http://www.eoeandroid.com/sdk/api/reference/android/provider/ContactsContract.Data.html
must get the dataId first :
ArrayList ops = Lists.newArrayList();
ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)
.withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)})
.withValue(Email.DATA, "somebody#android.com")
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);