Disable group member labels while in message request state.

This commit is contained in:
jeffrey-signal
2026-04-15 11:44:52 -04:00
parent 5fedd81921
commit c30e3cc1b7
10 changed files with 65 additions and 58 deletions

View File

@@ -215,7 +215,7 @@ class ConversationSettingsRepository(
@WorkerThread
fun isMessageRequestAccepted(recipient: Recipient): Boolean {
return RecipientUtil.isMessageRequestAccepted(context, recipient)
return RecipientUtil.isMessageRequestAccepted(recipient)
}
fun getMembershipCountDescription(liveGroup: LiveGroup): LiveData<String> {

View File

@@ -40,7 +40,7 @@ public class ConversationRepository {
private static final String TAG = Log.tag(ConversationRepository.class);
private final Context context;
private final Context context;
public ConversationRepository() {
this.context = AppDependencies.getApplication();
@@ -54,7 +54,7 @@ public class ConversationRepository {
int lastSeenPosition = 0;
long lastScrolled = metadata.getLastScrolled();
int lastScrolledPosition = 0;
boolean isMessageRequestAccepted = RecipientUtil.isMessageRequestAccepted(context, threadId);
boolean isMessageRequestAccepted = RecipientUtil.isMessageRequestAccepted(threadId);
boolean isConversationHidden = RecipientUtil.isRecipientHidden(threadId);
ConversationData.MessageRequestData messageRequestData = new ConversationData.MessageRequestData(isMessageRequestAccepted, isConversationHidden);
boolean showUniversalExpireTimerUpdate = false;

View File

@@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.conversation.colors.ColorizerV2
import org.thoughtcrime.securesms.conversation.colors.NameColor
import org.thoughtcrime.securesms.database.GroupTable
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.GroupRecord
import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.groups.GroupAccessControl
import org.thoughtcrime.securesms.groups.GroupId
@@ -23,6 +24,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.keyvalue.UiHintValues
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.recipients.RecipientUtil
import org.whispersystems.signalservice.api.NetworkResult
/**
@@ -56,6 +58,7 @@ class MemberLabelRepository private constructor(
fun getLabelSync(groupId: GroupId.V2, recipient: Recipient): MemberLabel? {
val aci = recipient.serviceId.orNull() as? ServiceId.ACI ?: return null
val groupRecord = groupsTable.getGroup(groupId).orNull() ?: return null
if (!isSelfAnActiveGroupMember(groupRecord)) return null
return groupRecord.requireV2GroupProperties().memberLabel(aci)?.sanitized()
}
@@ -66,8 +69,9 @@ class MemberLabelRepository private constructor(
@WorkerThread
fun getLabelsSync(groupId: GroupId.V2, recipients: Collection<Recipient>): Map<RecipientId, MemberLabel> {
val groupRecord = groupsTable.getGroup(groupId).orNull() ?: return emptyMap()
val labelsByAci = groupRecord.requireV2GroupProperties().memberLabelsByAci()
if (!isSelfAnActiveGroupMember(groupRecord)) return emptyMap()
val labelsByAci = groupRecord.requireV2GroupProperties().memberLabelsByAci()
return buildMap {
recipients.forEach { recipient ->
val aci = recipient.serviceId.orNull() as? ServiceId.ACI
@@ -98,6 +102,7 @@ class MemberLabelRepository private constructor(
suspend fun canSetLabel(groupId: GroupId.V2, recipient: Recipient): Boolean = withContext(Dispatchers.IO) {
val groupRecord = groupsTable.getGroup(groupId).orNull() ?: return@withContext false
if (!isSelfAnActiveGroupMember(groupRecord)) return@withContext false
if (groupRecord.isTerminated) return@withContext false
val memberLevel = groupRecord.memberLevel(recipient)
@@ -124,8 +129,9 @@ class MemberLabelRepository private constructor(
*/
suspend fun getMembersWithLabels(groupId: GroupId.V2): List<GroupMemberWithLabel> = withContext(Dispatchers.IO) {
val groupRecord = groupsTable.getGroup(groupId).orNull() ?: return@withContext emptyList()
val groupProperties = groupRecord.requireV2GroupProperties()
if (!isSelfAnActiveGroupMember(groupRecord)) return@withContext emptyList()
val groupProperties = groupRecord.requireV2GroupProperties()
val allMembers = groupProperties.getMemberRecipients(GroupTable.MemberSet.FULL_MEMBERS_INCLUDING_SELF)
val colorizer = ColorizerV2(groupMemberIds = allMembers.mapNotNull { it.serviceId.orNull() })
val labelsByAci = groupProperties.memberLabelsByAci()
@@ -160,6 +166,14 @@ class MemberLabelRepository private constructor(
fun markMemberLabelAboutOverrideWarningDismissed() {
uiHints.markMemberLabelAboutOverrideWarningDismissed()
}
@WorkerThread
private fun isSelfAnActiveGroupMember(groupRecord: GroupRecord): Boolean {
return when {
!groupRecord.memberLevel(Recipient.self()).isInGroup -> false
else -> RecipientUtil.isMessageRequestAccepted(Recipient.resolved(groupRecord.recipientId))
}
}
}
private fun MemberLabel.sanitized(): MemberLabel = this.copy(

View File

@@ -64,12 +64,12 @@ public class SendReadReceiptJob extends BaseJob {
@VisibleForTesting
public SendReadReceiptJob(long threadId, @NonNull RecipientId recipientId, List<Long> messageSentTimestamps, List<MessageId> messageIds) {
this(new Job.Parameters.Builder()
.addConstraint(NetworkConstraint.KEY)
.addConstraint(SealedSenderConstraint.KEY)
.setLifespan(TimeUnit.DAYS.toMillis(1))
.setMaxAttempts(Parameters.UNLIMITED)
.setQueue(recipientId.toQueueKey())
.build(),
.addConstraint(NetworkConstraint.KEY)
.addConstraint(SealedSenderConstraint.KEY)
.setLifespan(TimeUnit.DAYS.toMillis(1))
.setMaxAttempts(Parameters.UNLIMITED)
.setQueue(recipientId.toQueueKey())
.build(),
threadId,
recipientId,
ensureSize(messageSentTimestamps, MAX_TIMESTAMPS),
@@ -151,7 +151,7 @@ public class SendReadReceiptJob extends BaseJob {
if (!TextSecurePreferences.isReadReceiptsEnabled(context) || messageSentTimestamps.isEmpty()) return;
if (!RecipientUtil.isMessageRequestAccepted(context, threadId)) {
if (!RecipientUtil.isMessageRequestAccepted(threadId)) {
Log.w(TAG, "Refusing to send receipts to untrusted recipient");
return;
}

View File

@@ -171,7 +171,7 @@ public class SendViewedReceiptJob extends BaseJob {
return;
}
if (!RecipientUtil.isMessageRequestAccepted(context, threadId)) {
if (!RecipientUtil.isMessageRequestAccepted(threadId)) {
Log.w(TAG, "Refusing to send receipts to untrusted recipient");
return;
}
@@ -203,8 +203,8 @@ public class SendViewedReceiptJob extends BaseJob {
return;
}
SignalServiceMessageSender messageSender = AppDependencies.getSignalServiceMessageSender();
SignalServiceAddress remoteAddress = RecipientUtil.toSignalServiceAddress(context, recipient);
SignalServiceMessageSender messageSender = AppDependencies.getSignalServiceMessageSender();
SignalServiceAddress remoteAddress = RecipientUtil.toSignalServiceAddress(context, recipient);
SignalServiceReceiptMessage receiptMessage = new SignalServiceReceiptMessage(SignalServiceReceiptMessage.Type.VIEWED,
messageSentTimestamps,
timestamp);

View File

@@ -116,7 +116,7 @@ public final class MessageRequestRepository {
return new MessageRequestState(MessageRequestState.State.GROUP_V2_INVITE, reportedAsSpam);
}
default: {
if (RecipientUtil.isMessageRequestAccepted(context, threadId)) {
if (RecipientUtil.isMessageRequestAccepted(threadId)) {
return MessageRequestState.NONE;
} else {
boolean reportedAsSpam = reportedAsSpam(threadId);
@@ -131,7 +131,7 @@ public final class MessageRequestRepository {
return new MessageRequestState(MessageRequestState.State.LEGACY_INDIVIDUAL);
}
} else if (recipient.isPushV1Group()) {
if (RecipientUtil.isMessageRequestAccepted(context, threadId)) {
if (RecipientUtil.isMessageRequestAccepted(threadId)) {
return MessageRequestState.DEPRECATED_V1;
} else if (!recipient.isActiveGroup()) {
return MessageRequestState.NONE;
@@ -139,7 +139,7 @@ public final class MessageRequestRepository {
return MessageRequestState.DEPRECATED_V1;
}
} else {
if (RecipientUtil.isMessageRequestAccepted(context, threadId)) {
if (RecipientUtil.isMessageRequestAccepted(threadId)) {
return MessageRequestState.NONE;
} else {
Recipient.HiddenState hiddenState = RecipientUtil.getRecipientHiddenState(threadId);

View File

@@ -120,7 +120,7 @@ sealed class NotificationBuilder(protected val context: Context) {
}
fun addReplyActions(conversation: NotificationConversation) {
if (privacy.isDisplayMessage && isNotLocked && !conversation.recipient.isPushV1Group && RecipientUtil.isMessageRequestAccepted(context, conversation.recipient)) {
if (privacy.isDisplayMessage && isNotLocked && !conversation.recipient.isPushV1Group && RecipientUtil.isMessageRequestAccepted(conversation.recipient)) {
if (conversation.recipient.isPushV2Group) {
val group: Optional<GroupRecord> = SignalDatabase.groups.getGroup(conversation.recipient.requireGroupId())
if (group.isPresent && group.get().isAnnouncementGroup && !group.get().isAdmin(Recipient.self())) {

View File

@@ -139,7 +139,7 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco
fun getPrimaryText(context: Context): CharSequence {
return if (SignalStore.settings.messageNotificationsPrivacy.isDisplayMessage) {
if (RecipientUtil.isMessageRequestAccepted(context, thread.threadId)) {
if (RecipientUtil.isMessageRequestAccepted(thread.threadId)) {
getPrimaryTextActual(context)
} else {
SpanUtil.italic(context.getString(R.string.SingleRecipientNotificationBuilder_message_request))

View File

@@ -214,10 +214,10 @@ public class RecipientUtil {
private static void insertBlockedUpdate(@NonNull Recipient recipient, long threadId) {
try {
SignalDatabase.messages().insertMessageOutbox(
OutgoingMessage.blockedMessage(recipient, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds())),
threadId,
false,
null
OutgoingMessage.blockedMessage(recipient, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds())),
threadId,
false,
null
);
} catch (MmsException e) {
Log.w(TAG, "Unable to insert blocked message", e);
@@ -227,10 +227,10 @@ public class RecipientUtil {
private static void insertUnblockedUpdate(@NonNull Recipient recipient, long threadId) {
try {
SignalDatabase.messages().insertMessageOutbox(
OutgoingMessage.unblockedMessage(recipient, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds())),
threadId,
false,
null
OutgoingMessage.unblockedMessage(recipient, System.currentTimeMillis(), TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds())),
threadId,
false,
null
);
} catch (MmsException e) {
Log.w(TAG, "Unable to insert unblocked message", e);
@@ -277,7 +277,7 @@ public class RecipientUtil {
* also be the case that the thread in question is for a system contact or something of the like.
*/
@WorkerThread
public static boolean isMessageRequestAccepted(@NonNull Context context, long threadId) {
public static boolean isMessageRequestAccepted(long threadId) {
if (threadId < 0) {
return true;
}
@@ -293,10 +293,10 @@ public class RecipientUtil {
}
/**
* See {@link #isMessageRequestAccepted(Context, long)}.
* See {@link #isMessageRequestAccepted(long)}.
*/
@WorkerThread
public static boolean isMessageRequestAccepted(@NonNull Context context, @Nullable Recipient threadRecipient) {
public static boolean isMessageRequestAccepted(@Nullable Recipient threadRecipient) {
if (threadRecipient == null) {
return true;
}
@@ -306,7 +306,7 @@ public class RecipientUtil {
}
/**
* Like {@link #isMessageRequestAccepted(Context, long)} but with fewer checks around messages so it
* Like {@link #isMessageRequestAccepted(long)} but with fewer checks around messages so it
* is more likely to return false.
*/
@WorkerThread
@@ -334,10 +334,10 @@ public class RecipientUtil {
}
public static boolean isLegacyProfileSharingAccepted(@NonNull Recipient threadRecipient) {
return threadRecipient.isSelf() ||
return threadRecipient.isSelf() ||
threadRecipient.isProfileSharing() ||
threadRecipient.isSystemContact() ||
!threadRecipient.isRegistered() ||
threadRecipient.isSystemContact() ||
!threadRecipient.isRegistered() ||
threadRecipient.isHidden();
}
@@ -375,8 +375,8 @@ public class RecipientUtil {
}
if (threadId == -1 || SignalDatabase.messages().canSetUniversalTimer(threadId)) {
int expireTimerVersion = SignalDatabase.recipients().setExpireMessagesAndIncrementVersion(recipient.getId(), defaultTimer);
OutgoingMessage outgoingMessage = OutgoingMessage.expirationUpdateMessage(recipient, System.currentTimeMillis(), defaultTimer * 1000L, expireTimerVersion);
int expireTimerVersion = SignalDatabase.recipients().setExpireMessagesAndIncrementVersion(recipient.getId(), defaultTimer);
OutgoingMessage outgoingMessage = OutgoingMessage.expirationUpdateMessage(recipient, System.currentTimeMillis(), defaultTimer * 1000L, expireTimerVersion);
MessageSender.send(context, outgoingMessage, SignalDatabase.threads().getOrCreateThreadIdFor(recipient), MessageSender.SendType.SIGNAL, null, null);
return expireTimerVersion;
}
@@ -408,11 +408,6 @@ public class RecipientUtil {
return threadId != null && SignalDatabase.messages().getOutgoingSecureMessageCount(threadId) != 0;
}
public static boolean isSmsOnly(long threadId, @NonNull Recipient threadRecipient) {
return !threadRecipient.isRegistered() ||
noSecureMessagesAndNoCallsInThread(threadId);
}
@WorkerThread
private static boolean noSecureMessagesAndNoCallsInThread(@Nullable Long threadId) {
if (threadId == null) {