Add Change Number capability and Conversation Update item.

fork-5.53.8
Cody Henthorne 2021-09-08 13:38:39 -04:00 zatwierdzone przez Greyson Parrelli
rodzic bb446ac1d5
commit 77ff25ec49
31 zmienionych plików z 307 dodań i 34 usunięć

Wyświetl plik

@ -8,6 +8,38 @@
<option name="DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION" value="true" />
<option name="ALIGN_MULTILINE_ANNOTATION_PARAMETERS" value="true" />
<option name="ALIGN_MULTILINE_TEXT_BLOCKS" value="true" />
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="androidx" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="android" withSubpackages="true" static="true" />
<package name="androidx" withSubpackages="true" static="true" />
<package name="com" withSubpackages="true" static="true" />
<package name="junit" withSubpackages="true" static="true" />
<package name="net" withSubpackages="true" static="true" />
<package name="org" withSubpackages="true" static="true" />
<package name="java" withSubpackages="true" static="true" />
<package name="javax" withSubpackages="true" static="true" />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
</JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">

Wyświetl plik

@ -12,12 +12,13 @@ public final class AppCapabilities {
private static final boolean GV1_MIGRATION = true;
private static final boolean ANNOUNCEMENT_GROUPS = true;
private static final boolean SENDER_KEY = true;
private static final boolean CHANGE_NUMBER = true;
/**
* @param storageCapable Whether or not the user can use storage service. This is another way of
* asking if the user has set a Signal PIN or not.
*/
public static AccountAttributes.Capabilities getCapabilities(boolean storageCapable) {
return new AccountAttributes.Capabilities(UUID_CAPABLE, GV2_CAPABLE, storageCapable, GV1_MIGRATION, SENDER_KEY, ANNOUNCEMENT_GROUPS);
return new AccountAttributes.Capabilities(UUID_CAPABLE, GV2_CAPABLE, storageCapable, GV1_MIGRATION, SENDER_KEY, ANNOUNCEMENT_GROUPS, CHANGE_NUMBER);
}
}

Wyświetl plik

@ -87,6 +87,7 @@ public interface BindableConversationItem extends Unbindable, GiphyMp4Playable,
void onPlayInlineContent(ConversationMessage conversationMessage);
void onInMemoryMessageClicked(@NonNull InMemoryMessageRecord messageRecord);
void onViewGroupDescriptionChange(@Nullable GroupId groupId, @NonNull String description, boolean isMessageRequestAccepted);
void onChangeNumberUpdateContact(@NonNull Recipient recipient);
/** @return true if handled, false if you want to let the normal url handling continue */
boolean onUrlClicked(@NonNull String url);

Wyświetl plik

