Как правильно заставить агрегировать контакты при программном добавлении? - PullRequest
7 голосов
/ 23 февраля 2012

Я видел этот вопрос и ответ, но добавление информации о телефоне (и даже электронной почте) по-прежнему не приводит к правильной агрегации контактной информации (когда я проверяю приложение "Люди", я вижу несколько записей в одно и то же имя).

Вот код, который я использую для его проверки.

//get the account
Account acct = null;
Account[] accounts = AccountManager.get(getContext()).getAccounts(); 
for (Account acc : accounts){
    acct = acc;
}//assuming there's only one account in there (in my case I know there is)

//loop a few times, creating a new contact each time. In theory, if they have the same name they should aggregate
for(int i=0; i<3; i++){
    ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
    ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, acct.type)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, acct.name)
                .withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT) 
                .build());
    ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "ContactName")
                .build());
    ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "1234567890")
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, 1)
                .build());
    ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Email.DATA, "email@address.com")
                .withValue(ContactsContract.CommonDataKinds.Email.TYPE, 1)
                .build());

    try{        
        getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
    }
    catch (Exception e) {
        Log.e("Contacts", "Something went wrong during creation! " + e);
        e.printStackTrace();
    }
}

Ответы [ 2 ]

8 голосов
/ 23 февраля 2012

Если они не агрегируются автоматически, вы можете агрегировать их вручную, добавив строку в таблицу AggregationExceptions . Убедитесь, что вы заметили в документах, что вставка запрещена. Вы должны сделать обновление вместо этого. Это поймало меня дважды. Следующий код должен объединить два необработанных контакта с идентификаторами 1 и 2:

ContentValues cv = new ContentValues();
cv.put(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
cv.put(AggregationExceptions.RAW_CONTACT_ID1, 1);
cv.put(AggregationExceptions.RAW_CONTACT_ID2, 2);
getContentResolver().update(AggregationExceptions.CONTENT_URI, cv, null, null);
1 голос
/ 01 марта 2017

Вот модифицированный пример, включающий ссылки и различные данные для каждого, чтобы доказать, что он работает:

    Account acct = null;
    Account[] accounts = AccountManager.get(this).getAccounts();
    for (Account acc : accounts) {
        acct = acc;
    }
    //loop a few times, creating a new contact each time. In theory, if they have the same name they should aggregate
    final ArrayList<Uri> newlyCreatedContactsUris = new ArrayList<>();
    for (int i = 0; i < 2; i++) {
        ArrayList<ContentProviderOperation> ops = new ArrayList<>();
        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, acct == null ? null : acct.type)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, acct == null ? null : acct.name)
                .withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
                .build());
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, "ContactName" + i)
                .build());
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, Integer.toString(123456789 * (i + 1)))
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, 1)
                .build());
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Email.DATA, "email" + i + "@address.com")
                .withValue(ContactsContract.CommonDataKinds.Email.TYPE, 1)
                .build());

        try {
            final ContentProviderResult[] contentProviderResults = getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
            newlyCreatedContactsUris.add(contentProviderResults[0].uri);
            Log.d("AppLog", "done creating new contacts data");
        } catch (Exception e) {
            Log.e("AppLog", "Something went wrong during creation! " + e);
            e.printStackTrace();
        }
    }
    //Note: seems we can only link 2 contacts data together, not more
    ArrayList<ContentProviderOperation> mergeOps = new ArrayList<>();
    mergeOps.add(ContentProviderOperation.newUpdate(ContactsContract.AggregationExceptions.CONTENT_URI)
            .withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER)
            .withValue(AggregationExceptions.RAW_CONTACT_ID1, newlyCreatedContactsUris.get(0).getLastPathSegment())
            .withValue(AggregationExceptions.RAW_CONTACT_ID2, newlyCreatedContactsUris.get(1).getLastPathSegment())
            .build());
    try {
        final ContentProviderResult[] contentProviderResults2 = getApplicationContext().getContentResolver().applyBatch(ContactsContract.AUTHORITY, mergeOps);
        Log.d("AppLog", "done merging");
    } catch (RemoteException e) {
        e.printStackTrace();
    } catch (OperationApplicationException e) {
        e.printStackTrace();
    }

И результат:

enter image description here

В чем я не уверен:

  1. Как получить данные о существующих контактах и ​​затем решить, какие объединить? Я заметил, что встроенное приложение контактов может объединять контакты, но иногда не объединяет их, когда основной контакт принимает имя объединенного контакта. Как бы я это сделал?
  2. Как получилось, что в приложении контактов нет возможности отменить связь, в отличие от того же, что и пользовательский интерфейс?
  3. Как он решает, какую информацию заменить, какую добавить и т. Д ...?
  4. Каковы правила автоматического объединения контактов? Кажется, идентичного имени контакта достаточно, но оно может сделать это в неправильных случаях (потому что разные люди могут иметь одинаковое имя, даже включая фамилию).
  5. Действительно ли это правильный способ использовать getLastPathSegment для необработанного идентификатора контакта?
...