Use resolved recipients in the conversation list.
This commit is contained in:
parent
70e33518a9
commit
c877aba09f
9 changed files with 192 additions and 82 deletions
|
@ -13,13 +13,16 @@ import org.thoughtcrime.securesms.database.DatabaseContentProviders;
|
|||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.ThrottledDebouncer;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||
import org.thoughtcrime.securesms.util.paging.Invalidator;
|
||||
import org.thoughtcrime.securesms.util.paging.SizeFixResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
|
@ -66,15 +69,19 @@ abstract class ConversationListDataSource extends PositionalDataSource<Conversat
|
|||
List<Conversation> conversations = new ArrayList<>(params.requestedLoadSize);
|
||||
int totalCount = getTotalCount();
|
||||
int effectiveCount = params.requestedStartPosition;
|
||||
List<Recipient> recipients = new LinkedList<>();
|
||||
|
||||
try (ThreadDatabase.Reader reader = threadDatabase.readerFor(getCursor(params.requestedStartPosition, params.requestedLoadSize))) {
|
||||
ThreadRecord record;
|
||||
while ((record = reader.getNext()) != null && effectiveCount < totalCount && !isInvalid()) {
|
||||
conversations.add(new Conversation(record));
|
||||
recipients.add(record.getRecipient());
|
||||
effectiveCount++;
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationDependencies.getRecipientCache().addToCache(recipients);
|
||||
|
||||
if (!isInvalid()) {
|
||||
SizeFixResult<Conversation> result = SizeFixResult.ensureMultipleOfPageSize(conversations, params.requestedStartPosition, params.pageSize, totalCount);
|
||||
|
||||
|
@ -89,14 +96,18 @@ abstract class ConversationListDataSource extends PositionalDataSource<Conversat
|
|||
long start = System.currentTimeMillis();
|
||||
|
||||
List<Conversation> conversations = new ArrayList<>(params.loadSize);
|
||||
List<Recipient> recipients = new LinkedList<>();
|
||||
|
||||
try (ThreadDatabase.Reader reader = threadDatabase.readerFor(getCursor(params.startPosition, params.loadSize))) {
|
||||
ThreadRecord record;
|
||||
while ((record = reader.getNext()) != null && !isInvalid()) {
|
||||
conversations.add(new Conversation(record));
|
||||
recipients.add(record.getRecipient());
|
||||
}
|
||||
}
|
||||
|
||||
ApplicationDependencies.getRecipientCache().addToCache(recipients);
|
||||
|
||||
callback.onResult(conversations);
|
||||
|
||||
Log.d(TAG, "[Update] " + (System.currentTimeMillis() - start) + " ms | start: " + params.startPosition + ", size: " + params.loadSize + ", class: " + getClass().getSimpleName() + (isInvalid() ? " -- invalidated" : ""));
|
||||
|
|
|
@ -96,7 +96,7 @@ public final class GroupDatabase extends Database {
|
|||
|
||||
private static final String[] GROUP_PROJECTION = {
|
||||
GROUP_ID, RECIPIENT_ID, TITLE, MEMBERS, AVATAR_ID, AVATAR_KEY, AVATAR_CONTENT_TYPE, AVATAR_RELAY, AVATAR_DIGEST,
|
||||
TIMESTAMP, ACTIVE, MMS
|
||||
TIMESTAMP, ACTIVE, MMS, V2_MASTER_KEY, V2_REVISION, V2_DECRYPTED_GROUP
|
||||
};
|
||||
|
||||
static final List<String> TYPED_GROUP_PROJECTION = Stream.of(GROUP_PROJECTION).map(columnName -> TABLE_NAME + "." + columnName).toList();
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
|||
import org.thoughtcrime.securesms.storage.StorageSyncHelper.RecordUpdate;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncModels;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.CursorUtil;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
import org.thoughtcrime.securesms.util.SqlUtil;
|
||||
|
@ -827,44 +828,45 @@ public class RecipientDatabase extends Database {
|
|||
return out;
|
||||
}
|
||||
|
||||
private static @NonNull RecipientSettings getRecipientSettings(@NonNull Context context, @NonNull Cursor cursor) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
UUID uuid = UuidUtil.parseOrNull(cursor.getString(cursor.getColumnIndexOrThrow(UUID)));
|
||||
String username = cursor.getString(cursor.getColumnIndexOrThrow(USERNAME));
|
||||
String e164 = cursor.getString(cursor.getColumnIndexOrThrow(PHONE));
|
||||
String email = cursor.getString(cursor.getColumnIndexOrThrow(EMAIL));
|
||||
GroupId groupId = GroupId.parseNullableOrThrow(cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID)));
|
||||
int groupType = cursor.getInt(cursor.getColumnIndexOrThrow(GROUP_TYPE));
|
||||
boolean blocked = cursor.getInt(cursor.getColumnIndexOrThrow(BLOCKED)) == 1;
|
||||
String messageRingtone = cursor.getString(cursor.getColumnIndexOrThrow(MESSAGE_RINGTONE));
|
||||
String callRingtone = cursor.getString(cursor.getColumnIndexOrThrow(CALL_RINGTONE));
|
||||
int messageVibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(MESSAGE_VIBRATE));
|
||||
int callVibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(CALL_VIBRATE));
|
||||
static @NonNull RecipientSettings getRecipientSettings(@NonNull Context context, @NonNull Cursor cursor) {
|
||||
long id = CursorUtil.requireLong(cursor, ID);
|
||||
UUID uuid = UuidUtil.parseOrNull(CursorUtil.requireString(cursor, UUID));
|
||||
String username = CursorUtil.requireString(cursor, USERNAME);
|
||||
String e164 = CursorUtil.requireString(cursor, PHONE);
|
||||
String email = CursorUtil.requireString(cursor, EMAIL);
|
||||
GroupId groupId = GroupId.parseNullableOrThrow(CursorUtil.requireString(cursor, GROUP_ID));
|
||||
int groupType = CursorUtil.requireInt(cursor, GROUP_TYPE);
|
||||
boolean blocked = CursorUtil.requireBoolean(cursor, BLOCKED);
|
||||
String messageRingtone = CursorUtil.requireString(cursor, MESSAGE_RINGTONE);
|
||||
String callRingtone = CursorUtil.requireString(cursor, CALL_RINGTONE);
|
||||
int messageVibrateState = CursorUtil.requireInt(cursor, MESSAGE_VIBRATE);
|
||||
int callVibrateState = CursorUtil.requireInt(cursor, CALL_VIBRATE);
|
||||
long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL));
|
||||
String serializedColor = cursor.getString(cursor.getColumnIndexOrThrow(COLOR));
|
||||
int insightsBannerTier = cursor.getInt(cursor.getColumnIndexOrThrow(SEEN_INVITE_REMINDER));
|
||||
int defaultSubscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(DEFAULT_SUBSCRIPTION_ID));
|
||||
int expireMessages = cursor.getInt(cursor.getColumnIndexOrThrow(MESSAGE_EXPIRATION_TIME));
|
||||
int registeredState = cursor.getInt(cursor.getColumnIndexOrThrow(REGISTERED));
|
||||
String profileKeyString = cursor.getString(cursor.getColumnIndexOrThrow(PROFILE_KEY));
|
||||
String profileKeyCredentialString = cursor.getString(cursor.getColumnIndexOrThrow(PROFILE_KEY_CREDENTIAL));
|
||||
String systemDisplayName = cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_DISPLAY_NAME));
|
||||
String systemContactPhoto = cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_PHOTO_URI));
|
||||
String systemPhoneLabel = cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_PHONE_LABEL));
|
||||
String systemContactUri = cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_CONTACT_URI));
|
||||
String profileGivenName = cursor.getString(cursor.getColumnIndexOrThrow(PROFILE_GIVEN_NAME));
|
||||
String profileFamilyName = cursor.getString(cursor.getColumnIndexOrThrow(PROFILE_FAMILY_NAME));
|
||||
String signalProfileAvatar = cursor.getString(cursor.getColumnIndexOrThrow(SIGNAL_PROFILE_AVATAR));
|
||||
boolean profileSharing = cursor.getInt(cursor.getColumnIndexOrThrow(PROFILE_SHARING)) == 1;
|
||||
String serializedColor = CursorUtil.requireString(cursor, COLOR);
|
||||
int insightsBannerTier = CursorUtil.requireInt(cursor, SEEN_INVITE_REMINDER);
|
||||
int defaultSubscriptionId = CursorUtil.requireInt(cursor, DEFAULT_SUBSCRIPTION_ID);
|
||||
int expireMessages = CursorUtil.requireInt(cursor, MESSAGE_EXPIRATION_TIME);
|
||||
int registeredState = CursorUtil.requireInt(cursor, REGISTERED);
|
||||
String profileKeyString = CursorUtil.requireString(cursor, PROFILE_KEY);
|
||||
String profileKeyCredentialString = CursorUtil.requireString(cursor, PROFILE_KEY_CREDENTIAL);
|
||||
String systemDisplayName = CursorUtil.requireString(cursor, SYSTEM_DISPLAY_NAME);
|
||||
String systemContactPhoto = CursorUtil.requireString(cursor, SYSTEM_PHOTO_URI);
|
||||
String systemPhoneLabel = CursorUtil.requireString(cursor, SYSTEM_PHONE_LABEL);
|
||||
String systemContactUri = CursorUtil.requireString(cursor, SYSTEM_CONTACT_URI);
|
||||
String profileGivenName = CursorUtil.requireString(cursor, PROFILE_GIVEN_NAME);
|
||||
String profileFamilyName = CursorUtil.requireString(cursor, PROFILE_FAMILY_NAME);
|
||||
String signalProfileAvatar = CursorUtil.requireString(cursor, SIGNAL_PROFILE_AVATAR);
|
||||
boolean profileSharing = CursorUtil.requireBoolean(cursor, PROFILE_SHARING);
|
||||
long lastProfileFetch = cursor.getLong(cursor.getColumnIndexOrThrow(LAST_PROFILE_FETCH));
|
||||
String notificationChannel = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION_CHANNEL));
|
||||
int unidentifiedAccessMode = cursor.getInt(cursor.getColumnIndexOrThrow(UNIDENTIFIED_ACCESS_MODE));
|
||||
boolean forceSmsSelection = cursor.getInt(cursor.getColumnIndexOrThrow(FORCE_SMS_SELECTION)) == 1;
|
||||
int uuidCapabilityValue = cursor.getInt(cursor.getColumnIndexOrThrow(UUID_CAPABILITY));
|
||||
int groupsV2CapabilityValue = cursor.getInt(cursor.getColumnIndexOrThrow(GROUPS_V2_CAPABILITY));
|
||||
String storageKeyRaw = cursor.getString(cursor.getColumnIndexOrThrow(STORAGE_SERVICE_ID));
|
||||
String identityKeyRaw = cursor.getString(cursor.getColumnIndexOrThrow(IDENTITY_KEY));
|
||||
int identityStatusRaw = cursor.getInt(cursor.getColumnIndexOrThrow(IDENTITY_STATUS));
|
||||
String notificationChannel = CursorUtil.requireString(cursor, NOTIFICATION_CHANNEL);
|
||||
int unidentifiedAccessMode = CursorUtil.requireInt(cursor, UNIDENTIFIED_ACCESS_MODE);
|
||||
boolean forceSmsSelection = CursorUtil.requireBoolean(cursor, FORCE_SMS_SELECTION);
|
||||
int uuidCapabilityValue = CursorUtil.requireInt(cursor, UUID_CAPABILITY);
|
||||
int groupsV2CapabilityValue = CursorUtil.requireInt(cursor, GROUPS_V2_CAPABILITY);
|
||||
String storageKeyRaw = CursorUtil.requireString(cursor, STORAGE_SERVICE_ID);
|
||||
|
||||
Optional<String> identityKeyRaw = CursorUtil.getString(cursor, IDENTITY_KEY);
|
||||
Optional<Integer> identityStatusRaw = CursorUtil.getInt(cursor, IDENTITY_STATUS);
|
||||
|
||||
int masterKeyIndex = cursor.getColumnIndex(GroupDatabase.V2_MASTER_KEY);
|
||||
GroupMasterKey groupMasterKey = null;
|
||||
|
@ -909,9 +911,9 @@ public class RecipientDatabase extends Database {
|
|||
}
|
||||
|
||||
byte[] storageKey = storageKeyRaw != null ? Base64.decodeOrThrow(storageKeyRaw) : null;
|
||||
byte[] identityKey = identityKeyRaw != null ? Base64.decodeOrThrow(identityKeyRaw) : null;
|
||||
byte[] identityKey = identityKeyRaw.transform(Base64::decodeOrThrow).orNull();;
|
||||
|
||||
IdentityDatabase.VerifiedStatus identityStatus = IdentityDatabase.VerifiedStatus.forState(identityStatusRaw);
|
||||
IdentityDatabase.VerifiedStatus identityStatus = identityStatusRaw.transform(IdentityDatabase.VerifiedStatus::forState).or(IdentityDatabase.VerifiedStatus.DEFAULT);
|
||||
|
||||
return new RecipientSettings(RecipientId.from(id), uuid, username, e164, email, groupId, groupMasterKey, GroupType.fromId(groupType), blocked, muteUntil,
|
||||
VibrateState.fromId(messageVibrateState),
|
||||
|
|
|
@ -33,6 +33,7 @@ import net.sqlcipher.database.SQLiteDatabase;
|
|||
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
|
@ -42,9 +43,11 @@ import org.thoughtcrime.securesms.logging.Log;
|
|||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientDetails;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||
import org.thoughtcrime.securesms.util.CursorUtil;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
@ -928,9 +931,29 @@ public class ThreadDatabase extends Database {
|
|||
}
|
||||
|
||||
public ThreadRecord getCurrent() {
|
||||
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_ID)));
|
||||
Recipient recipient = Recipient.live(recipientId).get();
|
||||
RecipientId recipientId = RecipientId.from(CursorUtil.requireLong(cursor, ThreadDatabase.RECIPIENT_ID));
|
||||
RecipientSettings recipientSettings = RecipientDatabase.getRecipientSettings(context, cursor);
|
||||
|
||||
Recipient recipient;
|
||||
|
||||
if (recipientSettings.getGroupId() != null) {
|
||||
GroupDatabase.GroupRecord group = new GroupDatabase.Reader(cursor).getCurrent();
|
||||
|
||||
if (group != null) {
|
||||
RecipientDetails details = new RecipientDetails(group.getTitle(),
|
||||
group.hasAvatar() ? Optional.of(group.getAvatarId()) : Optional.absent(),
|
||||
false,
|
||||
false,
|
||||
recipientSettings,
|
||||
null);
|
||||
recipient = new Recipient(recipientId, details, false);
|
||||
} else {
|
||||
recipient = Recipient.live(recipientId).get();
|
||||
}
|
||||
} else {
|
||||
RecipientDetails details = RecipientDetails.forIndividual(context, recipientSettings);
|
||||
recipient = new Recipient(recipientId, details, false);
|
||||
}
|
||||
|
||||
int readReceiptCount = TextSecurePreferences.isReadReceiptsEnabled(context) ? cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.READ_RECEIPT_COUNT))
|
||||
: 0;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
@ -108,22 +143,21 @@ public final class LiveRecipientCache {
|
|||
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
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<>();
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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,10 +408,12 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* False iff it {@link #getDisplayName} would fall back to e164, email or unknown.
|
||||
|
@ -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);
|
||||
|
|
|
@ -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,8 +67,7 @@ public class RecipientDetails {
|
|||
final byte[] identityKey;
|
||||
final VerifiedStatus identityStatus;
|
||||
|
||||
RecipientDetails(@NonNull Context context,
|
||||
@Nullable String name,
|
||||
public RecipientDetails(@Nullable String name,
|
||||
@NonNull Optional<Long> groupAvatarId,
|
||||
boolean systemContact,
|
||||
boolean isLocalNumber,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
public final class CursorUtil {
|
||||
|
||||
private CursorUtil() {}
|
||||
|
||||
public static String requireString(@NonNull Cursor cursor, @NonNull String column) {
|
||||
return cursor.getString(cursor.getColumnIndexOrThrow(column));
|
||||
}
|
||||
|
||||
public static int requireInt(@NonNull Cursor cursor, @NonNull String column) {
|
||||
return cursor.getInt(cursor.getColumnIndexOrThrow(column));
|
||||
}
|
||||
|
||||
public static long requireLong(@NonNull Cursor cursor, @NonNull String column) {
|
||||
return cursor.getLong(cursor.getColumnIndexOrThrow(column));
|
||||
}
|
||||
|
||||
public static boolean requireBoolean(@NonNull Cursor cursor, @NonNull String column) {
|
||||
return requireInt(cursor, column) != 0;
|
||||
}
|
||||
|
||||
public static Optional<String> getString(@NonNull Cursor cursor, @NonNull String column) {
|
||||
if (cursor.getColumnIndex(column) < 0) {
|
||||
return Optional.absent();
|
||||
} else {
|
||||
return Optional.fromNullable(requireString(cursor, column));
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<Integer> getInt(@NonNull Cursor cursor, @NonNull String column) {
|
||||
if (cursor.getColumnIndex(column) < 0) {
|
||||
return Optional.absent();
|
||||
} else {
|
||||
return Optional.of(requireInt(cursor, column));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue