handle on-device contacts with unstable system uri

on device contacts (contacts not synced) have an unstable system uri.
For quicksy.im contacts we can identify the contact based on the phone number
instead.

fixes #4174
This commit is contained in:
Daniel Gultsch 2021-09-21 10:20:21 +02:00
parent d5994a8d65
commit 75c20a7a2b
5 changed files with 58 additions and 30 deletions

View file

@ -1,2 +1,11 @@
package eu.siacs.conversations.utils;public class PhoneNumberUtilWrapper { package eu.siacs.conversations.utils;
import android.content.Context;
import eu.siacs.conversations.xmpp.Jid;
public class PhoneNumberUtilWrapper {
public static String toFormattedPhoneNumber(Context context, Jid jid) {
throw new AssertionError("This method is not implemented in Conversations");
}
} }

View file

@ -538,6 +538,7 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
@Override @Override
protected void onStart() { protected void onStart() {
super.onStart();
final int theme = findTheme(); final int theme = findTheme();
if (this.mTheme != theme) { if (this.mTheme != theme) {
this.mSkipBackgroundBinding = true; this.mSkipBackgroundBinding = true;
@ -546,7 +547,6 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
this.mSkipBackgroundBinding = false; this.mSkipBackgroundBinding = false;
} }
mRedirectInProcess.set(false); mRedirectInProcess.set(false);
super.onStart();
} }
@Override @Override

View file

