PhoneNumberContact.java

  1package eu.siacs.conversations.android;
  2
  3import android.Manifest;
  4import android.content.Context;
  5import android.content.pm.PackageManager;
  6import android.database.Cursor;
  7import android.net.Uri;
  8import android.os.Build;
  9import android.provider.ContactsContract;
 10import android.util.Log;
 11
 12import com.google.common.collect.ImmutableMap;
 13import com.google.common.collect.HashMultimap;
 14import com.google.common.collect.Multimap;
 15
 16import java.util.ArrayList;
 17import java.util.Collection;
 18import java.util.Collections;
 19import java.util.HashMap;
 20import java.util.Map;
 21
 22import eu.siacs.conversations.Config;
 23import eu.siacs.conversations.utils.PhoneNumberUtilWrapper;
 24import io.michaelrocks.libphonenumber.android.NumberParseException;
 25
 26public class PhoneNumberContact extends AbstractPhoneContact {
 27
 28    private final String phoneNumber;
 29    private final String typeLabel;
 30    private final Collection<String> groups;
 31
 32    public String getPhoneNumber() {
 33        return phoneNumber;
 34    }
 35
 36    public String getTypeLabel() {
 37        return typeLabel;
 38    }
 39
 40    public Collection<String> getTags() {
 41        Collection<String> tags = new ArrayList(groups);
 42        tags.add(typeLabel);
 43        return tags;
 44    }
 45
 46    public Collection<String> getGroups() {
 47        return groups;
 48    }
 49
 50    private PhoneNumberContact(Context context, Cursor cursor, Collection<String> groups) throws IllegalArgumentException {
 51        super(cursor);
 52        try {
 53            this.phoneNumber = PhoneNumberUtilWrapper.normalize(context, cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
 54            this.typeLabel = ContactsContract.CommonDataKinds.Phone.getTypeLabel(
 55                context.getResources(),
 56                cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE)),
 57                cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.LABEL))
 58            ).toString();
 59            this.groups = groups;
 60        } catch (NumberParseException | NullPointerException e) {
 61            throw new IllegalArgumentException(e);
 62        }
 63    }
 64
 65    public static ImmutableMap<String, PhoneNumberContact> load(Context context) {
 66        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
 67            return ImmutableMap.of();
 68        }
 69
 70        final HashMap<String, String> groupTitles = new HashMap<>();
 71        try (final Cursor groups = context.getContentResolver().query(
 72            ContactsContract.Groups.CONTENT_URI,
 73            new String[]{
 74                ContactsContract.Groups._ID,
 75                ContactsContract.Groups.TITLE
 76            }, null, null, null
 77        )) {
 78            while (groups != null && groups.moveToNext()) {
 79                groupTitles.put(groups.getString(0), groups.getString(1));
 80            }
 81        } catch (final Exception e) {
 82            return ImmutableMap.of();
 83        }
 84
 85        final Multimap<String, String> contactGroupMap = HashMultimap.create();
 86        try(final Cursor contactGroups = context.getContentResolver().query(
 87            ContactsContract.Data.CONTENT_URI,
 88            new String[]{
 89                ContactsContract.Data.CONTACT_ID,
 90                ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID
 91            },
 92            ContactsContract.Data.MIMETYPE + "=?",
 93            new String[]{ContactsContract.CommonDataKinds.GroupMembership.CONTENT_ITEM_TYPE},
 94            null
 95        )) {
 96            while (contactGroups != null && contactGroups.moveToNext()) {
 97                final String groupTitle = groupTitles.get(contactGroups.getString(1));
 98                if (groupTitle != null) contactGroupMap.put(contactGroups.getString(0), groupTitle);
 99            }
100        } catch (final Exception e) {
101            return ImmutableMap.of();
102        }
103
104        final String[] PROJECTION = new String[]{
105                ContactsContract.Data._ID,
106                ContactsContract.Data.CONTACT_ID,
107                ContactsContract.Data.DISPLAY_NAME,
108                ContactsContract.Data.PHOTO_URI,
109                ContactsContract.Data.LOOKUP_KEY,
110                ContactsContract.CommonDataKinds.Phone.TYPE,
111                ContactsContract.CommonDataKinds.Phone.LABEL,
112                ContactsContract.CommonDataKinds.Phone.NUMBER};
113        final HashMap<String, PhoneNumberContact> contacts = new HashMap<>();
114        try (final Cursor cursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null)){
115            while (cursor != null && cursor.moveToNext()) {
116                try {
117                    final PhoneNumberContact contact = new PhoneNumberContact(context, cursor, contactGroupMap.get(cursor.getString(1)));
118                    final PhoneNumberContact preexisting = contacts.get(contact.getPhoneNumber());
119                    if (preexisting == null || preexisting.rating() < contact.rating()) {
120                        contacts.put(contact.getPhoneNumber(), contact);
121                    }
122                } catch (final IllegalArgumentException ignored) {
123
124                }
125            }
126        } catch (final Exception e) {
127            return ImmutableMap.of();
128        }
129        return ImmutableMap.copyOf(contacts);
130    }
131
132    public static PhoneNumberContact findByUriOrNumber(Collection<PhoneNumberContact> haystack, Uri uri, String number) {
133        final PhoneNumberContact byUri = findByUri(haystack, uri);
134        return byUri != null || number == null ? byUri : findByNumber(haystack, number);
135    }
136
137    public static PhoneNumberContact findByUri(Collection<PhoneNumberContact> haystack, Uri needle) {
138        for (PhoneNumberContact contact : haystack) {
139            if (needle.equals(contact.getLookupUri())) {
140                return contact;
141            }
142        }
143        return null;
144    }
145
146    private static PhoneNumberContact findByNumber(Collection<PhoneNumberContact> haystack, String needle) {
147        for (PhoneNumberContact contact : haystack) {
148            if (needle.equals(contact.getPhoneNumber())) {
149                return contact;
150            }
151        }
152        return null;
153    }
154}