Como consultar todos os contatos que pertencem a uma conta?

fundo

Os contatos no catálogo de endereços podem ter dados da conta anexados a eles. Cada aplicativo pode ter uma conta e, em seguida, adicionar suas próprias informações para o contato.

Aplicativos como Telegram, WhatsApp, Viber, ... - todos criam uma conta que adiciona informações e / ou ações aos contatos.

Aqui está um exemplo de contato que possui contas do WhatsApp e do Viber:

O problema

Estou tentando descobrir como buscar todos os contatos que possuem uma conta especificada.

Como o WhatsApp é o mais popular que eu conheço, meus testes se concentram nele.

Meu problema é que alguns usuários afirmam que o que eu fiz mal retorna contatos, e outros afirmam que não mostra nem um. Parece que geralmente funciona, e no meu caso sempre funcionou, mas algo provavelmente não é bom no código.

O que eu tentei

Eu consegui criar o próximo código, que para mim parece funcionar, obtendo um mapa de informações de telefone para contato, de todos os contatos do WhatsApp.

A idéia é obter todas as informações possíveis dos contatos do WhatsApp, em comparação com todos os dados básicos dos contatos e mesclar aqueles que correspondem à mesma chave de pesquisa.

Tentei usar uma consulta melhor para ingressar, mas falhei. Talvez também seja possível e possa ser mais eficiente.

Aqui está o código:

/**
 * returns a map of lookup-key to contact-info, of all WhatsApp contacts
 */
@NonNull
public HashMap<String, ContactInfo> getAllWhatsAppPhones(Context context) {
    ContentResolver cr = context.getContentResolver();
    final HashMap<String, ContactInfo> phoneToContactInfoMap = new HashMap<>();
    final HashMap<String, String> whatsAppLookupKeyToPhoneMap = new HashMap<>();
    final String phoneMimeType = Phone.CONTENT_ITEM_TYPE;
    final Cursor whatsAppCursor;
    whatsAppCursor = cr.query(Data.CONTENT_URI,
            new String[]{Phone.NUMBER, Phone.LOOKUP_KEY},
            Phone.MIMETYPE + " = ?", new String[]{WhatsAppStuff.WHATS_APP_MIME_TYPE}, null);
    if (whatsAppCursor == null)
        return phoneToContactInfoMap;
    Cursor contactCursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
            //null,
            new String[]{
                    Contacts.LOOKUP_KEY, Contacts._ID, Contacts.PHOTO_THUMBNAIL_URI,
                    ContactsContract.Contacts.DISPLAY_NAME,                        //        ContactsContract.CommonDataKinds.Phone.NUMBER,
            },
            "(" + Phone.MIMETYPE + " IS NULL OR " + Phone.MIMETYPE + " = '" + phoneMimeType + "') AND ("
                    + ContactsContract.RawContacts.ACCOUNT_TYPE + " = 'com.google' OR " + ContactsContract.RawContacts.ACCOUNT_TYPE + " IS NULL)",
            null, null);
    if (contactCursor == null) {
        whatsAppCursor.close();
        return phoneToContactInfoMap;
    }
    int progress = 0;
    final int phoneNumberIdx = whatsAppCursor.getColumnIndex(Phone.NUMBER);
    final int lookupKeyIdx = whatsAppCursor.getColumnIndex(Phone.LOOKUP_KEY);
    while (whatsAppCursor.moveToNext()) {
        final String phoneNumberValue = whatsAppCursor.getString(phoneNumberIdx);
        final int endIndex = phoneNumberValue.indexOf("@"),;
        if (endIndex < 0)
            continue;
        String lookupKey = whatsAppCursor.getString(lookupKeyIdx);
        final String phone = phoneNumberValue.substring(0, endIndex);
        if (!phone.isEmpty() && StringUtil.isAllDigits(phone)) {
            //Log.d("AppLog", "whatsApp phone:" + phone + " " + lookupKey);
            whatsAppLookupKeyToPhoneMap.put(lookupKey, phone);
        }
        if (markedToCancel != null && markedToCancel.get()) {
            whatsAppCursor.close();
            contactCursor.close();
            return phoneToContactInfoMap;
        }
        if (progressListener != null)
            progressListener.onProgressUpdate(progress++, maxProgress);
    }
    whatsAppCursor.close();
    if (whatsAppLookupKeyToPhoneMap.isEmpty())
        return phoneToContactInfoMap;
    //Log.d("AppLog", "getting info about whatsapp contacts");
    final int idColIdx = contactCursor.getColumnIndex(Contacts._ID);
    final int displayNameColIdx = contactCursor.getColumnIndex(Contacts.DISPLAY_NAME);
    final int lookupKeyColIdx = contactCursor.getColumnIndex(Contacts.LOOKUP_KEY);
    final int photoColIdx = contactCursor.getColumnIndex(Contacts.PHOTO_THUMBNAIL_URI);

    while (contactCursor.moveToNext()) {
        String lookupKey = contactCursor.getString(lookupKeyColIdx);
        String phoneNumber = whatsAppLookupKeyToPhoneMap.get(lookupKey);
        if (phoneNumber == null)
            continue;
        ContactInfo contactInfo = new ContactInfo();
        contactInfo.lookupKey = lookupKey;
        contactInfo.displayName = contactCursor.getString(displayNameColIdx);
        contactInfo.photoThumbUriStr = contactCursor.getString(photoColIdx);
        contactInfo.whatsAppPhoneNumber = phoneNumber;
        contactInfo.contactId = contactCursor.getLong(idColIdx);
        phoneToContactInfoMap.put(phoneNumber, contactInfo);
        if (markedToCancel != null && markedToCancel.get()) {
            contactCursor.close();
            return phoneToContactInfoMap;
        }
        if (progressListener != null)
            progressListener.onProgressUpdate(progress++, maxProgress);
    }
    contactCursor.close();
    return phoneToContactInfoMap;
}
A questão

Como escrevi, o código acima normalmente só funciona.

Como é que geralmente só funciona? O que falta para corrigi-lo?

Devo usarContacts.getLookupUri em vez de chave de pesquisa? Em caso afirmativo, como devo alterar o código acima para usá-lo?

Tentei usar um URI em vez de uma chave de pesquisa, mas não encontrou nenhum deles nos contatos normais.

questionAnswers(1)

yourAnswerToTheQuestion