@ -46,30 +46,30 @@ public class PhoneNumberContact extends AbstractPhoneContact {
ContactsContract.Data.PHOTO_URI, ContactsContract.Data.PHOTO_URI,
ContactsContract.Data.LOOKUP_KEY, ContactsContract.Data.LOOKUP_KEY,
ContactsContract.CommonDataKinds.Phone.NUMBER}; ContactsContract.CommonDataKinds.Phone.NUMBER};
final Cursor cursor; final HashMap<String, PhoneNumberContact> contacts = new HashMap<>();
try { try (final Cursor cursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null)){
cursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null); while (cursor != null && cursor.moveToNext()) {
try {
final PhoneNumberContact contact = new PhoneNumberContact(context, cursor);
final PhoneNumberContact preexisting = contacts.get(contact.getPhoneNumber());
if (preexisting == null || preexisting.rating() < contact.rating()) {
contacts.put(contact.getPhoneNumber(), contact);
}
} catch (final IllegalArgumentException ignored) {
}
}
} catch (final Exception e) { } catch (final Exception e) {
return ImmutableMap.of(); return ImmutableMap.of();
} }
final HashMap<String, PhoneNumberContact> contacts = new HashMap<>();
while (cursor != null && cursor.moveToNext()) {
try {
final PhoneNumberContact contact = new PhoneNumberContact(context, cursor);
final PhoneNumberContact preexisting = contacts.get(contact.getPhoneNumber());
if (preexisting == null || preexisting.rating() < contact.rating()) {
contacts.put(contact.getPhoneNumber(), contact);
}
} catch (final IllegalArgumentException e) {
Log.d(Config.LOGTAG, e.getMessage());
}
}
if (cursor != null) {
cursor.close();
}
return ImmutableMap.copyOf(contacts); return ImmutableMap.copyOf(contacts);
} }
public static PhoneNumberContact findByUriOrNumber(Collection<PhoneNumberContact> haystack, Uri uri, String number) {
final PhoneNumberContact byUri = findByUri(haystack, uri);
return byUri != null || number == null ? byUri : findByNumber(haystack, number);
}
public static PhoneNumberContact findByUri(Collection<PhoneNumberContact> haystack, Uri needle) { public static PhoneNumberContact findByUri(Collection<PhoneNumberContact> haystack, Uri needle) {
for (PhoneNumberContact contact : haystack) { for (PhoneNumberContact contact : haystack) {
if (needle.equals(contact.getLookupUri())) { if (needle.equals(contact.getLookupUri())) {
@ -78,4 +78,13 @@ public class PhoneNumberContact extends AbstractPhoneContact {
} }
return null; return null;
} }
private static PhoneNumberContact findByNumber(Collection<PhoneNumberContact> haystack, String needle) {
for (PhoneNumberContact contact : haystack) {
if (needle.equals(contact.getPhoneNumber())) {
return contact;
}
}
return null;
}
} }

View file

@ -2,6 +2,9 @@ package eu.siacs.conversations.entities;
import android.util.Base64; import android.util.Base64;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
@ -63,20 +66,15 @@ public class Entry implements Comparable<Entry> {
builder.append(jid.asBareJid().toEscapedString()); builder.append(jid.asBareJid().toEscapedString());
} }
} }
MessageDigest md; @SuppressWarnings("deprecation")
try { final byte[] sha1 = Hashing.sha1().hashString(builder.toString(), Charsets.UTF_8).asBytes();
md = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
return "";
}
byte[] sha1 = md.digest(builder.toString().getBytes());
return new String(Base64.encode(sha1, Base64.DEFAULT)).trim(); return new String(Base64.encode(sha1, Base64.DEFAULT)).trim();
} }
private static List<Entry> ofPhoneNumberContactsAndContacts(final Collection<PhoneNumberContact> phoneNumberContacts, Collection<Contact> systemContacts) { private static List<Entry> ofPhoneNumberContactsAndContacts(final Collection<PhoneNumberContact> phoneNumberContacts, Collection<Contact> systemContacts) {
ArrayList<Entry> entries = new ArrayList<>(); final ArrayList<Entry> entries = new ArrayList<>();
for(Contact contact : systemContacts) { for(Contact contact : systemContacts) {
PhoneNumberContact phoneNumberContact = PhoneNumberContact.findByUri(phoneNumberContacts, contact.getSystemAccount()); final PhoneNumberContact phoneNumberContact = PhoneNumberContact.findByUri(phoneNumberContacts, contact.getSystemAccount());
if (phoneNumberContact != null && phoneNumberContact.getPhoneNumber() != null) { if (phoneNumberContact != null && phoneNumberContact.getPhoneNumber() != null) {
Entry entry = findOrCreateByPhoneNumber(entries, phoneNumberContact.getPhoneNumber()); Entry entry = findOrCreateByPhoneNumber(entries, phoneNumberContact.getPhoneNumber());
entry.jids.add(contact.getJid().asBareJid()); entry.jids.add(contact.getJid().asBareJid());

View file

@ -382,9 +382,13 @@ public class QuickConversationsService extends AbstractQuickConversationsService
if (uri == null) { if (uri == null) {
continue; continue;
} }
PhoneNumberContact phoneNumberContact = PhoneNumberContact.findByUri(contacts, uri); final String number = getNumber(contact);
final PhoneNumberContact phoneNumberContact = PhoneNumberContact.findByUriOrNumber(contacts, uri, number);
final boolean needsCacheClean; final boolean needsCacheClean;
if (phoneNumberContact != null) { if (phoneNumberContact != null) {
if (!uri.equals(phoneNumberContact.getLookupUri())) {
Log.d(Config.LOGTAG, "lookupUri has changed from " + uri + " to " + phoneNumberContact.getLookupUri());
}
needsCacheClean = contact.setPhoneContact(phoneNumberContact); needsCacheClean = contact.setPhoneContact(phoneNumberContact);
} else { } else {
needsCacheClean = contact.unsetPhoneContact(PhoneNumberContact.class); needsCacheClean = contact.unsetPhoneContact(PhoneNumberContact.class);
@ -396,6 +400,14 @@ public class QuickConversationsService extends AbstractQuickConversationsService
} }
} }
private static String getNumber(final Contact contact) {
final Jid jid = contact.getJid();
if (jid.getLocal() != null && Config.QUICKSY_DOMAIN.equals(jid.getDomain())) {
return jid.getLocal();
}
return null;
}
private boolean considerSync(final 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(); final int hash = contacts.keySet().hashCode();
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": consider sync of " + hash); Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": consider sync of " + hash);