package fr.neamar.kiss.loader;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import fr.neamar.kiss.normalizer.PhoneNormalizer;
import fr.neamar.kiss.normalizer.StringNormalizer;
import fr.neamar.kiss.pojo.ContactsPojo;
public class LoadContactsPojos extends LoadPojos<ContactsPojo> {
public LoadContactsPojos(Context context) {
super(context, "contact://");
}
@Override
protected ArrayList<ContactsPojo> doInBackground(Void... params) {
long start = System.nanoTime();
// Run query
Cursor cur = context.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[]{ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.CommonDataKinds.Phone.TIMES_CONTACTED,
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER,
ContactsContract.CommonDataKinds.Phone.STARRED,
ContactsContract.CommonDataKinds.Phone.IS_PRIMARY,
ContactsContract.Contacts.PHOTO_ID,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID}, null, null, ContactsContract.CommonDataKinds.Phone.TIMES_CONTACTED + " DESC");
// Prevent duplicates by keeping in memory encountered phones.
// The string key is "phone" + "|" + "name" (so if two contacts
// with distinct name share same number, they both get displayed)
Map<String, ArrayList<ContactsPojo>> mapContacts = new HashMap<>();
if (cur != null) {
if (cur.getCount() > 0) {
int lookupIndex = cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
int timesContactedIndex = cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TIMES_CONTACTED);
int displayNameIndex = cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int numberIndex = cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int starredIndex = cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.STARRED);
int isPrimaryIndex = cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.IS_PRIMARY);
int photoIdIndex = cur.getColumnIndex(ContactsContract.Contacts.PHOTO_ID);
while (cur.moveToNext()) {
ContactsPojo contact = new ContactsPojo();
contact.lookupKey = cur.getString(lookupIndex);
contact.timesContacted = cur.getInt(timesContactedIndex);
contact.setName(cur.getString(displayNameIndex));
contact.phone = cur.getString(numberIndex);
if (contact.phone == null) {
contact.phone = "";
}
contact.phoneSimplified = PhoneNormalizer.simplifyPhoneNumber(contact.phone);
contact.starred = cur.getInt(starredIndex) != 0;
contact.primary = cur.getInt(isPrimaryIndex) != 0;
String photoId = cur.getString(photoIdIndex);
if (photoId != null) {
contact.icon = ContentUris.withAppendedId(ContactsContract.Data.CONTENT_URI,
Long.parseLong(photoId));
}
contact.id = pojoScheme + contact.lookupKey + contact.phone;
if (contact.name != null) {
contact.nameNormalized = StringNormalizer.normalize(contact.name);
if (mapContacts.containsKey(contact.lookupKey))
mapContacts.get(contact.lookupKey).add(contact);
else {
ArrayList<ContactsPojo> phones = new ArrayList<>();
phones.add(contact);
mapContacts.put(contact.lookupKey, phones);
}
}
}
}
cur.close();
}
// Retrieve contacts' nicknames
Cursor nickCursor = context.getContentResolver().query(
ContactsContract.Data.CONTENT_URI,
new String[]{
ContactsContract.CommonDataKinds.Nickname.NAME,
ContactsContract.Data.LOOKUP_KEY},
ContactsContract.Data.MIMETYPE + "= ?",
new String[]{ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE},
null);
if (nickCursor != null) {
if (nickCursor.getCount() > 0) {
int lookupKeyIndex = nickCursor.getColumnIndex(ContactsContract.Data.LOOKUP_KEY);
int nickNameIndex = nickCursor.getColumnIndex(ContactsContract.CommonDataKinds.Nickname.NAME);
while (nickCursor.moveToNext()) {
String lookupKey = nickCursor.getString(lookupKeyIndex);
String nick = nickCursor.getString(nickNameIndex);
if (nick != null && lookupKey != null && mapContacts.containsKey(lookupKey)) {
for (ContactsPojo contact : mapContacts.get(lookupKey)) {
contact.setNickname(nick);
}
}
}
}
nickCursor.close();
}
ArrayList<ContactsPojo> contacts = new ArrayList<>();
Pattern phoneFormatter = Pattern.compile("[ \\.\\(\\)]");
for (List<ContactsPojo> phones : mapContacts.values()) {
// Find primary phone and add this one.
Boolean hasPrimary = false;
for (ContactsPojo contact : phones) {
if (contact.primary) {
contacts.add(contact);
hasPrimary = true;
break;
}
}
// If not available, add all (excluding duplicates).
if (!hasPrimary) {
Map<String, Boolean> added = new HashMap<>();
for (ContactsPojo contact : phones) {
String uniqueKey = phoneFormatter.matcher(contact.phone).replaceAll("");
// TODO: what's this supposed to do?
//uniqueKey = uniqueKey.replaceAll("^\\+33", "0");
//uniqueKey = uniqueKey.replaceAll("^\\+1", "0");
if (!added.containsKey(uniqueKey)) {
added.put(uniqueKey, true);
contacts.add(contact);
}
}
}
}
long end = System.nanoTime();
Log.i("time", Long.toString((end - start) / 1000000) + " milliseconds to list contacts");
return contacts;
}
}