Add support for system names on the ContactRecord.

This commit is contained in:
Greyson Parrelli
2022-09-28 14:09:44 -04:00
parent 6e5f28339d
commit 1999db97f2
11 changed files with 197 additions and 66 deletions

View File

@@ -925,6 +925,21 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
ApplicationDependencies.getDatabaseObserver().notifyRecipientChanged(recipientId)
}
fun markAllSystemContactsNeedsSync() {
writableDatabase.withinTransaction { db ->
db
.select(ID)
.from(TABLE_NAME)
.where("$SYSTEM_CONTACT_URI NOT NULL")
.run()
.use { cursor ->
while (cursor.moveToNext()) {
rotateStorageId(RecipientId.from(cursor.requireLong(ID)))
}
}
}
}
fun applyStorageIdUpdates(storageIds: Map<RecipientId, StorageId>) {
val db = writableDatabase
db.beginTransaction()
@@ -3667,8 +3682,9 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
private fun getValuesForStorageContact(contact: SignalContactRecord, isInsert: Boolean): ContentValues {
return ContentValues().apply {
val profileName = ProfileName.fromParts(contact.givenName.orElse(null), contact.familyName.orElse(null))
val username: String? = contact.username.orElse(null)
val profileName = ProfileName.fromParts(contact.profileGivenName.orElse(null), contact.profileFamilyName.orElse(null))
val systemName = ProfileName.fromParts(contact.systemGivenName.orElse(null), contact.systemFamilyName.orElse(null))
val username = contact.username.orElse(null)
if (contact.serviceId.isValid) {
put(SERVICE_ID, contact.serviceId.toString())
@@ -3682,6 +3698,9 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
put(PROFILE_GIVEN_NAME, profileName.givenName)
put(PROFILE_FAMILY_NAME, profileName.familyName)
put(PROFILE_JOINED_NAME, profileName.toString())
put(SYSTEM_GIVEN_NAME, systemName.givenName)
put(SYSTEM_FAMILY_NAME, systemName.familyName)
put(SYSTEM_JOINED_NAME, systemName.toString())
put(PROFILE_KEY, contact.profileKey.map { source -> Base64.encodeBytes(source) }.orElse(null))
put(USERNAME, if (TextUtils.isEmpty(username)) null else username)
put(PROFILE_SHARING, if (contact.isProfileSharingEnabled) "1" else "0")

View File

@@ -61,6 +61,7 @@ import org.thoughtcrime.securesms.migrations.StickerLaunchMigrationJob;
import org.thoughtcrime.securesms.migrations.StickerMyDailyLifeMigrationJob;
import org.thoughtcrime.securesms.migrations.StorageCapabilityMigrationJob;
import org.thoughtcrime.securesms.migrations.StorageServiceMigrationJob;
import org.thoughtcrime.securesms.migrations.StorageServiceSystemNameMigrationJob;
import org.thoughtcrime.securesms.migrations.SyncDistributionListsMigrationJob;
import org.thoughtcrime.securesms.migrations.TrimByLengthSettingsMigrationJob;
import org.thoughtcrime.securesms.migrations.UserNotificationMigrationJob;
@@ -221,6 +222,7 @@ public final class JobManagerFactories {
put(StickerMyDailyLifeMigrationJob.KEY, new StickerMyDailyLifeMigrationJob.Factory());
put(StorageCapabilityMigrationJob.KEY, new StorageCapabilityMigrationJob.Factory());
put(StorageServiceMigrationJob.KEY, new StorageServiceMigrationJob.Factory());
put(StorageServiceSystemNameMigrationJob.KEY, new StorageServiceSystemNameMigrationJob.Factory());
put(TrimByLengthSettingsMigrationJob.KEY, new TrimByLengthSettingsMigrationJob.Factory());
put(UserNotificationMigrationJob.KEY, new UserNotificationMigrationJob.Factory());
put(UuidMigrationJob.KEY, new UuidMigrationJob.Factory());

View File

@@ -108,9 +108,10 @@ public class ApplicationMigrations {
static final int REFRESH_PNI_REGISTRATION_ID = 64;
static final int KBS_MIGRATION_2 = 65;
static final int PNI_2 = 66;
static final int SYSTEM_NAME_SYNC = 67;
}
public static final int CURRENT_VERSION = 66;
public static final int CURRENT_VERSION = 67;
/**
* This *must* be called after the {@link JobManager} has been instantiated, but *before* the call
@@ -476,6 +477,10 @@ public class ApplicationMigrations {
jobs.put(Version.PNI_2, new PniMigrationJob());
}
if (lastSeenVersion < Version.SYSTEM_NAME_SYNC) {
jobs.put(Version.SYSTEM_NAME_SYNC, new StorageServiceSystemNameMigrationJob());
}
return jobs;
}

View File

@@ -0,0 +1,56 @@
package org.thoughtcrime.securesms.migrations;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobs.DownloadLatestEmojiDataJob;
import org.thoughtcrime.securesms.jobs.EmojiSearchIndexDownloadJob;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
/**
* Added for when we started syncing contact names in storage service.
* Rotates the storageId of every system contact and then schedules a storage sync.
*/
public final class StorageServiceSystemNameMigrationJob extends MigrationJob {
public static final String KEY = "StorageServiceSystemNameMigrationJob";
StorageServiceSystemNameMigrationJob() {
this(new Parameters.Builder().build());
}
private StorageServiceSystemNameMigrationJob(@NonNull Parameters parameters) {
super(parameters);
}
@Override
public boolean isUiBlocking() {
return false;
}
@Override
public @NonNull String getFactoryKey() {
return KEY;
}
@Override
public void performMigration() {
SignalDatabase.recipients().markAllSystemContactsNeedsSync();
StorageSyncHelper.scheduleSyncForDataChange();
}
@Override
boolean shouldRetry(@NonNull Exception e) {
return false;
}
public static class Factory implements Job.Factory<StorageServiceSystemNameMigrationJob> {
@Override
public @NonNull StorageServiceSystemNameMigrationJob create(@NonNull Parameters parameters, @NonNull Data data) {
return new StorageServiceSystemNameMigrationJob(parameters);
}
}
}

View File

@@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.storage;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -17,7 +15,6 @@ import org.thoughtcrime.securesms.util.FeatureFlags;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
import org.whispersystems.signalservice.api.util.OptionalUtil;
import org.whispersystems.signalservice.internal.storage.protos.ContactRecord.IdentityState;
@@ -122,15 +119,15 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
remote = remote.withoutPni();
}
String givenName;
String familyName;
String profileGivenName;
String profileFamilyName;
if (remote.getGivenName().isPresent() || remote.getFamilyName().isPresent()) {
givenName = remote.getGivenName().orElse("");
familyName = remote.getFamilyName().orElse("");
if (remote.getProfileGivenName().isPresent() || remote.getProfileFamilyName().isPresent()) {
profileGivenName = remote.getProfileGivenName().orElse("");
profileFamilyName = remote.getProfileFamilyName().orElse("");
} else {
givenName = local.getGivenName().orElse("");
familyName = local.getFamilyName().orElse("");
profileGivenName = local.getProfileGivenName().orElse("");
profileFamilyName = local.getProfileFamilyName().orElse("");
}
IdentityState identityState;
@@ -198,8 +195,10 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
boolean hideStory = remote.shouldHideStory();
long unregisteredTimestamp = remote.getUnregisteredTimestamp();
boolean hidden = remote.isHidden();
boolean matchesRemote = doParamsMatch(remote, unknownFields, serviceId, pni, e164, givenName, familyName, profileKey, username, identityState, identityKey, blocked, profileSharing, archived, forcedUnread, muteUntil, hideStory, unregisteredTimestamp, hidden);
boolean matchesLocal = doParamsMatch(local, unknownFields, serviceId, pni, e164, givenName, familyName, profileKey, username, identityState, identityKey, blocked, profileSharing, archived, forcedUnread, muteUntil, hideStory, unregisteredTimestamp, hidden);
String systemGivenName = SignalStore.account().isPrimaryDevice() ? local.getSystemGivenName().orElse("") : remote.getSystemGivenName().orElse("");
String systemFamilyName = SignalStore.account().isPrimaryDevice() ? local.getSystemFamilyName().orElse("") : remote.getSystemFamilyName().orElse("");
boolean matchesRemote = doParamsMatch(remote, unknownFields, serviceId, pni, e164, profileGivenName, profileFamilyName, systemGivenName, systemFamilyName, profileKey, username, identityState, identityKey, blocked, profileSharing, archived, forcedUnread, muteUntil, hideStory, unregisteredTimestamp, hidden);
boolean matchesLocal = doParamsMatch(local, unknownFields, serviceId, pni, e164, profileGivenName, profileFamilyName, systemGivenName, systemFamilyName, profileKey, username, identityState, identityKey, blocked, profileSharing, archived, forcedUnread, muteUntil, hideStory, unregisteredTimestamp, hidden);
if (matchesRemote) {
return remote;
@@ -209,8 +208,10 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
return new SignalContactRecord.Builder(keyGenerator.generate(), serviceId, unknownFields)
.setE164(e164)
.setPni(pni)
.setGivenName(givenName)
.setFamilyName(familyName)
.setProfileGivenName(profileGivenName)
.setProfileFamilyName(profileFamilyName)
.setSystemGivenName(systemGivenName)
.setSystemFamilyName(systemFamilyName)
.setProfileKey(profileKey)
.setUsername(username)
.setIdentityState(identityState)
@@ -254,8 +255,10 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
@NonNull ServiceId serviceId,
@Nullable PNI pni,
@Nullable String e164,
@NonNull String givenName,
@NonNull String familyName,
@NonNull String profileGivenName,
@NonNull String profileFamilyName,
@NonNull String systemGivenName,
@NonNull String systemFamilyName,
@Nullable byte[] profileKey,
@NonNull String username,
@Nullable IdentityState identityState,
@@ -269,23 +272,25 @@ public class ContactRecordProcessor extends DefaultStorageRecordProcessor<Signal
long unregisteredTimestamp,
boolean hidden)
{
return Arrays.equals(contact.serializeUnknownFields(), unknownFields) &&
Objects.equals(contact.getServiceId(), serviceId) &&
Objects.equals(contact.getPni().orElse(null), pni) &&
Objects.equals(contact.getNumber().orElse(null), e164) &&
Objects.equals(contact.getGivenName().orElse(""), givenName) &&
Objects.equals(contact.getFamilyName().orElse(""), familyName) &&
Arrays.equals(contact.getProfileKey().orElse(null), profileKey) &&
Objects.equals(contact.getUsername().orElse(""), username) &&
Objects.equals(contact.getIdentityState(), identityState) &&
Arrays.equals(contact.getIdentityKey().orElse(null), identityKey) &&
contact.isBlocked() == blocked &&
contact.isProfileSharingEnabled() == profileSharing &&
contact.isArchived() == archived &&
contact.isForcedUnread() == forcedUnread &&
contact.getMuteUntil() == muteUntil &&
contact.shouldHideStory() == hideStory &&
contact.getUnregisteredTimestamp() == unregisteredTimestamp &&
return Arrays.equals(contact.serializeUnknownFields(), unknownFields) &&
Objects.equals(contact.getServiceId(), serviceId) &&
Objects.equals(contact.getPni().orElse(null), pni) &&
Objects.equals(contact.getNumber().orElse(null), e164) &&
Objects.equals(contact.getProfileGivenName().orElse(""), profileGivenName) &&
Objects.equals(contact.getProfileFamilyName().orElse(""), profileFamilyName) &&
Objects.equals(contact.getSystemGivenName().orElse(""), systemGivenName) &&
Objects.equals(contact.getSystemFamilyName().orElse(""), systemFamilyName) &&
Arrays.equals(contact.getProfileKey().orElse(null), profileKey) &&
Objects.equals(contact.getUsername().orElse(""), username) &&
Objects.equals(contact.getIdentityState(), identityState) &&
Arrays.equals(contact.getIdentityKey().orElse(null), identityKey) &&
contact.isBlocked() == blocked &&
contact.isProfileSharingEnabled() == profileSharing &&
contact.isArchived() == archived &&
contact.isForcedUnread() == forcedUnread &&
contact.getMuteUntil() == muteUntil &&
contact.shouldHideStory() == hideStory &&
contact.getUnregisteredTimestamp() == unregisteredTimestamp &&
contact.isHidden() == hidden;
}
}

View File

@@ -11,15 +11,12 @@ import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.model.DistributionListId;
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode;
import org.thoughtcrime.securesms.database.model.DistributionListRecord;
import org.thoughtcrime.securesms.database.model.RecipientRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.subscription.Subscriber;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.storage.SignalAccountRecord;
@@ -34,7 +31,6 @@ import org.whispersystems.signalservice.internal.storage.protos.AccountRecord;
import org.whispersystems.signalservice.internal.storage.protos.ContactRecord.IdentityState;
import org.whispersystems.signalservice.internal.storage.protos.GroupV2Record;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@@ -116,8 +112,10 @@ public final class StorageSyncModels {
.setE164(recipient.getE164())
.setPni(recipient.getPni())
.setProfileKey(recipient.getProfileKey())
.setGivenName(recipient.getProfileName().getGivenName())
.setFamilyName(recipient.getProfileName().getFamilyName())
.setProfileGivenName(recipient.getProfileName().getGivenName())
.setProfileFamilyName(recipient.getProfileName().getFamilyName())
.setSystemGivenName(recipient.getSystemProfileName().getGivenName())
.setSystemFamilyName(recipient.getSystemProfileName().getFamilyName())
.setBlocked(recipient.isBlocked())
.setProfileSharingEnabled(recipient.isProfileSharing() || recipient.getSystemContactUri() != null)
.setIdentityKey(recipient.getSyncExtras().getIdentityKey())