Búsqueda rápida de contactos por número telefónico Android

Esta semana tuve que implementar un componente custom (Pop Up) para un App de Android donde se necesita mostrar un listado de contactos, lo interesante es que los números telefónicos de los contactos que se muestran deben de coincidir con lo que vas escribiendo en un EditText.

Para realizarlo ocupé la librería ButterKnife que me facilita implementar el Listener OnTextChanged en el EditText para obtener los caracteres que va ingresando el usuario en tiempo real.

@OnTextChanged(R.id.accountSelected)
public void onTextChangedInSelectAccount(CharSequence text) {
mPresenter.quickSearchContact(popupTopLocation, text.toString());
}

Creamos un AsyncTaskLoader para obtener los contactos que cumplan contengan los digitos ingresados por el usuario:

Cursor contactPhones = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.TYPE,
ContactsContract.CommonDataKinds.Phone.LABEL,
ContactsContract.Data._ID},
ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER + " LIKE '%" + phoneNumber + "%'", null, ContactsCursorLoader.ORDER);

Una vez obtenido el cursor, lo utilizaremos para obtener el ID de los contactos que coinciden con la búsqueda, el id lo utilizaremos para poder obtener otra información del contacto como la foto del contacto:

ArrayList<DeviceContactModel> deviceContacts = new ArrayList<>();
if (contactPhones.moveToFirst()) {
for (contactPhones.moveToPrevious(); contactPhones.moveToNext(); ) {
final long contactId = contactPhones.getLong(contactPhones.getColumnIndex(ContactsContract.Data._ID));

Cursor contactCursor = getContext().getContentResolver().query(ContactsContract.Data.CONTENT_URI, {ContactsContract.Data._ID, ContactsContract.Data.DISPLAY_NAME_PRIMARY, ContactsContract.Data.PHOTO_URI}, ContactsContract.Data._ID + " = ? ", new String[]{String.valueOf(contactId)}, contactsCursorLoader.ORDER);

if (contactCursor.moveToFirst())
for (contactCursor.moveToPrevious(); contactCursor.moveToNext(); ) {
mDeviceContact.setContact(new ContactModel(contactCursor.getLong(0), contactCursor.getString(1), contactCursor.getString(2), Utils.getRandomContactBackground(), mContactDao.isContactFavorite(contactCursor.getLong(0)),
mContactDao.isContactRecent(contactCursor.getLong(0))));
}

if (mDeviceContact.getContact() != null)
deviceContacts.add(mDeviceContact);

Log.d(TAG, "Match Contacts:: " + deviceContacts.size());

contactCursor.close();

}
}

contactPhones.close();

Con esto podremos obtener de dos tablas diferentes toda la información que queramos del contacto, en mi caso ocupo las dos para poder mostrar mucha información del contacto, por lo que puedes obtener la que necesitas desde el primer cursor.

Es importante usar la Uri ContactsContract.CommonDataKinds.Phone.CONTENT_URI para buscar los teléfonos y ocupar ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER en la selección, debido a que regresa el número telefónico en formato E164 lo cual permite la búsqueda con el query en todas las versiones de Android a partir del 4.1.

Resultado Final