kopia lustrzana https://github.com/ryukoposting/Signal-Android
Stop checking very old capabilities.
rodzic
afe36b982f
commit
52965da8a5
|
@ -16,6 +16,7 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
|
||||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
|
||||||
import org.thoughtcrime.securesms.components.settings.configure
|
import org.thoughtcrime.securesms.components.settings.configure
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
|
import org.thoughtcrime.securesms.database.model.RecipientRecord
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
import org.thoughtcrime.securesms.groups.GroupId
|
import org.thoughtcrime.securesms.groups.GroupId
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
|
@ -266,17 +267,23 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildCapabilitySpan(recipient: Recipient): CharSequence {
|
private fun buildCapabilitySpan(recipient: Recipient): CharSequence {
|
||||||
return TextUtils.concat(
|
val capabilities: RecipientRecord.Capabilities? = SignalDatabase.recipients.getCapabilities(recipient.id)
|
||||||
colorize("GV1Migration", recipient.groupsV1MigrationCapability),
|
|
||||||
", ",
|
return if (capabilities != null) {
|
||||||
colorize("AnnouncementGroup", recipient.announcementGroupCapability),
|
TextUtils.concat(
|
||||||
", ",
|
colorize("GV1Migration", capabilities.groupsV1MigrationCapability),
|
||||||
colorize("SenderKey", recipient.senderKeyCapability),
|
", ",
|
||||||
", ",
|
colorize("AnnouncementGroup", capabilities.announcementGroupCapability),
|
||||||
colorize("ChangeNumber", recipient.changeNumberCapability),
|
", ",
|
||||||
", ",
|
colorize("SenderKey", capabilities.senderKeyCapability),
|
||||||
colorize("Stories", recipient.storiesCapability),
|
", ",
|
||||||
)
|
colorize("ChangeNumber", capabilities.changeNumberCapability),
|
||||||
|
", ",
|
||||||
|
colorize("Stories", capabilities.storiesCapability),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
"Recipient not found!"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun colorize(name: String, support: Recipient.Capability): CharSequence {
|
private fun colorize(name: String, support: Recipient.Capability): CharSequence {
|
||||||
|
|
|
@ -3431,6 +3431,21 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||||
updateExtras(recipientId) { b: RecipientExtras.Builder -> b.setManuallyShownAvatar(true) }
|
updateExtras(recipientId) { b: RecipientExtras.Builder -> b.setManuallyShownAvatar(true) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getCapabilities(id: RecipientId): RecipientRecord.Capabilities? {
|
||||||
|
readableDatabase
|
||||||
|
.select(CAPABILITIES)
|
||||||
|
.from(TABLE_NAME)
|
||||||
|
.where("$ID = ?", id)
|
||||||
|
.run()
|
||||||
|
.use { cursor ->
|
||||||
|
return if (cursor.moveToFirst()) {
|
||||||
|
readCapabilities(cursor)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateExtras(recipientId: RecipientId, updater: java.util.function.Function<RecipientExtras.Builder, RecipientExtras.Builder>) {
|
private fun updateExtras(recipientId: RecipientId, updater: java.util.function.Function<RecipientExtras.Builder, RecipientExtras.Builder>) {
|
||||||
val db = writableDatabase
|
val db = writableDatabase
|
||||||
db.beginTransaction()
|
db.beginTransaction()
|
||||||
|
@ -3626,7 +3641,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||||
SYSTEM_PHONE_LABEL to secondaryRecord.systemPhoneLabel,
|
SYSTEM_PHONE_LABEL to secondaryRecord.systemPhoneLabel,
|
||||||
SYSTEM_CONTACT_URI to secondaryRecord.systemContactUri,
|
SYSTEM_CONTACT_URI to secondaryRecord.systemContactUri,
|
||||||
PROFILE_SHARING to (primaryRecord.profileSharing || secondaryRecord.profileSharing),
|
PROFILE_SHARING to (primaryRecord.profileSharing || secondaryRecord.profileSharing),
|
||||||
CAPABILITIES to max(primaryRecord.rawCapabilities, secondaryRecord.rawCapabilities),
|
CAPABILITIES to max(primaryRecord.capabilities.rawBits, secondaryRecord.capabilities.rawBits),
|
||||||
MENTION_SETTING to if (primaryRecord.mentionSetting != MentionSetting.ALWAYS_NOTIFY) primaryRecord.mentionSetting.id else secondaryRecord.mentionSetting.id
|
MENTION_SETTING to if (primaryRecord.mentionSetting != MentionSetting.ALWAYS_NOTIFY) primaryRecord.mentionSetting.id else secondaryRecord.mentionSetting.id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -3901,7 +3916,6 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||||
}
|
}
|
||||||
|
|
||||||
val recipientId = RecipientId.from(cursor.requireLong(idColumnName))
|
val recipientId = RecipientId.from(cursor.requireLong(idColumnName))
|
||||||
val capabilities = cursor.requireLong(CAPABILITIES)
|
|
||||||
val distributionListId: DistributionListId? = DistributionListId.fromNullable(cursor.requireLong(DISTRIBUTION_LIST_ID))
|
val distributionListId: DistributionListId? = DistributionListId.fromNullable(cursor.requireLong(DISTRIBUTION_LIST_ID))
|
||||||
val avatarColor: AvatarColor = if (distributionListId != null) AvatarColor.UNKNOWN else AvatarColor.deserialize(cursor.requireString(AVATAR_COLOR))
|
val avatarColor: AvatarColor = if (distributionListId != null) AvatarColor.UNKNOWN else AvatarColor.deserialize(cursor.requireString(AVATAR_COLOR))
|
||||||
|
|
||||||
|
@ -3939,14 +3953,7 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||||
notificationChannel = cursor.requireString(NOTIFICATION_CHANNEL),
|
notificationChannel = cursor.requireString(NOTIFICATION_CHANNEL),
|
||||||
unidentifiedAccessMode = UnidentifiedAccessMode.fromMode(cursor.requireInt(UNIDENTIFIED_ACCESS_MODE)),
|
unidentifiedAccessMode = UnidentifiedAccessMode.fromMode(cursor.requireInt(UNIDENTIFIED_ACCESS_MODE)),
|
||||||
forceSmsSelection = cursor.requireBoolean(FORCE_SMS_SELECTION),
|
forceSmsSelection = cursor.requireBoolean(FORCE_SMS_SELECTION),
|
||||||
rawCapabilities = capabilities,
|
capabilities = readCapabilities(cursor),
|
||||||
groupsV1MigrationCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.GROUPS_V1_MIGRATION, Capabilities.BIT_LENGTH).toInt()),
|
|
||||||
senderKeyCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.SENDER_KEY, Capabilities.BIT_LENGTH).toInt()),
|
|
||||||
announcementGroupCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.ANNOUNCEMENT_GROUPS, Capabilities.BIT_LENGTH).toInt()),
|
|
||||||
changeNumberCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.CHANGE_NUMBER, Capabilities.BIT_LENGTH).toInt()),
|
|
||||||
storiesCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.STORIES, Capabilities.BIT_LENGTH).toInt()),
|
|
||||||
giftBadgesCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.GIFT_BADGES, Capabilities.BIT_LENGTH).toInt()),
|
|
||||||
pnpCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.PNP, Capabilities.BIT_LENGTH).toInt()),
|
|
||||||
insightsBannerTier = InsightsBannerTier.fromId(cursor.requireInt(SEEN_INVITE_REMINDER)),
|
insightsBannerTier = InsightsBannerTier.fromId(cursor.requireInt(SEEN_INVITE_REMINDER)),
|
||||||
storageId = Base64.decodeNullableOrThrow(cursor.requireString(STORAGE_SERVICE_ID)),
|
storageId = Base64.decodeNullableOrThrow(cursor.requireString(STORAGE_SERVICE_ID)),
|
||||||
mentionSetting = MentionSetting.fromId(cursor.requireInt(MENTION_SETTING)),
|
mentionSetting = MentionSetting.fromId(cursor.requireInt(MENTION_SETTING)),
|
||||||
|
@ -3964,6 +3971,20 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun readCapabilities(cursor: Cursor): RecipientRecord.Capabilities {
|
||||||
|
val capabilities = cursor.requireLong(CAPABILITIES)
|
||||||
|
return RecipientRecord.Capabilities(
|
||||||
|
rawBits = capabilities,
|
||||||
|
groupsV1MigrationCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.GROUPS_V1_MIGRATION, Capabilities.BIT_LENGTH).toInt()),
|
||||||
|
senderKeyCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.SENDER_KEY, Capabilities.BIT_LENGTH).toInt()),
|
||||||
|
announcementGroupCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.ANNOUNCEMENT_GROUPS, Capabilities.BIT_LENGTH).toInt()),
|
||||||
|
changeNumberCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.CHANGE_NUMBER, Capabilities.BIT_LENGTH).toInt()),
|
||||||
|
storiesCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.STORIES, Capabilities.BIT_LENGTH).toInt()),
|
||||||
|
giftBadgesCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.GIFT_BADGES, Capabilities.BIT_LENGTH).toInt()),
|
||||||
|
pnpCapability = Recipient.Capability.deserialize(Bitmask.read(capabilities, Capabilities.PNP, Capabilities.BIT_LENGTH).toInt()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseBadgeList(serializedBadgeList: ByteArray?): List<Badge> {
|
private fun parseBadgeList(serializedBadgeList: ByteArray?): List<Badge> {
|
||||||
var badgeList: BadgeList? = null
|
var badgeList: BadgeList? = null
|
||||||
if (serializedBadgeList != null) {
|
if (serializedBadgeList != null) {
|
||||||
|
|
|
@ -63,14 +63,7 @@ data class RecipientRecord(
|
||||||
val unidentifiedAccessMode: UnidentifiedAccessMode,
|
val unidentifiedAccessMode: UnidentifiedAccessMode,
|
||||||
@get:JvmName("isForceSmsSelection")
|
@get:JvmName("isForceSmsSelection")
|
||||||
val forceSmsSelection: Boolean,
|
val forceSmsSelection: Boolean,
|
||||||
val rawCapabilities: Long,
|
val capabilities: Capabilities,
|
||||||
val groupsV1MigrationCapability: Recipient.Capability,
|
|
||||||
val senderKeyCapability: Recipient.Capability,
|
|
||||||
val announcementGroupCapability: Recipient.Capability,
|
|
||||||
val changeNumberCapability: Recipient.Capability,
|
|
||||||
val storiesCapability: Recipient.Capability,
|
|
||||||
val giftBadgesCapability: Recipient.Capability,
|
|
||||||
val pnpCapability: Recipient.Capability,
|
|
||||||
val insightsBannerTier: InsightsBannerTier,
|
val insightsBannerTier: InsightsBannerTier,
|
||||||
val storageId: ByteArray?,
|
val storageId: ByteArray?,
|
||||||
val mentionSetting: MentionSetting,
|
val mentionSetting: MentionSetting,
|
||||||
|
@ -122,4 +115,29 @@ data class RecipientRecord(
|
||||||
val isForcedUnread: Boolean,
|
val isForcedUnread: Boolean,
|
||||||
val unregisteredTimestamp: Long
|
val unregisteredTimestamp: Long
|
||||||
)
|
)
|
||||||
|
|
||||||
|
data class Capabilities(
|
||||||
|
val rawBits: Long,
|
||||||
|
val groupsV1MigrationCapability: Recipient.Capability,
|
||||||
|
val senderKeyCapability: Recipient.Capability,
|
||||||
|
val announcementGroupCapability: Recipient.Capability,
|
||||||
|
val changeNumberCapability: Recipient.Capability,
|
||||||
|
val storiesCapability: Recipient.Capability,
|
||||||
|
val giftBadgesCapability: Recipient.Capability,
|
||||||
|
val pnpCapability: Recipient.Capability,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
@JvmField
|
||||||
|
val UNKNOWN = Capabilities(
|
||||||
|
0,
|
||||||
|
Recipient.Capability.UNKNOWN,
|
||||||
|
Recipient.Capability.UNKNOWN,
|
||||||
|
Recipient.Capability.UNKNOWN,
|
||||||
|
Recipient.Capability.UNKNOWN,
|
||||||
|
Recipient.Capability.UNKNOWN,
|
||||||
|
Recipient.Capability.UNKNOWN,
|
||||||
|
Recipient.Capability.UNKNOWN
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ public final class GroupsV1MigrationUtil {
|
||||||
registeredMembers = Stream.of(registeredMembers).map(Recipient::fresh).toList();
|
registeredMembers = Stream.of(registeredMembers).map(Recipient::fresh).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Recipient> possibleMembers = forced ? getMigratableManualMigrationMembers(registeredMembers)
|
List<Recipient> possibleMembers = forced ? registeredMembers
|
||||||
: getMigratableAutoMigrationMembers(registeredMembers);
|
: getMigratableAutoMigrationMembers(registeredMembers);
|
||||||
|
|
||||||
if (!forced && !groupRecipient.hasName()) {
|
if (!forced && !groupRecipient.hasName()) {
|
||||||
|
@ -200,17 +200,8 @@ public final class GroupsV1MigrationUtil {
|
||||||
* to consider them migratable in an auto-migration.
|
* to consider them migratable in an auto-migration.
|
||||||
*/
|
*/
|
||||||
private static @NonNull List<Recipient> getMigratableAutoMigrationMembers(@NonNull List<Recipient> registeredMembers) {
|
private static @NonNull List<Recipient> getMigratableAutoMigrationMembers(@NonNull List<Recipient> registeredMembers) {
|
||||||
return Stream.of(getMigratableManualMigrationMembers(registeredMembers))
|
|
||||||
.filter(r -> r.getProfileKey() != null)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* You can only migrate users that have the required capabilities.
|
|
||||||
*/
|
|
||||||
private static @NonNull List<Recipient> getMigratableManualMigrationMembers(@NonNull List<Recipient> registeredMembers) {
|
|
||||||
return Stream.of(registeredMembers)
|
return Stream.of(registeredMembers)
|
||||||
.filter(r -> r.getGroupsV1MigrationCapability() == Recipient.Capability.SUPPORTED)
|
.filter(r -> r.getProfileKey() != null)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +210,6 @@ public final class GroupsV1MigrationUtil {
|
||||||
*/
|
*/
|
||||||
public static boolean isAutoMigratable(@NonNull Recipient recipient) {
|
public static boolean isAutoMigratable(@NonNull Recipient recipient) {
|
||||||
return recipient.hasServiceId() &&
|
return recipient.hasServiceId() &&
|
||||||
recipient.getGroupsV1MigrationCapability() == Recipient.Capability.SUPPORTED &&
|
|
||||||
recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED &&
|
recipient.getRegistered() == RecipientDatabase.RegisteredState.REGISTERED &&
|
||||||
recipient.getProfileKey() != null;
|
recipient.getProfileKey() != null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,19 +68,7 @@ final class GroupsV1MigrationRepository {
|
||||||
return new MigrationState(Collections.emptyList(), Collections.emptyList());
|
return new MigrationState(Collections.emptyList(), Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Recipient> members = Recipient.resolvedList(group.getParticipantIds());
|
List<Recipient> members = Recipient.resolvedList(group.getParticipantIds());
|
||||||
Set<RecipientId> needsRefresh = Stream.of(members)
|
|
||||||
.filter(r -> r.getGroupsV1MigrationCapability() != Recipient.Capability.SUPPORTED)
|
|
||||||
.map(Recipient::getId)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
List<Job> jobs = RetrieveProfileJob.forRecipients(needsRefresh);
|
|
||||||
|
|
||||||
for (Job job : jobs) {
|
|
||||||
if (!ApplicationDependencies.getJobManager().runSynchronously(job, TimeUnit.SECONDS.toMillis(3)).isPresent()) {
|
|
||||||
Log.w(TAG, "Failed to refresh capabilities in time!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<Recipient> registered = Stream.of(members)
|
List<Recipient> registered = Stream.of(members)
|
||||||
|
@ -95,9 +83,7 @@ final class GroupsV1MigrationRepository {
|
||||||
group = group.fresh();
|
group = group.fresh();
|
||||||
|
|
||||||
List<Recipient> ineligible = Stream.of(members)
|
List<Recipient> ineligible = Stream.of(members)
|
||||||
.filter(r -> !r.hasServiceId() ||
|
.filter(r -> !r.hasServiceId() || r.getRegistered() != RecipientDatabase.RegisteredState.REGISTERED)
|
||||||
r.getGroupsV1MigrationCapability() != Recipient.Capability.SUPPORTED ||
|
|
||||||
r.getRegistered() != RecipientDatabase.RegisteredState.REGISTERED)
|
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
List<Recipient> invites = Stream.of(members)
|
List<Recipient> invites = Stream.of(members)
|
||||||
|
|
|
@ -66,49 +66,6 @@ public class GroupV1MigrationJob extends BaseJob {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void enqueueRoutineMigrationsIfNecessary(@NonNull Application application) {
|
|
||||||
if (!SignalStore.registrationValues().isRegistrationComplete() ||
|
|
||||||
!SignalStore.account().isRegistered() ||
|
|
||||||
SignalStore.account().getAci() == null)
|
|
||||||
{
|
|
||||||
Log.i(TAG, "Registration not complete. Skipping.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long timeSinceRefresh = System.currentTimeMillis() - SignalStore.misc().getLastGv1RoutineMigrationTime();
|
|
||||||
|
|
||||||
if (timeSinceRefresh < REFRESH_INTERVAL) {
|
|
||||||
Log.i(TAG, "Too soon to refresh. Did the last refresh " + timeSinceRefresh + " ms ago.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SignalStore.misc().setLastGv1RoutineMigrationTime(System.currentTimeMillis());
|
|
||||||
|
|
||||||
SignalExecutors.BOUNDED.execute(() -> {
|
|
||||||
JobManager jobManager = ApplicationDependencies.getJobManager();
|
|
||||||
List<ThreadRecord> threads = SignalDatabase.threads().getRecentV1Groups(ROUTINE_LIMIT);
|
|
||||||
Set<RecipientId> needsRefresh = new HashSet<>();
|
|
||||||
|
|
||||||
if (threads.size() > 0) {
|
|
||||||
Log.d(TAG, "About to enqueue refreshes for " + threads.size() + " groups.");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ThreadRecord thread : threads) {
|
|
||||||
jobManager.add(new GroupV1MigrationJob(thread.getRecipient().getId()));
|
|
||||||
|
|
||||||
needsRefresh.addAll(Stream.of(Recipient.resolvedList(thread.getRecipient().getParticipantIds()))
|
|
||||||
.filter(r -> r.getGroupsV1MigrationCapability() != Recipient.Capability.SUPPORTED)
|
|
||||||
.map(Recipient::getId)
|
|
||||||
.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needsRefresh.size() > 0) {
|
|
||||||
Log.w(TAG, "Enqueuing profile refreshes for " + needsRefresh.size() + " GV1 participants.");
|
|
||||||
RetrieveProfileJob.enqueue(needsRefresh);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Data serialize() {
|
public @NonNull Data serialize() {
|
||||||
return new Data.Builder().putString(KEY_RECIPIENT_ID, recipientId.serialize())
|
return new Data.Builder().putString(KEY_RECIPIENT_ID, recipientId.serialize())
|
||||||
|
|
|
@ -79,11 +79,6 @@ public final class SenderKeyDistributionSendJob extends BaseJob {
|
||||||
Recipient targetRecipient = Recipient.resolved(targetRecipientId);
|
Recipient targetRecipient = Recipient.resolved(targetRecipientId);
|
||||||
Recipient threadRecipient = Recipient.resolved(threadRecipientId);
|
Recipient threadRecipient = Recipient.resolved(threadRecipientId);
|
||||||
|
|
||||||
if (targetRecipient.getSenderKeyCapability() != Recipient.Capability.SUPPORTED) {
|
|
||||||
Log.w(TAG, targetRecipientId + " does not support sender key! Not sending.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetRecipient.isUnregistered()) {
|
if (targetRecipient.isUnregistered()) {
|
||||||
Log.w(TAG, threadRecipient.getId() + " not registered!");
|
Log.w(TAG, threadRecipient.getId() + " not registered!");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -13,7 +13,6 @@ public final class MiscellaneousValues extends SignalStoreValues {
|
||||||
private static final String LAST_PREKEY_REFRESH_TIME = "last_prekey_refresh_time";
|
private static final String LAST_PREKEY_REFRESH_TIME = "last_prekey_refresh_time";
|
||||||
private static final String MESSAGE_REQUEST_ENABLE_TIME = "message_request_enable_time";
|
private static final String MESSAGE_REQUEST_ENABLE_TIME = "message_request_enable_time";
|
||||||
private static final String LAST_PROFILE_REFRESH_TIME = "misc.last_profile_refresh_time";
|
private static final String LAST_PROFILE_REFRESH_TIME = "misc.last_profile_refresh_time";
|
||||||
private static final String LAST_GV1_ROUTINE_MIGRATION_TIME = "misc.last_gv1_routine_migration_time";
|
|
||||||
private static final String USERNAME_SHOW_REMINDER = "username.show.reminder";
|
private static final String USERNAME_SHOW_REMINDER = "username.show.reminder";
|
||||||
private static final String CLIENT_DEPRECATED = "misc.client_deprecated";
|
private static final String CLIENT_DEPRECATED = "misc.client_deprecated";
|
||||||
private static final String OLD_DEVICE_TRANSFER_LOCKED = "misc.old_device.transfer.locked";
|
private static final String OLD_DEVICE_TRANSFER_LOCKED = "misc.old_device.transfer.locked";
|
||||||
|
@ -62,14 +61,6 @@ public final class MiscellaneousValues extends SignalStoreValues {
|
||||||
putLong(LAST_PROFILE_REFRESH_TIME, time);
|
putLong(LAST_PROFILE_REFRESH_TIME, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLastGv1RoutineMigrationTime() {
|
|
||||||
return getLong(LAST_GV1_ROUTINE_MIGRATION_TIME, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastGv1RoutineMigrationTime(long time) {
|
|
||||||
putLong(LAST_GV1_ROUTINE_MIGRATION_TIME, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void hideUsernameReminder() {
|
public void hideUsernameReminder() {
|
||||||
putBoolean(USERNAME_SHOW_REMINDER, false);
|
putBoolean(USERNAME_SHOW_REMINDER, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,9 @@ import android.content.Context;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.AppCapabilities;
|
import org.thoughtcrime.securesms.AppCapabilities;
|
||||||
|
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.model.RecipientRecord;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.whispersystems.signalservice.api.account.AccountAttributes;
|
import org.whispersystems.signalservice.api.account.AccountAttributes;
|
||||||
|
@ -28,23 +31,31 @@ public final class LogSectionCapabilities implements LogSection {
|
||||||
|
|
||||||
Recipient self = Recipient.self();
|
Recipient self = Recipient.self();
|
||||||
|
|
||||||
AccountAttributes.Capabilities capabilities = AppCapabilities.getCapabilities(false);
|
AccountAttributes.Capabilities localCapabilities = AppCapabilities.getCapabilities(false);
|
||||||
|
RecipientRecord.Capabilities globalCapabilities = SignalDatabase.recipients().getCapabilities(self.getId());
|
||||||
|
|
||||||
return new StringBuilder().append("-- Local").append("\n")
|
StringBuilder builder = new StringBuilder().append("-- Local").append("\n")
|
||||||
.append("GV2 : ").append(capabilities.isGv2()).append("\n")
|
.append("GV2 : ").append(localCapabilities.isGv2()).append("\n")
|
||||||
.append("GV1 Migration : ").append(capabilities.isGv1Migration()).append("\n")
|
.append("GV1 Migration : ").append(localCapabilities.isGv1Migration()).append("\n")
|
||||||
.append("Sender Key : ").append(capabilities.isSenderKey()).append("\n")
|
.append("Sender Key : ").append(localCapabilities.isSenderKey()).append("\n")
|
||||||
.append("Announcement Groups: ").append(capabilities.isAnnouncementGroup()).append("\n")
|
.append("Announcement Groups: ").append(localCapabilities.isAnnouncementGroup()).append("\n")
|
||||||
.append("Change Number : ").append(capabilities.isChangeNumber()).append("\n")
|
.append("Change Number : ").append(localCapabilities.isChangeNumber()).append("\n")
|
||||||
.append("Stories : ").append(capabilities.isStories()).append("\n")
|
.append("Stories : ").append(localCapabilities.isStories()).append("\n")
|
||||||
.append("Gift Badges : ").append(capabilities.isGiftBadges()).append("\n")
|
.append("Gift Badges : ").append(localCapabilities.isGiftBadges()).append("\n")
|
||||||
.append("\n")
|
.append("\n")
|
||||||
.append("-- Global").append("\n")
|
.append("-- Global").append("\n");
|
||||||
.append("GV1 Migration : ").append(self.getGroupsV1MigrationCapability()).append("\n")
|
|
||||||
.append("Sender Key : ").append(self.getSenderKeyCapability()).append("\n")
|
if (globalCapabilities != null) {
|
||||||
.append("Announcement Groups: ").append(self.getAnnouncementGroupCapability()).append("\n")
|
builder.append("GV1 Migration : ").append(globalCapabilities.getGroupsV1MigrationCapability()).append("\n")
|
||||||
.append("Change Number : ").append(self.getChangeNumberCapability()).append("\n")
|
.append("Sender Key : ").append(globalCapabilities.getSenderKeyCapability()).append("\n")
|
||||||
.append("Stories : ").append(self.getStoriesCapability()).append("\n")
|
.append("Announcement Groups: ").append(globalCapabilities.getAnnouncementGroupCapability()).append("\n")
|
||||||
.append("Gift Badges : ").append(self.getGiftBadgesCapability()).append("\n");
|
.append("Change Number : ").append(globalCapabilities.getChangeNumberCapability()).append("\n")
|
||||||
|
.append("Stories : ").append(globalCapabilities.getStoriesCapability()).append("\n")
|
||||||
|
.append("Gift Badges : ").append(globalCapabilities.getGiftBadgesCapability()).append("\n");
|
||||||
|
} else {
|
||||||
|
builder.append("Self not found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,8 +242,7 @@ public final class GroupSendUtil {
|
||||||
validMembership = false;
|
validMembership = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recipient.getSenderKeyCapability() == Recipient.Capability.SUPPORTED &&
|
if (recipient.hasServiceId() &&
|
||||||
recipient.hasServiceId() &&
|
|
||||||
access.isPresent() &&
|
access.isPresent() &&
|
||||||
access.get().getTargetUnidentifiedAccess().isPresent() &&
|
access.get().getTargetUnidentifiedAccess().isPresent() &&
|
||||||
validMembership)
|
validMembership)
|
||||||
|
@ -258,10 +257,6 @@ public final class GroupSendUtil {
|
||||||
Log.i(TAG, "No DistributionId. Using legacy.");
|
Log.i(TAG, "No DistributionId. Using legacy.");
|
||||||
legacyTargets.addAll(senderKeyTargets);
|
legacyTargets.addAll(senderKeyTargets);
|
||||||
senderKeyTargets.clear();
|
senderKeyTargets.clear();
|
||||||
} else if (Recipient.self().getSenderKeyCapability() != Recipient.Capability.SUPPORTED) {
|
|
||||||
Log.i(TAG, "All of our devices do not support sender key. Using legacy.");
|
|
||||||
legacyTargets.addAll(senderKeyTargets);
|
|
||||||
senderKeyTargets.clear();
|
|
||||||
} else if (SignalStore.internalValues().removeSenderKeyMinimum()) {
|
} else if (SignalStore.internalValues().removeSenderKeyMinimum()) {
|
||||||
Log.i(TAG, "Sender key minimum removed. Using for " + senderKeyTargets.size() + " recipients.");
|
Log.i(TAG, "Sender key minimum removed. Using for " + senderKeyTargets.size() + " recipients.");
|
||||||
} else if (senderKeyTargets.size() < 2) {
|
} else if (senderKeyTargets.size() < 2) {
|
||||||
|
|
|
@ -127,7 +127,7 @@ public final class MessageDecryptionUtil {
|
||||||
Log.w(TAG, String.valueOf(envelope.getTimestamp()), e, true);
|
Log.w(TAG, String.valueOf(envelope.getTimestamp()), e, true);
|
||||||
Recipient sender = Recipient.external(context, e.getSender());
|
Recipient sender = Recipient.external(context, e.getSender());
|
||||||
|
|
||||||
if (sender.supportsMessageRetries() && Recipient.self().supportsMessageRetries() && FeatureFlags.retryReceipts()) {
|
if (FeatureFlags.retryReceipts()) {
|
||||||
jobs.add(handleRetry(context, sender, envelope, e));
|
jobs.add(handleRetry(context, sender, envelope, e));
|
||||||
postInternalErrorNotification(context);
|
postInternalErrorNotification(context);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.DistributionListId;
|
import org.thoughtcrime.securesms.database.model.DistributionListId;
|
||||||
import org.thoughtcrime.securesms.database.model.ProfileAvatarFileDetails;
|
import org.thoughtcrime.securesms.database.model.ProfileAvatarFileDetails;
|
||||||
|
import org.thoughtcrime.securesms.database.model.RecipientRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.RecipientExtras;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.RecipientExtras;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
|
@ -118,13 +119,7 @@ public class Recipient {
|
||||||
private final String notificationChannel;
|
private final String notificationChannel;
|
||||||
private final UnidentifiedAccessMode unidentifiedAccessMode;
|
private final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||||
private final boolean forceSmsSelection;
|
private final boolean forceSmsSelection;
|
||||||
private final Capability groupsV1MigrationCapability;
|
private final RecipientRecord.Capabilities capabilities;
|
||||||
private final Capability senderKeyCapability;
|
|
||||||
private final Capability announcementGroupCapability;
|
|
||||||
private final Capability changeNumberCapability;
|
|
||||||
private final Capability storiesCapability;
|
|
||||||
private final Capability giftBadgesCapability;
|
|
||||||
private final Capability pnpCapability;
|
|
||||||
private final InsightsBannerTier insightsBannerTier;
|
private final InsightsBannerTier insightsBannerTier;
|
||||||
private final byte[] storageId;
|
private final byte[] storageId;
|
||||||
private final MentionSetting mentionSetting;
|
private final MentionSetting mentionSetting;
|
||||||
|
@ -421,13 +416,7 @@ public class Recipient {
|
||||||
this.notificationChannel = null;
|
this.notificationChannel = null;
|
||||||
this.unidentifiedAccessMode = UnidentifiedAccessMode.DISABLED;
|
this.unidentifiedAccessMode = UnidentifiedAccessMode.DISABLED;
|
||||||
this.forceSmsSelection = false;
|
this.forceSmsSelection = false;
|
||||||
this.groupsV1MigrationCapability = Capability.UNKNOWN;
|
this.capabilities = RecipientRecord.Capabilities.UNKNOWN;
|
||||||
this.senderKeyCapability = Capability.UNKNOWN;
|
|
||||||
this.announcementGroupCapability = Capability.UNKNOWN;
|
|
||||||
this.changeNumberCapability = Capability.UNKNOWN;
|
|
||||||
this.storiesCapability = Capability.UNKNOWN;
|
|
||||||
this.giftBadgesCapability = Capability.UNKNOWN;
|
|
||||||
this.pnpCapability = Capability.UNKNOWN;
|
|
||||||
this.storageId = null;
|
this.storageId = null;
|
||||||
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
|
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
|
||||||
this.wallpaper = null;
|
this.wallpaper = null;
|
||||||
|
@ -481,13 +470,7 @@ public class Recipient {
|
||||||
this.notificationChannel = details.notificationChannel;
|
this.notificationChannel = details.notificationChannel;
|
||||||
this.unidentifiedAccessMode = details.unidentifiedAccessMode;
|
this.unidentifiedAccessMode = details.unidentifiedAccessMode;
|
||||||
this.forceSmsSelection = details.forceSmsSelection;
|
this.forceSmsSelection = details.forceSmsSelection;
|
||||||
this.groupsV1MigrationCapability = details.groupsV1MigrationCapability;
|
this.capabilities = details.capabilities;
|
||||||
this.senderKeyCapability = details.senderKeyCapability;
|
|
||||||
this.announcementGroupCapability = details.announcementGroupCapability;
|
|
||||||
this.changeNumberCapability = details.changeNumberCapability;
|
|
||||||
this.storiesCapability = details.storiesCapability;
|
|
||||||
this.giftBadgesCapability = details.giftBadgesCapability;
|
|
||||||
this.pnpCapability = details.pnpCapability;
|
|
||||||
this.storageId = details.storageId;
|
this.storageId = details.storageId;
|
||||||
this.mentionSetting = details.mentionSetting;
|
this.mentionSetting = details.mentionSetting;
|
||||||
this.wallpaper = details.wallpaper;
|
this.wallpaper = details.wallpaper;
|
||||||
|
@ -1022,39 +1005,20 @@ public class Recipient {
|
||||||
return forceSmsSelection;
|
return forceSmsSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Capability getGroupsV1MigrationCapability() {
|
|
||||||
return groupsV1MigrationCapability;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull Capability getSenderKeyCapability() {
|
|
||||||
return senderKeyCapability;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull Capability getAnnouncementGroupCapability() {
|
|
||||||
return announcementGroupCapability;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull Capability getChangeNumberCapability() {
|
public @NonNull Capability getChangeNumberCapability() {
|
||||||
return changeNumberCapability;
|
return capabilities.getChangeNumberCapability();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Capability getStoriesCapability() {
|
public @NonNull Capability getStoriesCapability() {
|
||||||
return storiesCapability;
|
return capabilities.getStoriesCapability();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Capability getGiftBadgesCapability() {
|
public @NonNull Capability getGiftBadgesCapability() {
|
||||||
return giftBadgesCapability;
|
return capabilities.getGiftBadgesCapability();
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Capability getPnpCapability() {
|
public @NonNull Capability getPnpCapability() {
|
||||||
return pnpCapability;
|
return capabilities.getPnpCapability();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if this recipient supports the message retry system, or false if we should use the legacy session reset system.
|
|
||||||
*/
|
|
||||||
public boolean supportsMessageRetries() {
|
|
||||||
return getSenderKeyCapability() == Capability.SUPPORTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable byte[] getProfileKey() {
|
public @Nullable byte[] getProfileKey() {
|
||||||
|
@ -1336,7 +1300,6 @@ public class Recipient {
|
||||||
Objects.equals(profileAvatar, other.profileAvatar) &&
|
Objects.equals(profileAvatar, other.profileAvatar) &&
|
||||||
Objects.equals(notificationChannel, other.notificationChannel) &&
|
Objects.equals(notificationChannel, other.notificationChannel) &&
|
||||||
unidentifiedAccessMode == other.unidentifiedAccessMode &&
|
unidentifiedAccessMode == other.unidentifiedAccessMode &&
|
||||||
groupsV1MigrationCapability == other.groupsV1MigrationCapability &&
|
|
||||||
insightsBannerTier == other.insightsBannerTier &&
|
insightsBannerTier == other.insightsBannerTier &&
|
||||||
Arrays.equals(storageId, other.storageId) &&
|
Arrays.equals(storageId, other.storageId) &&
|
||||||
mentionSetting == other.mentionSetting &&
|
mentionSetting == other.mentionSetting &&
|
||||||
|
|
|
@ -69,13 +69,7 @@ public class RecipientDetails {
|
||||||
final String notificationChannel;
|
final String notificationChannel;
|
||||||
final UnidentifiedAccessMode unidentifiedAccessMode;
|
final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||||
final boolean forceSmsSelection;
|
final boolean forceSmsSelection;
|
||||||
final Recipient.Capability groupsV1MigrationCapability;
|
final RecipientRecord.Capabilities capabilities;
|
||||||
final Recipient.Capability senderKeyCapability;
|
|
||||||
final Recipient.Capability announcementGroupCapability;
|
|
||||||
final Recipient.Capability changeNumberCapability;
|
|
||||||
final Recipient.Capability storiesCapability;
|
|
||||||
final Recipient.Capability giftBadgesCapability;
|
|
||||||
final Recipient.Capability pnpCapability;
|
|
||||||
final InsightsBannerTier insightsBannerTier;
|
final InsightsBannerTier insightsBannerTier;
|
||||||
final byte[] storageId;
|
final byte[] storageId;
|
||||||
final MentionSetting mentionSetting;
|
final MentionSetting mentionSetting;
|
||||||
|
@ -134,13 +128,7 @@ public class RecipientDetails {
|
||||||
this.notificationChannel = record.getNotificationChannel();
|
this.notificationChannel = record.getNotificationChannel();
|
||||||
this.unidentifiedAccessMode = record.getUnidentifiedAccessMode();
|
this.unidentifiedAccessMode = record.getUnidentifiedAccessMode();
|
||||||
this.forceSmsSelection = record.isForceSmsSelection();
|
this.forceSmsSelection = record.isForceSmsSelection();
|
||||||
this.groupsV1MigrationCapability = record.getGroupsV1MigrationCapability();
|
this.capabilities = record.getCapabilities();
|
||||||
this.senderKeyCapability = record.getSenderKeyCapability();
|
|
||||||
this.announcementGroupCapability = record.getAnnouncementGroupCapability();
|
|
||||||
this.changeNumberCapability = record.getChangeNumberCapability();
|
|
||||||
this.storiesCapability = record.getStoriesCapability();
|
|
||||||
this.giftBadgesCapability = record.getGiftBadgesCapability();
|
|
||||||
this.pnpCapability = record.getPnpCapability();
|
|
||||||
this.insightsBannerTier = record.getInsightsBannerTier();
|
this.insightsBannerTier = record.getInsightsBannerTier();
|
||||||
this.storageId = record.getStorageId();
|
this.storageId = record.getStorageId();
|
||||||
this.mentionSetting = record.getMentionSetting();
|
this.mentionSetting = record.getMentionSetting();
|
||||||
|
@ -195,13 +183,7 @@ public class RecipientDetails {
|
||||||
this.unidentifiedAccessMode = UnidentifiedAccessMode.UNKNOWN;
|
this.unidentifiedAccessMode = UnidentifiedAccessMode.UNKNOWN;
|
||||||
this.forceSmsSelection = false;
|
this.forceSmsSelection = false;
|
||||||
this.groupName = null;
|
this.groupName = null;
|
||||||
this.groupsV1MigrationCapability = Recipient.Capability.UNKNOWN;
|
this.capabilities = RecipientRecord.Capabilities.UNKNOWN;
|
||||||
this.senderKeyCapability = Recipient.Capability.UNKNOWN;
|
|
||||||
this.announcementGroupCapability = Recipient.Capability.UNKNOWN;
|
|
||||||
this.changeNumberCapability = Recipient.Capability.UNKNOWN;
|
|
||||||
this.storiesCapability = Recipient.Capability.UNKNOWN;
|
|
||||||
this.giftBadgesCapability = Recipient.Capability.UNKNOWN;
|
|
||||||
this.pnpCapability = Recipient.Capability.UNKNOWN;
|
|
||||||
this.storageId = null;
|
this.storageId = null;
|
||||||
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
|
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
|
||||||
this.wallpaper = null;
|
this.wallpaper = null;
|
||||||
|
|
|
@ -127,14 +127,16 @@ object RecipientDatabaseTestUtils {
|
||||||
notificationChannel,
|
notificationChannel,
|
||||||
unidentifiedAccessMode,
|
unidentifiedAccessMode,
|
||||||
forceSmsSelection,
|
forceSmsSelection,
|
||||||
capabilities,
|
RecipientRecord.Capabilities(
|
||||||
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.GROUPS_V1_MIGRATION, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
capabilities,
|
||||||
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.SENDER_KEY, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.GROUPS_V1_MIGRATION, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
||||||
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.ANNOUNCEMENT_GROUPS, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.SENDER_KEY, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
||||||
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.CHANGE_NUMBER, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.ANNOUNCEMENT_GROUPS, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
||||||
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.STORIES, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.CHANGE_NUMBER, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
||||||
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.GIFT_BADGES, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.STORIES, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
||||||
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.PNP, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.GIFT_BADGES, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
||||||
|
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientDatabase.Capabilities.PNP, RecipientDatabase.Capabilities.BIT_LENGTH).toInt()),
|
||||||
|
),
|
||||||
insightBannerTier,
|
insightBannerTier,
|
||||||
storageId,
|
storageId,
|
||||||
mentionSetting,
|
mentionSetting,
|
||||||
|
|
Ładowanie…
Reference in New Issue