From ddede475b4b3e6d0a55eb27fc889813283694579 Mon Sep 17 00:00:00 2001 From: Brice-W Date: Fri, 19 Mar 2021 16:25:00 +1100 Subject: [PATCH 1/8] Start of Update messages builder class implementation & usage for Input group updates --- .../securesms/database/Storage.kt | 9 ++- .../loki/protocol/ClosedGroupsProtocolV2.kt | 14 ++-- app/src/main/res/values/strings.xml | 8 ++ .../libsession/messaging/StorageProtocol.kt | 1 + .../MessageReceiverHandler.kt | 10 +-- .../utilities/UpdateMessageBuilder.kt | 74 +++++++++++++++++++ libsession/src/main/res/values/strings.xml | 8 ++ .../api/messages/SignalServiceGroup.java | 6 +- 8 files changed, 117 insertions(+), 13 deletions(-) create mode 100644 libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt 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; From 28cecc02363f2cb9bcefcd9570e72c16b35d42fc Mon Sep 17 00:00:00 2001 From: Brice-W Date: Tue, 23 Mar 2021 09:58:17 +1100 Subject: [PATCH 2/8] expiration timer messages generation updated --- .../conversation/ConversationActivity.java | 4 +- .../conversation/ConversationUpdateItem.java | 2 +- .../securesms/database/SmsDatabase.java | 2 +- .../loki/utilities/GroupDescription.kt | 1 + .../service/ExpiringMessageManager.java | 4 +- app/src/main/res/values/strings.xml | 1 + .../OutgoingExpirationUpdateMessage.java | 8 +-- .../utilities/UpdateMessageBuilder.kt | 54 ++++++++++++++----- libsession/src/main/res/values/strings.xml | 1 + 9 files changed, 56 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index ca14153ed3..e5bb1b85ba 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -89,6 +89,7 @@ import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate; import org.session.libsession.messaging.messages.visible.VisibleMessage; import org.session.libsession.messaging.sending_receiving.attachments.Attachment; import org.session.libsession.messaging.threads.DistributionTypes; +import org.session.libsession.messaging.utilities.UpdateMessageBuilder; import org.session.libsession.utilities.GroupUtil; import org.session.libsession.utilities.MediaTypes; import org.session.libsignal.libsignal.InvalidMessageException; @@ -808,7 +809,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity DatabaseFactory.getRecipientDatabase(ConversationActivity.this).setExpireMessages(recipient, expirationTime); ExpirationTimerUpdate message = new ExpirationTimerUpdate(expirationTime); message.setSentTimestamp(System.currentTimeMillis()); - OutgoingExpirationUpdateMessage outgoingMessage = OutgoingExpirationUpdateMessage.from(message, recipient); + String displayedMessage = UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(getApplicationContext(), expirationTime, null, false); + OutgoingExpirationUpdateMessage outgoingMessage = OutgoingExpirationUpdateMessage.from(message, recipient, displayedMessage); try { message.setId(DatabaseFactory.getMmsDatabase(ConversationActivity.this).insertMessageOutbox(outgoingMessage, getAllocatedThreadId(ConversationActivity.this), false, null)); MessageSender.send(message, recipient.getAddress()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java index 6b76c0572a..7efd5ca4e2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java @@ -175,7 +175,7 @@ public class ConversationUpdateItem extends LinearLayout icon.setImageResource(R.drawable.ic_group_grey600_24dp); icon.clearColorFilter(); - GroupDescription.Companion.getDescription(getContext(), messageRecord.getBody()).addListener(this); + GroupDescription.Companion.getDescription(getContext(), messageRecord.getBody()).addListener(this); //TODO Brice: could be removed if GroupDescription is removed body.setText(messageRecord.getDisplayBody(getContext())); title.setVisibility(GONE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 300a5c55f8..28dbbbe420 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -390,7 +390,7 @@ public class SmsDatabase extends MessagingDatabase { values.put(REPLY_PATH_PRESENT, message.isReplyPathPresent()); values.put(SERVICE_CENTER, message.getServiceCenterAddress()); - values.put(BODY, message.getMessageBody()); + values.put(BODY, message.getMessageBody()); //TODO Brice: is that encoded? values.put(TYPE, type); values.put(THREAD_ID, threadId); diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt index 62d48aa524..dd642beb59 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt @@ -13,6 +13,7 @@ import network.loki.messenger.R import org.session.libsignal.utilities.logging.Log import java.io.IOException +//TODO Brice: that class should be deprecated class GroupDescription(context: Context, groupContext: SignalServiceProtos.GroupContext?) { private val context: Context private val groupContext: SignalServiceProtos.GroupContext? diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java index 77eee247cd..5a60e291c4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.session.libsession.messaging.threads.Address; import org.session.libsession.messaging.threads.recipients.Recipient; +import org.session.libsession.messaging.utilities.UpdateMessageBuilder; import org.session.libsession.utilities.SSKEnvironment; import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.messages.SignalServiceGroup; @@ -78,10 +79,11 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM GroupContext groupContext = content.getDataMessage().getGroup(); groupInfo = Optional.of(new SignalServiceGroup(groupContext.getId().toByteArray(), SignalServiceGroup.GroupType.SIGNAL)); } + String updateMessage = UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, duration, senderPublicKey, false); IncomingMediaMessage mediaMessage = new IncomingMediaMessage(address, content.getDataMessage().getTimestamp(), -1, duration * 1000L, true, false, - Optional.absent(), + Optional.of(updateMessage), groupInfo, Optional.absent(), Optional.absent(), diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3c707cd5c7..ac5121c1d7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -501,6 +501,7 @@ %1$s added %2$s to the group. You removed %1$s from the group. %1$s removed %2$s from the group. + You were removed from the group. You called Contact called Missed call diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java index 77996ba11e..3fac6292f2 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java @@ -10,15 +10,15 @@ import java.util.LinkedList; public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage { - public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn) { - super(recipient, "", new LinkedList(), sentTimeMillis, + public OutgoingExpirationUpdateMessage(Recipient recipient, String body, long sentTimeMillis, long expiresIn) { + super(recipient, body, new LinkedList(), sentTimeMillis, DistributionTypes.CONVERSATION, expiresIn, null, Collections.emptyList(), Collections.emptyList()); } public static OutgoingExpirationUpdateMessage from(ExpirationTimerUpdate message, - Recipient recipient) { - return new OutgoingExpirationUpdateMessage(recipient, message.getSentTimestamp(), message.getDuration() * 1000); + Recipient recipient, String body) { + return new OutgoingExpirationUpdateMessage(recipient, body, message.getSentTimestamp(), message.getDuration() * 1000); } @Override 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 index bcc0d4761b..367e549c02 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -1,19 +1,23 @@ package org.session.libsession.messaging.utilities import android.content.Context +import android.text.SpannableString import org.session.libsession.R import org.session.libsession.messaging.MessagingConfiguration +import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate +import org.session.libsession.utilities.ExpirationUtil 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 { + fun buildGroupUpdateMessage(context: Context, groupInfo: SignalServiceGroup, sender: String? = null, isOutgoing: Boolean = false): String { val updateType = groupInfo.type - val senderName: String = if (!isOutgoing) { - MessagingConfiguration.shared.storage.getDisplayNameForRecipient(sender) ?: sender - } else { sender } var message: String = "" + if (!isOutgoing && sender == null) return message + val senderName: String? = if (!isOutgoing) { + MessagingConfiguration.shared.storage.getDisplayNameForRecipient(sender!!) ?: sender + } else { sender } + when (updateType) { SignalServiceGroup.Type.NEW_GROUP -> { message = if (isOutgoing) { @@ -40,13 +44,25 @@ object UpdateMessageBuilder { } } 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) + val storage = MessagingConfiguration.shared.storage + val userPublicKey = storage.getUserPublicKey()!! + // 1st case: you are part of the removed members + message = if (userPublicKey in groupInfo.members.get()) { + if (isOutgoing) { + context.getString(R.string.MessageRecord_left_group) + } else { + context.getString(R.string.MessageRecord_you_were_removed_from_the_group) + } } else { - context.getString(R.string.MessageRecord_s_removed_s_from_the_group, senderName, members) + // 2nd case: you are not part of the removed members + val members = groupInfo.members.get().joinToString(", ") { + storage.getDisplayNameForRecipient(it) ?: it + } + 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 -> { @@ -63,8 +79,20 @@ object UpdateMessageBuilder { return message } - fun buildExpirationTimerMessage(): String { - return "" + fun buildExpirationTimerMessage(context: Context, duration: Int, sender: String? = null, isOutgoing: Boolean = false): String { + val seconds = (duration!! / 1000) + if (!isOutgoing && sender == null) return "" + val senderName: String? = if (!isOutgoing) { + MessagingConfiguration.shared.storage.getDisplayNameForRecipient(sender!!) ?: sender + } else { sender } + return if (seconds <= 0) { + if (isOutgoing) context.getString(R.string.MessageRecord_you_disabled_disappearing_messages) + else context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, senderName) + } else { + val time = ExpirationUtil.getExpirationDisplayValue(context, seconds) + if (isOutgoing)context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time) + else context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, senderName, time) + } } fun buildDataExtractionMessage(): String { diff --git a/libsession/src/main/res/values/strings.xml b/libsession/src/main/res/values/strings.xml index ea6a33b70b..90cbb92869 100644 --- a/libsession/src/main/res/values/strings.xml +++ b/libsession/src/main/res/values/strings.xml @@ -495,6 +495,7 @@ %1$s added %2$s to the group. You removed %1$s from the group. %1$s removed %2$s from the group. + You were removed from the group. You called Contact called Missed call From 8df7d2bb49137e3f45b23f455653c67905577616 Mon Sep 17 00:00:00 2001 From: Brice-W Date: Thu, 8 Apr 2021 15:27:25 +1000 Subject: [PATCH 3/8] clean --- .../java/org/thoughtcrime/securesms/database/SmsDatabase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 1a7326f4c9..d5c34c5c54 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -390,7 +390,7 @@ public class SmsDatabase extends MessagingDatabase { values.put(REPLY_PATH_PRESENT, message.isReplyPathPresent()); values.put(SERVICE_CENTER, message.getServiceCenterAddress()); - values.put(BODY, message.getMessageBody()); //TODO Brice: is that encoded? + values.put(BODY, message.getMessageBody()); values.put(TYPE, type); values.put(THREAD_ID, threadId); From 9cdcdc43a604dfcb1d24e66131501fae4c66f56c Mon Sep 17 00:00:00 2001 From: Brice-W Date: Wed, 14 Apr 2021 16:37:04 +1000 Subject: [PATCH 4/8] redesign of group update messages management --- .../conversation/ConversationActivity.java | 18 +++----- .../securesms/database/MmsDatabase.java | 15 ++++--- .../securesms/database/SmsDatabase.java | 3 +- .../securesms/database/Storage.kt | 25 ++++------- .../database/model/MessageRecord.java | 2 + .../loki/protocol/ClosedGroupsProtocolV2.kt | 35 +++++++-------- .../service/ExpiringMessageManager.java | 19 ++++---- .../libsession/messaging/StorageProtocol.kt | 4 +- .../messages/control/ExpirationTimerUpdate.kt | 5 +++ .../messages/signal/IncomingGroupMessage.java | 14 ++---- .../OutgoingExpirationUpdateMessage.java | 7 +-- .../signal/OutgoingGroupMediaMessage.java | 44 +++++-------------- .../MessageReceiverHandler.kt | 35 ++++++++------- .../MessageSenderClosedGroup.kt | 15 ++++--- .../utilities/UpdateMessageBuilder.kt | 15 ++++--- .../api/messages/SignalServiceGroup.java | 2 +- 16 files changed, 117 insertions(+), 141 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index de07e941b3..1582f36227 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -89,7 +89,6 @@ import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate; import org.session.libsession.messaging.messages.visible.VisibleMessage; import org.session.libsession.messaging.sending_receiving.attachments.Attachment; import org.session.libsession.messaging.threads.DistributionTypes; -import org.session.libsession.messaging.utilities.UpdateMessageBuilder; import org.session.libsession.utilities.GroupUtil; import org.session.libsession.utilities.MediaTypes; import org.session.libsignal.libsignal.InvalidMessageException; @@ -159,7 +158,6 @@ import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.ImageSlide; import org.thoughtcrime.securesms.mms.MediaConstraints; import org.thoughtcrime.securesms.mms.MmsException; -import org.session.libsession.messaging.messages.signal.OutgoingExpirationUpdateMessage; import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage; import org.session.libsession.messaging.messages.signal.OutgoingSecureMediaMessage; import org.thoughtcrime.securesms.mms.QuoteId; @@ -176,6 +174,7 @@ import org.session.libsession.messaging.threads.recipients.RecipientModifiedList import org.thoughtcrime.securesms.search.model.MessageResult; import org.session.libsession.messaging.sending_receiving.MessageSender; import org.session.libsession.messaging.messages.signal.OutgoingTextMessage; +import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.MediaUtil; @@ -807,16 +806,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity @Override protected Void doInBackground(Void... params) { DatabaseFactory.getRecipientDatabase(ConversationActivity.this).setExpireMessages(recipient, expirationTime); - ExpirationTimerUpdate message = new ExpirationTimerUpdate(null, expirationTime); + ExpirationTimerUpdate message = new ExpirationTimerUpdate(expirationTime); + message.setRecipient(recipient.getAddress().serialize()); // we need the recipient in ExpiringMessageManager.insertOutgoingExpirationTimerMessage message.setSentTimestamp(System.currentTimeMillis()); - String displayedMessage = UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(getApplicationContext(), expirationTime, null, false); - OutgoingExpirationUpdateMessage outgoingMessage = OutgoingExpirationUpdateMessage.from(message, recipient, displayedMessage); - try { - message.setId(DatabaseFactory.getMmsDatabase(ConversationActivity.this).insertMessageOutbox(outgoingMessage, getAllocatedThreadId(ConversationActivity.this), false, null)); - MessageSender.send(message, recipient.getAddress()); - } catch (MmsException e) { - Log.w(TAG, e); - } + ExpiringMessageManager expiringMessageManager = ApplicationContext.getInstance(getApplicationContext()).getExpiringMessageManager(); + expiringMessageManager.setExpirationTimer(message); + MessageSender.send(message, recipient.getAddress()); + return null; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java index 700d64101a..de4248016f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -515,7 +515,7 @@ public class MmsDatabase extends MessagingDatabase { } if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) { - return new OutgoingGroupMediaMessage(recipient, body, attachments, timestamp, 0, quote, contacts, previews); + return new OutgoingGroupMediaMessage(recipient, body, null, attachments, timestamp, 0, quote, contacts, previews); } else if (Types.isExpirationTimerUpdate(outboxType)) { return new OutgoingExpirationUpdateMessage(recipient, timestamp, expiresIn); } @@ -689,8 +689,14 @@ public class MmsDatabase extends MessagingDatabase { { if (threadId == -1) { if(retrieved.isGroup()) { - ByteString decodedGroupId = ((OutgoingGroupMediaMessage)retrieved).getGroupContext().getId(); - String groupId = GroupUtil.doubleEncodeGroupID(decodedGroupId.toByteArray()); + String decodedGroupId = ((OutgoingGroupMediaMessage)retrieved).getGroupId(); + String groupId; + try { + groupId = GroupUtil.doubleEncodeGroupID(decodedGroupId); + } catch (IOException e) { + Log.e(TAG, "Couldn't encrypt group ID"); + throw new MmsException(e); + } Recipient group = Recipient.from(context, Address.fromSerialized(groupId), false); threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(group); } else { @@ -746,8 +752,7 @@ public class MmsDatabase extends MessagingDatabase { if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT; if (message.isGroup()) { - if (((OutgoingGroupMediaMessage)message).isGroupUpdate()) type |= Types.GROUP_UPDATE_BIT; - else if (((OutgoingGroupMediaMessage)message).isGroupQuit()) type |= Types.GROUP_QUIT_BIT; + type |= Types.GROUP_UPDATE_BIT; } if (message.isExpirationUpdate()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index d5c34c5c54..a5affbb569 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -347,8 +347,7 @@ public class SmsDatabase extends MessagingDatabase { type |= Types.SECURE_MESSAGE_BIT; } else if (message.isGroup()) { type |= Types.SECURE_MESSAGE_BIT; - if (((IncomingGroupMessage)message).isUpdate()) type |= Types.GROUP_UPDATE_BIT; - else if (((IncomingGroupMessage)message).isQuit()) type |= Types.GROUP_QUIT_BIT; + type |= Types.GROUP_UPDATE_BIT; } if (message.isPush()) type |= Types.PUSH_MESSAGE_BIT; 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 1c6a28b564..30c515e91d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -400,31 +400,22 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, DatabaseFactory.getGroupDatabase(context).updateMembers(groupID, members) } - override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type0: SignalServiceProtos.GroupContext.Type, type1: SignalServiceGroup.Type, name: String, members: Collection, admins: Collection, sentTimestamp: Long) { - val groupContextBuilder = SignalServiceProtos.GroupContext.newBuilder() - .setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID))) - .setType(type0) - .setName(name) - .addAllMembers(members) - .addAllAdmins(admins) - val group = SignalServiceGroup(type1, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList()) + override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection, admins: Collection, sentTimestamp: Long) { + val group = SignalServiceGroup(type, 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 messageBody = UpdateMessageBuilder.buildGroupUpdateMessage(context, group, senderPublicKey) - val infoMessage = IncomingGroupMessage(m, groupContextBuilder.build(), messageBody) + val infoMessage = IncomingGroupMessage(m, groupID, messageBody) val smsDB = DatabaseFactory.getSmsDatabase(context) smsDB.insertMessageInbox(infoMessage) } - override fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceProtos.GroupContext.Type, name: String, members: Collection, admins: Collection, threadID: Long, sentTimestamp: Long) { + override fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection, admins: Collection, threadID: Long, sentTimestamp: Long) { val userPublicKey = getUserPublicKey() val recipient = Recipient.from(context, Address.fromSerialized(groupID), false) - val groupContextBuilder = SignalServiceProtos.GroupContext.newBuilder() - .setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupID))) - .setType(type) - .setName(name) - .addAllMembers(members) - .addAllAdmins(admins) - val infoMessage = OutgoingGroupMediaMessage(recipient, groupContextBuilder.build(), null, sentTimestamp, 0, false, null, listOf(), listOf()) + + val group = SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList()) + val messageBody = UpdateMessageBuilder.buildGroupUpdateMessage(context, group, null, true) + val infoMessage = OutgoingGroupMediaMessage(recipient, messageBody, groupID, null, sentTimestamp, 0, false, null, listOf(), listOf()) val mmsDB = DatabaseFactory.getMmsDatabase(context) val mmsSmsDB = DatabaseFactory.getMmsSmsDatabase(context) if (mmsSmsDB.getMessageFor(sentTimestamp,userPublicKey) != null) return diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index b41e4ae78e..f4c9bb95a7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -24,6 +24,8 @@ import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import network.loki.messenger.R; + +import org.session.libsession.messaging.utilities.UpdateMessageBuilder; import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.SmsDatabase; import org.session.libsession.database.documents.IdentityKeyMismatch; 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 6d6f5b4971..df1d7c0b52 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 @@ -9,7 +9,6 @@ import org.session.libsignal.libsignal.ecc.ECKeyPair import org.session.libsignal.service.api.messages.SignalServiceGroup import org.session.libsignal.service.internal.push.SignalServiceProtos import org.session.libsignal.service.internal.push.SignalServiceProtos.DataMessage -import org.session.libsignal.service.internal.push.SignalServiceProtos.GroupContext import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded import org.session.libsignal.service.loki.utilities.toHexString import org.thoughtcrime.securesms.database.DatabaseFactory @@ -26,7 +25,6 @@ import org.session.libsession.messaging.sending_receiving.sendEncryptionKeyPair 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 @@ -105,11 +103,11 @@ object ClosedGroupsProtocolV2 { apiDB.addClosedGroupEncryptionKeyPair(encryptionKeyPair, groupPublicKey) // Notify the user (if we didn't make the group) if (userPublicKey != senderPublicKey) { - DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.NEW_GROUP, name, members, admins, sentTimestamp) + DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, sentTimestamp) } else if (prevGroup == null) { // only notify if we created this group val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID) - DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp) + DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, threadID, sentTimestamp) } // Notify the PN server LokiPushNotificationManager.performOperation(context, ClosedGroupOperation.Subscribe, groupPublicKey, userPublicKey) @@ -157,14 +155,14 @@ object ClosedGroupsProtocolV2 { MessageSender.generateAndSendNewEncryptionKeyPair(groupPublicKey, newMembers) } } - val (contextType, signalType) = - if (senderLeft) GroupContext.Type.QUIT to SignalServiceGroup.Type.QUIT - else GroupContext.Type.UPDATE to SignalServiceGroup.Type.MEMBER_REMOVED + val type = + if (senderLeft) SignalServiceGroup.Type.QUIT + else SignalServiceGroup.Type.UPDATE if (userPublicKey == senderPublicKey) { val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID) - DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, contextType, name, members, admins, threadID, sentTimestamp) + DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, type, name, members, admins, threadID, sentTimestamp) } else { - DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, members, admins, sentTimestamp) + DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, members, admins, sentTimestamp) } } @@ -192,9 +190,9 @@ object ClosedGroupsProtocolV2 { groupDB.updateMembers(groupID, newMembers.map { Address.fromSerialized(it) }) if (userPublicKey == senderPublicKey) { val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID) - DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp) + DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, threadID, sentTimestamp) } else { - DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.MEMBER_ADDED, name, members, admins, sentTimestamp) + DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, sentTimestamp) } if (userPublicKey in admins) { // send current encryption key to the latest added members @@ -231,9 +229,9 @@ object ClosedGroupsProtocolV2 { // Notify the user if (userPublicKey == senderPublicKey) { val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID) - DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID, sentTimestamp) + DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, threadID, sentTimestamp) } else { - DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.UPDATE, SignalServiceGroup.Type.NAME_CHANGE, name, members, admins, sentTimestamp) + DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.UPDATE, name, members, admins, sentTimestamp) } } @@ -273,9 +271,9 @@ object ClosedGroupsProtocolV2 { // Notify user if (userLeft) { val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID) - DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, GroupContext.Type.QUIT, name, members, admins, threadID, sentTimestamp) + DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.QUIT, name, members, admins, threadID, sentTimestamp) } else { - DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, GroupContext.Type.QUIT, SignalServiceGroup.Type.QUIT, name, members, admins, sentTimestamp) + DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.QUIT, name, members, admins, sentTimestamp) } } @@ -386,14 +384,13 @@ object ClosedGroupsProtocolV2 { } // Notify the user val wasSenderRemoved = !members.contains(senderPublicKey) - val type0 = if (wasSenderRemoved) GroupContext.Type.QUIT else GroupContext.Type.UPDATE - val type1 = if (wasSenderRemoved) SignalServiceGroup.Type.QUIT else SignalServiceGroup.Type.UPDATE + val type = if (wasSenderRemoved) SignalServiceGroup.Type.QUIT else SignalServiceGroup.Type.UPDATE val admins = group.admins.map { it.toString() } if (userPublicKey == senderPublicKey) { val threadID = DatabaseFactory.getLokiThreadDatabase(context).getThreadID(groupID) - DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, type0, name, members, admins, threadID, sentTimestamp) + DatabaseFactory.getStorage(context).insertOutgoingInfoMessage(context, groupID, type, name, members, admins, threadID, sentTimestamp) } else { - DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, type0, type1, name, members, admins, sentTimestamp) + DatabaseFactory.getStorage(context).insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, members, admins, sentTimestamp) } } // endregion diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java index 8cc1224d79..8d10605fc8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java @@ -78,8 +78,8 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM String senderPublicKey = message.getSender(); // Notify the user - if (userPublicKey.equals(senderPublicKey)) { - // sender is a linked device + if (senderPublicKey == null || userPublicKey.equals(senderPublicKey)) { + // sender is self or a linked device insertOutgoingExpirationTimerMessage(message); } else { insertIncomingExpirationTimerMessage(message); @@ -97,9 +97,10 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM Long sentTimestamp = message.getSentTimestamp(); String groupId = message.getGroupPublicKey(); int duration = message.getDuration(); + String messageBody = UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, duration, senderPublicKey, false); Optional groupInfo = Optional.absent(); - Address address = Address.fromSerialized((message.getSyncTarget() != null && !message.getSyncTarget().isEmpty()) ? message.getSyncTarget() : senderPublicKey); + Address address = Address.fromSerialized(senderPublicKey); Recipient recipient = Recipient.from(context, address, false); // if the sender is blocked, we don't display the update, except if it's in a closed group @@ -117,7 +118,7 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM IncomingMediaMessage mediaMessage = new IncomingMediaMessage(address, sentTimestamp, -1, duration * 1000L, true, false, - Optional.absent(), + Optional.of(messageBody), groupInfo, Optional.absent(), Optional.absent(), @@ -137,27 +138,25 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM private void insertOutgoingExpirationTimerMessage(ExpirationTimerUpdate message) { MmsDatabase database = DatabaseFactory.getMmsDatabase(context); - String senderPublicKey = message.getSender(); Long sentTimestamp = message.getSentTimestamp(); String groupId = message.getGroupPublicKey(); int duration = message.getDuration(); + String messageBody = UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, duration, null, true); - Address address = Address.fromSerialized((message.getSyncTarget() != null && !message.getSyncTarget().isEmpty()) ? message.getSyncTarget() : senderPublicKey); + Address address = Address.fromSerialized((message.getSyncTarget() != null && !message.getSyncTarget().isEmpty()) ? message.getSyncTarget() : message.getRecipient()); Recipient recipient = Recipient.from(context, address, false); try { if (groupId != null) { // conversation is a closed group - GroupContext groupContext = SignalServiceProtos.GroupContext.newBuilder() - .setId(ByteString.copyFrom(GroupUtil.getDecodedGroupIDAsData(groupId))).build(); - OutgoingGroupMediaMessage infoMessage = new OutgoingGroupMediaMessage(recipient, groupContext, null, sentTimestamp, duration * 1000L, true, null, Collections.emptyList(), Collections.emptyList()); + OutgoingGroupMediaMessage infoMessage = new OutgoingGroupMediaMessage(recipient, messageBody, groupId, null, sentTimestamp, duration * 1000L, true, null, Collections.emptyList(), Collections.emptyList()); database.insertSecureDecryptedMessageOutbox(infoMessage, -1, sentTimestamp); // we need the group ID as recipient for setExpireMessages below recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.doubleEncodeGroupID(groupId)), false); } else { // conversation is a 1-1 OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipient, - null, + messageBody, Collections.emptyList(), message.getSentTimestamp(), -1, 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 d4aaf2b2cb..d7d5624e24 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/StorageProtocol.kt @@ -117,9 +117,9 @@ interface StorageProtocol { fun removeClosedGroupPublicKey(groupPublicKey: String) fun addClosedGroupEncryptionKeyPair(encryptionKeyPair: ECKeyPair, groupPublicKey: String) fun removeAllClosedGroupEncryptionKeyPairs(groupPublicKey: String) - fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type0: SignalServiceProtos.GroupContext.Type, type1: SignalServiceGroup.Type, + fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection, admins: Collection, sentTimestamp: Long) - fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceProtos.GroupContext.Type, name: String, + fun insertOutgoingInfoMessage(context: Context, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection, admins: Collection, threadID: Long, sentTimestamp: Long) fun isClosedGroup(publicKey: String): Boolean fun getClosedGroupEncryptionKeyPairs(groupPublicKey: String): MutableList diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt index 85f34eed51..5dff39072c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/ExpirationTimerUpdate.kt @@ -33,6 +33,11 @@ class ExpirationTimerUpdate() : ControlMessage() { this.duration = duration } + internal constructor(duration: Int) : this() { + this.syncTarget = null + this.duration = duration + } + // validation override fun isValid(): Boolean { if (!super.isValid()) return false diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingGroupMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingGroupMessage.java index b0a7de08ee..901f151cdf 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingGroupMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingGroupMessage.java @@ -4,11 +4,11 @@ import static org.session.libsignal.service.internal.push.SignalServiceProtos.Gr public class IncomingGroupMessage extends IncomingTextMessage { - private final GroupContext groupContext; + private final String groupID; - public IncomingGroupMessage(IncomingTextMessage base, GroupContext groupContext, String body) { + public IncomingGroupMessage(IncomingTextMessage base, String groupID, String body) { super(base, body); - this.groupContext = groupContext; + this.groupID = groupID; } @Override @@ -16,12 +16,4 @@ public class IncomingGroupMessage extends IncomingTextMessage { return true; } - public boolean isUpdate() { - return groupContext.getType().getNumber() == GroupContext.Type.UPDATE_VALUE; - } - - public boolean isQuit() { - return groupContext.getType().getNumber() == GroupContext.Type.QUIT_VALUE; - } - } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java index 94f1016b56..087751e2fd 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java @@ -8,17 +8,18 @@ import org.session.libsession.messaging.threads.recipients.Recipient; import java.util.Collections; import java.util.LinkedList; +// TODO this class could be deleted if its usage in MmsDatabase.getOutgoingMessage is replaced by something elsex public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage { - public OutgoingExpirationUpdateMessage(Recipient recipient, String body, long sentTimeMillis, long expiresIn) { + public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn) { super(recipient, "", new LinkedList(), sentTimeMillis, DistributionTypes.CONVERSATION, expiresIn, true, null, Collections.emptyList(), Collections.emptyList()); } public static OutgoingExpirationUpdateMessage from(ExpirationTimerUpdate message, - Recipient recipient, String body) { - return new OutgoingExpirationUpdateMessage(recipient, body, message.getSentTimestamp(), message.getDuration() * 1000); + Recipient recipient) { + return new OutgoingExpirationUpdateMessage(recipient, message.getSentTimestamp(), message.getDuration() * 1000); } @Override diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingGroupMediaMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingGroupMediaMessage.java index 7f151ae7ee..a726286be6 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingGroupMediaMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingGroupMediaMessage.java @@ -19,10 +19,11 @@ import java.util.List; public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage { - private final GroupContext group; + private final String groupID; public OutgoingGroupMediaMessage(@NonNull Recipient recipient, - @NonNull String encodedGroupContext, + @NonNull String body, + @Nullable String groupId, @NonNull List avatar, long sentTimeMillis, long expiresIn, @@ -31,30 +32,15 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage { @NonNull List previews) throws IOException { - super(recipient, encodedGroupContext, avatar, sentTimeMillis, + super(recipient, body, avatar, sentTimeMillis, DistributionTypes.CONVERSATION, expiresIn, false, quote, contacts, previews); - this.group = GroupContext.parseFrom(Base64.decode(encodedGroupContext)); + this.groupID = groupId; } public OutgoingGroupMediaMessage(@NonNull Recipient recipient, - @NonNull GroupContext group, - @Nullable final Attachment avatar, - long expireIn, - @Nullable QuoteModel quote, - @NonNull List contacts, - @NonNull List previews) - { - super(recipient, Base64.encodeBytes(group.toByteArray()), - new LinkedList() {{if (avatar != null) add(avatar);}}, - System.currentTimeMillis(), - DistributionTypes.CONVERSATION, expireIn, false, quote, contacts, previews); - - this.group = group; - } - - public OutgoingGroupMediaMessage(@NonNull Recipient recipient, - @NonNull GroupContext group, + @NonNull String body, + @Nullable String groupId, @Nullable final Attachment avatar, long sentTime, long expireIn, @@ -63,12 +49,12 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage { @NonNull List contacts, @NonNull List previews) { - super(recipient, Base64.encodeBytes(group.toByteArray()), + super(recipient, body, new LinkedList() {{if (avatar != null) add(avatar);}}, sentTime, DistributionTypes.CONVERSATION, expireIn, expirationUpdate, quote, contacts, previews); - this.group = group; + this.groupID = groupId; } @Override @@ -76,15 +62,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage { return true; } - public boolean isGroupUpdate() { - return group.getType().getNumber() == GroupContext.Type.UPDATE_VALUE; - } - - public boolean isGroupQuit() { - return group.getType().getNumber() == GroupContext.Type.QUIT_VALUE; - } - - public GroupContext getGroupContext() { - return group; + public String getGroupId() { + return groupID; } } 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 00415aa9cc..b860f02732 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 @@ -243,8 +243,15 @@ private fun handleNewClosedGroup(sender: String, sentTimestamp: Long, groupPubli } else { storage.createGroup(groupID, name, LinkedList(members.map { Address.fromSerialized(it) }), null, null, LinkedList(admins.map { Address.fromSerialized(it) }), formationTimestamp) + val userPublicKey = TextSecurePreferences.getLocalNumber(context) // Notify the user - storage.insertIncomingInfoMessage(context, sender, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.NEW_GROUP, name, members, admins, sentTimestamp) + if (userPublicKey == sender) { + // sender is a linked device + val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) + storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, threadID, sentTimestamp) + } else { + storage.insertIncomingInfoMessage(context, sender, groupID, SignalServiceGroup.Type.CREATION, name, members, admins, sentTimestamp) + } } storage.setProfileSharing(Address.fromSerialized(groupID), true) // Add the group to the user's set of public keys to poll for @@ -304,9 +311,8 @@ private fun MessageReceiver.handleClosedGroupUpdated(message: ClosedGroupControl } // Notify the user val wasSenderRemoved = !members.contains(senderPublicKey) - val type0 = if (wasSenderRemoved) SignalServiceProtos.GroupContext.Type.QUIT else SignalServiceProtos.GroupContext.Type.UPDATE - val type1 = if (wasSenderRemoved) SignalServiceGroup.Type.QUIT else SignalServiceGroup.Type.UPDATE - storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, type0, type1, name, members, group.admins.map { it.toString() }, message.sentTimestamp!!) + val type = if (wasSenderRemoved) SignalServiceGroup.Type.QUIT else SignalServiceGroup.Type.MEMBER_REMOVED + storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, members, group.admins.map { it.toString() }, message.sentTimestamp!!) } private fun MessageReceiver.handleClosedGroupEncryptionKeyPair(message: ClosedGroupControlMessage) { @@ -378,9 +384,9 @@ private fun MessageReceiver.handleClosedGroupNameChanged(message: ClosedGroupCon if (userPublicKey == senderPublicKey) { // sender is a linked device val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) - storage.insertOutgoingInfoMessage(context, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, name, members, admins, threadID, message.sentTimestamp!!) + storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.NAME_CHANGE, name, members, admins, threadID, message.sentTimestamp!!) } else { - storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.NAME_CHANGE, name, members, admins, message.sentTimestamp!!) + storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.NAME_CHANGE, name, members, admins, message.sentTimestamp!!) } } @@ -413,9 +419,9 @@ private fun MessageReceiver.handleClosedGroupMembersAdded(message: ClosedGroupCo if (userPublicKey == senderPublicKey) { // sender is a linked device val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) - storage.insertOutgoingInfoMessage(context, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, name, members, admins, threadID, message.sentTimestamp!!) + storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.MEMBER_ADDED, name, updateMembers, admins, threadID, message.sentTimestamp!!) } else { - storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.UPDATE, SignalServiceGroup.Type.MEMBER_ADDED, name, members, admins, message.sentTimestamp!!) + storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.MEMBER_ADDED, name, updateMembers, admins, message.sentTimestamp!!) } if (userPublicKey in admins) { // send current encryption key to the latest added members @@ -477,17 +483,16 @@ private fun MessageReceiver.handleClosedGroupMembersRemoved(message: ClosedGroup MessageSender.generateAndSendNewEncryptionKeyPair(groupPublicKey, newMembers) } } - val (contextType, signalType) = - if (senderLeft) SignalServiceProtos.GroupContext.Type.QUIT to SignalServiceGroup.Type.QUIT - else SignalServiceProtos.GroupContext.Type.UPDATE to SignalServiceGroup.Type.MEMBER_REMOVED + val type = if (senderLeft) SignalServiceGroup.Type.QUIT + else SignalServiceGroup.Type.MEMBER_REMOVED // Notify the user if (userPublicKey == senderPublicKey) { // sender is a linked device val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) - storage.insertOutgoingInfoMessage(context, groupID, contextType, name, members, admins, threadID, message.sentTimestamp!!) + storage.insertOutgoingInfoMessage(context, groupID, type, name, updateMembers, admins, threadID, message.sentTimestamp!!) } else { - storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, contextType, signalType, name, members, admins, message.sentTimestamp!!) + storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, type, name, updateMembers, admins, message.sentTimestamp!!) } } @@ -533,9 +538,9 @@ private fun MessageReceiver.handleClosedGroupMemberLeft(message: ClosedGroupCont if (userLeft) { //sender is a linked device val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) - storage.insertOutgoingInfoMessage(context, groupID, SignalServiceProtos.GroupContext.Type.QUIT, name, members, admins, threadID, message.sentTimestamp!!) + storage.insertOutgoingInfoMessage(context, groupID, SignalServiceGroup.Type.QUIT, name, members, admins, threadID, message.sentTimestamp!!) } else { - storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceProtos.GroupContext.Type.QUIT, SignalServiceGroup.Type.QUIT, name, members, admins, message.sentTimestamp!!) + storage.insertIncomingInfoMessage(context, senderPublicKey, groupID, SignalServiceGroup.Type.QUIT, name, members, admins, message.sentTimestamp!!) } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroup.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroup.kt index 58f8ffe64c..143fa7fb3f 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroup.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSenderClosedGroup.kt @@ -15,6 +15,7 @@ import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.libsignal.ecc.Curve import org.session.libsignal.libsignal.ecc.ECKeyPair import org.session.libsignal.libsignal.util.guava.Optional +import org.session.libsignal.service.api.messages.SignalServiceGroup import org.session.libsignal.service.internal.push.SignalServiceProtos import org.session.libsignal.service.loki.utilities.hexEncodedPublicKey import org.session.libsignal.service.loki.utilities.removing05PrefixIfNeeded @@ -60,7 +61,7 @@ fun MessageSender.create(name: String, members: Collection): Promise) send(closedGroupControlMessage, Address.fromSerialized(member)) } // Notify the user - val infoType = SignalServiceProtos.GroupContext.Type.UPDATE + val infoType = SignalServiceGroup.Type.MEMBER_ADDED val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) - storage.insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime) + storage.insertOutgoingInfoMessage(context, groupID, infoType, name, membersToAdd, admins, threadID, sentTime) } fun MessageSender.removeMembers(groupPublicKey: String, membersToRemove: List) { @@ -189,9 +190,9 @@ fun MessageSender.removeMembers(groupPublicKey: String, membersToRemove: List { @@ -212,7 +213,7 @@ fun MessageSender.leave(groupPublicKey: String, notifyUser: Boolean = true): Pro storage.setActive(groupID, false) sendNonDurably(closedGroupControlMessage, Address.fromSerialized(groupID)).success { // Notify the user - val infoType = SignalServiceProtos.GroupContext.Type.QUIT + val infoType = SignalServiceGroup.Type.QUIT val threadID = storage.getOrCreateThreadIdFor(Address.fromSerialized(groupID)) if (notifyUser) { storage.insertOutgoingInfoMessage(context, groupID, infoType, name, updatedMembers, admins, threadID, sentTime) 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 index 367e549c02..2e2163f1ad 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -19,7 +19,7 @@ object UpdateMessageBuilder { } else { sender } when (updateType) { - SignalServiceGroup.Type.NEW_GROUP -> { + SignalServiceGroup.Type.CREATION -> { message = if (isOutgoing) { context.getString(R.string.MessageRecord_you_created_a_new_group) } else { @@ -79,24 +79,29 @@ object UpdateMessageBuilder { return message } - fun buildExpirationTimerMessage(context: Context, duration: Int, sender: String? = null, isOutgoing: Boolean = false): String { - val seconds = (duration!! / 1000) + fun buildExpirationTimerMessage(context: Context, duration: Long, sender: String? = null, isOutgoing: Boolean = false): String { if (!isOutgoing && sender == null) return "" val senderName: String? = if (!isOutgoing) { MessagingConfiguration.shared.storage.getDisplayNameForRecipient(sender!!) ?: sender } else { sender } - return if (seconds <= 0) { + return if (duration <= 0) { if (isOutgoing) context.getString(R.string.MessageRecord_you_disabled_disappearing_messages) else context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, senderName) } else { - val time = ExpirationUtil.getExpirationDisplayValue(context, seconds) + val time = ExpirationUtil.getExpirationDisplayValue(context, duration.toInt()) if (isOutgoing)context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time) else context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, senderName, time) } } + //TODO one this is merged in fun buildDataExtractionMessage(): String { return "" } + /*TODO retro compatibilite old update messages (MessageRecord) + ThreadRecord to display specific messages? (hard unless we can get the incoming / outgoing messages) + Clean code (comments, logs...) + Delete OutgoingExpirationUpdateMessage (check how its used in MmsDatabase l.520 to save messages and how to do the same when getting messages from db without breaking it) + */ } \ No newline at end of file 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 68856a87cd..5115844a12 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 @@ -38,7 +38,7 @@ public class SignalServiceGroup { DELIVER, QUIT, REQUEST_INFO, - NEW_GROUP, + CREATION, NAME_CHANGE, MEMBER_ADDED, MEMBER_REMOVED From abb1db7a7e40c812bcbf4ba646609793a01a59a7 Mon Sep 17 00:00:00 2001 From: Brice-W Date: Thu, 15 Apr 2021 14:41:29 +1000 Subject: [PATCH 5/8] new approach in update saving --- .../conversation/ConversationUpdateItem.java | 4 -- .../securesms/database/MmsDatabase.java | 23 ++++----- .../securesms/database/MmsSmsColumns.java | 3 ++ .../securesms/database/SmsDatabase.java | 2 +- .../securesms/database/Storage.kt | 11 +++-- .../database/model/DisplayRecord.java | 8 +++- .../database/model/MessageRecord.java | 40 +++++----------- .../database/model/ThreadRecord.java | 4 +- .../loki/utilities/GroupDescription.kt | 2 +- .../service/ExpiringMessageManager.java | 34 ++----------- .../messages/signal/IncomingGroupMessage.java | 6 ++- .../OutgoingExpirationUpdateMessage.java | 25 ++++++---- .../signal/OutgoingGroupMediaMessage.java | 27 ++++------- .../messages/signal/OutgoingMediaMessage.java | 8 +--- .../signal/OutgoingSecureMediaMessage.java | 3 +- .../utilities/UpdateMessageBuilder.kt | 24 ++++------ .../messaging/utilities/UpdateMessageData.kt | 48 +++++++++++++++++++ 17 files changed, 133 insertions(+), 139 deletions(-) create mode 100644 libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java index 7efd5ca4e2..46e0bef279 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java @@ -14,11 +14,9 @@ import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; - import org.thoughtcrime.securesms.BindableConversationItem; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.loki.utilities.GeneralUtilitiesKt; -import org.thoughtcrime.securesms.loki.utilities.GroupDescription; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.util.DateUtils; import org.session.libsignal.libsignal.util.guava.Optional; @@ -174,8 +172,6 @@ public class ConversationUpdateItem extends LinearLayout private void setGroupRecord(MessageRecord messageRecord) { icon.setImageResource(R.drawable.ic_group_grey600_24dp); icon.clearColorFilter(); - - GroupDescription.Companion.getDescription(getContext(), messageRecord.getBody()).addListener(this); //TODO Brice: could be removed if GroupDescription is removed body.setText(messageRecord.getDisplayBody(getContext())); title.setVisibility(GONE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java index de4248016f..d4a26b6ead 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -514,15 +514,7 @@ public class MmsDatabase extends MessagingDatabase { } } - if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) { - return new OutgoingGroupMediaMessage(recipient, body, null, attachments, timestamp, 0, quote, contacts, previews); - } else if (Types.isExpirationTimerUpdate(outboxType)) { - return new OutgoingExpirationUpdateMessage(recipient, timestamp, expiresIn); - } - - boolean expirationTimer = (outboxType & Types.EXPIRATION_TIMER_UPDATE_BIT) != 0; - - OutgoingMediaMessage message = new OutgoingMediaMessage(recipient, body, attachments, timestamp, subscriptionId, expiresIn, expirationTimer, distributionType, quote, contacts, previews, networkFailures, mismatches); + OutgoingMediaMessage message = new OutgoingMediaMessage(recipient, body, attachments, timestamp, subscriptionId, expiresIn, distributionType, quote, contacts, previews, networkFailures, mismatches); if (Types.isSecureType(outboxType)) { return new OutgoingSecureMediaMessage(message); @@ -532,8 +524,6 @@ public class MmsDatabase extends MessagingDatabase { } throw new NoSuchMessageException("No record found for id: " + messageId); - } catch (IOException e) { - throw new MmsException(e); } finally { if (cursor != null) cursor.close(); @@ -689,7 +679,12 @@ public class MmsDatabase extends MessagingDatabase { { if (threadId == -1) { if(retrieved.isGroup()) { - String decodedGroupId = ((OutgoingGroupMediaMessage)retrieved).getGroupId(); + String decodedGroupId; + if (retrieved instanceof OutgoingExpirationUpdateMessage) { + decodedGroupId = ((OutgoingExpirationUpdateMessage)retrieved).getGroupId(); + } else { + decodedGroupId = ((OutgoingGroupMediaMessage)retrieved).getGroupId(); + } String groupId; try { groupId = GroupUtil.doubleEncodeGroupID(decodedGroupId); @@ -751,8 +746,8 @@ public class MmsDatabase extends MessagingDatabase { if (message.isSecure()) type |= (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT); if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT; - if (message.isGroup()) { - type |= Types.GROUP_UPDATE_BIT; + if (message.isGroup() && message instanceof OutgoingGroupMediaMessage) { + if (((OutgoingGroupMediaMessage)message).isUpdateMessage()) type |= Types.GROUP_UPDATE_MESSAGE_BIT; } if (message.isExpirationUpdate()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java index 36b86023e6..ae8a470069 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java @@ -70,6 +70,7 @@ public interface MmsSmsColumns { protected static final long GROUP_UPDATE_BIT = 0x10000; protected static final long GROUP_QUIT_BIT = 0x20000; protected static final long EXPIRATION_TIMER_UPDATE_BIT = 0x40000; + protected static final long GROUP_UPDATE_MESSAGE_BIT = 0x80000; // Encrypted Storage Information XXX public static final long ENCRYPTION_MASK = 0xFF000000; @@ -213,6 +214,8 @@ public interface MmsSmsColumns { return (type & GROUP_UPDATE_BIT) != 0; } + public static boolean isGroupUpdateMessage(long type) { return (type & GROUP_UPDATE_MESSAGE_BIT) != 0; } + public static boolean isGroupQuit(long type) { return (type & GROUP_QUIT_BIT) != 0; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index a5affbb569..226645b39c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -347,7 +347,7 @@ public class SmsDatabase extends MessagingDatabase { type |= Types.SECURE_MESSAGE_BIT; } else if (message.isGroup()) { type |= Types.SECURE_MESSAGE_BIT; - type |= Types.GROUP_UPDATE_BIT; + if (((IncomingGroupMessage)message).isUpdateMessage()) type |= Types.GROUP_UPDATE_MESSAGE_BIT; } if (message.isPush()) type |= Types.PUSH_MESSAGE_BIT; 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 30c515e91d..dc2452b51d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -22,6 +22,7 @@ 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.messaging.utilities.UpdateMessageData import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.IdentityKeyUtil import org.session.libsession.utilities.TextSecurePreferences @@ -41,6 +42,7 @@ import org.thoughtcrime.securesms.loki.utilities.OpenGroupUtilities import org.thoughtcrime.securesms.loki.utilities.get import org.thoughtcrime.securesms.loki.utilities.getString import org.thoughtcrime.securesms.mms.PartAuthority +import java.util.* class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), StorageProtocol { override fun getUserPublicKey(): String? { @@ -403,8 +405,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, override fun insertIncomingInfoMessage(context: Context, senderPublicKey: String, groupID: String, type: SignalServiceGroup.Type, name: String, members: Collection, admins: Collection, sentTimestamp: Long) { val group = SignalServiceGroup(type, 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 messageBody = UpdateMessageBuilder.buildGroupUpdateMessage(context, group, senderPublicKey) - val infoMessage = IncomingGroupMessage(m, groupID, messageBody) + val updateData = UpdateMessageData.buildGroupUpdate(type, name, members).toJSON() + val infoMessage = IncomingGroupMessage(m, groupID, updateData, true) val smsDB = DatabaseFactory.getSmsDatabase(context) smsDB.insertMessageInbox(infoMessage) } @@ -413,9 +415,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, val userPublicKey = getUserPublicKey() val recipient = Recipient.from(context, Address.fromSerialized(groupID), false) - val group = SignalServiceGroup(type, GroupUtil.getDecodedGroupIDAsData(groupID), SignalServiceGroup.GroupType.SIGNAL, name, members.toList(), null, admins.toList()) - val messageBody = UpdateMessageBuilder.buildGroupUpdateMessage(context, group, null, true) - val infoMessage = OutgoingGroupMediaMessage(recipient, messageBody, groupID, null, sentTimestamp, 0, false, null, listOf(), listOf()) + val updateData = UpdateMessageData.buildGroupUpdate(type, name, members).toJSON() + val infoMessage = OutgoingGroupMediaMessage(recipient, updateData, groupID, null, sentTimestamp, 0, true, null, listOf(), listOf()) val mmsDB = DatabaseFactory.getMmsDatabase(context) val mmsSmsDB = DatabaseFactory.getMmsSmsDatabase(context) if (mmsSmsDB.getMessageFor(sentTimestamp,userPublicKey) != null) return diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java index ab40f3381c..d3be43d879 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java @@ -109,6 +109,7 @@ public abstract class DisplayRecord { public boolean isLokiSessionRestoreDone() { return SmsDatabase.Types.isLokiSessionRestoreDoneType(type); } + // TODO isGroupUpdate and isGroupQuit are kept for compatibility with old update messages, they can be removed later on public boolean isGroupUpdate() { return SmsDatabase.Types.isGroupUpdate(type); } @@ -117,8 +118,13 @@ public abstract class DisplayRecord { return SmsDatabase.Types.isGroupQuit(type); } + public boolean isGroupUpdateMessage() { + return SmsDatabase.Types.isGroupUpdateMessage(type); + } + + //TODO isGroupAction can be replaced by isGroupUpdateMessage in the code when the 2 functions above are removed public boolean isGroupAction() { - return isGroupUpdate() || isGroupQuit(); + return isGroupUpdate() || isGroupQuit() || isGroupUpdateMessage(); } public boolean isExpirationTimerUpdate() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index f4c9bb95a7..631883eb5b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -26,14 +26,13 @@ import android.text.style.StyleSpan; import network.loki.messenger.R; import org.session.libsession.messaging.utilities.UpdateMessageBuilder; +import org.session.libsession.messaging.utilities.UpdateMessageData; import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.SmsDatabase; import org.session.libsession.database.documents.IdentityKeyMismatch; import org.session.libsession.database.documents.NetworkFailure; import org.session.libsession.messaging.threads.recipients.Recipient; -import org.session.libsession.utilities.ExpirationUtil; -import org.thoughtcrime.securesms.loki.utilities.GroupDescription; import java.util.List; @@ -92,39 +91,22 @@ public abstract class MessageRecord extends DisplayRecord { @Override public SpannableString getDisplayBody(@NonNull Context context) { - if (isGroupUpdate() && isOutgoing()) { + if(isGroupUpdateMessage()) { + UpdateMessageData updateMessageData = UpdateMessageData.Companion.fromJSON(getBody()); + return new SpannableString(UpdateMessageBuilder.INSTANCE.buildGroupUpdateMessage(context, updateMessageData, getIndividualRecipient().getAddress().serialize(), isOutgoing())); + } else if (isExpirationTimerUpdate()) { + int seconds = (int) (getExpiresIn() / 1000); + return new SpannableString(UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, seconds, getIndividualRecipient().getAddress().serialize(), isOutgoing())); + } + // TODO below lines are left here for compatibility with older group update messages, it can be deleted later on + else if (isGroupUpdate() && isOutgoing()) { return new SpannableString(context.getString(R.string.MessageRecord_you_updated_group)); } else if (isGroupUpdate()) { - return new SpannableString(GroupDescription.Companion.getDescription(context, getBody()).toString(getIndividualRecipient())); + return new SpannableString(context.getString(R.string.MessageRecord_s_updated_group, getIndividualRecipient().toShortString())); } else if (isGroupQuit() && isOutgoing()) { return new SpannableString(context.getString(R.string.MessageRecord_left_group)); } else if (isGroupQuit()) { return new SpannableString(context.getString(R.string.ConversationItem_group_action_left, getIndividualRecipient().toShortString())); - } else if (isIncomingCall()) { - return new SpannableString(context.getString(R.string.MessageRecord_s_called_you, getIndividualRecipient().toShortString())); - } else if (isOutgoingCall()) { - return new SpannableString(context.getString(R.string.MessageRecord_you_called)); - } else if (isMissedCall()) { - return new SpannableString(context.getString(R.string.MessageRecord_missed_call)); - } else if (isJoined()) { - return new SpannableString(context.getString(R.string.MessageRecord_s_joined_signal, getIndividualRecipient().toShortString())); - } else if (isExpirationTimerUpdate()) { - int seconds = (int)(getExpiresIn() / 1000); - if (seconds <= 0) { - return isOutgoing() ? new SpannableString(context.getString(R.string.MessageRecord_you_disabled_disappearing_messages)) - : new SpannableString(context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, getIndividualRecipient().toShortString())); - } - String time = ExpirationUtil.getExpirationDisplayValue(context, seconds); - return isOutgoing() ? new SpannableString(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time)) - : new SpannableString(context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, getIndividualRecipient().toShortString(), time)); - } else if (isIdentityUpdate()) { - return new SpannableString(context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, getIndividualRecipient().toShortString())); - } else if (isIdentityVerified()) { - if (isOutgoing()) return new SpannableString(context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified, getIndividualRecipient().toShortString())); - else return new SpannableString(context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified_from_another_device, getIndividualRecipient().toShortString())); - } else if (isIdentityDefault()) { - if (isOutgoing()) return new SpannableString(context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified, getIndividualRecipient().toShortString())); - else return new SpannableString(context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device, getIndividualRecipient().toShortString())); } return new SpannableString(getBody()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java index e2a286c854..eab5931c84 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/ThreadRecord.java @@ -28,6 +28,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.session.libsession.messaging.threads.recipients.Recipient; +import org.session.libsession.messaging.utilities.UpdateMessageBuilder; +import org.session.libsession.messaging.utilities.UpdateMessageData; import org.session.libsession.utilities.ExpirationUtil; import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.SmsDatabase; @@ -73,7 +75,7 @@ public class ThreadRecord extends DisplayRecord { @Override public SpannableString getDisplayBody(@NonNull Context context) { Recipient recipient = getRecipient(); - if (isGroupUpdate()) { + if (isGroupUpdate() || isGroupUpdateMessage()) { return emphasisAdded(context.getString(R.string.ThreadRecord_group_updated)); } else if (isGroupQuit()) { return emphasisAdded(context.getString(R.string.ThreadRecord_left_the_group)); diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt index dd642beb59..3844b9fbf6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt @@ -13,7 +13,7 @@ import network.loki.messenger.R import org.session.libsignal.utilities.logging.Log import java.io.IOException -//TODO Brice: that class should be deprecated +//TODO that class isn't used anymore class GroupDescription(context: Context, groupContext: SignalServiceProtos.GroupContext?) { private val context: Context private val groupContext: SignalServiceProtos.GroupContext? diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java b/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java index 8d10605fc8..dd23927bc3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.java @@ -2,16 +2,12 @@ package org.thoughtcrime.securesms.service; import android.content.Context; -import com.google.protobuf.ByteString; import org.jetbrains.annotations.NotNull; import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate; -import org.session.libsession.messaging.messages.signal.OutgoingGroupMediaMessage; -import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage; +import org.session.libsession.messaging.messages.signal.OutgoingExpirationUpdateMessage; import org.session.libsession.messaging.threads.Address; -import org.session.libsession.messaging.threads.DistributionTypes; 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.SSKEnvironment; import org.session.libsession.utilities.TextSecurePreferences; @@ -27,7 +23,6 @@ import org.session.libsession.messaging.messages.signal.IncomingMediaMessage; import org.thoughtcrime.securesms.mms.MmsException; import java.io.IOException; -import java.util.Collections; import java.util.Comparator; import java.util.TreeSet; import java.util.concurrent.Executor; @@ -97,7 +92,6 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM Long sentTimestamp = message.getSentTimestamp(); String groupId = message.getGroupPublicKey(); int duration = message.getDuration(); - String messageBody = UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, duration, senderPublicKey, false); Optional groupInfo = Optional.absent(); Address address = Address.fromSerialized(senderPublicKey); @@ -118,7 +112,7 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM IncomingMediaMessage mediaMessage = new IncomingMediaMessage(address, sentTimestamp, -1, duration * 1000L, true, false, - Optional.of(messageBody), + Optional.absent(), groupInfo, Optional.absent(), Optional.absent(), @@ -141,36 +135,18 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM Long sentTimestamp = message.getSentTimestamp(); String groupId = message.getGroupPublicKey(); int duration = message.getDuration(); - String messageBody = UpdateMessageBuilder.INSTANCE.buildExpirationTimerMessage(context, duration, null, true); Address address = Address.fromSerialized((message.getSyncTarget() != null && !message.getSyncTarget().isEmpty()) ? message.getSyncTarget() : message.getRecipient()); Recipient recipient = Recipient.from(context, address, false); try { + OutgoingExpirationUpdateMessage timerUpdateMessage = new OutgoingExpirationUpdateMessage(recipient, sentTimestamp, duration * 1000L, groupId); + database.insertSecureDecryptedMessageOutbox(timerUpdateMessage, -1, sentTimestamp); + if (groupId != null) { - // conversation is a closed group - OutgoingGroupMediaMessage infoMessage = new OutgoingGroupMediaMessage(recipient, messageBody, groupId, null, sentTimestamp, duration * 1000L, true, null, Collections.emptyList(), Collections.emptyList()); - database.insertSecureDecryptedMessageOutbox(infoMessage, -1, sentTimestamp); // we need the group ID as recipient for setExpireMessages below recipient = Recipient.from(context, Address.fromSerialized(GroupUtil.doubleEncodeGroupID(groupId)), false); - } else { - // conversation is a 1-1 - OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipient, - messageBody, - Collections.emptyList(), - message.getSentTimestamp(), - -1, - duration * 1000L, - true, - DistributionTypes.DEFAULT, - null, - Collections.emptyList(), - Collections.emptyList(), - Collections.emptyList(), - Collections.emptyList()); - database.insertSecureDecryptedMessageOutbox(mediaMessage, -1, sentTimestamp); } - //set the timer to the conversation DatabaseFactory.getRecipientDatabase(context).setExpireMessages(recipient, duration); diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingGroupMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingGroupMessage.java index 901f151cdf..125267afb7 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingGroupMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/IncomingGroupMessage.java @@ -5,10 +5,12 @@ import static org.session.libsignal.service.internal.push.SignalServiceProtos.Gr public class IncomingGroupMessage extends IncomingTextMessage { private final String groupID; + private final boolean updateMessage; - public IncomingGroupMessage(IncomingTextMessage base, String groupID, String body) { + public IncomingGroupMessage(IncomingTextMessage base, String groupID, String body, boolean updateMessage) { super(base, body); this.groupID = groupID; + this.updateMessage = updateMessage; } @Override @@ -16,4 +18,6 @@ public class IncomingGroupMessage extends IncomingTextMessage { return true; } + public boolean isUpdateMessage() { return updateMessage; } + } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java index 087751e2fd..b45f33c78f 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingExpirationUpdateMessage.java @@ -1,6 +1,5 @@ package org.session.libsession.messaging.messages.signal; -import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate; import org.session.libsession.messaging.sending_receiving.attachments.Attachment; import org.session.libsession.messaging.threads.DistributionTypes; import org.session.libsession.messaging.threads.recipients.Recipient; @@ -8,18 +7,15 @@ import org.session.libsession.messaging.threads.recipients.Recipient; import java.util.Collections; import java.util.LinkedList; -// TODO this class could be deleted if its usage in MmsDatabase.getOutgoingMessage is replaced by something elsex public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage { - public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn) { - super(recipient, "", new LinkedList(), sentTimeMillis, - DistributionTypes.CONVERSATION, expiresIn, true, null, Collections.emptyList(), - Collections.emptyList()); - } + private final String groupId; - public static OutgoingExpirationUpdateMessage from(ExpirationTimerUpdate message, - Recipient recipient) { - return new OutgoingExpirationUpdateMessage(recipient, message.getSentTimestamp(), message.getDuration() * 1000); + public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn, String groupId) { + super(recipient, "", new LinkedList(), sentTimeMillis, + DistributionTypes.CONVERSATION, expiresIn, null, Collections.emptyList(), + Collections.emptyList()); + this.groupId = groupId; } @Override @@ -27,4 +23,13 @@ public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage return true; } + @Override + public boolean isGroup() { + return groupId != null; + } + + public String getGroupId() { + return groupId; + } + } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingGroupMediaMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingGroupMediaMessage.java index a726286be6..574c47cd19 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingGroupMediaMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingGroupMediaMessage.java @@ -20,23 +20,7 @@ import java.util.List; public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage { private final String groupID; - - public OutgoingGroupMediaMessage(@NonNull Recipient recipient, - @NonNull String body, - @Nullable String groupId, - @NonNull List avatar, - long sentTimeMillis, - long expiresIn, - @Nullable QuoteModel quote, - @NonNull List contacts, - @NonNull List previews) - throws IOException - { - super(recipient, body, avatar, sentTimeMillis, - DistributionTypes.CONVERSATION, expiresIn, false, quote, contacts, previews); - - this.groupID = groupId; - } + private final boolean isUpdateMessage; public OutgoingGroupMediaMessage(@NonNull Recipient recipient, @NonNull String body, @@ -44,7 +28,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage { @Nullable final Attachment avatar, long sentTime, long expireIn, - boolean expirationUpdate, + boolean updateMessage, @Nullable QuoteModel quote, @NonNull List contacts, @NonNull List previews) @@ -52,9 +36,10 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage { super(recipient, body, new LinkedList() {{if (avatar != null) add(avatar);}}, sentTime, - DistributionTypes.CONVERSATION, expireIn, expirationUpdate, quote, contacts, previews); + DistributionTypes.CONVERSATION, expireIn, quote, contacts, previews); this.groupID = groupId; + this.isUpdateMessage = updateMessage; } @Override @@ -65,4 +50,8 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage { public String getGroupId() { return groupID; } + + public boolean isUpdateMessage() { + return isUpdateMessage; + } } diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingMediaMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingMediaMessage.java index 9a6618dc4a..d8d4dff3c5 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingMediaMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingMediaMessage.java @@ -26,7 +26,6 @@ public class OutgoingMediaMessage { private final int distributionType; private final int subscriptionId; private final long expiresIn; - private final boolean expirationUpdate; private final QuoteModel outgoingQuote; private final List networkFailures = new LinkedList<>(); @@ -37,7 +36,6 @@ public class OutgoingMediaMessage { public OutgoingMediaMessage(Recipient recipient, String message, List attachments, long sentTimeMillis, int subscriptionId, long expiresIn, - boolean expirationUpdate, int distributionType, @Nullable QuoteModel outgoingQuote, @NonNull List contacts, @@ -52,7 +50,6 @@ public class OutgoingMediaMessage { this.attachments = attachments; this.subscriptionId = subscriptionId; this.expiresIn = expiresIn; - this.expirationUpdate = expirationUpdate; this.outgoingQuote = outgoingQuote; this.contacts.addAll(contacts); @@ -69,7 +66,6 @@ public class OutgoingMediaMessage { this.sentTimeMillis = that.sentTimeMillis; this.subscriptionId = that.subscriptionId; this.expiresIn = that.expiresIn; - this.expirationUpdate = that.expirationUpdate; this.outgoingQuote = that.outgoingQuote; this.identityKeyMismatches.addAll(that.identityKeyMismatches); @@ -89,7 +85,7 @@ public class OutgoingMediaMessage { previews = Collections.singletonList(linkPreview); } return new OutgoingMediaMessage(recipient, message.getText(), attachments, message.getSentTimestamp(), -1, - recipient.getExpireMessages() * 1000, false, DistributionTypes.DEFAULT, outgoingQuote, Collections.emptyList(), + recipient.getExpireMessages() * 1000, DistributionTypes.DEFAULT, outgoingQuote, Collections.emptyList(), previews, Collections.emptyList(), Collections.emptyList()); } @@ -113,7 +109,7 @@ public class OutgoingMediaMessage { return false; } - public boolean isExpirationUpdate() { return expirationUpdate; } + public boolean isExpirationUpdate() { return false; } public long getSentTimeMillis() { return sentTimeMillis; diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingSecureMediaMessage.java b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingSecureMediaMessage.java index c7822d8b90..8b5e7ddef0 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingSecureMediaMessage.java +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/signal/OutgoingSecureMediaMessage.java @@ -19,12 +19,11 @@ public class OutgoingSecureMediaMessage extends OutgoingMediaMessage { long sentTimeMillis, int distributionType, long expiresIn, - boolean expirationUpdate, @Nullable QuoteModel quote, @NonNull List contacts, @NonNull List previews) { - super(recipient, body, attachments, sentTimeMillis, -1, expiresIn, expirationUpdate, distributionType, quote, contacts, previews, Collections.emptyList(), Collections.emptyList()); + super(recipient, body, attachments, sentTimeMillis, -1, expiresIn, distributionType, quote, contacts, previews, Collections.emptyList(), Collections.emptyList()); } public OutgoingSecureMediaMessage(OutgoingMediaMessage base) { 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 index 2e2163f1ad..6d3dbb858d 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -1,17 +1,15 @@ package org.session.libsession.messaging.utilities import android.content.Context -import android.text.SpannableString import org.session.libsession.R import org.session.libsession.messaging.MessagingConfiguration -import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsession.utilities.ExpirationUtil import org.session.libsignal.service.api.messages.SignalServiceGroup object UpdateMessageBuilder { - fun buildGroupUpdateMessage(context: Context, groupInfo: SignalServiceGroup, sender: String? = null, isOutgoing: Boolean = false): String { - val updateType = groupInfo.type + fun buildGroupUpdateMessage(context: Context, updateData: UpdateMessageData, sender: String? = null, isOutgoing: Boolean = false): String { + val updateType = updateData.type var message: String = "" if (!isOutgoing && sender == null) return message val senderName: String? = if (!isOutgoing) { @@ -28,13 +26,13 @@ object UpdateMessageBuilder { } SignalServiceGroup.Type.NAME_CHANGE -> { message = if (isOutgoing) { - context.getString(R.string.MessageRecord_you_renamed_the_group_to_s, groupInfo.name.get()) + context.getString(R.string.MessageRecord_you_renamed_the_group_to_s, updateData.groupName) } else { - context.getString(R.string.MessageRecord_s_renamed_the_group_to_s, senderName, groupInfo.name.get()) + context.getString(R.string.MessageRecord_s_renamed_the_group_to_s, senderName, updateData.groupName) } } SignalServiceGroup.Type.MEMBER_ADDED -> { - val members = groupInfo.members.get().joinToString(", ") { + val members = updateData.updatedMembers.joinToString(", ") { MessagingConfiguration.shared.storage.getDisplayNameForRecipient(it) ?: it } message = if (isOutgoing) { @@ -47,7 +45,7 @@ object UpdateMessageBuilder { val storage = MessagingConfiguration.shared.storage val userPublicKey = storage.getUserPublicKey()!! // 1st case: you are part of the removed members - message = if (userPublicKey in groupInfo.members.get()) { + message = if (userPublicKey in updateData.updatedMembers) { if (isOutgoing) { context.getString(R.string.MessageRecord_left_group) } else { @@ -55,7 +53,7 @@ object UpdateMessageBuilder { } } else { // 2nd case: you are not part of the removed members - val members = groupInfo.members.get().joinToString(", ") { + val members = updateData.updatedMembers.joinToString(", ") { storage.getDisplayNameForRecipient(it) ?: it } if (isOutgoing) { @@ -94,14 +92,8 @@ object UpdateMessageBuilder { } } - //TODO one this is merged in + //TODO do this when the current update is merged fun buildDataExtractionMessage(): String { return "" } - - /*TODO retro compatibilite old update messages (MessageRecord) - ThreadRecord to display specific messages? (hard unless we can get the incoming / outgoing messages) - Clean code (comments, logs...) - Delete OutgoingExpirationUpdateMessage (check how its used in MmsDatabase l.520 to save messages and how to do the same when getting messages from db without breaking it) - */ } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt new file mode 100644 index 0000000000..bca6c7acf4 --- /dev/null +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt @@ -0,0 +1,48 @@ +package org.session.libsession.messaging.utilities + +import com.fasterxml.jackson.core.JsonParseException +import org.session.libsignal.service.api.messages.SignalServiceGroup +import org.session.libsignal.utilities.JsonUtil +import org.session.libsignal.utilities.logging.Log +import java.util.* + +// class used to save update messages details +class UpdateMessageData () { + + var type: SignalServiceGroup.Type = SignalServiceGroup.Type.UNKNOWN + var groupName: String? = null + var updatedMembers: Collection = Collections.emptyList() + + constructor(type: SignalServiceGroup.Type, groupName: String?, updatedMembers: Collection): this() { + this.type = type + this.groupName = groupName + this.updatedMembers = updatedMembers + } + + companion object { + val TAG = UpdateMessageData::class.simpleName + + fun buildGroupUpdate(type: SignalServiceGroup.Type, name: String, members: Collection): UpdateMessageData { + return when(type) { + SignalServiceGroup.Type.NAME_CHANGE -> UpdateMessageData(type, name, Collections.emptyList()) + SignalServiceGroup.Type.MEMBER_ADDED -> UpdateMessageData(type,null, members) + SignalServiceGroup.Type.MEMBER_REMOVED -> UpdateMessageData(type,null, members) + else -> UpdateMessageData(type,null, Collections.emptyList()) + } + } + + fun fromJSON(json: String): UpdateMessageData { + return try { + JsonUtil.fromJson(json, UpdateMessageData::class.java) + } catch (e: JsonParseException) { + Log.e(TAG, "${e.message}") + UpdateMessageData(SignalServiceGroup.Type.UNKNOWN, null, Collections.emptyList()) + } + } + } + + fun toJSON(): String { + return JsonUtil.toJson(this) + } + +} \ No newline at end of file From a346bb4ea528db020c7e9cd13893046c5fcdcd46 Mon Sep 17 00:00:00 2001 From: Brice-W Date: Thu, 15 Apr 2021 15:44:42 +1000 Subject: [PATCH 6/8] clean --- .../libsession/messaging/utilities/UpdateMessageBuilder.kt | 2 +- .../libsession/messaging/utilities/UpdateMessageData.kt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) 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 index 6d3dbb858d..85be978379 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -96,4 +96,4 @@ object UpdateMessageBuilder { fun buildDataExtractionMessage(): String { return "" } -} \ No newline at end of file +} diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt index bca6c7acf4..a21e403b78 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt @@ -44,5 +44,4 @@ class UpdateMessageData () { fun toJSON(): String { return JsonUtil.toJson(this) } - -} \ No newline at end of file +} From 2a1dfff8c46e5da8eb01f803fc2a674a119c7ddb Mon Sep 17 00:00:00 2001 From: Brice-W Date: Thu, 15 Apr 2021 16:33:40 +1000 Subject: [PATCH 7/8] translations added --- app/src/main/res/values-fr/strings.xml | 40 ++++++++++++++++++++++++++ app/src/main/res/values/strings.xml | 4 +-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d562e0c62a..728266183e 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -418,6 +418,15 @@ Vous avez reçu un message chiffré avec une ancienne version de Signal qui n’est plus prise en charge. Veuillez demander à l’expéditeur de mettre Session à jour vers la version la plus récente et de renvoyer son message. Vous avez quitté le groupe Vous avez mis le groupe à jour. + Vous avez créée un nouveau groupe. + %1$s vous a ajouté au groupe. + Vous avez renommé le groupe en \'%1$s\' + %1$s a renommé le groupe en \'%2$s\' + Vous avez ajouté %1$s au groupe. + %1$s a ajouté %2$s au groupe. + Vous avez supprimé %1$s du groupe. + %1$s a supprimé %2$s du groupe. + Vous avez été supprimé du groupe. Vous avez appelé Contact appelé Appel manqué @@ -1483,4 +1492,35 @@ Vous avez reçu un message d’échange de clés pour une version de protocole i Groupes privés Groupes publics + + + Appliquer + Terminé + + Modifier le groupe + Saisissez un nouveau nom de groupe + Membres + Ajouter des membres + Le nom du groupe ne peut pas être vide + Veuillez saisir un nom plus court + Les groupes doivent avoir au moins un membre + Un des membres du group a un Session ID invalide + Êtes vous sûr de vouloir suprimer ce membre du groupe? + Membre supprimé du groupe + + Supprimer le membre du groupe + + Contacts + + Thème + Jour + Nuit + Système + + Copier le Session ID + + Pièce jointe + Message vocal + Détails + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ac5121c1d7..4ed3697e63 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -495,8 +495,8 @@ 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 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. From 2b7cf7c1b446d28d70858e98769395c740ee14a5 Mon Sep 17 00:00:00 2001 From: Brice-W Date: Fri, 16 Apr 2021 15:54:39 +1000 Subject: [PATCH 8/8] added Kind sealed class in UpdateMessageData + minor fixes --- .../loki/utilities/GroupDescription.kt | 104 ------------------ app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../utilities/UpdateMessageBuilder.kt | 7 +- .../messaging/utilities/UpdateMessageData.kt | 35 +++--- libsession/src/main/res/values/strings.xml | 1 + 6 files changed, 29 insertions(+), 120 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt deleted file mode 100644 index 3844b9fbf6..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/utilities/GroupDescription.kt +++ /dev/null @@ -1,104 +0,0 @@ -package org.thoughtcrime.securesms.loki.utilities - -import android.content.Context -import org.session.libsession.messaging.threads.Address -import org.session.libsession.messaging.threads.recipients.Recipient -import org.session.libsession.messaging.threads.recipients.RecipientModifiedListener -import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsignal.utilities.Base64 -import org.session.libsignal.service.internal.push.SignalServiceProtos -import java.util.* - -import network.loki.messenger.R -import org.session.libsignal.utilities.logging.Log -import java.io.IOException - -//TODO that class isn't used anymore -class GroupDescription(context: Context, groupContext: SignalServiceProtos.GroupContext?) { - private val context: Context - private val groupContext: SignalServiceProtos.GroupContext? - private val newMembers: MutableList - private val removedMembers: MutableList - private var wasCurrentUserRemoved: Boolean = false - private fun toRecipient(hexEncodedPublicKey: String): Recipient { - val address = Address.fromSerialized(hexEncodedPublicKey) - return Recipient.from(context, address, false) - } - - fun toString(sender: Recipient): String { - if (wasCurrentUserRemoved) { - return context.getString(R.string.GroupUtil_you_were_removed_from_group) - } - val description = StringBuilder() - description.append(context.getString(R.string.MessageRecord_s_updated_group, sender.toShortString())) - if (groupContext == null) { - return description.toString() - } - val title = groupContext.name - if (!newMembers.isEmpty()) { - description.append("\n") - description.append(context.resources.getQuantityString(R.plurals.GroupUtil_joined_the_group, - newMembers.size, toString(newMembers))) - } - if (!removedMembers.isEmpty()) { - description.append("\n") - description.append(context.resources.getQuantityString(R.plurals.GroupUtil_removed_from_the_group, - removedMembers.size, toString(removedMembers))) - } - if (title != null && !title.trim { it <= ' ' }.isEmpty()) { - val separator = if (!newMembers.isEmpty() || !removedMembers.isEmpty()) " " else "\n" - description.append(separator) - description.append(context.getString(R.string.GroupUtil_group_name_is_now, title)) - } - return description.toString() - } - - fun addListener(listener: RecipientModifiedListener?) { - if (!newMembers.isEmpty()) { - for (member in newMembers) { - member.addListener(listener) - } - } - } - - private fun toString(recipients: List): String { - var result = "" - for (i in recipients.indices) { - result += recipients[i].toShortString() - if (i != recipients.size - 1) result += ", " - } - return result - } - - init { - this.context = context.applicationContext - this.groupContext = groupContext - newMembers = LinkedList() - removedMembers = LinkedList() - if (groupContext != null) { - val newMembers = groupContext.newMembersList - for (member in newMembers) { - this.newMembers.add(toRecipient(member)) - } - val removedMembers = groupContext.removedMembersList - for (member in removedMembers) { - this.removedMembers.add(toRecipient(member)) - } - wasCurrentUserRemoved = removedMembers.contains(TextSecurePreferences.getLocalNumber(context)) - } - } - - companion object { - fun getDescription(context: Context, encodedGroup: String?): GroupDescription { - return if (encodedGroup == null) { - GroupDescription(context, null) - } else try { - val groupContext = SignalServiceProtos.GroupContext.parseFrom(Base64.decode(encodedGroup)) - GroupDescription(context, groupContext) - } catch (e: IOException) { - Log.w("Loki", e) - GroupDescription(context, null) - } - } - } -} \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 728266183e..f156dad77b 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -427,6 +427,7 @@ Vous avez supprimé %1$s du groupe. %1$s a supprimé %2$s du groupe. Vous avez été supprimé du groupe. + Vous Vous avez appelé Contact appelé Appel manqué diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4ed3697e63..c7279e90ce 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -502,6 +502,7 @@ You removed %1$s from the group. %1$s removed %2$s from the group. You were removed from the group. + You You called Contact called Missed call 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 index 85be978379..d6f446e364 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -8,13 +8,14 @@ import org.session.libsignal.service.api.messages.SignalServiceGroup object UpdateMessageBuilder { - fun buildGroupUpdateMessage(context: Context, updateData: UpdateMessageData, sender: String? = null, isOutgoing: Boolean = false): String { - val updateType = updateData.type + fun buildGroupUpdateMessage(context: Context, updateMessageData: UpdateMessageData, sender: String? = null, isOutgoing: Boolean = false): String { var message: String = "" + val updateData = updateMessageData.kind as? UpdateMessageData.Kind.GroupUpdate ?: return message + val updateType = updateData.type if (!isOutgoing && sender == null) return message val senderName: String? = if (!isOutgoing) { MessagingConfiguration.shared.storage.getDisplayNameForRecipient(sender!!) ?: sender - } else { sender } + } else { context.getString(R.string.MessageRecord_you) } when (updateType) { SignalServiceGroup.Type.CREATION -> { diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt index a21e403b78..5ca4bbbf9c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageData.kt @@ -1,5 +1,7 @@ package org.session.libsession.messaging.utilities +import com.fasterxml.jackson.annotation.JsonSubTypes +import com.fasterxml.jackson.annotation.JsonTypeInfo import com.fasterxml.jackson.core.JsonParseException import org.session.libsignal.service.api.messages.SignalServiceGroup import org.session.libsignal.utilities.JsonUtil @@ -9,14 +11,21 @@ import java.util.* // class used to save update messages details class UpdateMessageData () { - var type: SignalServiceGroup.Type = SignalServiceGroup.Type.UNKNOWN - var groupName: String? = null - var updatedMembers: Collection = Collections.emptyList() + var kind: Kind? = null - constructor(type: SignalServiceGroup.Type, groupName: String?, updatedMembers: Collection): this() { - this.type = type - this.groupName = groupName - this.updatedMembers = updatedMembers + //the annotations below are required for serialization. Any new Kind class MUST be declared as JsonSubTypes as well + @JsonTypeInfo(use = JsonTypeInfo.Id.NAME) + @JsonSubTypes( + JsonSubTypes.Type(Kind.GroupUpdate::class, name = "GroupUpdate") + ) + sealed class Kind { + class GroupUpdate( var type: SignalServiceGroup.Type, var groupName: String?, var updatedMembers: Collection): Kind() { + constructor(): this(SignalServiceGroup.Type.UNKNOWN, null, Collections.emptyList()) //default constructor required for json serialization + } + } + + constructor(kind: Kind): this() { + this.kind = kind } companion object { @@ -24,19 +33,19 @@ class UpdateMessageData () { fun buildGroupUpdate(type: SignalServiceGroup.Type, name: String, members: Collection): UpdateMessageData { return when(type) { - SignalServiceGroup.Type.NAME_CHANGE -> UpdateMessageData(type, name, Collections.emptyList()) - SignalServiceGroup.Type.MEMBER_ADDED -> UpdateMessageData(type,null, members) - SignalServiceGroup.Type.MEMBER_REMOVED -> UpdateMessageData(type,null, members) - else -> UpdateMessageData(type,null, Collections.emptyList()) + SignalServiceGroup.Type.NAME_CHANGE -> UpdateMessageData(Kind.GroupUpdate(type, name, Collections.emptyList())) + SignalServiceGroup.Type.MEMBER_ADDED -> UpdateMessageData(Kind.GroupUpdate(type,null, members)) + SignalServiceGroup.Type.MEMBER_REMOVED -> UpdateMessageData(Kind.GroupUpdate(type,null, members)) + else -> UpdateMessageData(Kind.GroupUpdate(type,null, Collections.emptyList())) } } fun fromJSON(json: String): UpdateMessageData { - return try { + return try { JsonUtil.fromJson(json, UpdateMessageData::class.java) } catch (e: JsonParseException) { Log.e(TAG, "${e.message}") - UpdateMessageData(SignalServiceGroup.Type.UNKNOWN, null, Collections.emptyList()) + UpdateMessageData(Kind.GroupUpdate(SignalServiceGroup.Type.UNKNOWN, null, Collections.emptyList())) } } } diff --git a/libsession/src/main/res/values/strings.xml b/libsession/src/main/res/values/strings.xml index 90cbb92869..116b106017 100644 --- a/libsession/src/main/res/values/strings.xml +++ b/libsession/src/main/res/values/strings.xml @@ -496,6 +496,7 @@ You removed %1$s from the group. %1$s removed %2$s from the group. You were removed from the group. + You You called Contact called Missed call