@ -30,6 +30,7 @@ import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity
import org.thoughtcrime.securesms.lock.v2.KbsConstants
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType
import org.thoughtcrime.securesms.pin.RegistrationLockV2Dialog
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.ServiceUtil
import org.thoughtcrime.securesms.util.ThemeUtil
@ -104,7 +105,7 @@ class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFrag
sectionHeaderPref(R.string.AccountSettingsFragment__account)
if (FeatureFlags.changeNumber()) {
if (FeatureFlags.changeNumber() && Recipient.self().changeNumberCapability == Recipient.Capability.SUPPORTED) {
clickPref(
title = DSLSettingsText.from(R.string.AccountSettingsFragment__change_phone_number),
onClick = {

Wyświetl plik

@ -86,7 +86,6 @@ import org.thoughtcrime.securesms.contactshare.ContactUtil;
import org.thoughtcrime.securesms.contactshare.SharedContactDetailsActivity;
import org.thoughtcrime.securesms.conversation.ConversationAdapter.ItemClickListener;
import org.thoughtcrime.securesms.conversation.ConversationAdapter.StickyHeaderViewHolder;
import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationMessageFactory;
import org.thoughtcrime.securesms.conversation.colors.Colorizer;
import org.thoughtcrime.securesms.conversation.colors.ColorizerView;
import org.thoughtcrime.securesms.conversation.mutiselect.MultiselectItemAnimator;
@ -136,6 +135,7 @@ import org.thoughtcrime.securesms.ratelimit.RecaptchaProofBottomSheetFragment;
import org.thoughtcrime.securesms.reactions.ReactionsBottomSheetDialogFragment;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientExporter;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.ui.bottomsheet.RecipientBottomSheetDialogFragment;
import org.thoughtcrime.securesms.revealable.ViewOnceMessageActivity;
@ -1718,6 +1718,11 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
GroupDescriptionDialog.show(getChildFragmentManager(), groupId, description, isMessageRequestAccepted);
}
}
@Override
public void onChangeNumberUpdateContact(@NonNull Recipient recipient) {
startActivity(RecipientExporter.export(recipient).asAddContactIntent());
}
}
public void refreshList() {

Wyświetl plik

@ -408,6 +408,14 @@ public final class ConversationUpdateItem extends FrameLayout
eventListener.onBadDecryptLearnMoreClicked(conversationMessage.getMessageRecord().getRecipient().getId());
}
});
} else if (conversationMessage.getMessageRecord().isChangeNumber() && conversationMessage.getMessageRecord().getIndividualRecipient().isSystemContact()) {
actionButton.setText(R.string.ConversationUpdateItem_update_contact);
actionButton.setVisibility(VISIBLE);
actionButton.setOnClickListener(v -> {
if (batchSelected.isEmpty() && eventListener != null) {
eventListener.onChangeNumberUpdateContact(conversationMessage.getMessageRecord().getIndividualRecipient());
}
});
} else {
actionButton.setVisibility(GONE);
actionButton.setOnClickListener(null);
@ -480,10 +488,11 @@ public final class ConversationUpdateItem extends FrameLayout
}
private static boolean isSameType(@NonNull MessageRecord current, @NonNull MessageRecord candidate) {
return (current.isGroupUpdate() && candidate.isGroupUpdate()) ||
(current.isProfileChange() && candidate.isProfileChange()) ||
(current.isGroupCall() && candidate.isGroupCall()) ||
(current.isExpirationTimerUpdate() && candidate.isExpirationTimerUpdate());
return (current.isGroupUpdate() && candidate.isGroupUpdate()) ||
(current.isProfileChange() && candidate.isProfileChange()) ||
(current.isGroupCall() && candidate.isGroupCall()) ||
(current.isExpirationTimerUpdate() && candidate.isExpirationTimerUpdate()) ||
(current.isChangeNumber() && candidate.isChangeNumber());
}
@Override

Wyświetl plik

@ -7,7 +7,6 @@ import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.FeatureFlags;
import java.util.Set;
import java.util.stream.Collectors;
@ -188,7 +187,8 @@ final class MenuState {
messageRecord.isProfileChange() ||
messageRecord.isGroupV1MigrationEvent() ||
messageRecord.isChatSessionRefresh() ||
messageRecord.isInMemoryMessageRecord();
messageRecord.isInMemoryMessageRecord() ||
messageRecord.isChangeNumber();
}
private final static class Builder {

Wyświetl plik

@ -491,6 +491,8 @@ public final class ConversationListItem extends ConstraintLayout
return emphasisAdded(context, context.getString(R.string.ThreadRecord_message_could_not_be_processed), defaultTint);
} else if (SmsDatabase.Types.isProfileChange(thread.getType())) {
return emphasisAdded(context, "", defaultTint);
} else if (SmsDatabase.Types.isChangeNumber(thread.getType())) {
return emphasisAdded(context, "", defaultTint);
} else if (MmsSmsColumns.Types.isBadDecryptType(thread.getType())) {
return emphasisAdded(context, context.getString(R.string.ThreadRecord_delivery_issue), defaultTint);
} else {

Wyświetl plik

@ -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);

Wyświetl plik

@ -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();

Wyświetl plik

@ -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;

Wyświetl plik

@ -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 + " = ? " +

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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()) {

Wyświetl plik

@ -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) {

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -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() {

Wyświetl plik

@ -131,6 +131,7 @@ public final class JobManagerFactories {
put(PushNotificationReceiveJob.KEY, new PushNotificationReceiveJob.Factory());
put(PushTextSendJob.KEY, new PushTextSendJob.Factory());
put(ReactionSendJob.KEY, new ReactionSendJob.Factory());
put(RecipientChangedNumberJob.KEY, new RecipientChangedNumberJob.Factory());
put(RefreshAttributesJob.KEY, new RefreshAttributesJob.Factory());
put(RefreshOwnProfileJob.KEY, new RefreshOwnProfileJob.Factory());
put(RefreshPreKeysJob.KEY, new RefreshPreKeysJob.Factory());

Wyświetl plik

@ -0,0 +1,57 @@
package org.thoughtcrime.securesms.jobs
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.jobmanager.Data
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
/**
* Insert change number update items in all threads (1:1 and group) with [recipientId].
*/
class RecipientChangedNumberJob(parameters: Parameters, private val recipientId: RecipientId) : BaseJob(parameters) {
constructor(recipientId: RecipientId) : this(
Parameters.Builder().setQueue("RecipientChangedNumberJob_${recipientId.toQueueKey()}").build(),
recipientId
)
override fun serialize(): Data {
return Data.Builder()
.putString(KEY_RECIPIENT_ID, recipientId.serialize())
.build()
}
override fun getFactoryKey(): String {
return KEY
}
override fun onRun() {
val recipient: Recipient = Recipient.resolved(recipientId)
if (!recipient.isBlocked && !recipient.isGroup && !recipient.isSelf) {
Log.i(TAG, "Writing a number change event.")
DatabaseFactory.getSmsDatabase(context).insertNumberChangeMessages(recipient)
} else {
Log.i(TAG, "Number changed but not relevant. blocked: ${recipient.isBlocked} isGroup: ${recipient.isGroup} isSelf: ${recipient.isSelf}")
}
}
override fun onShouldRetry(e: Exception): Boolean = false
override fun onFailure() = Unit
class Factory : Job.Factory<RecipientChangedNumberJob> {
override fun create(parameters: Parameters, data: Data): RecipientChangedNumberJob {
return RecipientChangedNumberJob(parameters, RecipientId.from(data.getString(KEY_RECIPIENT_ID)))
}
}
companion object {
const val KEY = "RecipientChangedNumberJob"
private val TAG = Log.tag(RecipientChangedNumberJob::class.java)
private const val KEY_RECIPIENT_ID = "recipient_id"
}
}

Wyświetl plik

@ -103,6 +103,7 @@ public class RefreshAttributesJob extends BaseJob {
"\n GV1 Migration? " + capabilities.isGv1Migration() +
"\n Sender Key? " + capabilities.isSenderKey() +
"\n Announcement Groups? " + capabilities.isAnnouncementGroup() +
"\n Change Number? " + capabilities.isChangeNumber() +
"\n UUID? " + capabilities.isUuid());
SignalServiceAccountManager signalAccountManager = ApplicationDependencies.getSignalServiceAccountManager();

Wyświetl plik

@ -35,11 +35,13 @@ public final class LogSectionCapabilities implements LogSection {
.append("GV1 Migration : ").append(capabilities.isGv1Migration()).append("\n")
.append("Sender Key : ").append(capabilities.isSenderKey()).append("\n")
.append("Announcement Groups: ").append(capabilities.isAnnouncementGroup()).append("\n")
.append("Change Number : ").append(capabilities.isChangeNumber()).append("\n")
.append("\n")
.append("-- Global").append("\n")
.append("GV2 : ").append(self.getGroupsV2Capability()).append("\n")
.append("GV1 Migration : ").append(self.getGroupsV1MigrationCapability()).append("\n")
.append("Sender Key : ").append(self.getSenderKeyCapability()).append("\n")
.append("Announcement Groups: ").append(self.getAnnouncementGroupCapability()).append("\n");
.append("Announcement Groups: ").append(self.getAnnouncementGroupCapability()).append("\n")
.append("Change Number : ").append(self.getChangeNumberCapability()).append("\n");
}
}

Wyświetl plik

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.migrations;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
@ -40,7 +41,8 @@ public class ApplicationMigrations {
private static final int LEGACY_CANONICAL_VERSION = 455;
private static final class Version {
@VisibleForTesting
static final class Version {
static final int LEGACY = 1;
static final int RECIPIENT_ID = 2;
static final int RECIPIENT_SEARCH = 3;
@ -84,9 +86,10 @@ public class ApplicationMigrations {
static final int STICKER_MY_DAILY_LIFE = 42;
static final int SENDER_KEY_3 = 43;
static final int CHANGE_NUMBER_SYNC = 44;
static final int CHANGE_NUMBER_CAPABILITY = 45;
}
public static final int CURRENT_VERSION = 43;
public static final int CURRENT_VERSION = 45;
/**
* This *must* be called after the {@link JobManager} has been instantiated, but *before* the call
@ -372,6 +375,10 @@ public class ApplicationMigrations {
jobs.put(Version.CHANGE_NUMBER_SYNC, new AccountRecordMigrationJob());
}
if (lastSeenVersion < Version.CHANGE_NUMBER_CAPABILITY) {
jobs.put(Version.CHANGE_NUMBER_CAPABILITY, new AttributesMigrationJob());
}
return jobs;
}

Wyświetl plik

@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.recipients;
import static org.thoughtcrime.securesms.database.RecipientDatabase.InsightsBannerTier;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@ -63,6 +61,8 @@ import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.thoughtcrime.securesms.database.RecipientDatabase.InsightsBannerTier;
public class Recipient {
private static final String TAG = Log.tag(Recipient.class);
@ -110,6 +110,7 @@ public class Recipient {
private final Capability groupsV1MigrationCapability;
private final Capability senderKeyCapability;
private final Capability announcementGroupCapability;
private final Capability changeNumberCapability;
private final InsightsBannerTier insightsBannerTier;
private final byte[] storageId;
private final MentionSetting mentionSetting;
@ -362,6 +363,7 @@ public class Recipient {
this.groupsV1MigrationCapability = Capability.UNKNOWN;
this.senderKeyCapability = Capability.UNKNOWN;
this.announcementGroupCapability = Capability.UNKNOWN;
this.changeNumberCapability = Capability.UNKNOWN;
this.storageId = null;
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
this.wallpaper = null;
@ -414,6 +416,7 @@ public class Recipient {
this.groupsV1MigrationCapability = details.groupsV1MigrationCapability;
this.senderKeyCapability = details.senderKeyCapability;
this.announcementGroupCapability = details.announcementGroupCapability;
this.changeNumberCapability = details.changeNumberCapability;
this.storageId = details.storageId;
this.mentionSetting = details.mentionSetting;
this.wallpaper = details.wallpaper;
@ -918,6 +921,10 @@ public class Recipient {
return announcementGroupCapability;
}
public @NonNull Capability getChangeNumberCapability() {
return changeNumberCapability;
}
/**
* True if this recipient supports the message retry system, or false if we should use the legacy session reset system.
*/

Wyświetl plik

@ -65,6 +65,7 @@ public class RecipientDetails {
final Recipient.Capability groupsV1MigrationCapability;
final Recipient.Capability senderKeyCapability;
final Recipient.Capability announcementGroupCapability;
final Recipient.Capability changeNumberCapability;
final InsightsBannerTier insightsBannerTier;
final byte[] storageId;
final MentionSetting mentionSetting;
@ -121,6 +122,7 @@ public class RecipientDetails {
this.groupsV1MigrationCapability = settings.getGroupsV1MigrationCapability();
this.senderKeyCapability = settings.getSenderKeyCapability();
this.announcementGroupCapability = settings.getAnnouncementGroupCapability();
this.changeNumberCapability = settings.getChangeNumberCapability();
this.insightsBannerTier = settings.getInsightsBannerTier();
this.storageId = settings.getStorageId();
this.mentionSetting = settings.getMentionSetting();
@ -177,6 +179,7 @@ public class RecipientDetails {
this.groupsV1MigrationCapability = Recipient.Capability.UNKNOWN;
this.senderKeyCapability = Recipient.Capability.UNKNOWN;
this.announcementGroupCapability = Recipient.Capability.UNKNOWN;
this.changeNumberCapability = Recipient.Capability.UNKNOWN;
this.storageId = null;
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
this.wallpaper = null;

Wyświetl plik

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#FF000000"
android:pathData="M2.41,3.05a3.15,3.15 0,0 0,-0.16 3.12,13.11 13.11,0 0,0 7.58,7.58A3.15,3.15 0,0 0,13 13.59a2.83,2.83 0,0 0,1 -1.16,1.27 1.27,0 0,0 -0.4,-1.62l-2,-1.38a1.27,1.27 0,0 0,-1.65 0.16c-0.22,0.24 -0.37,0.4 -0.54,0.6a0.65,0.65 0,0 1,-0.87 0.12A15.06,15.06 0,0 1,7 9a15.06,15.06 0,0 1,-1.29 -1.5,0.65 0.65,0 0,1 0.12,-0.87l0.6,-0.54a1.27,1.27 0,0 0,0.16 -1.65l-1.38,-2a1.27,1.27 0,0 0,-1.62 -0.4A2.83,2.83 0,0 0,2.41 3.05Z"/>
</vector>

Wyświetl plik

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:fillColor="#FF000000"
android:pathData="M11.17,14.14a4.94,4.94 0,0 1,-1.63 -0.32,12.87 12.87,0 0,1 -4.47,-2.89A12.87,12.87 0,0 1,2.18 6.46,3.49 3.49,0 0,1 2.39,3.1h0a3.17,3.17 0,0 1,1.22 -1,1.69 1.69,0 0,1 2.18,0.51L7.08,4.42A1.68,1.68 0,0 1,6.86 6.6l-0.56,0.52s-0.07,0.1 0,0.13A11.37,11.37 0,0 0,7.41 8.59,10.62 10.62,0 0,0 8.75,9.75s0.09,0 0.13,0c0.17,-0.2 0.31,-0.35 0.52,-0.57a1.68,1.68 0,0 1,2.18 -0.22l1.84,1.29A1.68,1.68 0,0 1,14 12.35a3.15,3.15 0,0 1,-1 1.26A3,3 0,0 1,11.17 14.14ZM4.42,2.86a0.68,0.68 0,0 0,-0.31 0.08,2.13 2.13,0 0,0 -0.9,0.74h0a2.47,2.47 0,0 0,-0.09 2.45,11.77 11.77,0 0,0 6.75,6.75 2.47,2.47 0,0 0,2.45 -0.09,2.12 2.12,0 0,0 0.72,-0.85 0.7,0.7 0,0 0,-0.19 -0.91L11,9.74a0.67,0.67 0,0 0,-0.88 0.08c-0.21,0.22 -0.34,0.36 -0.5,0.55a1.09,1.09 0,0 1,-1.48 0.18A13.27,13.27 0,0 1,6.7 9.3,13.27 13.27,0 0,1 5.45,7.85a1.09,1.09 0,0 1,0.18 -1.48c0.19,-0.16 0.33,-0.29 0.55,-0.5A0.67,0.67 0,0 0,6.26 5L5,3.15A0.73,0.73 0,0 0,4.42 2.86Z"/>
</vector>

Wyświetl plik

@ -1209,6 +1209,7 @@
<string name="MessageRecord_you_marked_your_safety_number_with_s_unverified">You marked your safety number with %s unverified</string>
<string name="MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device">You marked your safety number with %s unverified from another device</string>
<string name="MessageRecord_a_message_from_s_couldnt_be_delivered">A message from %s couldn\'t be delivered</string>
<string name="MessageRecord_s_changed_their_number_to_a_new_number">%1$s changed their number to a new number.</string>
<!-- Group Calling update messages -->
<string name="MessageRecord_s_started_a_group_call_s">%1$s started a group call · %2$s</string>
@ -1950,6 +1951,7 @@
<string name="ConversationUpdateItem_call_is_full">Call is full</string>
<string name="ConversationUpdateItem_invite_friends">Invite friends</string>
<string name="ConversationUpdateItem_enable_call_notifications">Enable Call Notifications</string>
<string name="ConversationUpdateItem_update_contact">Update contact</string>
<string name="ConversationUpdateItem_no_groups_in_common_review_requests_carefully">No groups in common. Review requests carefully.</string>
<string name="ConversationUpdateItem_no_contacts_in_this_group_review_requests_carefully">No contacts in this group. Review requests carefully.</string>
<string name="ConversationUpdateItem_view">View</string>
@ -3505,7 +3507,7 @@
<string name="ChangeNumberEnterPhoneNumberFragment__new_phone_number">New phone number</string>
<string name="ChangeNumberEnterPhoneNumberFragment__the_phone_number_you_entered_doesnt_match_your_accounts">The phone number you entered doesn\'t match your account\'s.</string>
<string name="ChangeNumberEnterPhoneNumberFragment__you_must_specify_your_old_number_country_code">You must specify your old number\'s country code</string>
<string name="ChangeNumberEnterPhoneNumberFragment__you_must_specify_your_old_phone_number">You must specify your old number</string>
<string name="ChangeNumberEnterPhoneNumberFragment__you_must_specify_your_old_phone_number">You must specify your old phone number</string>
<string name="ChangeNumberEnterPhoneNumberFragment__you_must_specify_your_new_number_country_code">You must specify your new number\'s country code</string>
<string name="ChangeNumberEnterPhoneNumberFragment__you_must_specify_your_new_phone_number">You must specify your new phone number</string>

Wyświetl plik

@ -0,0 +1,19 @@
package org.thoughtcrime.securesms.migrations
import org.junit.Assert.assertEquals
import org.junit.Test
import java.lang.reflect.Field
import java.lang.reflect.Modifier
class ApplicationMigrationsTest {
@Test
fun `ensure ApplicationMigration CURRENT_VERSION matches max version`() {
val fields: Array<Field> = ApplicationMigrations.Version::class.java.declaredFields
val maxField: Int? = fields.filter { Modifier.isStatic(it.modifiers) && it.type == Int::class.java }
.map { it.getInt(null) }
.maxOrNull()
assertEquals(ApplicationMigrations.CURRENT_VERSION, maxField)
}
}

Wyświetl plik

@ -9,8 +9,6 @@ package org.whispersystems.signalservice.api.account;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
public class AccountAttributes {
@JsonProperty
@ -134,16 +132,20 @@ public class AccountAttributes {
@JsonProperty
private boolean announcementGroup;
@JsonProperty
private boolean changeNumber;
@JsonCreator
public Capabilities() {}
public Capabilities(boolean uuid, boolean gv2, boolean storage, boolean gv1Migration, boolean senderKey, boolean announcementGroup) {
public Capabilities(boolean uuid, boolean gv2, boolean storage, boolean gv1Migration, boolean senderKey, boolean announcementGroup, boolean changeNumber) {
this.uuid = uuid;
this.gv2 = gv2;
this.storage = storage;
this.gv1Migration = gv1Migration;
this.senderKey = senderKey;
this.announcementGroup = announcementGroup;
this.changeNumber = changeNumber;
}
public boolean isUuid() {
@ -169,5 +171,9 @@ public class AccountAttributes {
public boolean isAnnouncementGroup() {
return announcementGroup;
}
public boolean isChangeNumber() {
return changeNumber;
}
}
}

Wyświetl plik

@ -127,6 +127,9 @@ public class SignalServiceProfile {
@JsonProperty
private boolean announcementGroup;
@JsonProperty
private boolean changeNumber;
@JsonCreator
public Capabilities() {}
@ -149,6 +152,10 @@ public class SignalServiceProfile {
public boolean isAnnouncementGroup() {
return announcementGroup;
}
public boolean isChangeNumber() {
return changeNumber;
}
}
public ProfileKeyCredentialResponse getProfileKeyCredentialResponse() {

Wyświetl plik

@ -16,7 +16,7 @@ public final class AccountAttributesTest {
"reglock1234",
new byte[10],
false,
new AccountAttributes.Capabilities(true, true, true, true, true, true),
new AccountAttributes.Capabilities(true, true, true, true, true, true, true),
false));
assertEquals("{\"signalingKey\":\"skey\"," +
"\"registrationId\":123," +
@ -28,18 +28,18 @@ public final class AccountAttributesTest {
"\"unidentifiedAccessKey\":\"AAAAAAAAAAAAAA==\"," +
"\"unrestrictedUnidentifiedAccess\":false," +
"\"discoverableByPhoneNumber\":false," +
"\"capabilities\":{\"uuid\":true,\"storage\":true,\"senderKey\":true,\"announcementGroup\":true,\"gv2-3\":true,\"gv1-migration\":true}}", json);
"\"capabilities\":{\"uuid\":true,\"storage\":true,\"senderKey\":true,\"announcementGroup\":true,\"changeNumber\":true,\"gv2-3\":true,\"gv1-migration\":true}}", json);
}
@Test
public void gv2_true() {
String json = JsonUtil.toJson(new AccountAttributes.Capabilities(false, true, false, false, false, false));
assertEquals("{\"uuid\":false,\"storage\":false,\"senderKey\":false,\"announcementGroup\":false,\"gv2-3\":true,\"gv1-migration\":false}", json);
String json = JsonUtil.toJson(new AccountAttributes.Capabilities(false, true, false, false, false, false, false));
assertEquals("{\"uuid\":false,\"storage\":false,\"senderKey\":false,\"announcementGroup\":false,\"changeNumber\":false,\"gv2-3\":true,\"gv1-migration\":false}", json);
}
@Test
public void gv2_false() {
String json = JsonUtil.toJson(new AccountAttributes.Capabilities(false, false, false, false, false, false));
assertEquals("{\"uuid\":false,\"storage\":false,\"senderKey\":false,\"announcementGroup\":false,\"gv2-3\":false,\"gv1-migration\":false}", json);
String json = JsonUtil.toJson(new AccountAttributes.Capabilities(false, false, false, false, false, false, false));
assertEquals("{\"uuid\":false,\"storage\":false,\"senderKey\":false,\"announcementGroup\":false,\"changeNumber\":false,\"gv2-3\":false,\"gv1-migration\":false}", json);
}
}