diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 3a5fe5147f..03d86dd627 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -19,6 +19,7 @@ import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel import org.session.libsession.messaging.threads.Address import org.session.libsession.messaging.threads.GroupRecord import org.session.libsession.messaging.threads.recipients.Recipient +import org.session.libsession.messaging.utilities.UpdateMessageBuilder import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.libsignal.ecc.ECKeyPair @@ -79,6 +80,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, return recipient.profileKey } + override fun getDisplayNameForRecipient(recipientPublicKey: String): String? { + val database = DatabaseFactory.getLokiUserDatabase(context) + return database.getDisplayName(recipientPublicKey) + } + override fun getOrGenerateRegistrationID(): Int { var registrationID = TextSecurePreferences.getLocalRegistrationId(context) if (registrationID == null) { @@ -397,7 +403,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, .addAllAdmins(admins) val group = SignalServiceGroup(type1, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList()) val m = IncomingTextMessage(Address.fromSerialized(senderPublicKey), 1, System.currentTimeMillis(), "", Optional.of(group), 0, true) - val infoMessage = IncomingGroupMessage(m, groupContextBuilder.build(), "") + val messageBody = UpdateMessageBuilder.buildGroupUpdateMessage(context, group, senderPublicKey) + val infoMessage = IncomingGroupMessage(m, groupContextBuilder.build(), messageBody) val smsDB = DatabaseFactory.getSmsDatabase(context) smsDB.insertMessageInbox(infoMessage) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocolV2.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocolV2.kt index 9fba4b66ef..9aa4ddd389 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocolV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupsProtocolV2.kt @@ -33,6 +33,7 @@ import org.session.libsignal.utilities.Hex import org.session.libsession.messaging.threads.Address import org.session.libsession.messaging.threads.GroupRecord import org.session.libsession.messaging.threads.recipients.Recipient +import org.session.libsession.messaging.utilities.UpdateMessageBuilder import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.TextSecurePreferences @@ -361,7 +362,7 @@ object ClosedGroupsProtocolV2 { apiDB.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey) // Notify the user (if we didn't make the group) if (userPublicKey != senderPublicKey) { - insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins, sentTimestamp) + insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.NEW_GROUP, name, members, admins, sentTimestamp) } else if (prevGroup == null) { // only notify if we created this group val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID) @@ -415,12 +416,12 @@ object ClosedGroupsProtocolV2 { } val (contextType, signalType) = if (senderLeft) GroupContext.Type.QUIT to SignalServiceGroup.Type.QUIT - else GroupContext.Type.UPDATE to SignalServiceGroup.Type.UPDATE + else GroupContext.Type.UPDATE to SignalServiceGroup.Type.MEMBER_REMOVED if (userPublicKey == senderPublicKey) { val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID) insertOutgoingInfoMessage(context, groupID, contextType, name, members, admins, threadID, sentTimestamp) } else { - insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, members, admins, sentTimestamp) + insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, updateMembers, admins, sentTimestamp) } } @@ -450,7 +451,7 @@ object ClosedGroupsProtocolV2 { val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID) insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp) } else { - insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins, sentTimestamp) + insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.MEMBER_ADDED, name, updateMembers, admins, sentTimestamp) } if (userPublicKey in admins) { // send current encryption key to the latest added members @@ -489,7 +490,7 @@ object ClosedGroupsProtocolV2 { val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID) insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp) } else { - insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins, sentTimestamp) + insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.NAME_CHANGE, name, members, admins, sentTimestamp) } } @@ -608,7 +609,8 @@ object ClosedGroupsProtocolV2 { .addAllAdmins(admins) val group = SignalServiceGroup(type1, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList()) val m = IncomingTextMessage(Address.fromSerialized(senderPublicKey), 1, sentTimestamp, "", Optional.of(group), 0, true) - val infoMessage = IncomingGroupMessage(m, groupContextBuilder.build(), "") + val messageBody = UpdateMessageBuilder.buildGroupUpdateMessage(context, group, senderPublicKey) + val infoMessage = IncomingGroupMessage(m, groupContextBuilder.build(), messageBody) val smsDB = DatabaseFactory.getSmsDatabase(context) smsDB.insertMessageInbox(infoMessage) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0ff4e7f611..09c7b0f1be 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -493,6 +493,14 @@ Received a message encrypted using an old version of Session that is no longer supported. Please ask the sender to update to the most recent version and resend the message. You have left the group. You updated the group. + You created a new group. + %1$s added you to the group. + You renamed the group to %1$s + %1$s renamed the group to: %2$s + You added %1$s to the group. + %1$s added %2$s to the group. + You removed %1$s from the group. + %1$s removed %2$s from the group. You called Contact called Missed call diff --git a/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt index e3062f73ee..5c66b2bd06 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt @@ -34,6 +34,7 @@ interface StorageProtocol { fun getUserProfilePictureURL(): String? fun getProfileKeyForRecipient(recipientPublicKey: String): ByteArray? + fun getDisplayNameForRecipient(recipientPublicKey: String): String? // Signal Protocol diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt index 530badd329..740c181798 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageReceiverHandler.kt @@ -239,7 +239,7 @@ private fun handleNewClosedGroup(sender: String, groupPublicKey: String, name: S storage.createGroup(groupID, name, LinkedList(members.map { Address.fromSerialized(it) }), null, null, LinkedList(admins.map { Address.fromSerialized(it) }), formationTimestamp) // Notify the user - storage.insertIncomingInfoMessage(context, sender, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins) + storage.insertIncomingInfoMessage(context, sender, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.NEW_GROUP, name, members, admins) } storage.setProfileSharing(Address.fromSerialized(groupID), true) // Add the group to the user's set of public keys to poll for @@ -356,7 +356,7 @@ private fun MessageReceiver.handleClosedGroupNameChanged(message: ClosedGroupCon val name = kind.name storage.updateTitle(groupID, name) - storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins) + storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.NAME_CHANGE, name, members, admins) } private fun MessageReceiver.handleClosedGroupMembersAdded(message: ClosedGroupControlMessage) { @@ -388,7 +388,7 @@ private fun MessageReceiver.handleClosedGroupMembersAdded(message: ClosedGroupCo MessageSender.sendLatestEncryptionKeyPair(member, groupPublicKey) } } - storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.UPDATE, name, members, admins) + storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.MEMBER_ADDED, name, updateMembers, admins) } private fun MessageReceiver.handleClosedGroupMembersRemoved(message: ClosedGroupControlMessage) { @@ -435,9 +435,9 @@ private fun MessageReceiver.handleClosedGroupMembersRemoved(message: ClosedGroup } val (contextType, signalType) = if (senderLeft) SignalServiceProtos.GroupContext.Type.QUIT to SignalServiceGroup.Type.QUIT - else SignalServiceProtos.GroupContext.Type.UPDATE to SignalServiceGroup.Type.UPDATE + else SignalServiceProtos.GroupContext.Type.UPDATE to SignalServiceGroup.Type.MEMBER_REMOVED - storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, members, admins) + storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, updateMembers, admins) } private fun MessageReceiver.handleClosedGroupMemberLeft(message: ClosedGroupControlMessage) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt new file mode 100644 index 0000000000..bcc0d4761b --- /dev/null +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -0,0 +1,74 @@ +package org.session.libsession.messaging.utilities + +import android.content.Context +import org.session.libsession.R +import org.session.libsession.messaging.MessagingConfiguration +import org.session.libsignal.service.api.messages.SignalServiceGroup +import org.session.libsignal.service.internal.push.SignalServiceProtos + +object UpdateMessageBuilder { + + fun buildGroupUpdateMessage(context: Context, groupInfo: SignalServiceGroup, sender: String, isOutgoing: Boolean = false): String { + val updateType = groupInfo.type + val senderName: String = if (!isOutgoing) { + MessagingConfiguration.shared.storage.getDisplayNameForRecipient(sender) ?: sender + } else { sender } + var message: String = "" + when (updateType) { + SignalServiceGroup.Type.NEW_GROUP -> { + message = if (isOutgoing) { + context.getString(R.string.MessageRecord_you_created_a_new_group) + } else { + context.getString(R.string.MessageRecord_s_added_you_to_the_group, senderName) + } + } + SignalServiceGroup.Type.NAME_CHANGE -> { + message = if (isOutgoing) { + context.getString(R.string.MessageRecord_you_renamed_the_group_to_s, groupInfo.name.get()) + } else { + context.getString(R.string.MessageRecord_s_renamed_the_group_to_s, senderName, groupInfo.name.get()) + } + } + SignalServiceGroup.Type.MEMBER_ADDED -> { + val members = groupInfo.members.get().joinToString(", ") { + MessagingConfiguration.shared.storage.getDisplayNameForRecipient(it) ?: it + } + message = if (isOutgoing) { + context.getString(R.string.MessageRecord_you_added_s_to_the_group, members) + } else { + context.getString(R.string.MessageRecord_s_added_s_to_the_group, senderName, members) + } + } + SignalServiceGroup.Type.MEMBER_REMOVED -> { + val members = groupInfo.members.get().joinToString(", ") { + MessagingConfiguration.shared.storage.getDisplayNameForRecipient(it) ?: it + } + message = if (isOutgoing) { + context.getString(R.string.MessageRecord_you_removed_s_from_the_group, members) + } else { + context.getString(R.string.MessageRecord_s_removed_s_from_the_group, senderName, members) + } + } + SignalServiceGroup.Type.QUIT -> { + message = if (isOutgoing) { + context.getString(R.string.MessageRecord_left_group) + } else { + context.getString(R.string.ConversationItem_group_action_left, senderName) + } + } + else -> { + message = context.getString(R.string.MessageRecord_s_updated_group, senderName) + } + } + return message + } + + fun buildExpirationTimerMessage(): String { + return "" + } + + fun buildDataExtractionMessage(): String { + return "" + } + +} \ No newline at end of file diff --git a/libsession/src/main/res/values/strings.xml b/libsession/src/main/res/values/strings.xml index 70b424bd22..ea6a33b70b 100644 --- a/libsession/src/main/res/values/strings.xml +++ b/libsession/src/main/res/values/strings.xml @@ -487,6 +487,14 @@ Received a message encrypted using an old version of Session that is no longer supported. Please ask the sender to update to the most recent version and resend the message. You have left the group. You updated the group. + You created a new group. + %1$s added you to the group. + You renamed the group to %1$s + %1$s renamed the group to: %2$s + You added %1$s to the group. + %1$s added %2$s to the group. + You removed %1$s from the group. + %1$s removed %2$s from the group. You called Contact called Missed call diff --git a/libsignal/src/main/java/org/session/libsignal/service/api/messages/SignalServiceGroup.java b/libsignal/src/main/java/org/session/libsignal/service/api/messages/SignalServiceGroup.java index b503531097..68856a87cd 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/api/messages/SignalServiceGroup.java +++ b/libsignal/src/main/java/org/session/libsignal/service/api/messages/SignalServiceGroup.java @@ -37,7 +37,11 @@ public class SignalServiceGroup { UPDATE, DELIVER, QUIT, - REQUEST_INFO + REQUEST_INFO, + NEW_GROUP, + NAME_CHANGE, + MEMBER_ADDED, + MEMBER_REMOVED } private final byte[] groupId;