如何以编程方式更改 phone 中的联系人?

How to change programmatically a Contact from phone?

这是我的代码:

FL.i(TAG, "Test Contact Creation editXelionContact")

    val shouldResetXelionContact = xelionContact.isDefault
    var editResult = if (shouldResetXelionContact) RESET_FAILED else NOT_CREATED_FAILED

    if (xelionContact.isAnonymous) {
        FL.i(TAG, "Test Contact Creation Do not edit XelionContact to anonymous: $xelionContact")
        return NOT_CREATED_ANONYMOUS
    }

    if (!xelionContact.isValid) {
        EXCEPTION_HANDLER.logAndReport("Test Contact Creation xelionContact not valid: name and/or number for XelionContact not set")
        FL.i(TAG,"Test Contact Creation xelionContact not valid: name and/or number for XelionContact not set")
        return editResult
    }

    if (!isCorrectNumberOfXelionContacts(1)) {
        EXCEPTION_HANDLER.logAndReport("Test Contact Creation Do not edit contact: invalid number of contacts (not 1)")
        FL.i(TAG,"Test Contact Creation Do not edit contact: invalid number of contacts (not 1)")
        return editResult
    }

    val existingXelionContact = existingXelionContact
    val shouldUpdateXelionContactConstantValues = !XelionContact.isLatestVersion
    if (shouldResetXelionContact && existingXelionContact.isDefault && !shouldUpdateXelionContactConstantValues) {
        FL.i(TAG, "Test Contact Creation Do not reset the XelionContact if it is already default: $xelionContact")
        return NOT_RESET_ALREADY_DEFAULT
    }

    if (shouldResetXelionContact && !TELEPHONY_MANAGER.isPhoneIdle) {
        FL.d(TAG, "Test Contact Creation Don't reset the XelionContact to default while the phone is ringing or while calling.")
        resetXelionContactAfterCallEnded = true // To reset directly when call ends
        startXelionContactResetTimer() // To be sure reset will always be called (when CallLogChanged is unregistered reset won't be called anymore)
        return NOT_RESET_CALL_BUSY
    }

    FL.i(TAG, "Test Contact Creation Edit contact. From: $existingXelionContact to: $xelionContact")

    val ops = ArrayList<ContentProviderOperation>()

    var builder = getNewOperationBuilderForUpdateWithSelection(SELECTION_NAME)
    builder.withValue(StructuredName.GIVEN_NAME, xelionContact.readableName)
    ops.add(builder.build())

    if (!shouldResetXelionContact) { // If the XelionContact should be reset, then do not save the default phone number, but remember the last received phoneNumber
        builder = getNewOperationBuilderForUpdateWithSelection(SELECTION_PHONE_NUMBER_WORK)
        builder.withValue(Phone.NUMBER, xelionContact.phoneNumber!!.number)
        ops.add(builder.build())
        FL.i(TAG, "Test Contact Creation Edit contact. If the XelionContact should be reset, then do not save the default phone number, but remember the last received phoneNumber")
    }

    if (shouldUpdateXelionContactConstantValues) {
        builder = getNewOperationBuilderForUpdateWithSelection(SELECTION_NOTE)
        builder.withValue(Note.NOTE, xelionContact.note)
        ops.add(builder.build())

        if (!existingXelionContact.hasPhoto()) {
            builder = getNewOperationBuilderForInsert(existingXelionContact.rawContactId, Photo.CONTENT_ITEM_TYPE)
        } else {
            builder = getNewOperationBuilderForUpdateWithSelection(SELECTION_PHOTO)
        }
        builder.withValue(Photo.PHOTO, xelionContact.photo)
        ops.add(builder.build())
    }

    try {
        FL.i("Test Contact Creation OPERATIONS ================")
        for (item in ops){
            FL.i("Test Contact Creation op: " + item.toString())
        }
        FL.i("Test Contact Creation OPERATIONS END")
        val result = contentResolver.applyBatch(AUTHORITY, ops)
        dumpResults("editXelionContact", result)
        if (result.size > 0 && result.size == ops.size) {
            editResult = if (shouldResetXelionContact) RESET else CREATED
        }
    } catch (e: Exception) {
        EXCEPTION_HANDLER.logAndReport(e)
        FL.i(TAG, "Test Contact Creation createXelionContact5: ${e.message}")
    }

    return editResult

日志:

Test Contact Creation OPERATIONS ================
Test Contact Creation op: mType: 2, mUri: content://com.android.contacts/data, mSelection: 
account_type='com.xelion.android.account' AND mimetype='vnd.android.cursor.item/name', mExpectedCount: null, mYieldAllowed: false, mValues: data2=Alin Rosu via Xelion, mValuesBackReferences: null, mSelectionArgsBackReferences: null
I/Xelion7 dev: Test Contact Creation op: mType: 2, mUri: content://com.android.contacts/data, mSelection: account_type='com.xelion.android.account' AND mimetype='vnd.android.cursor.item/phone_v2' AND data2='3', mExpectedCount: null, mYieldAllowed: false, mValues: data1=+31157630779, mValuesBackReferences: null, mSelectionArgsBackReferences: null
Test Contact Creation OPERATIONS END
V/_PHONE_CONTACT_ XelionContactManager: Test Contact editXelionContact ContentProviderResult: dumpResults
V/_PHONE_CONTACT_ XelionContactManager: Test Contact editXelionContact ContentProviderResult:ContentProviderResult(count=0)
V/_PHONE_CONTACT_ XelionContactManager: Test Contact editXelionContact ContentProviderResult:ContentProviderResult(count=0)

这在三星以外的所有其他手机上都能正常工作,三星是否以某种方式处理联系人。不同的?我在做什么?还有为什么我的 ContentProviderResult 是 0?

编辑:

缺少代码:

 private fun getNewOperationBuilderForUpdateWithSelection(selectionName: String): ContentProviderOperation.Builder {
    val builder = ContentProviderOperation.newUpdate(Data.CONTENT_URI)
    builder.withSelection(getSelectionWithXelionContact(selectionName), null)
    return builder
}

  private fun getSelectionWithXelionContact(vararg extraSelections: String): String {
    val selection = StringBuilder(SELECTION_XELION_CONTACT)
    for (extraSelection in extraSelections) {
        StringFormatter.addOptionalDelimiterAndString(selection, " AND ", extraSelection)
    }
    return selection.toString()
}

   private val SELECTION_XELION_CONTACT = RawContacts.ACCOUNT_TYPE + "='" + XelionAccountManager.XELION_ACCOUNT_TYPE + "'"

    private val SELECTION_NAME = Data.MIMETYPE + "='" + StructuredName.CONTENT_ITEM_TYPE + "'"

And I Do use the mime type and account type as Marmor assumes in his answer down.

注意:这适用于大多数手机。 GooglePixel 3、华为Mate 10 Pro、vivo S1 Pro、一加6T都是我亲自测试过的。仅在三星上它不起作用。 注 2:我确实通过解决方法解决了这个问题,方法是在收到推送通知时删除联系人,然后再次创建它。出于某种原因,在三星设备上对其进行编辑是行不通的,但在创建时效果很好。 但还是想知道为什么会这样。是不是因为三星手机可能使用不同的 "name" 列。展示?喜欢 "given_name" 或 "display_name"?

好吧,您没有 post getNewOperationBuilderForUpdateWithSelection(SELECTION_NAME) 的代码,但从日志来看,我假设这选择了 account_type='com.xelion.android.account' AND mimetype='vnd.android.cursor.item/name',它缺少一些条件来指定您的联系人正在尝试编辑。

这基本上是说用 mimetype "name" 更新帐户 X 中的所有行,并将它们全部更新为 Alin。这可能会更改许多联系人,而不仅仅是您当前尝试编辑的联系人。 您可能应该将 AND CONTACT_ID = X 添加到您的选择中。