Android write contacts [duplicate] - android

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.

Related

How to add city field to a contact in Android using ContentProviderOperation

I'm creating a contacts app that will have all the basic features of a Contacts app (and some extra features of course). While implementing the basic features, I'm stuck at a place:
I'm having an activity in which the user can change the city name of a contact. If the user is already having a city, I can update it using the following code:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
String contactId = id; // got it from ContactsContract.Contacts._ID
String mimeType = ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE;
String selection = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredPostal.TYPE + " = ?";
String[] values = new String[]{contactId, mimeType, String.valueOf(ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME)};
ops.add(
android.content.ContentProviderOperation.newUpdate(
android.provider.ContactsContract.Data.CONTENT_URI)
.withSelection(selection, values)
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, "California")
.build()
);
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
But, the above code is not working for a contact that doesn't have any details other than phone number. After browsing a lot, I've found the following way to do it:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
String rawContactId = id;
String mimeType = ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE;
String[] values = new String[]{contactId, mimeType, String.valueOf(ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME)};
ops.add(
android.content.ContentProviderOperation.newInsert(
android.provider.ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
.withValue(ContactsContract.Data.MIMETYPE, mimeType)
.withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, "California")
.build()
);
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
In the above case, I'm getting the rawContactId from ContactsContract.RawContacts.CONTENT_URI with ContactsContract.Data.CONTACT_ID equal to normal contactId. I was getting different rawContactId for different accounts - Google, WhatsApp, Skype, etc. I tried updating with all the rawContactIds, but still it was not getting updated. Can anybody please help me how to fix it?
You didn't specify what exactly is not working when you apply to above code, but I can see a few issues in it.
First you need to have a clear understanding of how contact data is stored in the database:
Contacts - each entry represents one contact, and groups together one or more RawContacts
RawContacts - each entry represents data about a contact that was synced in by some SyncAdapter (e.g. Whatsapp, Google, Facebook, Viber), this groups multiple Data entries
Data - The actual data about a contact, emails, phones, etc. each line is a single piece of data that belongs to a single RawContact
ISSUE 1
So if you're trying to update an existing postal-address, you should be careful not to use contactId as your key, because a single contact (referenced by a contactId) may have multiple postal-addresses in multiple raw-contacts each with multiple postal-address data rows.
your newUpdate call might then update the city in ALL addresses.
So if you have a contact "David" that has addresses:
123 lane, New York, United States
456 drive, Missouri, United States
789 alley, Paris, France
and your user is now trying to update "Paris" to "Lyon", your code might update ALL 3 addresses to Lyon.
Your key then must be the current Data._ID of the specific Data row you're trying to update.
ISSUE 2
If you're trying to insert a new data row to an existing raw-contact, for example a completely new postal-address, you'll need to specify the specific RawContact ID you're trying to insert into, and not use withValueBackReference - that's only useful when you're now creating a whole new RawContact, and don't know what will be the RawContact ID it'll get yet, so you're doing a back-reference to the ID your new RawContact will get from a previous call to newInsert of a RawContact row.
Also, in this case just the CITY value is not enough, as you'll get a whole postal-address comprised of CITY only, like this:
123 lane, New York, United States
456 drive, Missouri, United States
789 alley, Paris, France
Lyon
What you want to do here is collect all the postal-address values, and add them all into a single new Data row, like so:
ops.add(
ContentProviderOperation.newInsert(Data.CONTENT_URI)
.withValue(Data.RAW_CONTACT_ID, rawContactId)
.withValue(Data.MIMETYPE, mimeType)
.withValue(StructuredPostal.STREET, "123 Lane")
.withValue(StructuredPostal.CITY, "Los Angles")
.withValue(StructuredPostal.REGION, "California")
.withValue(StructuredPostal.COUNTRY, "United States")
.build()
);
ISSUE 3
If you're trying to insert just the CITY value to an existing postal-address row, you'll need to do an update, not an insert, into the specific Data ID, something like this:
String selection = Data._ID + " = ?";
ops.add(
ContentProviderOperation.newUpdate(Data.CONTENT_URI)
.withSelection(selection, new String[]{ dataId })
.withValue(StructuredPostal.CITY, "Los Angeles")
.build()
);

