27

I am trying to insert new RawContact contacts, but the RawContact added doesn't get displayed when I view the contacts through Contacts or phonebook. As I understand if we create a RawContact and there is no contact associated with it then the contact will be automatically inserted. I get a valid value of rawContactId and no exceptions are thrown, so I assume the insertion is successful. Am I doing anything wrong or am I missing something? I am using the code example from developer site, just pasting it here:

 ContentValues values = new ContentValues();
 values.put(RawContacts.ACCOUNT_TYPE, accountType); 
 values.put(RawContacts.ACCOUNT_NAME, accountName);
 Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values); 
 long rawContactId = ContentUris.parseId(rawContactUri); 

 values.clear(); 
 values.put(Data.RAW_CONTACT_ID, rawContactId); 
 values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 
 values.put(StructuredName.DISPLAY_NAME, "Mike Sullivan"); 
 getContentResolver().insert(Data.CONTENT_URI, values); 
Sam
  • 86,580
  • 20
  • 181
  • 179
Alok Save
  • 202,538
  • 53
  • 430
  • 533

3 Answers3

37

I thought this Q was long forgotten but Since someone upvoted it, I am assuming someone else also faces the same problem as me. After a little struggle I was able to figure out the problem and insert contacts, Hope this helps, here is the sample code:

ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
int rawContactInsertIndex = ops.size();

ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
   .withValue(RawContacts.ACCOUNT_TYPE, null)
   .withValue(RawContacts.ACCOUNT_NAME,null )
   .build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
   .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex)
   .withValue(Data.MIMETYPE,Phone.CONTENT_ITEM_TYPE)
   .withValue(Phone.NUMBER, "9X-XXXXXXXXX")
   .build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
   .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
   .withValue(Data.MIMETYPE,StructuredName.CONTENT_ITEM_TYPE)
   .withValue(StructuredName.DISPLAY_NAME, "Mike Sullivan")
   .build());  
ContentProviderResult[] res = getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
Senthil
  • 1,244
  • 10
  • 25
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • This solution directly adds the contact. Is there a way to start the android "add contact" activity with some pre-populated data (which includes a StructuredName)? If so, would you care to answer here: http://stackoverflow.com/questions/7545609/how-to-add-a-contact-with-first-name-and-last-name-via-intent – Dino Oct 17 '11 at 16:33
  • If I use "null" as the account name and type I get an error when doing applyBatch on my Samsung phone. Any update on this? – Simon MacDonald Jan 06 '12 at 18:27
  • It works fine. please let me know how to get contactid after inserting the contact – AndroidRaji Dec 20 '12 at 13:03
  • why this add contact two times? – Tofeeq Ahmad Aug 30 '13 at 06:56
  • which data to import? ContactsContract.Data, ContactsContract.Contacts.Data OR ContactsContract.RawContacts.Data – Sarthak Majithia Apr 21 '15 at 05:53
  • if getContentResolver is not working because you are in a fragment first getActivity() also if ContentProviderResult is not working try try { ContentProviderResult[] res = 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(); } – NVA Jan 20 '18 at 02:23
7

A client reported to me that the solution in the answer above(by Als) doesn't work on some HTC devices. So after a few days of frustration I came up with this solution:

String name = "First Family";
String phone = "0123456789";
ContentValues values = new ContentValues();
values.put(Data.DISPLAY_NAME, name);
Uri rawContactUri = c.getContentResolver().insert(RawContacts.CONTENT_URI, values);
long rawContactId = ContentUris.parseId(rawContactUri);
long contactId = Util.getContactId(c, rawContactId);
System.out.println("rawContactId = " + rawContactId);
System.out.println("contactId = " + contactId);

