Add Change Number capability and Conversation Update item.

This commit is contained in:
Cody Henthorne
2021-09-08 13:38:39 -04:00
committed by Greyson Parrelli
parent bb446ac1d5
commit 77ff25ec49
31 changed files with 307 additions and 34 deletions

View File

@@ -167,6 +167,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
public abstract long insertMessageOutbox(@NonNull OutgoingMediaMessage message, long threadId, boolean forceSms, int defaultReceiptStatus, @Nullable SmsDatabase.InsertListener insertListener) throws MmsException;
public abstract void insertProfileNameChangeMessages(@NonNull Recipient recipient, @NonNull String newProfileName, @NonNull String previousProfileName);
public abstract void insertGroupV1MigrationEvents(@NonNull RecipientId recipientId, long threadId, @NonNull GroupMigrationMembershipChange membershipChange);
public abstract void insertNumberChangeMessages(@NonNull Recipient recipient);
public abstract boolean deleteMessage(long messageId);
abstract void deleteThread(long threadId);

View File

@@ -503,6 +503,11 @@ public class MmsDatabase extends MessageDatabase {
throw new UnsupportedOperationException();
}
@Override
public void insertNumberChangeMessages(@NonNull Recipient recipient) {
throw new UnsupportedOperationException();
}
@Override
public void endTransaction(SQLiteDatabase database) {
database.endTransaction();

View File

@@ -77,6 +77,7 @@ public interface MmsSmsColumns {
protected static final long OUTGOING_VIDEO_CALL_TYPE = 11;
protected static final long GROUP_CALL_TYPE = 12;
protected static final long BAD_DECRYPT_TYPE = 13;
protected static final long CHANGE_NUMBER_TYPE = 14;
protected static final long BASE_INBOX_TYPE = 20;
protected static final long BASE_OUTBOX_TYPE = 21;
@@ -334,6 +335,10 @@ public interface MmsSmsColumns {
return type == GV1_MIGRATION_TYPE;
}
public static boolean isChangeNumber(long type) {
return type == CHANGE_NUMBER_TYPE;
}
public static long translateFromSystemBaseType(long theirType) {
// public static final int NONE_TYPE = 0;
// public static final int INBOX_TYPE = 1;

View File

@@ -108,7 +108,7 @@ public class MmsSmsDatabase extends Database {
MmsSmsColumns.RECEIPT_TIMESTAMP};
private static final String SNIPPET_QUERY = "SELECT " + MmsSmsColumns.ID + ", 0 AS " + TRANSPORT + ", " + SmsDatabase.TYPE + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + SmsDatabase.TABLE_NAME + " " +
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + SmsDatabase.TYPE + " NOT IN (" + SmsDatabase.Types.PROFILE_CHANGE_TYPE + ", " + SmsDatabase.Types.GV1_MIGRATION_TYPE + ") " +
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + SmsDatabase.TYPE + " NOT IN (" + SmsDatabase.Types.PROFILE_CHANGE_TYPE + ", " + SmsDatabase.Types.GV1_MIGRATION_TYPE + ", " + SmsDatabase.Types.CHANGE_NUMBER_TYPE + ") " +
"UNION ALL " +
"SELECT " + MmsSmsColumns.ID + ", 1 AS " + TRANSPORT + ", " + MmsDatabase.MESSAGE_BOX + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + MmsDatabase.TABLE_NAME + " " +
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? " +

View File

@@ -29,9 +29,9 @@ import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsMapper;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
import org.thoughtcrime.securesms.database.model.IdentityRecord;
import org.thoughtcrime.securesms.database.IdentityDatabase.VerifiedStatus;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.database.model.IdentityRecord;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.database.model.databaseprotos.ChatColor;
import org.thoughtcrime.securesms.database.model.databaseprotos.DeviceLastResetTime;
@@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.v2.ProfileKeySet;
import org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor;
import org.thoughtcrime.securesms.jobs.RecipientChangedNumberJob;
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
@@ -59,6 +60,7 @@ import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.IdentityUtil;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.thoughtcrime.securesms.util.StringUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaperFactory;
@@ -167,6 +169,7 @@ public class RecipientDatabase extends Database {
static final int GROUPS_V1_MIGRATION = 1;
static final int SENDER_KEY = 2;
static final int ANNOUNCEMENT_GROUPS = 3;
static final int CHANGE_NUMBER = 4;
}
private static final String[] RECIPIENT_PROJECTION = new String[] {
@@ -421,12 +424,17 @@ public class RecipientDatabase extends Database {
}
public @NonNull RecipientId getAndPossiblyMerge(@Nullable UUID uuid, @Nullable String e164, boolean highTrust) {
return getAndPossiblyMerge(uuid, e164, highTrust, false);
}
public @NonNull RecipientId getAndPossiblyMerge(@Nullable UUID uuid, @Nullable String e164, boolean highTrust, boolean changeSelf) {
if (uuid == null && e164 == null) {
throw new IllegalArgumentException("Must provide a UUID or E164!");
}
RecipientId recipientNeedingRefresh = null;
Pair<RecipientId, RecipientId> remapped = null;
RecipientId recipientChangedNumber = null;
boolean transactionSuccessful = false;
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
@@ -485,9 +493,15 @@ public class RecipientDatabase extends Database {
} else if (!byE164.isPresent() && byUuid.isPresent()) {
if (e164 != null) {
if (highTrust) {
Log.i(TAG, String.format(Locale.US, "Found out about an E164 (%s) for a known UUID user (%s). High-trust, so updating.", e164, byUuid.get()), true);
setPhoneNumberOrThrow(byUuid.get(), e164);
finalId = byUuid.get();
if (Objects.equals(uuid, TextSecurePreferences.getLocalUuid(context)) && !changeSelf) {
Log.w(TAG, String.format(Locale.US, "Found out about an E164 (%s) for our own UUID user (%s). High-trust but not change self, doing nothing.", e164, byUuid.get()), true);
finalId = byUuid.get();
} else {
Log.i(TAG, String.format(Locale.US, "Found out about an E164 (%s) for a known UUID user (%s). High-trust, so updating.", e164, byUuid.get()), true);
setPhoneNumberOrThrow(byUuid.get(), e164);
finalId = byUuid.get();
recipientChangedNumber = finalId;
}
} else {
Log.i(TAG, String.format(Locale.US, "Found out about an E164 (%s) for a known UUID user (%s). Low-trust, so doing nothing.", e164, byUuid.get()), true);
finalId = byUuid.get();
@@ -552,6 +566,10 @@ public class RecipientDatabase extends Database {
StorageSyncHelper.scheduleSyncForDataChange();
RecipientId.clearCache();
}
if (recipientChangedNumber != null) {
ApplicationDependencies.getJobManager().add(new RecipientChangedNumberJob(recipientChangedNumber));
}
}
}
}
@@ -1616,6 +1634,7 @@ public class RecipientDatabase extends Database {
value = Bitmask.update(value, Capabilities.GROUPS_V1_MIGRATION, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isGv1Migration()).serialize());
value = Bitmask.update(value, Capabilities.SENDER_KEY, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isSenderKey()).serialize());
value = Bitmask.update(value, Capabilities.ANNOUNCEMENT_GROUPS, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isAnnouncementGroup()).serialize());
value = Bitmask.update(value, Capabilities.CHANGE_NUMBER, Capabilities.BIT_LENGTH, Recipient.Capability.fromBoolean(capabilities.isChangeNumber()).serialize());
ContentValues values = new ContentValues(1);
values.put(CAPABILITIES, value);
@@ -2040,7 +2059,7 @@ public class RecipientDatabase extends Database {
try {
RecipientId id = Recipient.self().getId();
RecipientId newId = getAndPossiblyMerge(Recipient.self().requireUuid(), e164, true);
RecipientId newId = getAndPossiblyMerge(Recipient.self().requireUuid(), e164, true, true);
if (id.equals(newId)) {
Log.i(TAG, "[updateSelfPhone] Phone updated for self");
@@ -3159,6 +3178,7 @@ public class RecipientDatabase extends Database {
private final Recipient.Capability groupsV1MigrationCapability;
private final Recipient.Capability senderKeyCapability;
private final Recipient.Capability announcementGroupCapability;
private final Recipient.Capability changeNumberCapability;
private final InsightsBannerTier insightsBannerTier;
private final byte[] storageId;
private final MentionSetting mentionSetting;
@@ -3251,6 +3271,7 @@ public class RecipientDatabase extends Database {
this.groupsV1MigrationCapability = Recipient.Capability.deserialize((int) Bitmask.read(capabilities, Capabilities.GROUPS_V1_MIGRATION, Capabilities.BIT_LENGTH));
this.senderKeyCapability = Recipient.Capability.deserialize((int) Bitmask.read(capabilities, Capabilities.SENDER_KEY, Capabilities.BIT_LENGTH));
this.announcementGroupCapability = Recipient.Capability.deserialize((int) Bitmask.read(capabilities, Capabilities.ANNOUNCEMENT_GROUPS, Capabilities.BIT_LENGTH));
this.changeNumberCapability = Recipient.Capability.deserialize((int) Bitmask.read(capabilities, Capabilities.CHANGE_NUMBER, Capabilities.BIT_LENGTH));
this.insightsBannerTier = insightsBannerTier;
this.storageId = storageId;
this.mentionSetting = mentionSetting;
@@ -3408,6 +3429,10 @@ public class RecipientDatabase extends Database {
return announcementGroupCapability;
}
public @NonNull Recipient.Capability getChangeNumberCapability() {
return changeNumberCapability;
}
public @Nullable byte[] getStorageId() {
return storageId;
}

View File

@@ -73,6 +73,7 @@ import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -270,8 +271,8 @@ public class SmsDatabase extends MessageDatabase {
}
private @NonNull SqlUtil.Query buildMeaningfulMessagesQuery(long threadId) {
String query = THREAD_ID + " = ? AND (NOT " + TYPE + " & ? AND TYPE != ?)";
return SqlUtil.buildQuery(query, threadId, IGNORABLE_TYPESMASK_WHEN_COUNTING, Types.PROFILE_CHANGE_TYPE);
String query = THREAD_ID + " = ? AND (NOT " + TYPE + " & ? AND TYPE != ? AND TYPE != ?)";
return SqlUtil.buildQuery(query, threadId, IGNORABLE_TYPESMASK_WHEN_COUNTING, Types.PROFILE_CHANGE_TYPE, Types.CHANGE_NUMBER_TYPE);
}
@Override
@@ -1027,6 +1028,53 @@ public class SmsDatabase extends MessageDatabase {
databaseHelper.getSignalWritableDatabase().insert(TABLE_NAME, null, values);
}
@Override
public void insertNumberChangeMessages(@NonNull Recipient recipient) {
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
List<GroupDatabase.GroupRecord> groupRecords = DatabaseFactory.getGroupDatabase(context).getGroupsContainingMember(recipient.getId(), false);
List<Long> threadIdsToUpdate = new LinkedList<>();
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
db.beginTransaction();
try {
threadIdsToUpdate.add(threadDatabase.getThreadIdFor(recipient.getId()));
for (GroupDatabase.GroupRecord groupRecord : groupRecords) {
if (groupRecord.isActive()) {
threadIdsToUpdate.add(threadDatabase.getThreadIdFor(groupRecord.getRecipientId()));
}
}
threadIdsToUpdate.stream()
.filter(Objects::nonNull)
.forEach(threadId -> {
ContentValues values = new ContentValues();
values.put(RECIPIENT_ID, recipient.getId().serialize());
values.put(ADDRESS_DEVICE_ID, 1);
values.put(DATE_RECEIVED, System.currentTimeMillis());
values.put(DATE_SENT, System.currentTimeMillis());
values.put(READ, 1);
values.put(TYPE, Types.CHANGE_NUMBER_TYPE);
values.put(THREAD_ID, threadId);
values.putNull(BODY);
db.insert(TABLE_NAME, null, values);
});
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
threadIdsToUpdate.stream()
.filter(Objects::nonNull)
.forEach(threadId -> {
TrimThreadJob.enqueueAsync(threadId);
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
notifyConversationListeners(threadId);
});
}
@Override
public Optional<InsertResult> insertMessageInbox(IncomingTextMessage message, long type) {
if (message.isJoined()) {

View File

@@ -1514,7 +1514,8 @@ public class ThreadDatabase extends Database {
private boolean isSilentType(long type) {
return MmsSmsColumns.Types.isProfileChange(type) ||
MmsSmsColumns.Types.isGroupV1MigrationEvent(type);
MmsSmsColumns.Types.isGroupV1MigrationEvent(type) ||
MmsSmsColumns.Types.isChangeNumber(type);
}
public Reader readerFor(Cursor cursor) {

View File

@@ -178,6 +178,10 @@ public abstract class DisplayRecord {
return SmsDatabase.Types.isProfileChange(type);
}
public boolean isChangeNumber() {
return SmsDatabase.Types.isChangeNumber(type);
}
public int getDeliveryStatus() {
return deliveryStatus;
}

View File

@@ -187,6 +187,8 @@ public abstract class MessageRecord extends DisplayRecord {
else return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_info_16);
} else if (isProfileChange()) {
return staticUpdateDescription(getProfileChangeDescription(context), R.drawable.ic_update_profile_16);
} else if (isChangeNumber()) {
return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_s_changed_their_number_to_a_new_number, r.getDisplayName(context)), R.drawable.ic_phone_16);
} else if (isEndSession()) {
if (isOutgoing()) return staticUpdateDescription(context.getString(R.string.SmsMessageRecord_secure_session_reset), R.drawable.ic_update_info_16);
else return fromRecipient(getIndividualRecipient(), r-> context.getString(R.string.SmsMessageRecord_secure_session_reset_s, r.getDisplayName(context)), R.drawable.ic_update_info_16);
@@ -484,7 +486,8 @@ public abstract class MessageRecord extends DisplayRecord {
public boolean isUpdate() {
return isGroupAction() || isJoined() || isExpirationTimerUpdate() || isCallLog() ||
isEndSession() || isIdentityUpdate() || isIdentityVerified() || isIdentityDefault() ||
isProfileChange() || isGroupV1MigrationEvent() || isChatSessionRefresh() || isBadDecryptType();
isProfileChange() || isGroupV1MigrationEvent() || isChatSessionRefresh() || isBadDecryptType() ||
isChangeNumber();
}
public boolean isMediaPending() {