@@ -9,6 +9,8 @@ import android.os.Build;
import android.provider.ContactsContract;
import android.util.Log;
+import com.google.common.collect.ImmutableMap;
+
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -20,7 +22,7 @@ import io.michaelrocks.libphonenumber.android.NumberParseException;
public class PhoneNumberContact extends AbstractPhoneContact {
- private String phoneNumber;
+ private final String phoneNumber;
public String getPhoneNumber() {
return phoneNumber;
@@ -29,15 +31,15 @@ public class PhoneNumberContact extends AbstractPhoneContact {
private PhoneNumberContact(Context context, Cursor cursor) throws IllegalArgumentException {
super(cursor);
try {
- this.phoneNumber = PhoneNumberUtilWrapper.normalize(context,cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
+ this.phoneNumber = PhoneNumberUtilWrapper.normalize(context, cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
} catch (NumberParseException | NullPointerException e) {
throw new IllegalArgumentException(e);
}
}
- public static Map<String, PhoneNumberContact> load(Context context) {
+ public static ImmutableMap<String, PhoneNumberContact> load(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
- return Collections.emptyMap();
+ return ImmutableMap.of();
}
final String[] PROJECTION = new String[]{ContactsContract.Data._ID,
ContactsContract.Data.DISPLAY_NAME,
@@ -47,8 +49,8 @@ public class PhoneNumberContact extends AbstractPhoneContact {
final Cursor cursor;
try {
cursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null);
- } catch (Exception e) {
- return Collections.emptyMap();
+ } catch (final Exception e) {
+ return ImmutableMap.of();
}
final HashMap<String, PhoneNumberContact> contacts = new HashMap<>();
while (cursor != null && cursor.moveToNext()) {
@@ -58,18 +60,18 @@ public class PhoneNumberContact extends AbstractPhoneContact {
if (preexisting == null || preexisting.rating() < contact.rating()) {
contacts.put(contact.getPhoneNumber(), contact);
}
- } catch (IllegalArgumentException e) {
- Log.d(Config.LOGTAG, "unable to create phone contact");
+ } catch (final IllegalArgumentException e) {
+ Log.d(Config.LOGTAG, e.getMessage());
}
}
if (cursor != null) {
cursor.close();
}
- return contacts;
+ return ImmutableMap.copyOf(contacts);
}
public static PhoneNumberContact findByUri(Collection<PhoneNumberContact> haystack, Uri needle) {
- for(PhoneNumberContact contact : haystack) {
+ for (PhoneNumberContact contact : haystack) {
if (needle.equals(contact.getLookupUri())) {
return contact;
}
@@ -9,6 +9,8 @@ import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.Log;
+import com.google.common.collect.ImmutableMap;
+
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
@@ -24,6 +26,7 @@ import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -350,8 +353,12 @@ public class QuickConversationsService extends AbstractQuickConversationsService
private void considerSync(boolean forced) {
- Map<String, PhoneNumberContact> contacts = PhoneNumberContact.load(service);
- for (Account account : service.getAccounts()) {
+ final ImmutableMap<String, PhoneNumberContact> allContacts = PhoneNumberContact.load(service);
+ for (final Account account : service.getAccounts()) {
+ final Map<String, PhoneNumberContact> contacts = filtered(allContacts, account.getJid().getLocal());
+ if (contacts.size() < allContacts.size()) {
+ Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": found own phone number in address book. ignoring...");
+ }
refresh(account, contacts.values());
if (!considerSync(account, contacts, forced)) {
service.syncRoster(account);
@@ -359,6 +366,15 @@ public class QuickConversationsService extends AbstractQuickConversationsService
}
}
+ @SafeVarargs
+ private static <A, B> Map<A, B> filtered(final Map<A, B> input, final A... filters) {
+ final HashMap<A, B> result = new HashMap<>(input);
+ for (final A filtered : filters) {
+ result.remove(filtered);
+ }
+ return result;
+ }
+
private void refresh(Account account, Collection<PhoneNumberContact> contacts) {
for (Contact contact : account.getRoster().getWithSystemAccounts(PhoneNumberContact.class)) {
final Uri uri = contact.getSystemAccount();
@@ -379,7 +395,7 @@ public class QuickConversationsService extends AbstractQuickConversationsService
}
}
- private boolean considerSync(Account account, final Map<String, PhoneNumberContact> contacts, final boolean forced) {
+ private boolean considerSync(final Account account, final Map<String, PhoneNumberContact> contacts, final boolean forced) {
final int hash = contacts.keySet().hashCode();
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": consider sync of " + hash);
if (!mLastSyncAttempt.retry(hash) && !forced) {
@@ -389,14 +405,14 @@ public class QuickConversationsService extends AbstractQuickConversationsService
mRunningSyncJobs.incrementAndGet();
final Jid syncServer = Jid.of(API_DOMAIN);
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": sending phone list to " + syncServer);
- List<Element> entries = new ArrayList<>();
- for (PhoneNumberContact c : contacts.values()) {
+ final List<Element> entries = new ArrayList<>();
+ for (final PhoneNumberContact c : contacts.values()) {
entries.add(new Element("entry").setAttribute("number", c.getPhoneNumber()));
}
- IqPacket query = new IqPacket(IqPacket.TYPE.GET);
+ final IqPacket query = new IqPacket(IqPacket.TYPE.GET);
query.setTo(syncServer);
- Element book = new Element("phone-book", Namespace.SYNCHRONIZATION).setChildren(entries);
- String statusQuo = Entry.statusQuo(contacts.values(), account.getRoster().getWithSystemAccounts(PhoneNumberContact.class));
+ final Element book = new Element("phone-book", Namespace.SYNCHRONIZATION).setChildren(entries);
+ final String statusQuo = Entry.statusQuo(contacts.values(), account.getRoster().getWithSystemAccounts(PhoneNumberContact.class));
book.setAttribute("ver", statusQuo);
query.addChild(book);
mLastSyncAttempt = Attempt.create(hash);
@@ -404,14 +420,14 @@ public class QuickConversationsService extends AbstractQuickConversationsService
if (response.getType() == IqPacket.TYPE.RESULT) {
final Element phoneBook = response.findChild("phone-book", Namespace.SYNCHRONIZATION);
if (phoneBook != null) {
- List<Contact> withSystemAccounts = account.getRoster().getWithSystemAccounts(PhoneNumberContact.class);
+ final List<Contact> withSystemAccounts = account.getRoster().getWithSystemAccounts(PhoneNumberContact.class);
for (Entry entry : Entry.ofPhoneBook(phoneBook)) {
- PhoneNumberContact phoneContact = contacts.get(entry.getNumber());
+ final PhoneNumberContact phoneContact = contacts.get(entry.getNumber());
if (phoneContact == null) {
continue;
}
- for (Jid jid : entry.getJids()) {
- Contact contact = account.getRoster().getContact(jid);
+ for (final Jid jid : entry.getJids()) {
+ final Contact contact = account.getRoster().getContact(jid);
final boolean needsCacheClean = contact.setPhoneContact(phoneContact);
if (needsCacheClean) {
service.getAvatarService().clear(contact);
@@ -419,7 +435,7 @@ public class QuickConversationsService extends AbstractQuickConversationsService
withSystemAccounts.remove(contact);
}
}
- for (Contact contact : withSystemAccounts) {
+ for (final Contact contact : withSystemAccounts) {
final boolean needsCacheClean = contact.unsetPhoneContact(PhoneNumberContact.class);
if (needsCacheClean) {
service.getAvatarService().clear(contact);
@@ -37,7 +37,7 @@ public class PhoneNumberUtilWrapper {
public static String normalize(Context context, String input) throws IllegalArgumentException, NumberParseException {
final Phonenumber.PhoneNumber number = getInstance(context).parse(input, LocationProvider.getUserCountry(context));
if (!getInstance(context).isValidNumber(number)) {
- throw new IllegalArgumentException("Not a valid phone number");
+ throw new IllegalArgumentException(String.format("%s is not a valid phone number", input));
}
return normalize(context, number);
}