values.clear();
values.put(Phone.NUMBER, phone);
values.put(Phone.TYPE, Phone.TYPE_OTHER);
values.put(Phone.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
values.put(Data.RAW_CONTACT_ID, rawContactId);
c.getContentResolver().insert(Data.CONTENT_URI, values);

values.clear();
values.put(Data.MIMETYPE, Data.CONTENT_TYPE);
values.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
values.put(Data.RAW_CONTACT_ID, rawContactId);
c.getContentResolver().insert(Data.CONTENT_URI, values);

values.clear();
values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
values.put(Data.RAW_CONTACT_ID, rawContactId);
c.getContentResolver().insert(Data.CONTENT_URI, values);



public static long getContactId(Context context, long rawContactId) {
    Cursor cur = null;
    try {
        cur = context.getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI, new String[] { ContactsContract.RawContacts.CONTACT_ID }, ContactsContract.RawContacts._ID + "=" + rawContactId, null, null);
        if (cur.moveToFirst()) {
            return cur.getLong(cur.getColumnIndex(ContactsContract.RawContacts.CONTACT_ID));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (cur != null) {
            cur.close();
        }
    }
    return -1l;
}
Milan
  • 900
  • 2
  • 14
  • 25
  • @anqe1ki11er: Are you sure the answer(below not one in Q) marked as solution did not work? because it works for me on Motorola device. – Alok Save Dec 17 '10 at 04:00
  • @Als. A client of mine reported to me that your solution doesn't work on some newer HTC devices. I don't know on which. But I saw a stack trace, so I'm quite sure that the answer below doesn't work on all devices. If it helps, I know that my client uses deviceanywhere for testing. – Milan Dec 21 '10 at 22:31
  • @shesjulie You don't have to import any class, Util.getContactId() is my own method, its code is below. Sorry I forgot to include it in my first post. – Milan Dec 21 '10 at 22:36
  • public static long getContactId(Context context, long rawContactId) { Cursor cur = null; try { cur = context.getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI, new String[] { ContactsContract.RawContacts.CONTACT_ID }, ContactsContract.RawContacts._ID + "=" + rawContactId, null, null); if (cur.moveToFirst()) { return cur.getLong(cur.getColumnIndex(ContactsContract.RawContacts.CONTACT_ID)); } } catch (Exception e) { e.printStackTrace(); } finally { if (cur != null) { cur.close(); } } return -1l; } – Milan Dec 21 '10 at 22:39
  • @anqe1ki11er: I don't see anything specific to a device in the code i wrote. It is all vanilla Android framework, So I am not sure why it should fail for a particular device.The solution should work on emulator as well as all devices which support and use Android vanilla framework. I guess HTC has modified the framework for contacts then. – Alok Save Dec 22 '10 at 05:50
  • 1
    @Als: Yes, your code works perfectly on emulator and almost all devices. So I agree with you that it is HTC's fault, they probably modified the contact framework. – Milan Dec 23 '10 at 00:48
  • @anqe1ki11er: I don't understand the 3rd paragraph where it says {values.put(Data.MIMETYPE, Data.CONTENT_TYPE)}. There is no such MIMETYPE. (I checked it on HTC Desire running HTC Android 2.2). Thanks. – OferR Jul 20 '11 at 13:10
  • why it shows error in Util.getContactId(c, rawContactId). what is c? – AndroidRaji Dec 17 '12 at 06:54
  • I see this code does not use `.withValue(RawContacts.ACCOUNT_TYPE, null)` and similar. Is that the motivation for all this other logic? – Harry Moreno Jan 03 '16 at 17:49
1

To have a visible contact created, it needs to belong to a visible group. Have a look at gmail contacts on your computer to view groups and visibility.

To find a visible group on the device, do something like this:

    Long myContactsGroupId = null;
    sqlWhere = ContactsContract.Groups.ACCOUNT_TYPE + " = 'com.google'  AND  " + ContactsContract.Groups.GROUP_VISIBLE + " = 1";
    Cursor cursor = getContentResolver().query(ContactsContract.Groups.CONTENT_URI, new String[] {"_id"}, sqlWhere, null, "_id");
    if (cursor.moveToFirst()) {
        myContactsGroupId = cursor.getLong(0);
    }

To add the group to the rawContact:

        cv.clear();
        cv.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE);
        cv.put(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID, myContactsGroupId);
        cv.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
        getContentResolver().insert(ContactsContract.Data.CONTENT_URI, cv);

Or the ops version:

         ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID, myContactsGroupId)
                .build());

@anqe1ki11er:

I don't understand the 3rd paragraph in your answer where it says:

values.put(Data.MIMETYPE, Data.CONTENT_TYPE) ...

There is no such MIMETYPE. (I checked it on HTC Desire running HTC Android 2.2).

Thanks.

OferR
  • 1,634
  • 19
  • 21