do not include own phone number in sycn

Daniel Gultsch created

fixes #3960

Change summary

src/compat/java/eu/siacs/conversations/ui/widget/EmojiWrapperEditText.java      |  3 
src/quicksy/java/eu/siacs/conversations/android/PhoneNumberContact.java         | 22 
src/quicksy/java/eu/siacs/conversations/services/QuickConversationsService.java | 42 
src/quicksy/java/eu/siacs/conversations/utils/PhoneNumberUtilWrapper.java       |  2 
4 files changed, 44 insertions(+), 25 deletions(-)

Detailed changes

src/compat/java/eu/siacs/conversations/ui/widget/EmojiWrapperEditText.java 🔗

@@ -1,9 +1,10 @@
 package eu.siacs.conversations.ui.widget;
 
 import android.content.Context;
-import androidx.emoji.widget.EmojiAppCompatEditText;
 import android.util.AttributeSet;
 
+import androidx.emoji.widget.EmojiAppCompatEditText;
+
 public class EmojiWrapperEditText extends EmojiAppCompatEditText {
 
     public EmojiWrapperEditText(Context context) {

src/quicksy/java/eu/siacs/conversations/android/PhoneNumberContact.java 🔗

@@ -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;
             }

src/quicksy/java/eu/siacs/conversations/services/QuickConversationsService.java 🔗

@@ -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);

src/quicksy/java/eu/siacs/conversations/utils/PhoneNumberUtilWrapper.java 🔗

@@ -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);
     }