Fix 'Unknown' shown for PNI group invites.

This commit is contained in:
Cody Henthorne 2025-01-17 11:18:44 -05:00 committed by Greyson Parrelli
parent b52f9588ef
commit e945efac8b
6 changed files with 47 additions and 31 deletions

View file

@ -452,11 +452,11 @@ public final class ConversationUpdateItem extends FrameLayout
boolean isRingingOnLocalDevice = groupCallUpdateDetails.isRingingOnLocalDevice; boolean isRingingOnLocalDevice = groupCallUpdateDetails.isRingingOnLocalDevice;
boolean endedRecently = GroupCallUpdateDetailsUtil.checkCallEndedRecently(groupCallUpdateDetails); boolean endedRecently = GroupCallUpdateDetailsUtil.checkCallEndedRecently(groupCallUpdateDetails);
UpdateDescription updateDescription = MessageRecord.getGroupCallUpdateDescription(getContext(), conversationMessage.getMessageRecord().getBody(), true); UpdateDescription updateDescription = MessageRecord.getGroupCallUpdateDescription(getContext(), conversationMessage.getMessageRecord().getBody(), true);
Collection<ACI> acis = updateDescription.getMentioned(); Collection<ServiceId> serviceIds = updateDescription.getMentioned();
int text = 0; int text = 0;
if (Util.hasItems(acis) || isRingingOnLocalDevice) { if (Util.hasItems(serviceIds) || isRingingOnLocalDevice) {
if (acis.contains(SignalStore.account().requireAci())) { if (serviceIds.contains(SignalStore.account().requireAci())) {
text = R.string.ConversationUpdateItem_return_to_call; text = R.string.ConversationUpdateItem_return_to_call;
} else if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).isCallFull) { } else if (GroupCallUpdateDetailsUtil.parse(conversationMessage.getMessageRecord().getBody()).isCallFull) {
text = R.string.ConversationUpdateItem_call_is_full; text = R.string.ConversationUpdateItem_call_is_full;

View file

@ -32,7 +32,7 @@ public class GroupCallUpdateMessageFactory implements UpdateDescription.Spannabl
private final ACI selfAci; private final ACI selfAci;
public GroupCallUpdateMessageFactory(@NonNull Context context, public GroupCallUpdateMessageFactory(@NonNull Context context,
@NonNull List<ACI> joinedMembers, @NonNull List<ServiceId> joinedMembers,
boolean withTime, boolean withTime,
@NonNull GroupCallUpdateDetails groupCallUpdateDetails) @NonNull GroupCallUpdateDetails groupCallUpdateDetails)
{ {

View file

@ -233,9 +233,10 @@ final class GroupsV2UpdateMessageProducer {
updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, update.revokerAci, R.drawable.ic_update_group_decline_16)); updates.add(updateDescription(R.string.MessageRecord_s_revoked_your_invitation_to_the_group, update.revokerAci, R.drawable.ic_update_group_decline_16));
} }
} }
private void describeGroupExpirationTimerUpdate(@NonNull GroupExpirationTimerUpdate update, @NonNull List<UpdateDescription> updates) { private void describeGroupExpirationTimerUpdate(@NonNull GroupExpirationTimerUpdate update, @NonNull List<UpdateDescription> updates) {
final int duration = Math.toIntExact(update.expiresInMs / 1000); final int duration = Math.toIntExact(update.expiresInMs / 1000);
String time = ExpirationUtil.getExpirationDisplayValue(context, duration); String time = ExpirationUtil.getExpirationDisplayValue(context, duration);
if (update.updaterAci == null) { if (update.updaterAci == null) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_disappearing_message_time_set_to_s, time), R.drawable.ic_update_timer_16)); updates.add(updateDescription(context.getString(R.string.MessageRecord_disappearing_message_time_set_to_s, time), R.drawable.ic_update_timer_16));
} else { } else {
@ -269,11 +270,13 @@ final class GroupsV2UpdateMessageProducer {
} }
private void describeGroupV2MigrationDroppedMembersUpdate(@NonNull GroupV2MigrationDroppedMembersUpdate update, @NonNull List<UpdateDescription> updates) { private void describeGroupV2MigrationDroppedMembersUpdate(@NonNull GroupV2MigrationDroppedMembersUpdate update, @NonNull List<UpdateDescription> updates) {
updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_removed, update.droppedMembersCount, update.droppedMembersCount), R.drawable.ic_update_group_remove_16)); updates.add(updateDescription(context.getResources()
.getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_removed, update.droppedMembersCount, update.droppedMembersCount), R.drawable.ic_update_group_remove_16));
} }
private void describeGroupV2MigrationInvitedMembersUpdate(@NonNull GroupV2MigrationInvitedMembersUpdate update, @NonNull List<UpdateDescription> updates) { private void describeGroupV2MigrationInvitedMembersUpdate(@NonNull GroupV2MigrationInvitedMembersUpdate update, @NonNull List<UpdateDescription> updates) {
updates.add(updateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_invited, update.invitedMembersCount, update.invitedMembersCount), R.drawable.ic_update_group_remove_16)); updates.add(updateDescription(context.getResources()
.getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_invited, update.invitedMembersCount, update.invitedMembersCount), R.drawable.ic_update_group_remove_16));
} }
private void describeGroupV2MigrationUpdate(@NonNull GroupV2MigrationUpdate update, @NonNull List<UpdateDescription> updates) { private void describeGroupV2MigrationUpdate(@NonNull GroupV2MigrationUpdate update, @NonNull List<UpdateDescription> updates) {
@ -357,7 +360,7 @@ final class GroupsV2UpdateMessageProducer {
boolean requestingMemberIsYou = selfIds.matches(update.requestorAci); boolean requestingMemberIsYou = selfIds.matches(update.requestorAci);
if (requestingMemberIsYou) { if (requestingMemberIsYou) {
updates.add(updateDescription(context.getString(R.string.MessageRecord_you_canceled_your_request_to_join_the_group), R.drawable.ic_update_group_decline_16)); updates.add(updateDescription(context.getString(R.string.MessageRecord_you_canceled_your_request_to_join_the_group), R.drawable.ic_update_group_decline_16));
} else { } else {
updates.add(updateDescription(R.string.MessageRecord_s_canceled_their_request_to_join_the_group, update.requestorAci, R.drawable.ic_update_group_decline_16)); updates.add(updateDescription(R.string.MessageRecord_s_canceled_their_request_to_join_the_group, update.requestorAci, R.drawable.ic_update_group_decline_16));
} }
@ -501,6 +504,7 @@ final class GroupsV2UpdateMessageProducer {
updates.add(updateDescription(R.plurals.MessageRecord_s_invited_members, update.inviteeCount, update.inviterAci, update.inviteeCount, R.drawable.ic_update_group_add_16)); updates.add(updateDescription(R.plurals.MessageRecord_s_invited_members, update.inviteeCount, update.inviterAci, update.inviteeCount, R.drawable.ic_update_group_add_16));
} }
} }
private void describeSelfInvitedOtherUserToGroupUpdate(@NonNull SelfInvitedOtherUserToGroupUpdate update, @NonNull List<UpdateDescription> updates) { private void describeSelfInvitedOtherUserToGroupUpdate(@NonNull SelfInvitedOtherUserToGroupUpdate update, @NonNull List<UpdateDescription> updates) {
updates.add(updateDescription(R.string.MessageRecord_you_invited_s_to_the_group, update.inviteeServiceId, R.drawable.ic_update_group_add_16)); updates.add(updateDescription(R.string.MessageRecord_you_invited_s_to_the_group, update.inviteeServiceId, R.drawable.ic_update_group_add_16));
} }
@ -662,12 +666,17 @@ final class GroupsV2UpdateMessageProducer {
private AccessControl.AccessRequired backupGv2AccessLevelToGroups(@NonNull GroupV2AccessLevel accessLevel) { private AccessControl.AccessRequired backupGv2AccessLevelToGroups(@NonNull GroupV2AccessLevel accessLevel) {
switch (accessLevel) { switch (accessLevel) {
case ANY: return AccessControl.AccessRequired.ANY; case ANY:
case MEMBER: return AccessControl.AccessRequired.MEMBER; return AccessControl.AccessRequired.ANY;
case ADMINISTRATOR: return AccessControl.AccessRequired.ADMINISTRATOR; case MEMBER:
case UNSATISFIABLE: return AccessControl.AccessRequired.UNSATISFIABLE; return AccessControl.AccessRequired.MEMBER;
case ADMINISTRATOR:
return AccessControl.AccessRequired.ADMINISTRATOR;
case UNSATISFIABLE:
return AccessControl.AccessRequired.UNSATISFIABLE;
default: default:
case UNKNOWN: return AccessControl.AccessRequired.UNKNOWN; case UNKNOWN:
return AccessControl.AccessRequired.UNKNOWN;
} }
} }
@ -1483,7 +1492,7 @@ final class GroupsV2UpdateMessageProducer {
@NonNull ByteString serviceId1Bytes, @NonNull ByteString serviceId1Bytes,
@DrawableRes int iconResource) @DrawableRes int iconResource)
{ {
ACI serviceId = ACI.parseOrUnknown(serviceId1Bytes); ServiceId serviceId = ServiceId.parseOrUnknown(serviceId1Bytes);
RecipientId recipientId = RecipientId.from(serviceId); RecipientId recipientId = RecipientId.from(serviceId);
return UpdateDescription.mentioning( return UpdateDescription.mentioning(
@ -1502,8 +1511,8 @@ final class GroupsV2UpdateMessageProducer {
@NonNull ByteString serviceId2Bytes, @NonNull ByteString serviceId2Bytes,
@DrawableRes int iconResource) @DrawableRes int iconResource)
{ {
ACI serviceId1 = ACI.parseOrUnknown(serviceId1Bytes); ServiceId serviceId1 = ServiceId.parseOrUnknown(serviceId1Bytes);
ACI serviceId2 = ACI.parseOrUnknown(serviceId2Bytes); ServiceId serviceId2 = ServiceId.parseOrUnknown(serviceId2Bytes);
RecipientId recipientId1 = RecipientId.from(serviceId1); RecipientId recipientId1 = RecipientId.from(serviceId1);
RecipientId recipientId2 = RecipientId.from(serviceId2); RecipientId recipientId2 = RecipientId.from(serviceId2);
@ -1525,7 +1534,7 @@ final class GroupsV2UpdateMessageProducer {
@NonNull Object formatArg, @NonNull Object formatArg,
@DrawableRes int iconResource) @DrawableRes int iconResource)
{ {
ACI serviceId = ACI.parseOrUnknown(serviceId1Bytes); ServiceId serviceId = ServiceId.parseOrUnknown(serviceId1Bytes);
RecipientId recipientId = RecipientId.from(serviceId); RecipientId recipientId = RecipientId.from(serviceId);
return UpdateDescription.mentioning( return UpdateDescription.mentioning(
@ -1546,7 +1555,7 @@ final class GroupsV2UpdateMessageProducer {
@NonNull Object formatArg, @NonNull Object formatArg,
@DrawableRes int iconResource) @DrawableRes int iconResource)
{ {
ACI serviceId = ACI.parseOrUnknown(serviceId1Bytes); ServiceId serviceId = ServiceId.parseOrUnknown(serviceId1Bytes);
RecipientId recipientId = RecipientId.from(serviceId); RecipientId recipientId = RecipientId.from(serviceId);
return UpdateDescription.mentioning( return UpdateDescription.mentioning(

View file

@ -526,10 +526,10 @@ public abstract class MessageRecord extends DisplayRecord {
public static @NonNull UpdateDescription getGroupCallUpdateDescription(@NonNull Context context, @NonNull String body, boolean withTime) { public static @NonNull UpdateDescription getGroupCallUpdateDescription(@NonNull Context context, @NonNull String body, boolean withTime) {
GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(body); GroupCallUpdateDetails groupCallUpdateDetails = GroupCallUpdateDetailsUtil.parse(body);
List<ACI> joinedMembers = Stream.of(groupCallUpdateDetails.inCallUuids) List<ServiceId> joinedMembers = Stream.of(groupCallUpdateDetails.inCallUuids)
.map(UuidUtil::parseOrNull) .map(UuidUtil::parseOrNull)
.withoutNulls() .withoutNulls()
.map(ACI::from) .<ServiceId>map(ACI::from)
.toList(); .toList();
UpdateDescription.SpannableFactory stringFactory = new GroupCallUpdateMessageFactory(context, joinedMembers, withTime, groupCallUpdateDetails); UpdateDescription.SpannableFactory stringFactory = new GroupCallUpdateMessageFactory(context, joinedMembers, withTime, groupCallUpdateDetails);

View file

@ -30,14 +30,14 @@ public final class UpdateDescription {
Spannable create(); Spannable create();
} }
private final Collection<ACI> mentioned; private final Collection<ServiceId> mentioned;
private final SpannableFactory stringFactory; private final SpannableFactory stringFactory;
private final Spannable staticString; private final Spannable staticString;
private final int lightIconResource; private final int lightIconResource;
private final int lightTint; private final int lightTint;
private final int darkTint; private final int darkTint;
private UpdateDescription(@NonNull Collection<ACI> mentioned, private UpdateDescription(@NonNull Collection<ServiceId> mentioned,
@Nullable SpannableFactory stringFactory, @Nullable SpannableFactory stringFactory,
@Nullable Spannable staticString, @Nullable Spannable staticString,
@DrawableRes int iconResource, @DrawableRes int iconResource,
@ -62,11 +62,11 @@ public final class UpdateDescription {
* @param mentioned UUIDs of recipients that are mentioned in the string. * @param mentioned UUIDs of recipients that are mentioned in the string.
* @param stringFactory The background method for generating the string. * @param stringFactory The background method for generating the string.
*/ */
public static UpdateDescription mentioning(@NonNull Collection<ACI> mentioned, public static UpdateDescription mentioning(@NonNull Collection<ServiceId> mentioned,
@NonNull SpannableFactory stringFactory, @NonNull SpannableFactory stringFactory,
@DrawableRes int iconResource) @DrawableRes int iconResource)
{ {
return new UpdateDescription(mentioned.stream().filter(ACI::isValid).collect(Collectors.toList()), return new UpdateDescription(mentioned.stream().filter(ServiceId::isValid).collect(Collectors.toList()),
stringFactory, stringFactory,
null, null,
iconResource, iconResource,
@ -127,7 +127,7 @@ public final class UpdateDescription {
} }
@AnyThread @AnyThread
public @NonNull Collection<ACI> getMentioned() { public @NonNull Collection<ServiceId> getMentioned() {
return mentioned; return mentioned;
} }
@ -158,7 +158,7 @@ public final class UpdateDescription {
); );
} }
Set<ACI> allMentioned = new HashSet<>(); Set<ServiceId> allMentioned = new HashSet<>();
for (UpdateDescription updateDescription : updateDescriptions) { for (UpdateDescription updateDescription : updateDescriptions) {
allMentioned.addAll(updateDescription.getMentioned()); allMentioned.addAll(updateDescription.getMentioned());

View file

@ -98,6 +98,13 @@ sealed class ServiceId(val libSignalServiceId: LibSignalServiceId) {
@JvmStatic @JvmStatic
@Throws(IllegalArgumentException::class) @Throws(IllegalArgumentException::class)
fun parseOrThrow(bytes: ByteString): ServiceId = parseOrThrow(bytes.toByteArray()) fun parseOrThrow(bytes: ByteString): ServiceId = parseOrThrow(bytes.toByteArray())
/** Parses a ServiceId serialized as a ByteString. Returns [ACI.UNKNOWN] if not parseable. */
@JvmStatic
@Throws(IllegalArgumentException::class)
fun parseOrUnknown(bytes: ByteString): ServiceId {
return parseOrNull(bytes) ?: ACI.UNKNOWN
}
} }
val rawUuid: UUID = libSignalServiceId.rawUUID val rawUuid: UUID = libSignalServiceId.rawUUID