如何以编程方式更改 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
添加到您的选择中。
这是我的代码:
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
添加到您的选择中。