Use resolved recipients in the conversation list.

This commit is contained in:
Greyson Parrelli
2020-07-02 08:19:52 -07:00
parent 70e33518a9
commit c877aba09f
9 changed files with 192 additions and 82 deletions

View File

@@ -40,7 +40,6 @@ public final class LiveRecipient {
private final AtomicReference<Recipient> recipient;
private final RecipientDatabase recipientDatabase;
private final GroupDatabase groupDatabase;
private final String unnamedGroupName;
LiveRecipient(@NonNull Context context, @NonNull MutableLiveData<Recipient> liveData, @NonNull Recipient defaultRecipient) {
this.context = context.getApplicationContext();
@@ -48,7 +47,6 @@ public final class LiveRecipient {
this.recipient = new AtomicReference<>(defaultRecipient);
this.recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
this.groupDatabase = DatabaseFactory.getGroupDatabase(context);
this.unnamedGroupName = context.getString(R.string.RecipientProvider_unnamed_group);
this.observers = new CopyOnWriteArraySet<>();
this.foreverObserver = recipient -> {
for (RecipientForeverObserver o : observers) {
@@ -175,21 +173,13 @@ public final class LiveRecipient {
private @NonNull Recipient fetchAndCacheRecipientFromDisk(@NonNull RecipientId id) {
RecipientSettings settings = recipientDatabase.getRecipientSettings(id);
RecipientDetails details = settings.getGroupId() != null ? getGroupRecipientDetails(settings)
: getIndividualRecipientDetails(settings);
: RecipientDetails.forIndividual(context, settings);
Recipient recipient = new Recipient(id, details);
Recipient recipient = new Recipient(id, details, true);
RecipientIdCache.INSTANCE.put(recipient);
return recipient;
}
private @NonNull RecipientDetails getIndividualRecipientDetails(RecipientSettings settings) {
boolean systemContact = !TextUtils.isEmpty(settings.getSystemDisplayName());
boolean isLocalNumber = (settings.getE164() != null && settings.getE164().equals(TextSecurePreferences.getLocalNumber(context))) ||
(settings.getUuid() != null && settings.getUuid().equals(TextSecurePreferences.getLocalUuid(context)));
return new RecipientDetails(context, null, Optional.absent(), systemContact, isLocalNumber, settings, null);
}
@WorkerThread
private @NonNull RecipientDetails getGroupRecipientDetails(@NonNull RecipientSettings settings) {
Optional<GroupRecord> groupRecord = groupDatabase.getGroup(settings.getId());
@@ -199,21 +189,17 @@ public final class LiveRecipient {
List<Recipient> members = Stream.of(groupRecord.get().getMembers()).filterNot(RecipientId::isUnknown).map(this::fetchAndCacheRecipientFromDisk).toList();
Optional<Long> avatarId = Optional.absent();
if (settings.getGroupId() != null && settings.getGroupId().isPush() && title == null) {
title = unnamedGroupName;
}
if (groupRecord.get().hasAvatar()) {
avatarId = Optional.of(groupRecord.get().getAvatarId());
}
return new RecipientDetails(context, title, avatarId, false, false, settings, members);
return new RecipientDetails(title, avatarId, false, false, settings, members);
}
return new RecipientDetails(context, unnamedGroupName, Optional.absent(), false, false, settings, null);
return new RecipientDetails(null, Optional.absent(), false, false, settings, null);
}
private synchronized void set(@NonNull Recipient recipient) {
synchronized void set(@NonNull Recipient recipient) {
this.recipient.set(recipient);
this.liveData.postValue(recipient);
}

View File

@@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -75,6 +76,40 @@ public final class LiveRecipientCache {
return live;
}
/**
* Adds a recipient to the cache if we don't have an entry. This will also update a cache entry
* if the provided recipient is resolved, or if the existing cache entry is unresolved.
*
* If the recipient you add is unresolved, this will enqueue a resolve on a background thread.
*/
@AnyThread
public synchronized void addToCache(@NonNull Collection<Recipient> newRecipients) {
for (Recipient recipient : newRecipients) {
LiveRecipient live = recipients.get(recipient.getId());
boolean needsResolve = false;
if (live == null) {
live = new LiveRecipient(context, new MutableLiveData<>(), recipient);
recipients.put(recipient.getId(), live);
needsResolve = recipient.isResolving();
} else if (live.get().isResolving() || !recipient.isResolving()) {
live.set(recipient);
needsResolve = recipient.isResolving();
}
if (needsResolve) {
MissingRecipientException prettyStackTraceError = new MissingRecipientException(recipient.getId());
SignalExecutors.BOUNDED.execute(() -> {
try {
recipient.resolve();
} catch (MissingRecipientException e) {
throw prettyStackTraceError;
}
});
}
}
}
@NonNull Recipient getSelf() {
synchronized (this) {
if (localRecipientId == null) {
@@ -107,23 +142,22 @@ public final class LiveRecipientCache {
}
SignalExecutors.BOUNDED.execute(() -> {
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
List<Recipient> recipients = new ArrayList<>();
try (ThreadDatabase.Reader reader = threadDatabase.readerFor(threadDatabase.getConversationList())) {
int i = 0;
ThreadRecord record = null;
List<Recipient> recipients = new ArrayList<>();
int i = 0;
ThreadRecord record = null;
while ((record = reader.getNext()) != null && i < CACHE_WARM_MAX) {
recipients.add(record.getRecipient());
i++;
}
Log.d(TAG, "Warming up " + recipients.size() + " recipients.");
Collections.reverse(recipients);
Stream.of(recipients).map(Recipient::getId).forEach(this::getLive);
}
Log.d(TAG, "Warming up " + recipients.size() + " recipients.");
Collections.reverse(recipients);
Stream.of(recipients).map(Recipient::getId).forEach(this::getLive);
});
}

View File

@@ -54,7 +54,7 @@ import static org.thoughtcrime.securesms.database.RecipientDatabase.InsightsBann
public class Recipient {
public static final Recipient UNKNOWN = new Recipient(RecipientId.UNKNOWN, new RecipientDetails());
public static final Recipient UNKNOWN = new Recipient(RecipientId.UNKNOWN, new RecipientDetails(), true);
private static final FallbackPhotoProvider DEFAULT_FALLBACK_PHOTO_PROVIDER = new FallbackPhotoProvider();
private static final String TAG = Log.tag(Recipient.class);
@@ -344,9 +344,9 @@ public class Recipient {
this.identityStatus = VerifiedStatus.DEFAULT;
}
Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details) {
public Recipient(@NonNull RecipientId id, @NonNull RecipientDetails details, boolean resolved) {
this.id = id;
this.resolving = false;
this.resolving = !resolved;
this.uuid = details.uuid;
this.username = details.username;
this.e164 = details.e164;
@@ -408,9 +408,11 @@ public class Recipient {
}
return Util.join(names, ", ");
} else if (name == null && groupId != null && groupId.isPush()) {
return context.getString(R.string.RecipientProvider_unnamed_group);
} else {
return this.name;
}
return this.name;
}
/**
@@ -657,7 +659,7 @@ public class Recipient {
public @NonNull FallbackContactPhoto getFallbackContactPhoto(@NonNull FallbackPhotoProvider fallbackPhotoProvider) {
if (localNumber) return fallbackPhotoProvider.getPhotoForLocalNumber();
if (isResolving()) return fallbackPhotoProvider.getPhotoForResolvingRecipient();
else if (isResolving()) return fallbackPhotoProvider.getPhotoForResolvingRecipient();
else if (isGroupInternal()) return fallbackPhotoProvider.getPhotoForGroup();
else if (isGroup()) return fallbackPhotoProvider.getPhotoForGroup();
else if (!TextUtils.isEmpty(name)) return fallbackPhotoProvider.getPhotoForRecipientWithName(name);

View File

@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.recipients;
import android.content.Context;
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -66,13 +67,12 @@ public class RecipientDetails {
final byte[] identityKey;
final VerifiedStatus identityStatus;
RecipientDetails(@NonNull Context context,
@Nullable String name,
@NonNull Optional<Long> groupAvatarId,
boolean systemContact,
boolean isLocalNumber,
@NonNull RecipientSettings settings,
@Nullable List<Recipient> participants)
public RecipientDetails(@Nullable String name,
@NonNull Optional<Long> groupAvatarId,
boolean systemContact,
boolean isLocalNumber,
@NonNull RecipientSettings settings,
@Nullable List<Recipient> participants)
{
this.groupAvatarId = groupAvatarId;
this.systemContactPhoto = Util.uri(settings.getSystemContactPhotoUri());
@@ -161,4 +161,12 @@ public class RecipientDetails {
this.identityKey = null;
this.identityStatus = VerifiedStatus.DEFAULT;
}
public static @NonNull RecipientDetails forIndividual(@NonNull Context context, @NonNull RecipientSettings settings) {
boolean systemContact = !TextUtils.isEmpty(settings.getSystemDisplayName());
boolean isLocalNumber = (settings.getE164() != null && settings.getE164().equals(TextSecurePreferences.getLocalNumber(context))) ||
(settings.getUuid() != null && settings.getUuid().equals(TextSecurePreferences.getLocalUuid(context)));
return new RecipientDetails(null, Optional.absent(), systemContact, isLocalNumber, settings, null);
}
}