Android how to add phone number to existing contact [duplicate]

Im trying to add a phone number to an already existing contact on a Droid-phone. Doing it at the same time as I create a contact is trivial, as the backreference I supply simply is 0 when creating a ContentProviderOperation. But trying to find the backreference through querying for a display name like this does not work:
Cursor rawContactsReferenceCursor =
contentResolver.query(Data.CONTENT_URI,
new String[]{Data.RAW_CONTACT_ID},
Data.DISPLAY_NAME+"=\""+displayName+"\"", null, null);
While I do get a raw contact ID, the following code just generates an IndexOutOfBoundException (rawConcactReferenceID is the variable I got from the previous query):
ArrayList<ContentProviderOperation> op_list =
new ArrayList<ContentProviderOperation>();
op_list.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)
.withValueBackReference(Data.RAW_CONTACT_ID, rawConcactReferenceID)
.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
.withValue(Phone.NUMBER, testNumber)
.withValue(Phone.TYPE, Phone.TYPE_CUSTOM)
.withValue(Phone.LABEL, testLabel)
.build());
ContentProviderResult[] result =
contentResolver.applyBatch(ContactsContract.AUTHORITY, op_list);
The big challenge is a huge lack of good documentation. I would be very satisfied to just get my hands on some working copypasta to study.
Cheers,
I found an answer. It is not atomic if you want to add several things right away, but hey, who needs stupid atomicity?
ContentValues values = new ContentValues();
values.put(Data.RAW_CONTACT_ID, new Integer(contactId).intValue());
values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
values.put(Phone.NUMBER, dataValue);
values.put(Phone.TYPE, Phone.TYPE_CUSTOM);
values.put(Phone.LABEL, customLabel);
Uri dataUri = getContentResolver().insert(Data.CONTENT_URI, values);
I've had a similar problem with email addresses. Here's the solution I used that worked:
ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
.withValue(Data.RAW_CONTACT_ID, id)
.withValue(Email.DATA, value)
.withValue(Email.MIMETYPE, .Email.CONTENT_ITEM_TYPE)
.withValue(Email.LABEL, label)
.withValue(Email.TYPE, Email.TYPE_CUSTOM)
.build());
ContentProviderResult[] res = cr.applyBatch(ContactsContract.AUTHORITY, ops);
The same solution should work for telephone numbers.
These links may provide some help:
http://www.higherpass.com/Android/Tutorials/Working-With-Android-Contacts/1/
http://developer.android.com/resources/samples/ContactManager/src/com/example/android/contactmanager/ContactAdder.html

Inserting contact with android and querying the result uri returns no entries

Im developing an application which is dealing with the android contacts API. I implemented methods to insert, update and query contacts. So far everything worked (writing and reading contacts).
At one point in my project Im experiencing a strange behaviour.
I insert a contact using batch mode. I receive the URI to the RawContact. I do this in a background thread.
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
int rawContactInsertIndex = ops.size();
// create rawContact
ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
.withValue(RawContacts.ACCOUNT_TYPE, ConstantsContract.ACCOUNT_TYPE)
.withValue(RawContacts.ACCOUNT_NAME, accountName).build());
ops.add(createInsertOperation().withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
.withValue(StructuredName.DISPLAY_NAME, displayName).withValue(StructuredName.GIVEN_NAME, firstName)
.withValue(StructuredName.FAMILY_NAME, lastName).build());
ContentProviderResult[] results = context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
if (results.length > 0) {
result = results[0];
}
Then i request and store the lookup uri
RawContacts.getContactLookupUri(this.getContentResolver(), myContantRawContactUri);
I am able to query the contact using the rawContactUri directly after inserting it (in the same thread). The lookup uri returns null.
Uri rawContactUri = appUser.getRawContactUri(ctx);
if (rawContactUri == null) {
return null;
}
String lastPathSegment = rawContactUri.getLastPathSegment();
long rawContactId = Long.decode(lastPathSegment);
if (rawContactUri != null) {
contact = readContactWithID(rawContactId, ContactsContract.Data.RAW_CONTACT_ID);
In a different place in the project I want to query the contact i inserted by the stored lookup uri or raw contact uri. Both return no rows from the content provider. I tried it in the main thread and in another background thread.
ctx.getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, ContactsContract.Data.RAW_CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?", new String[] { contactID + "", ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE }, null);
My first thought was that it could be related to the context.getContentResolver(). But the android documentation states, that the ContentResolver objects scope is the application's package, so you have on ContentResolver for the whole app. Am I right?
What am I doing wrong? Why does the same rawContactUri return the contact at one place and does not on another place? And why do I get a lookup uri from a raw contact, which is not working at all?
Update:
I analyzed the database using sqlite. When I insert the contact, the rows in raw_contacts and contacts are created. The deleted flag is set to 0, so it is not marked for deletion. If I then read the contact in another place in the application, it returns null. The database dump at this point of time does not contain the rows for the contact anymore.
Update 2:
I tested my app with the emulator in versions 2.3.3, 4.0, and 4.1. The described behavior only appears with 4.1 Jelly Bean.
Ok, i found the solution. It was actually my own fault. I added a contact before i added my custom account to the AccountManager. This obviously deleted the contact because it had the same account type set.

New contacts created using ContactsContract do not appear in Contacts app

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.

Add number to contact on Android 2.0

Im trying to add a phone number to an already existing contact on a Droid-phone. Doing it at the same time as I create a contact is trivial, as the backreference I supply simply is 0 when creating a ContentProviderOperation. But trying to find the backreference through querying for a display name like this does not work:
Cursor rawContactsReferenceCursor =
contentResolver.query(Data.CONTENT_URI,
new String[]{Data.RAW_CONTACT_ID},
Data.DISPLAY_NAME+"=\""+displayName+"\"", null, null);
While I do get a raw contact ID, the following code just generates an IndexOutOfBoundException (rawConcactReferenceID is the variable I got from the previous query):
ArrayList<ContentProviderOperation> op_list =
new ArrayList<ContentProviderOperation>();
op_list.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI)
.withValueBackReference(Data.RAW_CONTACT_ID, rawConcactReferenceID)
.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
.withValue(Phone.NUMBER, testNumber)
.withValue(Phone.TYPE, Phone.TYPE_CUSTOM)
.withValue(Phone.LABEL, testLabel)
.build());
ContentProviderResult[] result =
contentResolver.applyBatch(ContactsContract.AUTHORITY, op_list);
The big challenge is a huge lack of good documentation. I would be very satisfied to just get my hands on some working copypasta to study.
Cheers,
I found an answer. It is not atomic if you want to add several things right away, but hey, who needs stupid atomicity?
ContentValues values = new ContentValues();
values.put(Data.RAW_CONTACT_ID, new Integer(contactId).intValue());
values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
values.put(Phone.NUMBER, dataValue);
values.put(Phone.TYPE, Phone.TYPE_CUSTOM);
values.put(Phone.LABEL, customLabel);
Uri dataUri = getContentResolver().insert(Data.CONTENT_URI, values);
I've had a similar problem with email addresses. Here's the solution I used that worked:
ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
.withValue(Data.RAW_CONTACT_ID, id)
.withValue(Email.DATA, value)
.withValue(Email.MIMETYPE, .Email.CONTENT_ITEM_TYPE)
.withValue(Email.LABEL, label)
.withValue(Email.TYPE, Email.TYPE_CUSTOM)
.build());
ContentProviderResult[] res = cr.applyBatch(ContactsContract.AUTHORITY, ops);
The same solution should work for telephone numbers.
These links may provide some help:
http://www.higherpass.com/Android/Tutorials/Working-With-Android-Contacts/1/
http://developer.android.com/resources/samples/ContactManager/src/com/example/android/contactmanager/ContactAdder.html

Categories

Resources