Optimistically fetch profiles.

This commit is contained in:
Greyson Parrelli
2020-06-12 10:22:46 -07:00
committed by Greyson Parrelli
parent f5626f678d
commit ce940235b0
11 changed files with 169 additions and 29 deletions

View File

@@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.v2.ProfileKeySet;
@@ -60,6 +61,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -102,6 +104,7 @@ public class RecipientDatabase extends Database {
private static final String PROFILE_KEY_CREDENTIAL = "profile_key_credential";
private static final String SIGNAL_PROFILE_AVATAR = "signal_profile_avatar";
private static final String PROFILE_SHARING = "profile_sharing";
private static final String LAST_PROFILE_FETCH = "last_profile_fetch";
private static final String UNIDENTIFIED_ACCESS_MODE = "unidentified_access_mode";
private static final String FORCE_SMS_SELECTION = "force_sms_selection";
private static final String UUID_CAPABILITY = "uuid_supported";
@@ -123,7 +126,8 @@ public class RecipientDatabase extends Database {
BLOCKED, MESSAGE_RINGTONE, CALL_RINGTONE, MESSAGE_VIBRATE, CALL_VIBRATE, MUTE_UNTIL, COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, MESSAGE_EXPIRATION_TIME, REGISTERED,
PROFILE_KEY, PROFILE_KEY_CREDENTIAL,
SYSTEM_DISPLAY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_PHONE_TYPE, SYSTEM_CONTACT_URI,
PROFILE_GIVEN_NAME, PROFILE_FAMILY_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, NOTIFICATION_CHANNEL,
PROFILE_GIVEN_NAME, PROFILE_FAMILY_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, LAST_PROFILE_FETCH,
NOTIFICATION_CHANNEL,
UNIDENTIFIED_ACCESS_MODE,
FORCE_SMS_SELECTION,
UUID_CAPABILITY, GROUPS_V2_CAPABILITY,
@@ -295,6 +299,7 @@ public class RecipientDatabase extends Database {
PROFILE_JOINED_NAME + " TEXT DEFAULT NULL, " +
SIGNAL_PROFILE_AVATAR + " TEXT DEFAULT NULL, " +
PROFILE_SHARING + " INTEGER DEFAULT 0, " +
LAST_PROFILE_FETCH + " INTEGER DEFAULT 0, " +
UNIDENTIFIED_ACCESS_MODE + " INTEGER DEFAULT 0, " +
FORCE_SMS_SELECTION + " INTEGER DEFAULT 0, " +
UUID_CAPABILITY + " INTEGER DEFAULT " + Recipient.Capability.UNKNOWN.serialize() + ", " +
@@ -842,6 +847,7 @@ public class RecipientDatabase extends Database {
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;
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;
@@ -908,7 +914,7 @@ public class RecipientDatabase extends Database {
systemDisplayName, systemContactPhoto,
systemPhoneLabel, systemContactUri,
ProfileName.fromParts(profileGivenName, profileFamilyName), signalProfileAvatar,
AvatarHelper.hasAvatar(context, RecipientId.from(id)), profileSharing,
AvatarHelper.hasAvatar(context, RecipientId.from(id)), profileSharing, lastProfileFetch,
notificationChannel, UnidentifiedAccessMode.fromMode(unidentifiedAccessMode),
forceSmsSelection,
Recipient.Capability.deserialize(uuidCapabilityValue),
@@ -1587,6 +1593,53 @@ public class RecipientDatabase extends Database {
return recipients;
}
/**
* @param lastInteractionThreshold Only include contacts that have been interacted with since this time.
* @param lastProfileFetchThreshold Only include contacts that haven't their profile fetched after this time.
* @param limit Only return at most this many contact.
*/
public List<RecipientId> getRecipientsForRoutineProfileFetch(long lastInteractionThreshold, long lastProfileFetchThreshold, int limit) {
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
Set<Recipient> recipientsWithinInteractionThreshold = new LinkedHashSet<>();
try (ThreadDatabase.Reader reader = threadDatabase.readerFor(threadDatabase.getRecentPushConversationList(-1, false))) {
ThreadRecord record;
while ((record = reader.getNext()) != null && record.getDate() > lastInteractionThreshold) {
Recipient recipient = Recipient.resolved(record.getRecipient().getId());
if (recipient.isGroup()) {
recipientsWithinInteractionThreshold.addAll(recipient.getParticipants());
} else {
recipientsWithinInteractionThreshold.add(recipient);
}
}
}
return Stream.of(recipientsWithinInteractionThreshold)
.filterNot(Recipient::isLocalNumber)
.filter(r -> r.getLastProfileFetchTime() < lastProfileFetchThreshold)
.limit(limit)
.map(Recipient::getId)
.toList();
}
public void markProfilesFetched(@NonNull Collection<RecipientId> ids, long time) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.beginTransaction();
try {
ContentValues values = new ContentValues(1);
values.put(LAST_PROFILE_FETCH, time);
for (RecipientId id : ids) {
db.update(TABLE_NAME, values, ID_WHERE, new String[] { id.serialize() });
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
public void applyBlockedUpdate(@NonNull List<SignalServiceAddress> blocked, List<byte[]> groupIds) {
List<String> blockedE164 = Stream.of(blocked)
.filter(b -> b.getNumber().isPresent())
@@ -1885,6 +1938,7 @@ public class RecipientDatabase extends Database {
private final String signalProfileAvatar;
private final boolean hasProfileImage;
private final boolean profileSharing;
private final long lastProfileFetch;
private final String notificationChannel;
private final UnidentifiedAccessMode unidentifiedAccessMode;
private final boolean forceSmsSelection;
@@ -1923,6 +1977,7 @@ public class RecipientDatabase extends Database {
@Nullable String signalProfileAvatar,
boolean hasProfileImage,
boolean profileSharing,
long lastProfileFetch,
@Nullable String notificationChannel,
@NonNull UnidentifiedAccessMode unidentifiedAccessMode,
boolean forceSmsSelection,
@@ -1961,6 +2016,7 @@ public class RecipientDatabase extends Database {
this.signalProfileAvatar = signalProfileAvatar;
this.hasProfileImage = hasProfileImage;
this.profileSharing = profileSharing;
this.lastProfileFetch = lastProfileFetch;
this.notificationChannel = notificationChannel;
this.unidentifiedAccessMode = unidentifiedAccessMode;
this.forceSmsSelection = forceSmsSelection;
@@ -2091,6 +2147,10 @@ public class RecipientDatabase extends Database {
return profileSharing;
}
public long getLastProfileFetch() {
return lastProfileFetch;
}
public @Nullable String getNotificationChannel() {
return notificationChannel;
}

View File

@@ -135,8 +135,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
private static final int REMOTE_DELETE = 60;
private static final int COLOR_MIGRATION = 61;
private static final int LAST_SCROLLED = 62;
private static final int LAST_PROFILE_FETCH = 63;
private static final int DATABASE_VERSION = 62;
private static final int DATABASE_VERSION = 63;
private static final String DATABASE_NAME = "signal.db";
private final Context context;
@@ -911,6 +912,10 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE thread ADD COLUMN last_scrolled INTEGER DEFAULT 0");
}
if (oldVersion < LAST_PROFILE_FETCH) {
db.execSQL("ALTER TABLE recipient ADD COLUMN last_profile_fetch INTEGER DEFAULT 0");
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();