Add Change Number capability and Conversation Update item.
This commit is contained in:
parent
bb446ac1d5
commit
77ff25ec49
31 changed files with 307 additions and 34 deletions
32
.idea/codeStyles/Project.xml
generated
32
.idea/codeStyles/Project.xml
generated
|
@ -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">
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 + " = ? " +
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
9
app/src/main/res/drawable-night/ic_phone_16.xml
Normal file
9
app/src/main/res/drawable-night/ic_phone_16.xml
Normal file
|
@ -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>
|
9
app/src/main/res/drawable/ic_phone_16.xml
Normal file
9
app/src/main/res/drawable/ic_phone_16.xml
Normal file
|
@ -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>
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue