Search code examples
androidandroid-contentproviderandroid-contactsandroid-contentresolver

How to update multiple phone numbers using ContentProviderOperation


First, my contact insertion code:

    fun makeRawContact(): ContentProviderOperation.Builder {
        return ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, getString(R.string.account_type_contacts))
            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
    }

    fun makeData(mimeType: String): ContentProviderOperation.Builder {
        return ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
            .withValue(ContactsContract.Data.MIMETYPE, mimeType)
    }

    fun insert(): Int {
        val ops = ArrayList<ContentProviderOperation>()
        ops += makeRawContact().build()
        ops += makeData(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, "testinsert")
            .build()

        ops += makeData(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "12345678")
            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, 1)
            .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, null)
            .build()

        val result = contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
    }

Suppose that the raw id is 8 by calling insert().

If I want to update name of contact, I call like this:

    fun updateData(rawId: Long, mimeType: String): ContentProviderOperation.Builder {
        return ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
            .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=?", arrayOf(rawId.toString()))
            .withValue(ContactsContract.Data.MIMETYPE, mimeType)
    }

    fun update() {
        val ops = ArrayList<ContentProviderOperation>()
        ops += updateData(8, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, "testupdate")
            .build()
        val result = contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
    }

I want to update two phone numbers on contact with raw id 8, but it has only one phone number 12345678. I think that one should be updated and the other should be inserted, so I'm trying to get data id of the phone number through ContentResolver and raw id. But this seems to be complex, so I ask question. Is there a better way? I've seen how to delete all and insert new phone numbers, but I believe there is a better way.

Thanks.


Solution

  • If you're implementing a full blown contact editor that allows the user to view and edit info items then you should attach a flag to each row that says if that row was untouched/deleted/inserted/updated, and then you iterate through the rows and update the DB accordingly.

    If you're not doing something like that, the cleanest approach I've seen is to delete whatever existing phones there are in the DB for that raw-contact, and insert the new/updated ones.

    Try to put both delete operation and insert operations into the same applyBatch call so there won't be any race conditions here with some other app / thread trying to update the same raw-contact.