public void updateContact(ReadableMap contact, Promise promise) {

        String recordID = contact.hasKey("recordID") ? contact.getString("recordID") : null;
        String rawContactId = contact.hasKey("rawContactId") ? contact.getString("rawContactId") : null;

        if (rawContactId == null || recordID == null) {
            promise.reject("Invalid recordId or rawContactId");
            return;
        }

        String givenName = contact.hasKey("givenName") ? contact.getString("givenName") : null;
        String middleName = contact.hasKey("middleName") ? contact.getString("middleName") : null;
        String familyName = contact.hasKey("familyName") ? contact.getString("familyName") : null;
        String prefix = contact.hasKey("prefix") ? contact.getString("prefix") : null;
        String suffix = contact.hasKey("suffix") ? contact.getString("suffix") : null;
        String company = contact.hasKey("company") ? contact.getString("company") : null;
        String jobTitle = contact.hasKey("jobTitle") ? contact.getString("jobTitle") : null;
        String department = contact.hasKey("department") ? contact.getString("department") : null;
        String note = contact.hasKey("note") ? contact.getString("note") : null;
        String thumbnailPath = contact.hasKey("thumbnailPath") ? contact.getString("thumbnailPath") : null;

        ReadableArray phoneNumbers = contact.hasKey("phoneNumbers") ? contact.getArray("phoneNumbers") : null;
        int numOfPhones = 0;
        String[] phones = null;
        Integer[] phonesTypes = null;
        String[] phonesLabels = null;
        String[] phoneIds = null;
        if (phoneNumbers != null) {
            numOfPhones = phoneNumbers.size();
            phones = new String[numOfPhones];
            phonesTypes = new Integer[numOfPhones];
            phonesLabels = new String[numOfPhones];
            phoneIds = new String[numOfPhones];
            for (int i = 0; i < numOfPhones; i++) {
                ReadableMap phoneMap = phoneNumbers.getMap(i);
                String phoneNumber = phoneMap.getString("number");
                String phoneLabel = phoneMap.getString("label");
                String phoneId = phoneMap.hasKey("id") ? phoneMap.getString("id") : null;
                phones[i] = phoneNumber;
                phonesTypes[i] = mapStringToPhoneType(phoneLabel);
                phonesLabels[i] = phoneLabel;
                phoneIds[i] = phoneId;
            }
        }

        ReadableArray urlAddresses = contact.hasKey("urlAddresses") ? contact.getArray("urlAddresses") : null;
        int numOfUrls = 0;
        String[] urls = null;
        String[] urlIds = null;

        if (urlAddresses != null) {
            numOfUrls = urlAddresses.size();
            urls = new String[numOfUrls];
            urlIds = new String[numOfUrls];
            for (int i = 0; i < numOfUrls; i++) {
                ReadableMap urlMap = urlAddresses.getMap(i);
                urls[i] = urlMap.getString("url");
                urlIds[i] = urlMap.hasKey("id") ? urlMap.getString("id") : null;
            }
        }

        ReadableArray emailAddresses = contact.hasKey("emailAddresses") ? contact.getArray("emailAddresses") : null;
        int numOfEmails = 0;
        String[] emails = null;
        Integer[] emailsTypes = null;
        String[] emailsLabels = null;
        String[] emailIds = null;

        if (emailAddresses != null) {
            numOfEmails = emailAddresses.size();
            emails = new String[numOfEmails];
            emailIds = new String[numOfEmails];
            emailsTypes = new Integer[numOfEmails];
            emailsLabels = new String[numOfEmails];
            for (int i = 0; i < numOfEmails; i++) {
                ReadableMap emailMap = emailAddresses.getMap(i);
                emails[i] = emailMap.getString("email");
                String label = emailMap.getString("label");
                emailsTypes[i] = mapStringToEmailType(label);
                emailsLabels[i] = label;
                emailIds[i] = emailMap.hasKey("id") ? emailMap.getString("id") : null;
            }
        }

        ReadableArray postalAddresses = contact.hasKey("postalAddresses") ? contact.getArray("postalAddresses") : null;
        int numOfPostalAddresses = 0;
        String[] postalAddressesStreet = null;
        String[] postalAddressesCity = null;
        String[] postalAddressesState = null;
        String[] postalAddressesRegion = null;
        String[] postalAddressesPostCode = null;
        String[] postalAddressesCountry = null;
        Integer[] postalAddressesType = null;
        String[] postalAddressesLabel = null;
        if (postalAddresses != null) {
            numOfPostalAddresses = postalAddresses.size();
            postalAddressesStreet = new String[numOfPostalAddresses];
            postalAddressesCity = new String[numOfPostalAddresses];
            postalAddressesState = new String[numOfPostalAddresses];
            postalAddressesRegion = new String[numOfPostalAddresses];
            postalAddressesPostCode = new String[numOfPostalAddresses];
            postalAddressesCountry = new String[numOfPostalAddresses];
            postalAddressesType = new Integer[numOfPostalAddresses];
            postalAddressesLabel = new String[numOfPostalAddresses];
            for (int i = 0; i < numOfPostalAddresses; i++) {
                String postalLabel = getValueFromKey(postalAddresses.getMap(i), "label");
                postalAddressesStreet[i] = getValueFromKey(postalAddresses.getMap(i), "street");
                postalAddressesCity[i] = getValueFromKey(postalAddresses.getMap(i), "city");
                postalAddressesState[i] = getValueFromKey(postalAddresses.getMap(i), "state");
                postalAddressesRegion[i] = getValueFromKey(postalAddresses.getMap(i), "region");
                postalAddressesPostCode[i] = getValueFromKey(postalAddresses.getMap(i), "postCode");
                postalAddressesCountry[i] = getValueFromKey(postalAddresses.getMap(i), "country");
                postalAddressesType[i] = mapStringToPostalAddressType(postalLabel);
                postalAddressesLabel[i] = postalLabel;
            }
        }

        ReadableArray imAddresses = contact.hasKey("imAddresses") ? contact.getArray("imAddresses") : null;
        int numOfIMAddresses = 0;
        String[] imAccounts = null;
        String[] imProtocols = null;
        String[] imAddressIds = null;

        if (imAddresses != null) {
            numOfIMAddresses = imAddresses.size();
            imAccounts = new String[numOfIMAddresses];
            imProtocols = new String[numOfIMAddresses];
            imAddressIds = new String[numOfIMAddresses];
            for (int i = 0; i < numOfIMAddresses; i++) {
                ReadableMap imAddressMap = imAddresses.getMap(i);
                imAccounts[i] = imAddressMap.getString("username");
                imProtocols[i] = imAddressMap.getString("service");
                imAddressIds[i] = imAddressMap.hasKey("id") ? imAddressMap.getString("id") : null;
            }
        }

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();

        ContentProviderOperation.Builder op = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                .withSelection(ContactsContract.Data.CONTACT_ID + "=?", new String[] { String.valueOf(recordID) })
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, givenName)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, middleName)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, familyName)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX, prefix)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, suffix);
        ops.add(op.build());

        op = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + " = ?",
                        new String[] { String.valueOf(recordID), ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE })
                .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, company)
                .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, jobTitle)
                .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, department);
        ops.add(op.build());

        op.withYieldAllowed(true);

        if (phoneNumbers != null) {
            // remove existing phoneNumbers first
            op = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
                    .withSelection(
                            ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + " = ?",
                            new String[] { String.valueOf(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE),
                                    String.valueOf(rawContactId) });
            ops.add(op.build());

            // add passed phonenumbers
            for (int i = 0; i < numOfPhones; i++) {
                op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                        .withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
                        .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                        .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phones[i])
                        .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phonesTypes[i])
                        .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, phonesLabels[i]);
                ops.add(op.build());
            }
        }

        for (int i = 0; i < numOfUrls; i++) {
            if (urlIds[i] == null) {
                op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                        .withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
                        .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE)
                        .withValue(ContactsContract.CommonDataKinds.Website.URL, urls[i]);
            } else {
                op = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                        .withSelection(ContactsContract.Data._ID + "=?", new String[] { String.valueOf(urlIds[i]) })
                        .withValue(ContactsContract.CommonDataKinds.Website.URL, urls[i]);
            }
            ops.add(op.build());
        }

        if (emailAddresses != null) {
            // remove existing emails first
            op = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
                    .withSelection(
                            ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + " = ?",
                            new String[] { String.valueOf(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE),
                                    String.valueOf(rawContactId) });
            ops.add(op.build());

            // add passed email addresses
            for (int i = 0; i < numOfEmails; i++) {
                op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                        .withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
                        .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
                        .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, emails[i])
                        .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailsTypes[i])
                        .withValue(ContactsContract.CommonDataKinds.Email.LABEL, emailsLabels[i]);
                ops.add(op.build());
            }
        }

        // remove existing note first
        op = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
                .withSelection(
                        ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + " = ?",
                        new String[] { String.valueOf(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE), String.valueOf(rawContactId) });
        ops.add(op.build());

        if (note != null) {
            op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                    .withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE)
                    .withValue(ContactsContract.CommonDataKinds.Note.NOTE, note);
            ops.add(op.build());
        }

        if (thumbnailPath != null && !thumbnailPath.isEmpty()) {
            Bitmap photo = getThumbnailBitmap(thumbnailPath);

            if (photo != null) {
                ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                        .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                        .withValue(ContactsContract.Data.MIMETYPE,
                                ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
                        .withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, toByteArray(photo))
                        .build());
            }
        }

        if (postalAddresses != null) {
            // remove existing addresses
            op = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
                    .withSelection(
                            ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + " = ?",
                            new String[] { String.valueOf(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE),
                                    String.valueOf(rawContactId) });
            ops.add(op.build());

            for (int i = 0; i < numOfPostalAddresses; i++) {
                op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                        .withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
                        .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
                        .withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, postalAddressesType[i])
                        .withValue(ContactsContract.CommonDataKinds.StructuredPostal.LABEL, postalAddressesLabel[i])
                        .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, postalAddressesStreet[i])
                        .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, postalAddressesCity[i])
                        .withValue(ContactsContract.CommonDataKinds.StructuredPostal.REGION, postalAddressesState[i])
                        .withValue(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, postalAddressesPostCode[i])
                        .withValue(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, postalAddressesCountry[i]);
                ops.add(op.build());
            }
        }

        if (imAddresses != null) {
            // remove existing IM addresses
            op = ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
                    .withSelection(
                            ContactsContract.Data.MIMETYPE + "=? AND " + ContactsContract.Data.RAW_CONTACT_ID + " = ?",
                            new String[] { String.valueOf(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE),
                                    String.valueOf(rawContactId) });
            ops.add(op.build());

            // add passed IM addresses
            for (int i = 0; i < numOfIMAddresses; i++) {
                op = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                        .withValue(ContactsContract.Data.RAW_CONTACT_ID, String.valueOf(rawContactId))
                        .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
                        .withValue(ContactsContract.CommonDataKinds.Im.DATA, imAccounts[i])
                        .withValue(ContactsContract.CommonDataKinds.Im.TYPE, ContactsContract.CommonDataKinds.Im.TYPE_HOME)
                        .withValue(ContactsContract.CommonDataKinds.Im.PROTOCOL, ContactsContract.CommonDataKinds.Im.PROTOCOL_CUSTOM)
                        .withValue(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL, imProtocols[i]);
                ops.add(op.build());
            }
        }

        Context ctx = getReactApplicationContext();
        try {
            ContentResolver cr = ctx.getContentResolver();
            ContentProviderResult[] result = cr.applyBatch(ContactsContract.AUTHORITY, ops);

            if (result != null && result.length > 0) {

                ContactsProvider contactsProvider = new ContactsProvider(cr);
                WritableMap updatedContact = contactsProvider.getContactById(recordID);

                promise.resolve(updatedContact); // success
            }
        } catch (Exception e) {
            promise.reject(e.toString());
        }
    }
Retrieves <code>contact</code> for contact, or <code>null</code> if not
available.

@param contactId contact identifier, <code>recordID</code>
android/src/main/java/com/rt2zz/reactnativecontacts/impl/ContactsManagerImpl.java