From ffa280bc1b79ffe9fcf403425d2bb97e3e3ae271 Mon Sep 17 00:00:00 2001 From: charles Date: Mon, 3 Oct 2022 13:15:14 +1100 Subject: [PATCH 001/744] fix: Disable typing and message requests in read-only open groups --- .../conversation/v2/ConversationActivityV2.kt | 1 + .../conversation/v2/messages/VisibleMessageView.kt | 5 +++-- .../securesms/groups/OpenGroupManager.kt | 2 +- .../libsession/messaging/open_groups/OpenGroup.kt | 13 ++++++++----- .../sending_receiving/pollers/OpenGroupPoller.kt | 1 + 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 467be2c0b6..d4e09b6b67 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -466,6 +466,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe // called from onCreate private fun setUpInputBar() { + binding!!.inputBar.isVisible = viewModel.openGroup == null || viewModel.openGroup?.canWrite == true binding!!.inputBar.delegate = this binding!!.inputBarRecordingView.delegate = this // GIF button diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index bd68693005..0507394dbd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -153,12 +153,13 @@ class VisibleMessageView : LinearLayout { if (isGroupThread && !message.isOutgoing) { if (isEndOfMessageCluster) { + val openGroup = lokiThreadDb.getOpenGroupChat(threadID) binding.profilePictureView.root.publicKey = senderSessionID binding.profilePictureView.root.glide = glide binding.profilePictureView.root.update(message.individualRecipient) binding.profilePictureView.root.setOnClickListener { if (thread.isOpenGroupRecipient) { - if (IdPrefix.fromValue(senderSessionID) == IdPrefix.BLINDED) { + if (IdPrefix.fromValue(senderSessionID) == IdPrefix.BLINDED && openGroup?.canWrite == true) { val intent = Intent(context, ConversationActivityV2::class.java) intent.putExtra(ConversationActivityV2.FROM_GROUP_THREAD_ID, threadID) intent.putExtra(ConversationActivityV2.ADDRESS, Address.fromSerialized(senderSessionID)) @@ -169,7 +170,7 @@ class VisibleMessageView : LinearLayout { } } if (thread.isOpenGroupRecipient) { - val openGroup = lokiThreadDb.getOpenGroupChat(threadID) ?: return + openGroup ?: return var standardPublicKey = "" var blindedPublicKey: String? = null if (IdPrefix.fromValue(senderSessionID) == IdPrefix.BLINDED) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt index d39ba709df..ee83427ab5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/OpenGroupManager.kt @@ -83,7 +83,7 @@ object OpenGroupManager { if (threadID < 0) { threadID = GroupManager.createOpenGroup(openGroupID, context, null, info.name).threadId } - val openGroup = OpenGroup(server, room, info.name, info.infoUpdates, publicKey) + val openGroup = OpenGroup(server, room, info.name, info.infoUpdates, publicKey, info.write) threadDB.setOpenGroupChat(openGroup, threadID) } diff --git a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroup.kt b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroup.kt index 9efeaf15d0..5a31e374d4 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroup.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/open_groups/OpenGroup.kt @@ -12,15 +12,17 @@ data class OpenGroup( val name: String, val publicKey: String, val infoUpdates: Int, + val canWrite: Boolean, ) { - constructor(server: String, room: String, name: String, infoUpdates: Int, publicKey: String) : this( + constructor(server: String, room: String, name: String, infoUpdates: Int, publicKey: String, canWrite: Boolean) : this( server = server, room = room, id = "$server.$room", name = name, publicKey = publicKey, infoUpdates = infoUpdates, + canWrite = canWrite ) companion object { @@ -29,13 +31,13 @@ data class OpenGroup( return try { val json = JsonUtil.fromJson(jsonAsString) if (!json.has("room")) return null - val room = json.get("room").asText().toLowerCase(Locale.US) - val server = json.get("server").asText().toLowerCase(Locale.US) + val room = json.get("room").asText().lowercase(Locale.US) + val server = json.get("server").asText().lowercase(Locale.US) val displayName = json.get("displayName").asText() val publicKey = json.get("publicKey").asText() val infoUpdates = json.get("infoUpdates")?.asText()?.toIntOrNull() ?: 0 - val capabilities = json.get("capabilities")?.asText()?.split(",") ?: emptyList() - OpenGroup(server, room, displayName, infoUpdates, publicKey) + val canWrite = json.get("canWrite")?.asText()?.toBoolean() ?: true + OpenGroup(server, room, displayName, infoUpdates, publicKey, canWrite) } catch (e: Exception) { Log.w("Loki", "Couldn't parse open group from JSON: $jsonAsString.", e); null @@ -59,6 +61,7 @@ data class OpenGroup( "displayName" to name, "publicKey" to publicKey, "infoUpdates" to infoUpdates.toString(), + "canWrite" to canWrite.toString() ) val joinURL: String get() = "$server/$room?public_key=$publicKey" diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt index 7bb00f8f35..fba7013718 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/OpenGroupPoller.kt @@ -126,6 +126,7 @@ class OpenGroupPoller(private val server: String, private val executorService: S name = pollInfo.details?.name ?: "", infoUpdates = pollInfo.details?.infoUpdates ?: 0, publicKey = publicKey, + canWrite = pollInfo.write ) // - Open Group changes storage.updateOpenGroup(openGroup) From 99f70e5c216b110a62993bd8fdd8c5ec7dd5e52e Mon Sep 17 00:00:00 2001 From: charles Date: Mon, 3 Oct 2022 13:42:47 +1100 Subject: [PATCH 002/744] Move open group query into click handler --- .../securesms/conversation/v2/messages/VisibleMessageView.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index 0507394dbd..834f00ca98 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -153,12 +153,12 @@ class VisibleMessageView : LinearLayout { if (isGroupThread && !message.isOutgoing) { if (isEndOfMessageCluster) { - val openGroup = lokiThreadDb.getOpenGroupChat(threadID) binding.profilePictureView.root.publicKey = senderSessionID binding.profilePictureView.root.glide = glide binding.profilePictureView.root.update(message.individualRecipient) binding.profilePictureView.root.setOnClickListener { if (thread.isOpenGroupRecipient) { + val openGroup = lokiThreadDb.getOpenGroupChat(threadID) if (IdPrefix.fromValue(senderSessionID) == IdPrefix.BLINDED && openGroup?.canWrite == true) { val intent = Intent(context, ConversationActivityV2::class.java) intent.putExtra(ConversationActivityV2.FROM_GROUP_THREAD_ID, threadID) @@ -170,7 +170,7 @@ class VisibleMessageView : LinearLayout { } } if (thread.isOpenGroupRecipient) { - openGroup ?: return + val openGroup = lokiThreadDb.getOpenGroupChat(threadID) ?: return var standardPublicKey = "" var blindedPublicKey: String? = null if (IdPrefix.fromValue(senderSessionID) == IdPrefix.BLINDED) { From c537da6acd3047fa93f7e8ef7036463075d57ab0 Mon Sep 17 00:00:00 2001 From: charles Date: Mon, 3 Oct 2022 16:31:29 +1100 Subject: [PATCH 003/744] fix: Show message sender in push notifications for groups --- .../MultipleRecipientNotificationBuilder.java | 15 ++++++++------- .../SingleRecipientNotificationBuilder.java | 17 +++++++++-------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java index 81332e87d9..3425162c22 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/MultipleRecipientNotificationBuilder.java @@ -52,8 +52,8 @@ public class MultipleRecipientNotificationBuilder extends AbstractNotificationBu public void setMostRecentSender(Recipient recipient, Recipient threadRecipient) { String displayName = recipient.toShortString(); - if (threadRecipient.isOpenGroupRecipient()) { - displayName = getOpenGroupDisplayName(recipient); + if (threadRecipient.isGroupRecipient()) { + displayName = getGroupDisplayName(recipient, threadRecipient.isOpenGroupRecipient()); } if (privacy.isDisplayContact()) { setContentText(context.getString(R.string.MessageNotifier_most_recent_from_s, displayName)); @@ -78,8 +78,8 @@ public class MultipleRecipientNotificationBuilder extends AbstractNotificationBu public void addMessageBody(@NonNull Recipient sender, Recipient threadRecipient, @Nullable CharSequence body) { String displayName = sender.toShortString(); - if (threadRecipient.isOpenGroupRecipient()) { - displayName = getOpenGroupDisplayName(sender); + if (threadRecipient.isGroupRecipient()) { + displayName = getGroupDisplayName(sender, threadRecipient.isOpenGroupRecipient()); } if (privacy.isDisplayMessage()) { SpannableStringBuilder builder = new SpannableStringBuilder(); @@ -113,14 +113,15 @@ public class MultipleRecipientNotificationBuilder extends AbstractNotificationBu } /** - * @param recipient the * individual * recipient for which to get the open group display name. + * @param recipient the * individual * recipient for which to get the display name. + * @param openGroupRecipient whether in an open group context */ - private String getOpenGroupDisplayName(Recipient recipient) { + private String getGroupDisplayName(Recipient recipient, boolean openGroupRecipient) { SessionContactDatabase contactDB = DatabaseComponent.get(context).sessionContactDatabase(); String sessionID = recipient.getAddress().serialize(); Contact contact = contactDB.getContactWithSessionID(sessionID); if (contact == null) { return sessionID; } - String displayName = contact.displayName(Contact.ContactContext.OPEN_GROUP); + String displayName = contact.displayName(openGroupRecipient ? Contact.ContactContext.OPEN_GROUP : Contact.ContactContext.REGULAR); if (displayName == null) { return sessionID; } return displayName; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java index b461081cfe..ea547379d3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java @@ -117,15 +117,15 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil setNumber(messageCount); } - public void setPrimaryMessageBody(@NonNull Recipient threadRecipients, + public void setPrimaryMessageBody(@NonNull Recipient threadRecipient, @NonNull Recipient individualRecipient, @NonNull CharSequence message, @Nullable SlideDeck slideDeck) { SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); - if (privacy.isDisplayContact() && threadRecipients.isOpenGroupRecipient()) { - String displayName = getOpenGroupDisplayName(individualRecipient); + if (privacy.isDisplayContact() && threadRecipient.isGroupRecipient()) { + String displayName = getGroupDisplayName(individualRecipient, threadRecipient.isOpenGroupRecipient()); stringBuilder.append(Util.getBoldedString(displayName + ": ")); } @@ -214,8 +214,8 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil { SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); - if (privacy.isDisplayContact() && threadRecipient.isOpenGroupRecipient()) { - String displayName = getOpenGroupDisplayName(individualRecipient); + if (privacy.isDisplayContact() && threadRecipient.isGroupRecipient()) { + String displayName = getGroupDisplayName(individualRecipient, threadRecipient.isOpenGroupRecipient()); stringBuilder.append(Util.getBoldedString(displayName + ": ")); } @@ -334,14 +334,15 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil } /** - * @param recipient the * individual * recipient for which to get the open group display name. + * @param recipient the * individual * recipient for which to get the display name. + * @param openGroupRecipient whether in an open group context */ - private String getOpenGroupDisplayName(Recipient recipient) { + private String getGroupDisplayName(Recipient recipient, boolean openGroupRecipient) { SessionContactDatabase contactDB = DatabaseComponent.get(context).sessionContactDatabase(); String sessionID = recipient.getAddress().serialize(); Contact contact = contactDB.getContactWithSessionID(sessionID); if (contact == null) { return sessionID; } - String displayName = contact.displayName(Contact.ContactContext.OPEN_GROUP); + String displayName = contact.displayName(openGroupRecipient ? Contact.ContactContext.OPEN_GROUP : Contact.ContactContext.REGULAR); if (displayName == null) { return sessionID; } return displayName; } From 1f7edadc5982feb670140fa6eb59319a8d8d4fe0 Mon Sep 17 00:00:00 2001 From: charles Date: Tue, 4 Oct 2022 15:23:58 +1100 Subject: [PATCH 004/744] Add profile data to message request responses --- .../control/MessageRequestResponse.kt | 17 +- libsignal/protobuf/SignalService.proto | 4 +- .../libsignal/protos/SignalServiceProtos.java | 316 ++++++++++++++++-- 3 files changed, 315 insertions(+), 22 deletions(-) diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/MessageRequestResponse.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/MessageRequestResponse.kt index f5a65e4ca4..5722f707bd 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/MessageRequestResponse.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/MessageRequestResponse.kt @@ -1,15 +1,22 @@ package org.session.libsession.messaging.messages.control +import com.google.protobuf.ByteString +import org.session.libsession.messaging.messages.visible.Profile import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.utilities.Log -class MessageRequestResponse(val isApproved: Boolean) : ControlMessage() { +class MessageRequestResponse(val isApproved: Boolean, val profile: Profile? = null) : ControlMessage() { override val isSelfSendValid: Boolean = true override fun toProto(): SignalServiceProtos.Content? { + val profileProto = SignalServiceProtos.DataMessage.LokiProfile.newBuilder() + profile?.displayName?.let { profileProto.displayName = it } + profile?.profilePictureURL?.let { profileProto.profilePicture = it } val messageRequestResponseProto = SignalServiceProtos.MessageRequestResponse.newBuilder() .setIsApproved(isApproved) + .setProfile(profileProto.build()) + profile?.profileKey?.let { messageRequestResponseProto.profileKey = ByteString.copyFrom(it) } return try { SignalServiceProtos.Content.newBuilder() .setMessageRequestResponse(messageRequestResponseProto.build()) @@ -26,7 +33,13 @@ class MessageRequestResponse(val isApproved: Boolean) : ControlMessage() { fun fromProto(proto: SignalServiceProtos.Content): MessageRequestResponse? { val messageRequestResponseProto = if (proto.hasMessageRequestResponse()) proto.messageRequestResponse else return null val isApproved = messageRequestResponseProto.isApproved - return MessageRequestResponse(isApproved) + val profileProto = messageRequestResponseProto.profile + val profile = Profile().apply { + displayName = profileProto.displayName + profileKey = messageRequestResponseProto.profileKey.toByteArray() + profilePictureURL = profileProto.profilePicture + } + return MessageRequestResponse(isApproved, profile) } } diff --git a/libsignal/protobuf/SignalService.proto b/libsignal/protobuf/SignalService.proto index e1c1c856d9..50c5218334 100644 --- a/libsignal/protobuf/SignalService.proto +++ b/libsignal/protobuf/SignalService.proto @@ -233,7 +233,9 @@ message ConfigurationMessage { message MessageRequestResponse { // @required - required bool isApproved = 1; // Whether the request was approved + required bool isApproved = 1; + optional bytes profileKey = 2; + optional DataMessage.LokiProfile profile = 3; } message ReceiptMessage { diff --git a/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java b/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java index ead1b6255e..7c44087f83 100644 --- a/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java +++ b/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java @@ -21504,6 +21504,30 @@ public final class SignalServiceProtos { * */ boolean getIsApproved(); + + // optional bytes profileKey = 2; + /** + * optional bytes profileKey = 2; + */ + boolean hasProfileKey(); + /** + * optional bytes profileKey = 2; + */ + com.google.protobuf.ByteString getProfileKey(); + + // optional .signalservice.DataMessage.LokiProfile profile = 3; + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + boolean hasProfile(); + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile getProfile(); + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfileOrBuilder getProfileOrBuilder(); } /** * Protobuf type {@code signalservice.MessageRequestResponse} @@ -21561,6 +21585,24 @@ public final class SignalServiceProtos { isApproved_ = input.readBool(); break; } + case 18: { + bitField0_ |= 0x00000002; + profileKey_ = input.readBytes(); + break; + } + case 26: { + org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.Builder subBuilder = null; + if (((bitField0_ & 0x00000004) == 0x00000004)) { + subBuilder = profile_.toBuilder(); + } + profile_ = input.readMessage(org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(profile_); + profile_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000004; + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -21625,8 +21667,48 @@ public final class SignalServiceProtos { return isApproved_; } + // optional bytes profileKey = 2; + public static final int PROFILEKEY_FIELD_NUMBER = 2; + private com.google.protobuf.ByteString profileKey_; + /** + * optional bytes profileKey = 2; + */ + public boolean hasProfileKey() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes profileKey = 2; + */ + public com.google.protobuf.ByteString getProfileKey() { + return profileKey_; + } + + // optional .signalservice.DataMessage.LokiProfile profile = 3; + public static final int PROFILE_FIELD_NUMBER = 3; + private org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile profile_; + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public boolean hasProfile() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile getProfile() { + return profile_; + } + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfileOrBuilder getProfileOrBuilder() { + return profile_; + } + private void initFields() { isApproved_ = false; + profileKey_ = com.google.protobuf.ByteString.EMPTY; + profile_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.getDefaultInstance(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -21647,6 +21729,12 @@ public final class SignalServiceProtos { if (((bitField0_ & 0x00000001) == 0x00000001)) { output.writeBool(1, isApproved_); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, profileKey_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeMessage(3, profile_); + } getUnknownFields().writeTo(output); } @@ -21660,6 +21748,14 @@ public final class SignalServiceProtos { size += com.google.protobuf.CodedOutputStream .computeBoolSize(1, isApproved_); } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, profileKey_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, profile_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -21768,6 +21864,7 @@ public final class SignalServiceProtos { } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getProfileFieldBuilder(); } } private static Builder create() { @@ -21778,6 +21875,14 @@ public final class SignalServiceProtos { super.clear(); isApproved_ = false; bitField0_ = (bitField0_ & ~0x00000001); + profileKey_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); + if (profileBuilder_ == null) { + profile_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.getDefaultInstance(); + } else { + profileBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); return this; } @@ -21810,6 +21915,18 @@ public final class SignalServiceProtos { to_bitField0_ |= 0x00000001; } result.isApproved_ = isApproved_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.profileKey_ = profileKey_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + if (profileBuilder_ == null) { + result.profile_ = profile_; + } else { + result.profile_ = profileBuilder_.build(); + } result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -21829,6 +21946,12 @@ public final class SignalServiceProtos { if (other.hasIsApproved()) { setIsApproved(other.getIsApproved()); } + if (other.hasProfileKey()) { + setProfileKey(other.getProfileKey()); + } + if (other.hasProfile()) { + mergeProfile(other.getProfile()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -21909,6 +22032,159 @@ public final class SignalServiceProtos { return this; } + // optional bytes profileKey = 2; + private com.google.protobuf.ByteString profileKey_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes profileKey = 2; + */ + public boolean hasProfileKey() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * optional bytes profileKey = 2; + */ + public com.google.protobuf.ByteString getProfileKey() { + return profileKey_; + } + /** + * optional bytes profileKey = 2; + */ + public Builder setProfileKey(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + profileKey_ = value; + onChanged(); + return this; + } + /** + * optional bytes profileKey = 2; + */ + public Builder clearProfileKey() { + bitField0_ = (bitField0_ & ~0x00000002); + profileKey_ = getDefaultInstance().getProfileKey(); + onChanged(); + return this; + } + + // optional .signalservice.DataMessage.LokiProfile profile = 3; + private org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile profile_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile, org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.Builder, org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfileOrBuilder> profileBuilder_; + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public boolean hasProfile() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile getProfile() { + if (profileBuilder_ == null) { + return profile_; + } else { + return profileBuilder_.getMessage(); + } + } + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public Builder setProfile(org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile value) { + if (profileBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + profile_ = value; + onChanged(); + } else { + profileBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + return this; + } + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public Builder setProfile( + org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.Builder builderForValue) { + if (profileBuilder_ == null) { + profile_ = builderForValue.build(); + onChanged(); + } else { + profileBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + return this; + } + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public Builder mergeProfile(org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile value) { + if (profileBuilder_ == null) { + if (((bitField0_ & 0x00000004) == 0x00000004) && + profile_ != org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.getDefaultInstance()) { + profile_ = + org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.newBuilder(profile_).mergeFrom(value).buildPartial(); + } else { + profile_ = value; + } + onChanged(); + } else { + profileBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000004; + return this; + } + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public Builder clearProfile() { + if (profileBuilder_ == null) { + profile_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.getDefaultInstance(); + onChanged(); + } else { + profileBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.Builder getProfileBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return getProfileFieldBuilder().getBuilder(); + } + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + public org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfileOrBuilder getProfileOrBuilder() { + if (profileBuilder_ != null) { + return profileBuilder_.getMessageOrBuilder(); + } else { + return profile_; + } + } + /** + * optional .signalservice.DataMessage.LokiProfile profile = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile, org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.Builder, org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfileOrBuilder> + getProfileFieldBuilder() { + if (profileBuilder_ == null) { + profileBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile, org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfile.Builder, org.session.libsignal.protos.SignalServiceProtos.DataMessage.LokiProfileOrBuilder>( + profile_, + getParentForChildren(), + isClean()); + profile_ = null; + } + return profileBuilder_; + } + // @@protoc_insertion_point(builder_scope:signalservice.MessageRequestResponse) } @@ -25921,24 +26197,26 @@ public final class SignalServiceProtos { "\001 \002(\014\022\014\n\004name\030\002 \002(\t\022\026\n\016profilePicture\030\003 ", "\001(\t\022\022\n\nprofileKey\030\004 \001(\014\022\022\n\nisApproved\030\005 " + "\001(\010\022\021\n\tisBlocked\030\006 \001(\010\022\024\n\014didApproveMe\030\007" + - " \001(\010\",\n\026MessageRequestResponse\022\022\n\nisAppr" + - "oved\030\001 \002(\010\"u\n\016ReceiptMessage\0220\n\004type\030\001 \002" + - "(\0162\".signalservice.ReceiptMessage.Type\022\021" + - "\n\ttimestamp\030\002 \003(\004\"\036\n\004Type\022\014\n\010DELIVERY\020\000\022" + - "\010\n\004READ\020\001\"\354\001\n\021AttachmentPointer\022\n\n\002id\030\001 " + - "\002(\006\022\023\n\013contentType\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\022\014\n" + - "\004size\030\004 \001(\r\022\021\n\tthumbnail\030\005 \001(\014\022\016\n\006digest" + - "\030\006 \001(\014\022\020\n\010fileName\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022", - "\r\n\005width\030\t \001(\r\022\016\n\006height\030\n \001(\r\022\017\n\007captio" + - "n\030\013 \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_M" + - "ESSAGE\020\001\"\365\001\n\014GroupContext\022\n\n\002id\030\001 \001(\014\022.\n" + - "\004type\030\002 \001(\0162 .signalservice.GroupContext" + - ".Type\022\014\n\004name\030\003 \001(\t\022\017\n\007members\030\004 \003(\t\0220\n\006" + - "avatar\030\005 \001(\0132 .signalservice.AttachmentP" + - "ointer\022\016\n\006admins\030\006 \003(\t\"H\n\004Type\022\013\n\007UNKNOW" + - "N\020\000\022\n\n\006UPDATE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020" + - "\n\014REQUEST_INFO\020\004B3\n\034org.session.libsigna" + - "l.protosB\023SignalServiceProtos" + " \001(\010\"y\n\026MessageRequestResponse\022\022\n\nisAppr" + + "oved\030\001 \002(\010\022\022\n\nprofileKey\030\002 \001(\014\0227\n\007profil" + + "e\030\003 \001(\0132&.signalservice.DataMessage.Loki" + + "Profile\"u\n\016ReceiptMessage\0220\n\004type\030\001 \002(\0162" + + "\".signalservice.ReceiptMessage.Type\022\021\n\tt" + + "imestamp\030\002 \003(\004\"\036\n\004Type\022\014\n\010DELIVERY\020\000\022\010\n\004" + + "READ\020\001\"\354\001\n\021AttachmentPointer\022\n\n\002id\030\001 \002(\006" + + "\022\023\n\013contentType\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\022\014\n\004si", + "ze\030\004 \001(\r\022\021\n\tthumbnail\030\005 \001(\014\022\016\n\006digest\030\006 " + + "\001(\014\022\020\n\010fileName\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022\r\n\005" + + "width\030\t \001(\r\022\016\n\006height\030\n \001(\r\022\017\n\007caption\030\013" + + " \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_MESS" + + "AGE\020\001\"\365\001\n\014GroupContext\022\n\n\002id\030\001 \001(\014\022.\n\004ty" + + "pe\030\002 \001(\0162 .signalservice.GroupContext.Ty" + + "pe\022\014\n\004name\030\003 \001(\t\022\017\n\007members\030\004 \003(\t\0220\n\006ava" + + "tar\030\005 \001(\0132 .signalservice.AttachmentPoin" + + "ter\022\016\n\006admins\030\006 \003(\t\"H\n\004Type\022\013\n\007UNKNOWN\020\000" + + "\022\n\n\006UPDATE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020\n\014R", + "EQUEST_INFO\020\004B3\n\034org.session.libsignal.p" + + "rotosB\023SignalServiceProtos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -26064,7 +26342,7 @@ public final class SignalServiceProtos { internal_static_signalservice_MessageRequestResponse_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_MessageRequestResponse_descriptor, - new java.lang.String[] { "IsApproved", }); + new java.lang.String[] { "IsApproved", "ProfileKey", "Profile", }); internal_static_signalservice_ReceiptMessage_descriptor = getDescriptor().getMessageTypes().get(10); internal_static_signalservice_ReceiptMessage_fieldAccessorTable = new From 140877f4e3201fbfc26845abf2cab8cc53457700 Mon Sep 17 00:00:00 2001 From: charles Date: Tue, 4 Oct 2022 18:31:20 +1100 Subject: [PATCH 005/744] Refactor --- .../securesms/database/Storage.kt | 16 +++++-------- .../libsession/database/StorageProtocol.kt | 5 ++-- .../control/MessageRequestResponse.kt | 2 +- .../messaging/messages/visible/Profile.kt | 2 +- .../sending_receiving/MessageSender.kt | 23 +++++-------------- 5 files changed, 16 insertions(+), 32 deletions(-) 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 14116e9e4b..1017da624b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -23,6 +23,7 @@ import org.session.libsession.messaging.messages.signal.OutgoingGroupMediaMessag import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage import org.session.libsession.messaging.messages.signal.OutgoingTextMessage import org.session.libsession.messaging.messages.visible.Attachment +import org.session.libsession.messaging.messages.visible.Profile import org.session.libsession.messaging.messages.visible.Reaction import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.open_groups.GroupMember @@ -69,16 +70,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, return DatabaseComponent.get(context).lokiAPIDatabase().getUserX25519KeyPair() } - override fun getUserDisplayName(): String? { - return TextSecurePreferences.getProfileName(context) - } - - override fun getUserProfileKey(): ByteArray? { - return ProfileKeyUtil.getProfileKey(context) - } - - override fun getUserProfilePictureURL(): String? { - return TextSecurePreferences.getProfilePictureURL(context) + override fun getUserProfile(): Profile { + val displayName = TextSecurePreferences.getProfileName(context)!! + val profileKey = ProfileKeyUtil.getProfileKey(context) + val profilePictureUrl = TextSecurePreferences.getProfilePictureURL(context) + return Profile(displayName, profileKey, profilePictureUrl) } override fun setUserProfilePictureURL(newValue: String) { diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index fb1aac3d22..e4c66daff5 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -12,6 +12,7 @@ import org.session.libsession.messaging.messages.Message import org.session.libsession.messaging.messages.control.ConfigurationMessage import org.session.libsession.messaging.messages.control.MessageRequestResponse import org.session.libsession.messaging.messages.visible.Attachment +import org.session.libsession.messaging.messages.visible.Profile import org.session.libsession.messaging.messages.visible.Reaction import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.open_groups.GroupMember @@ -34,9 +35,7 @@ interface StorageProtocol { // General fun getUserPublicKey(): String? fun getUserX25519KeyPair(): ECKeyPair - fun getUserDisplayName(): String? - fun getUserProfileKey(): ByteArray? - fun getUserProfilePictureURL(): String? + fun getUserProfile(): Profile fun setUserProfilePictureURL(newProfilePicture: String) // Signal fun getOrGenerateRegistrationID(): Int diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/control/MessageRequestResponse.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/control/MessageRequestResponse.kt index 5722f707bd..6584634fe9 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/control/MessageRequestResponse.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/control/MessageRequestResponse.kt @@ -5,7 +5,7 @@ import org.session.libsession.messaging.messages.visible.Profile import org.session.libsignal.protos.SignalServiceProtos import org.session.libsignal.utilities.Log -class MessageRequestResponse(val isApproved: Boolean, val profile: Profile? = null) : ControlMessage() { +class MessageRequestResponse(val isApproved: Boolean, var profile: Profile? = null) : ControlMessage() { override val isSelfSendValid: Boolean = true diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt index cf792e6a84..ce6b61524c 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/Profile.kt @@ -25,7 +25,7 @@ class Profile() { } } - internal constructor(displayName: String, profileKey: ByteArray? = null, profilePictureURL: String? = null) : this() { + constructor(displayName: String, profileKey: ByteArray? = null, profilePictureURL: String? = null) : this() { this.displayName = displayName this.profileKey = profileKey this.profilePictureURL = profilePictureURL diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt index d6a4618d96..f6d26dbe91 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt @@ -12,9 +12,9 @@ import org.session.libsession.messaging.messages.control.CallMessage import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage import org.session.libsession.messaging.messages.control.ConfigurationMessage import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate +import org.session.libsession.messaging.messages.control.MessageRequestResponse import org.session.libsession.messaging.messages.control.UnsendRequest import org.session.libsession.messaging.messages.visible.LinkPreview -import org.session.libsession.messaging.messages.visible.Profile import org.session.libsession.messaging.messages.visible.Quote import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.open_groups.OpenGroupApi @@ -118,14 +118,10 @@ object MessageSender { } // Attach the user's profile if needed if (message is VisibleMessage) { - val displayName = storage.getUserDisplayName()!! - val profileKey = storage.getUserProfileKey() - val profilePictureUrl = storage.getUserProfilePictureURL() - if (profileKey != null && profilePictureUrl != null) { - message.profile = Profile(displayName, profileKey, profilePictureUrl) - } else { - message.profile = Profile(displayName) - } + message.profile = storage.getUserProfile() + } + if (message is MessageRequestResponse) { + message.profile = storage.getUserProfile() } // Convert it to protobuf val proto = message.toProto() ?: throw Error.ProtoConversionFailed @@ -257,14 +253,7 @@ object MessageSender { try { // Attach the user's profile if needed if (message is VisibleMessage) { - val displayName = storage.getUserDisplayName()!! - val profileKey = storage.getUserProfileKey() - val profilePictureUrl = storage.getUserProfilePictureURL() - if (profileKey != null && profilePictureUrl != null) { - message.profile = Profile(displayName, profileKey, profilePictureUrl) - } else { - message.profile = Profile(displayName) - } + message.profile = storage.getUserProfile() } when (destination) { is Destination.OpenGroup -> { From eb74f901c12820b1687f23c83aa549d775b57f5e Mon Sep 17 00:00:00 2001 From: charles Date: Wed, 5 Oct 2022 10:05:26 +1100 Subject: [PATCH 006/744] Persist profile data --- .../securesms/database/Storage.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) 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 1017da624b..c5e67a0603 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.database import android.content.Context import android.net.Uri +import org.session.libsession.avatars.AvatarHelper import org.session.libsession.database.StorageProtocol import org.session.libsession.messaging.BlindedIdMapping import org.session.libsession.messaging.calls.CallMessageType @@ -42,6 +43,7 @@ import org.session.libsession.utilities.Address.Companion.fromSerialized import org.session.libsession.utilities.GroupRecord import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.ProfileKeyUtil +import org.session.libsession.utilities.SSKEnvironment import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.crypto.ecc.ECKeyPair @@ -59,6 +61,7 @@ import org.thoughtcrime.securesms.groups.OpenGroupManager import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob import org.thoughtcrime.securesms.mms.PartAuthority import org.thoughtcrime.securesms.util.SessionMetaProtocol +import java.security.MessageDigest class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, helper), StorageProtocol { @@ -760,6 +763,25 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, val smsDb = DatabaseComponent.get(context).smsDatabase() val sender = Recipient.from(context, fromSerialized(senderPublicKey), false) val threadId = threadDB.getOrCreateThreadIdFor(sender) + val profile = response.profile + if (profile != null) { + val profileManager = SSKEnvironment.shared.profileManager + val name = profile.displayName!! + if (name.isNotEmpty()) { + profileManager.setName(context, sender, name) + } + val newProfileKey = profile.profileKey + + val needsProfilePicture = !AvatarHelper.avatarFileExists(context, sender.address) + val profileKeyValid = newProfileKey?.isNotEmpty() == true && (newProfileKey.size == 16 || newProfileKey.size == 32) && profile.profilePictureURL?.isNotEmpty() == true + val profileKeyChanged = (sender.profileKey == null || !MessageDigest.isEqual(sender.profileKey, newProfileKey)) + + if ((profileKeyValid && profileKeyChanged) || (profileKeyValid && needsProfilePicture)) { + profileManager.setProfileKey(context, sender, newProfileKey!!) + profileManager.setUnidentifiedAccessMode(context, sender, Recipient.UnidentifiedAccessMode.UNKNOWN) + profileManager.setProfilePictureURL(context, sender, profile.profilePictureURL!!) + } + } threadDB.setHasSent(threadId, true) val mappingDb = DatabaseComponent.get(context).blindedIdMappingDatabase() val mappings = mutableMapOf() From 10d0134269d178bc1381d0f90519c72d1dc936bc Mon Sep 17 00:00:00 2001 From: charles Date: Wed, 19 Oct 2022 13:15:05 +1100 Subject: [PATCH 007/744] fix: Use text color secondary for conversation pinned icon --- app/src/main/res/values/themes.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 88f1a6a2f4..c6b6f3ba96 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -352,7 +352,7 @@ @color/classic_dark_1 ?colorCellBackground @color/classic_dark_2 - @color/classic_dark_4 + ?android:textColorSecondary @color/classic_dark_3 @color/classic_dark_0 @@ -435,7 +435,7 @@ @color/classic_light_5 ?colorCellBackground @color/classic_light_6 - @color/classic_light_2 + ?android:textColorSecondary @color/classic_light_3 @color/classic_light_0 @@ -513,7 +513,7 @@ @color/ocean_dark_3 ?colorCellBackground @color/ocean_dark_4 - ?colorAccent + ?android:textColorSecondary ?colorAccent @color/ocean_dark_0 @color/ocean_dark_3 @@ -632,7 +632,7 @@ ?colorAccent ?colorCellBackground @color/ocean_light_5 - ?android:textColorPrimary + ?android:textColorSecondary From 7750de3e3a5a85d2a66e2991dd2310d26aacb025 Mon Sep 17 00:00:00 2001 From: charles Date: Thu, 20 Oct 2022 15:17:23 +1100 Subject: [PATCH 008/744] feat: Improved disappearing messages --- libsignal/protobuf/SignalService.proto | 13 + .../libsignal/protos/SignalServiceProtos.java | 1118 +++++++++++++++-- 2 files changed, 1032 insertions(+), 99 deletions(-) diff --git a/libsignal/protobuf/SignalService.proto b/libsignal/protobuf/SignalService.proto index e1c1c856d9..016fccaa2c 100644 --- a/libsignal/protobuf/SignalService.proto +++ b/libsignal/protobuf/SignalService.proto @@ -43,6 +43,11 @@ message UnsendRequest { } message Content { + enum ExpirationType { + DELETE_AFTER_SEND = 1; + DELETE_AFTER_READ = 2; + } + optional DataMessage dataMessage = 1; optional CallMessage callMessage = 3; optional ReceiptMessage receiptMessage = 5; @@ -51,6 +56,14 @@ message Content { optional DataExtractionNotification dataExtractionNotification = 8; optional UnsendRequest unsendRequest = 9; optional MessageRequestResponse messageRequestResponse = 10; + optional ExpirationType expirationType = 11; + optional uint32 expirationTimer = 12; + optional uint64 lastDisappearingMessageChangeTimestamp = 13; +} + +message SyncedExpiry { + required string serverHash = 1; + required uint64 expirationTimestamp = 2; } message KeyPair { diff --git a/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java b/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java index ead1b6255e..0d0a875f71 100644 --- a/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java +++ b/libsignal/src/main/java/org/session/libsignal/protos/SignalServiceProtos.java @@ -2468,6 +2468,36 @@ public final class SignalServiceProtos { * optional .signalservice.MessageRequestResponse messageRequestResponse = 10; */ org.session.libsignal.protos.SignalServiceProtos.MessageRequestResponseOrBuilder getMessageRequestResponseOrBuilder(); + + // optional .signalservice.Content.ExpirationType expirationType = 11; + /** + * optional .signalservice.Content.ExpirationType expirationType = 11; + */ + boolean hasExpirationType(); + /** + * optional .signalservice.Content.ExpirationType expirationType = 11; + */ + org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType getExpirationType(); + + // optional uint32 expirationTimer = 12; + /** + * optional uint32 expirationTimer = 12; + */ + boolean hasExpirationTimer(); + /** + * optional uint32 expirationTimer = 12; + */ + int getExpirationTimer(); + + // optional uint64 lastDisappearingMessageChangeTimestamp = 13; + /** + * optional uint64 lastDisappearingMessageChangeTimestamp = 13; + */ + boolean hasLastDisappearingMessageChangeTimestamp(); + /** + * optional uint64 lastDisappearingMessageChangeTimestamp = 13; + */ + long getLastDisappearingMessageChangeTimestamp(); } /** * Protobuf type {@code signalservice.Content} @@ -2624,6 +2654,27 @@ public final class SignalServiceProtos { bitField0_ |= 0x00000080; break; } + case 88: { + int rawValue = input.readEnum(); + org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType value = org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType.valueOf(rawValue); + if (value == null) { + unknownFields.mergeVarintField(11, rawValue); + } else { + bitField0_ |= 0x00000100; + expirationType_ = value; + } + break; + } + case 96: { + bitField0_ |= 0x00000200; + expirationTimer_ = input.readUInt32(); + break; + } + case 104: { + bitField0_ |= 0x00000400; + lastDisappearingMessageChangeTimestamp_ = input.readUInt64(); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -2663,6 +2714,88 @@ public final class SignalServiceProtos { return PARSER; } + /** + * Protobuf enum {@code signalservice.Content.ExpirationType} + */ + public enum ExpirationType + implements com.google.protobuf.ProtocolMessageEnum { + /** + * DELETE_AFTER_SEND = 1; + */ + DELETE_AFTER_SEND(0, 1), + /** + * DELETE_AFTER_READ = 2; + */ + DELETE_AFTER_READ(1, 2), + ; + + /** + * DELETE_AFTER_SEND = 1; + */ + public static final int DELETE_AFTER_SEND_VALUE = 1; + /** + * DELETE_AFTER_READ = 2; + */ + public static final int DELETE_AFTER_READ_VALUE = 2; + + + public final int getNumber() { return value; } + + public static ExpirationType valueOf(int value) { + switch (value) { + case 1: return DELETE_AFTER_SEND; + case 2: return DELETE_AFTER_READ; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public ExpirationType findValueByNumber(int number) { + return ExpirationType.valueOf(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + return getDescriptor().getValues().get(index); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return org.session.libsignal.protos.SignalServiceProtos.Content.getDescriptor().getEnumTypes().get(0); + } + + private static final ExpirationType[] VALUES = values(); + + public static ExpirationType valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + return VALUES[desc.getIndex()]; + } + + private final int index; + private final int value; + + private ExpirationType(int index, int value) { + this.index = index; + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:signalservice.Content.ExpirationType) + } + private int bitField0_; // optional .signalservice.DataMessage dataMessage = 1; public static final int DATAMESSAGE_FIELD_NUMBER = 1; @@ -2840,6 +2973,54 @@ public final class SignalServiceProtos { return messageRequestResponse_; } + // optional .signalservice.Content.ExpirationType expirationType = 11; + public static final int EXPIRATIONTYPE_FIELD_NUMBER = 11; + private org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType expirationType_; + /** + * optional .signalservice.Content.ExpirationType expirationType = 11; + */ + public boolean hasExpirationType() { + return ((bitField0_ & 0x00000100) == 0x00000100); + } + /** + * optional .signalservice.Content.ExpirationType expirationType = 11; + */ + public org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType getExpirationType() { + return expirationType_; + } + + // optional uint32 expirationTimer = 12; + public static final int EXPIRATIONTIMER_FIELD_NUMBER = 12; + private int expirationTimer_; + /** + * optional uint32 expirationTimer = 12; + */ + public boolean hasExpirationTimer() { + return ((bitField0_ & 0x00000200) == 0x00000200); + } + /** + * optional uint32 expirationTimer = 12; + */ + public int getExpirationTimer() { + return expirationTimer_; + } + + // optional uint64 lastDisappearingMessageChangeTimestamp = 13; + public static final int LASTDISAPPEARINGMESSAGECHANGETIMESTAMP_FIELD_NUMBER = 13; + private long lastDisappearingMessageChangeTimestamp_; + /** + * optional uint64 lastDisappearingMessageChangeTimestamp = 13; + */ + public boolean hasLastDisappearingMessageChangeTimestamp() { + return ((bitField0_ & 0x00000400) == 0x00000400); + } + /** + * optional uint64 lastDisappearingMessageChangeTimestamp = 13; + */ + public long getLastDisappearingMessageChangeTimestamp() { + return lastDisappearingMessageChangeTimestamp_; + } + private void initFields() { dataMessage_ = org.session.libsignal.protos.SignalServiceProtos.DataMessage.getDefaultInstance(); callMessage_ = org.session.libsignal.protos.SignalServiceProtos.CallMessage.getDefaultInstance(); @@ -2849,6 +3030,9 @@ public final class SignalServiceProtos { dataExtractionNotification_ = org.session.libsignal.protos.SignalServiceProtos.DataExtractionNotification.getDefaultInstance(); unsendRequest_ = org.session.libsignal.protos.SignalServiceProtos.UnsendRequest.getDefaultInstance(); messageRequestResponse_ = org.session.libsignal.protos.SignalServiceProtos.MessageRequestResponse.getDefaultInstance(); + expirationType_ = org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType.DELETE_AFTER_SEND; + expirationTimer_ = 0; + lastDisappearingMessageChangeTimestamp_ = 0L; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -2934,6 +3118,15 @@ public final class SignalServiceProtos { if (((bitField0_ & 0x00000080) == 0x00000080)) { output.writeMessage(10, messageRequestResponse_); } + if (((bitField0_ & 0x00000100) == 0x00000100)) { + output.writeEnum(11, expirationType_.getNumber()); + } + if (((bitField0_ & 0x00000200) == 0x00000200)) { + output.writeUInt32(12, expirationTimer_); + } + if (((bitField0_ & 0x00000400) == 0x00000400)) { + output.writeUInt64(13, lastDisappearingMessageChangeTimestamp_); + } getUnknownFields().writeTo(output); } @@ -2975,6 +3168,18 @@ public final class SignalServiceProtos { size += com.google.protobuf.CodedOutputStream .computeMessageSize(10, messageRequestResponse_); } + if (((bitField0_ & 0x00000100) == 0x00000100)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(11, expirationType_.getNumber()); + } + if (((bitField0_ & 0x00000200) == 0x00000200)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(12, expirationTimer_); + } + if (((bitField0_ & 0x00000400) == 0x00000400)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(13, lastDisappearingMessageChangeTimestamp_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -3147,6 +3352,12 @@ public final class SignalServiceProtos { messageRequestResponseBuilder_.clear(); } bitField0_ = (bitField0_ & ~0x00000080); + expirationType_ = org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType.DELETE_AFTER_SEND; + bitField0_ = (bitField0_ & ~0x00000100); + expirationTimer_ = 0; + bitField0_ = (bitField0_ & ~0x00000200); + lastDisappearingMessageChangeTimestamp_ = 0L; + bitField0_ = (bitField0_ & ~0x00000400); return this; } @@ -3239,6 +3450,18 @@ public final class SignalServiceProtos { } else { result.messageRequestResponse_ = messageRequestResponseBuilder_.build(); } + if (((from_bitField0_ & 0x00000100) == 0x00000100)) { + to_bitField0_ |= 0x00000100; + } + result.expirationType_ = expirationType_; + if (((from_bitField0_ & 0x00000200) == 0x00000200)) { + to_bitField0_ |= 0x00000200; + } + result.expirationTimer_ = expirationTimer_; + if (((from_bitField0_ & 0x00000400) == 0x00000400)) { + to_bitField0_ |= 0x00000400; + } + result.lastDisappearingMessageChangeTimestamp_ = lastDisappearingMessageChangeTimestamp_; result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -3279,6 +3502,15 @@ public final class SignalServiceProtos { if (other.hasMessageRequestResponse()) { mergeMessageRequestResponse(other.getMessageRequestResponse()); } + if (other.hasExpirationType()) { + setExpirationType(other.getExpirationType()); + } + if (other.hasExpirationTimer()) { + setExpirationTimer(other.getExpirationTimer()); + } + if (other.hasLastDisappearingMessageChangeTimestamp()) { + setLastDisappearingMessageChangeTimestamp(other.getLastDisappearingMessageChangeTimestamp()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -4290,6 +4522,108 @@ public final class SignalServiceProtos { return messageRequestResponseBuilder_; } + // optional .signalservice.Content.ExpirationType expirationType = 11; + private org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType expirationType_ = org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType.DELETE_AFTER_SEND; + /** + * optional .signalservice.Content.ExpirationType expirationType = 11; + */ + public boolean hasExpirationType() { + return ((bitField0_ & 0x00000100) == 0x00000100); + } + /** + * optional .signalservice.Content.ExpirationType expirationType = 11; + */ + public org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType getExpirationType() { + return expirationType_; + } + /** + * optional .signalservice.Content.ExpirationType expirationType = 11; + */ + public Builder setExpirationType(org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000100; + expirationType_ = value; + onChanged(); + return this; + } + /** + * optional .signalservice.Content.ExpirationType expirationType = 11; + */ + public Builder clearExpirationType() { + bitField0_ = (bitField0_ & ~0x00000100); + expirationType_ = org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType.DELETE_AFTER_SEND; + onChanged(); + return this; + } + + // optional uint32 expirationTimer = 12; + private int expirationTimer_ ; + /** + * optional uint32 expirationTimer = 12; + */ + public boolean hasExpirationTimer() { + return ((bitField0_ & 0x00000200) == 0x00000200); + } + /** + * optional uint32 expirationTimer = 12; + */ + public int getExpirationTimer() { + return expirationTimer_; + } + /** + * optional uint32 expirationTimer = 12; + */ + public Builder setExpirationTimer(int value) { + bitField0_ |= 0x00000200; + expirationTimer_ = value; + onChanged(); + return this; + } + /** + * optional uint32 expirationTimer = 12; + */ + public Builder clearExpirationTimer() { + bitField0_ = (bitField0_ & ~0x00000200); + expirationTimer_ = 0; + onChanged(); + return this; + } + + // optional uint64 lastDisappearingMessageChangeTimestamp = 13; + private long lastDisappearingMessageChangeTimestamp_ ; + /** + * optional uint64 lastDisappearingMessageChangeTimestamp = 13; + */ + public boolean hasLastDisappearingMessageChangeTimestamp() { + return ((bitField0_ & 0x00000400) == 0x00000400); + } + /** + * optional uint64 lastDisappearingMessageChangeTimestamp = 13; + */ + public long getLastDisappearingMessageChangeTimestamp() { + return lastDisappearingMessageChangeTimestamp_; + } + /** + * optional uint64 lastDisappearingMessageChangeTimestamp = 13; + */ + public Builder setLastDisappearingMessageChangeTimestamp(long value) { + bitField0_ |= 0x00000400; + lastDisappearingMessageChangeTimestamp_ = value; + onChanged(); + return this; + } + /** + * optional uint64 lastDisappearingMessageChangeTimestamp = 13; + */ + public Builder clearLastDisappearingMessageChangeTimestamp() { + bitField0_ = (bitField0_ & ~0x00000400); + lastDisappearingMessageChangeTimestamp_ = 0L; + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:signalservice.Content) } @@ -4301,6 +4635,574 @@ public final class SignalServiceProtos { // @@protoc_insertion_point(class_scope:signalservice.Content) } + public interface SyncedExpiryOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // required string serverHash = 1; + /** + * required string serverHash = 1; + */ + boolean hasServerHash(); + /** + * required string serverHash = 1; + */ + java.lang.String getServerHash(); + /** + * required string serverHash = 1; + */ + com.google.protobuf.ByteString + getServerHashBytes(); + + // required uint64 expirationTimestamp = 2; + /** + * required uint64 expirationTimestamp = 2; + */ + boolean hasExpirationTimestamp(); + /** + * required uint64 expirationTimestamp = 2; + */ + long getExpirationTimestamp(); + } + /** + * Protobuf type {@code signalservice.SyncedExpiry} + */ + public static final class SyncedExpiry extends + com.google.protobuf.GeneratedMessage + implements SyncedExpiryOrBuilder { + // Use SyncedExpiry.newBuilder() to construct. + private SyncedExpiry(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private SyncedExpiry(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final SyncedExpiry defaultInstance; + public static SyncedExpiry getDefaultInstance() { + return defaultInstance; + } + + public SyncedExpiry getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private SyncedExpiry( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + serverHash_ = input.readBytes(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + expirationTimestamp_ = input.readUInt64(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.session.libsignal.protos.SignalServiceProtos.internal_static_signalservice_SyncedExpiry_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.session.libsignal.protos.SignalServiceProtos.internal_static_signalservice_SyncedExpiry_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry.class, org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public SyncedExpiry parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new SyncedExpiry(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // required string serverHash = 1; + public static final int SERVERHASH_FIELD_NUMBER = 1; + private java.lang.Object serverHash_; + /** + * required string serverHash = 1; + */ + public boolean hasServerHash() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string serverHash = 1; + */ + public java.lang.String getServerHash() { + java.lang.Object ref = serverHash_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + if (bs.isValidUtf8()) { + serverHash_ = s; + } + return s; + } + } + /** + * required string serverHash = 1; + */ + public com.google.protobuf.ByteString + getServerHashBytes() { + java.lang.Object ref = serverHash_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + serverHash_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // required uint64 expirationTimestamp = 2; + public static final int EXPIRATIONTIMESTAMP_FIELD_NUMBER = 2; + private long expirationTimestamp_; + /** + * required uint64 expirationTimestamp = 2; + */ + public boolean hasExpirationTimestamp() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint64 expirationTimestamp = 2; + */ + public long getExpirationTimestamp() { + return expirationTimestamp_; + } + + private void initFields() { + serverHash_ = ""; + expirationTimestamp_ = 0L; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasServerHash()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasExpirationTimestamp()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getServerHashBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt64(2, expirationTimestamp_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getServerHashBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(2, expirationTimestamp_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code signalservice.SyncedExpiry} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.session.libsignal.protos.SignalServiceProtos.SyncedExpiryOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.session.libsignal.protos.SignalServiceProtos.internal_static_signalservice_SyncedExpiry_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.session.libsignal.protos.SignalServiceProtos.internal_static_signalservice_SyncedExpiry_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry.class, org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry.Builder.class); + } + + // Construct using org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + serverHash_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + expirationTimestamp_ = 0L; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.session.libsignal.protos.SignalServiceProtos.internal_static_signalservice_SyncedExpiry_descriptor; + } + + public org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry getDefaultInstanceForType() { + return org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry.getDefaultInstance(); + } + + public org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry build() { + org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry buildPartial() { + org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry result = new org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.serverHash_ = serverHash_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.expirationTimestamp_ = expirationTimestamp_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry) { + return mergeFrom((org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry other) { + if (other == org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry.getDefaultInstance()) return this; + if (other.hasServerHash()) { + bitField0_ |= 0x00000001; + serverHash_ = other.serverHash_; + onChanged(); + } + if (other.hasExpirationTimestamp()) { + setExpirationTimestamp(other.getExpirationTimestamp()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasServerHash()) { + + return false; + } + if (!hasExpirationTimestamp()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.session.libsignal.protos.SignalServiceProtos.SyncedExpiry) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // required string serverHash = 1; + private java.lang.Object serverHash_ = ""; + /** + * required string serverHash = 1; + */ + public boolean hasServerHash() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required string serverHash = 1; + */ + public java.lang.String getServerHash() { + java.lang.Object ref = serverHash_; + if (!(ref instanceof java.lang.String)) { + java.lang.String s = ((com.google.protobuf.ByteString) ref) + .toStringUtf8(); + serverHash_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * required string serverHash = 1; + */ + public com.google.protobuf.ByteString + getServerHashBytes() { + java.lang.Object ref = serverHash_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + serverHash_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * required string serverHash = 1; + */ + public Builder setServerHash( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + serverHash_ = value; + onChanged(); + return this; + } + /** + * required string serverHash = 1; + */ + public Builder clearServerHash() { + bitField0_ = (bitField0_ & ~0x00000001); + serverHash_ = getDefaultInstance().getServerHash(); + onChanged(); + return this; + } + /** + * required string serverHash = 1; + */ + public Builder setServerHashBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + serverHash_ = value; + onChanged(); + return this; + } + + // required uint64 expirationTimestamp = 2; + private long expirationTimestamp_ ; + /** + * required uint64 expirationTimestamp = 2; + */ + public boolean hasExpirationTimestamp() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required uint64 expirationTimestamp = 2; + */ + public long getExpirationTimestamp() { + return expirationTimestamp_; + } + /** + * required uint64 expirationTimestamp = 2; + */ + public Builder setExpirationTimestamp(long value) { + bitField0_ |= 0x00000002; + expirationTimestamp_ = value; + onChanged(); + return this; + } + /** + * required uint64 expirationTimestamp = 2; + */ + public Builder clearExpirationTimestamp() { + bitField0_ = (bitField0_ & ~0x00000002); + expirationTimestamp_ = 0L; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:signalservice.SyncedExpiry) + } + + static { + defaultInstance = new SyncedExpiry(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:signalservice.SyncedExpiry) + } + public interface KeyPairOrBuilder extends com.google.protobuf.MessageOrBuilder { @@ -25725,6 +26627,11 @@ public final class SignalServiceProtos { private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_signalservice_Content_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_signalservice_SyncedExpiry_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_signalservice_SyncedExpiry_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_signalservice_KeyPair_descriptor; private static @@ -25839,7 +26746,7 @@ public final class SignalServiceProtos { "\002(\004\0223\n\006action\030\002 \002(\0162#.signalservice.Typi" + "ngMessage.Action\"\"\n\006Action\022\013\n\007STARTED\020\000\022" + "\013\n\007STOPPED\020\001\"2\n\rUnsendRequest\022\021\n\ttimesta", - "mp\030\001 \002(\004\022\016\n\006author\030\002 \002(\t\"\345\003\n\007Content\022/\n\013" + + "mp\030\001 \002(\004\022\016\n\006author\030\002 \002(\t\"\255\005\n\007Content\022/\n\013" + "dataMessage\030\001 \001(\0132\032.signalservice.DataMe" + "ssage\022/\n\013callMessage\030\003 \001(\0132\032.signalservi" + "ce.CallMessage\0225\n\016receiptMessage\030\005 \001(\0132\035" + @@ -25851,94 +26758,101 @@ public final class SignalServiceProtos { "e.DataExtractionNotification\0223\n\runsendRe", "quest\030\t \001(\0132\034.signalservice.UnsendReques" + "t\022E\n\026messageRequestResponse\030\n \001(\0132%.sign" + - "alservice.MessageRequestResponse\"0\n\007KeyP" + - "air\022\021\n\tpublicKey\030\001 \002(\014\022\022\n\nprivateKey\030\002 \002" + - "(\014\"\226\001\n\032DataExtractionNotification\022<\n\004typ" + - "e\030\001 \002(\0162..signalservice.DataExtractionNo" + - "tification.Type\022\021\n\ttimestamp\030\002 \001(\004\"\'\n\004Ty" + - "pe\022\016\n\nSCREENSHOT\020\001\022\017\n\013MEDIA_SAVED\020\002\"\361\r\n\013" + - "DataMessage\022\014\n\004body\030\001 \001(\t\0225\n\013attachments" + - "\030\002 \003(\0132 .signalservice.AttachmentPointer", - "\022*\n\005group\030\003 \001(\0132\033.signalservice.GroupCon" + - "text\022\r\n\005flags\030\004 \001(\r\022\023\n\013expireTimer\030\005 \001(\r" + - "\022\022\n\nprofileKey\030\006 \001(\014\022\021\n\ttimestamp\030\007 \001(\004\022" + - "/\n\005quote\030\010 \001(\0132 .signalservice.DataMessa" + - "ge.Quote\0223\n\007preview\030\n \003(\0132\".signalservic" + - "e.DataMessage.Preview\0225\n\010reaction\030\013 \001(\0132" + - "#.signalservice.DataMessage.Reaction\0227\n\007" + - "profile\030e \001(\0132&.signalservice.DataMessag" + - "e.LokiProfile\022K\n\023openGroupInvitation\030f \001" + - "(\0132..signalservice.DataMessage.OpenGroup", - "Invitation\022W\n\031closedGroupControlMessage\030" + - "h \001(\01324.signalservice.DataMessage.Closed" + - "GroupControlMessage\022\022\n\nsyncTarget\030i \001(\t\032" + - "\225\002\n\005Quote\022\n\n\002id\030\001 \002(\004\022\016\n\006author\030\002 \002(\t\022\014\n" + - "\004text\030\003 \001(\t\022F\n\013attachments\030\004 \003(\01321.signa" + - "lservice.DataMessage.Quote.QuotedAttachm" + - "ent\032\231\001\n\020QuotedAttachment\022\023\n\013contentType\030" + - "\001 \001(\t\022\020\n\010fileName\030\002 \001(\t\0223\n\tthumbnail\030\003 \001" + - "(\0132 .signalservice.AttachmentPointer\022\r\n\005" + - "flags\030\004 \001(\r\"\032\n\005Flags\022\021\n\rVOICE_MESSAGE\020\001\032", - "V\n\007Preview\022\013\n\003url\030\001 \002(\t\022\r\n\005title\030\002 \001(\t\022/" + - "\n\005image\030\003 \001(\0132 .signalservice.Attachment" + - "Pointer\032:\n\013LokiProfile\022\023\n\013displayName\030\001 " + - "\001(\t\022\026\n\016profilePicture\030\002 \001(\t\0320\n\023OpenGroup" + - "Invitation\022\013\n\003url\030\001 \002(\t\022\014\n\004name\030\003 \002(\t\032\374\003" + - "\n\031ClosedGroupControlMessage\022G\n\004type\030\001 \002(" + - "\01629.signalservice.DataMessage.ClosedGrou" + - "pControlMessage.Type\022\021\n\tpublicKey\030\002 \001(\014\022" + - "\014\n\004name\030\003 \001(\t\0221\n\021encryptionKeyPair\030\004 \001(\013" + - "2\026.signalservice.KeyPair\022\017\n\007members\030\005 \003(", - "\014\022\016\n\006admins\030\006 \003(\014\022U\n\010wrappers\030\007 \003(\0132C.si" + - "gnalservice.DataMessage.ClosedGroupContr" + - "olMessage.KeyPairWrapper\022\027\n\017expirationTi" + - "mer\030\010 \001(\r\032=\n\016KeyPairWrapper\022\021\n\tpublicKey" + - "\030\001 \002(\014\022\030\n\020encryptedKeyPair\030\002 \002(\014\"r\n\004Type" + - "\022\007\n\003NEW\020\001\022\027\n\023ENCRYPTION_KEY_PAIR\020\003\022\017\n\013NA" + - "ME_CHANGE\020\004\022\021\n\rMEMBERS_ADDED\020\005\022\023\n\017MEMBER" + - "S_REMOVED\020\006\022\017\n\013MEMBER_LEFT\020\007\032\222\001\n\010Reactio" + - "n\022\n\n\002id\030\001 \002(\004\022\016\n\006author\030\002 \002(\t\022\r\n\005emoji\030\003" + - " \001(\t\022:\n\006action\030\004 \002(\0162*.signalservice.Dat", - "aMessage.Reaction.Action\"\037\n\006Action\022\t\n\005RE" + - "ACT\020\000\022\n\n\006REMOVE\020\001\"$\n\005Flags\022\033\n\027EXPIRATION" + - "_TIMER_UPDATE\020\002\"\352\001\n\013CallMessage\022-\n\004type\030" + - "\001 \002(\0162\037.signalservice.CallMessage.Type\022\014" + - "\n\004sdps\030\002 \003(\t\022\027\n\017sdpMLineIndexes\030\003 \003(\r\022\017\n" + - "\007sdpMids\030\004 \003(\t\022\014\n\004uuid\030\005 \002(\t\"f\n\004Type\022\r\n\t" + - "PRE_OFFER\020\006\022\t\n\005OFFER\020\001\022\n\n\006ANSWER\020\002\022\026\n\022PR" + - "OVISIONAL_ANSWER\020\003\022\022\n\016ICE_CANDIDATES\020\004\022\014" + - "\n\010END_CALL\020\005\"\245\004\n\024ConfigurationMessage\022E\n" + - "\014closedGroups\030\001 \003(\0132/.signalservice.Conf", - "igurationMessage.ClosedGroup\022\022\n\nopenGrou" + - "ps\030\002 \003(\t\022\023\n\013displayName\030\003 \001(\t\022\026\n\016profile" + - "Picture\030\004 \001(\t\022\022\n\nprofileKey\030\005 \001(\014\022=\n\010con" + - "tacts\030\006 \003(\0132+.signalservice.Configuratio" + - "nMessage.Contact\032\233\001\n\013ClosedGroup\022\021\n\tpubl" + - "icKey\030\001 \001(\014\022\014\n\004name\030\002 \001(\t\0221\n\021encryptionK" + - "eyPair\030\003 \001(\0132\026.signalservice.KeyPair\022\017\n\007" + - "members\030\004 \003(\014\022\016\n\006admins\030\005 \003(\014\022\027\n\017expirat" + - "ionTimer\030\006 \001(\r\032\223\001\n\007Contact\022\021\n\tpublicKey\030" + - "\001 \002(\014\022\014\n\004name\030\002 \002(\t\022\026\n\016profilePicture\030\003 ", - "\001(\t\022\022\n\nprofileKey\030\004 \001(\014\022\022\n\nisApproved\030\005 " + - "\001(\010\022\021\n\tisBlocked\030\006 \001(\010\022\024\n\014didApproveMe\030\007" + - " \001(\010\",\n\026MessageRequestResponse\022\022\n\nisAppr" + - "oved\030\001 \002(\010\"u\n\016ReceiptMessage\0220\n\004type\030\001 \002" + - "(\0162\".signalservice.ReceiptMessage.Type\022\021" + - "\n\ttimestamp\030\002 \003(\004\"\036\n\004Type\022\014\n\010DELIVERY\020\000\022" + - "\010\n\004READ\020\001\"\354\001\n\021AttachmentPointer\022\n\n\002id\030\001 " + - "\002(\006\022\023\n\013contentType\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\022\014\n" + - "\004size\030\004 \001(\r\022\021\n\tthumbnail\030\005 \001(\014\022\016\n\006digest" + - "\030\006 \001(\014\022\020\n\010fileName\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022", - "\r\n\005width\030\t \001(\r\022\016\n\006height\030\n \001(\r\022\017\n\007captio" + - "n\030\013 \001(\t\022\013\n\003url\030e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_M" + - "ESSAGE\020\001\"\365\001\n\014GroupContext\022\n\n\002id\030\001 \001(\014\022.\n" + - "\004type\030\002 \001(\0162 .signalservice.GroupContext" + - ".Type\022\014\n\004name\030\003 \001(\t\022\017\n\007members\030\004 \003(\t\0220\n\006" + - "avatar\030\005 \001(\0132 .signalservice.AttachmentP" + - "ointer\022\016\n\006admins\030\006 \003(\t\"H\n\004Type\022\013\n\007UNKNOW" + - "N\020\000\022\n\n\006UPDATE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020" + - "\n\014REQUEST_INFO\020\004B3\n\034org.session.libsigna" + - "l.protosB\023SignalServiceProtos" + "alservice.MessageRequestResponse\022=\n\016expi" + + "rationType\030\013 \001(\0162%.signalservice.Content" + + ".ExpirationType\022\027\n\017expirationTimer\030\014 \001(\r" + + "\022.\n&lastDisappearingMessageChangeTimesta" + + "mp\030\r \001(\004\">\n\016ExpirationType\022\025\n\021DELETE_AFT" + + "ER_SEND\020\001\022\025\n\021DELETE_AFTER_READ\020\002\"?\n\014Sync" + + "edExpiry\022\022\n\nserverHash\030\001 \002(\t\022\033\n\023expirati" + + "onTimestamp\030\002 \002(\004\"0\n\007KeyPair\022\021\n\tpublicKe", + "y\030\001 \002(\014\022\022\n\nprivateKey\030\002 \002(\014\"\226\001\n\032DataExtr" + + "actionNotification\022<\n\004type\030\001 \002(\0162..signa" + + "lservice.DataExtractionNotification.Type" + + "\022\021\n\ttimestamp\030\002 \001(\004\"\'\n\004Type\022\016\n\nSCREENSHO" + + "T\020\001\022\017\n\013MEDIA_SAVED\020\002\"\361\r\n\013DataMessage\022\014\n\004" + + "body\030\001 \001(\t\0225\n\013attachments\030\002 \003(\0132 .signal" + + "service.AttachmentPointer\022*\n\005group\030\003 \001(\013" + + "2\033.signalservice.GroupContext\022\r\n\005flags\030\004" + + " \001(\r\022\023\n\013expireTimer\030\005 \001(\r\022\022\n\nprofileKey\030" + + "\006 \001(\014\022\021\n\ttimestamp\030\007 \001(\004\022/\n\005quote\030\010 \001(\0132", + " .signalservice.DataMessage.Quote\0223\n\007pre" + + "view\030\n \003(\0132\".signalservice.DataMessage.P" + + "review\0225\n\010reaction\030\013 \001(\0132#.signalservice" + + ".DataMessage.Reaction\0227\n\007profile\030e \001(\0132&" + + ".signalservice.DataMessage.LokiProfile\022K" + + "\n\023openGroupInvitation\030f \001(\0132..signalserv" + + "ice.DataMessage.OpenGroupInvitation\022W\n\031c" + + "losedGroupControlMessage\030h \001(\01324.signals" + + "ervice.DataMessage.ClosedGroupControlMes" + + "sage\022\022\n\nsyncTarget\030i \001(\t\032\225\002\n\005Quote\022\n\n\002id", + "\030\001 \002(\004\022\016\n\006author\030\002 \002(\t\022\014\n\004text\030\003 \001(\t\022F\n\013" + + "attachments\030\004 \003(\01321.signalservice.DataMe" + + "ssage.Quote.QuotedAttachment\032\231\001\n\020QuotedA" + + "ttachment\022\023\n\013contentType\030\001 \001(\t\022\020\n\010fileNa" + + "me\030\002 \001(\t\0223\n\tthumbnail\030\003 \001(\0132 .signalserv" + + "ice.AttachmentPointer\022\r\n\005flags\030\004 \001(\r\"\032\n\005" + + "Flags\022\021\n\rVOICE_MESSAGE\020\001\032V\n\007Preview\022\013\n\003u" + + "rl\030\001 \002(\t\022\r\n\005title\030\002 \001(\t\022/\n\005image\030\003 \001(\0132 " + + ".signalservice.AttachmentPointer\032:\n\013Loki" + + "Profile\022\023\n\013displayName\030\001 \001(\t\022\026\n\016profileP", + "icture\030\002 \001(\t\0320\n\023OpenGroupInvitation\022\013\n\003u" + + "rl\030\001 \002(\t\022\014\n\004name\030\003 \002(\t\032\374\003\n\031ClosedGroupCo" + + "ntrolMessage\022G\n\004type\030\001 \002(\01629.signalservi" + + "ce.DataMessage.ClosedGroupControlMessage" + + ".Type\022\021\n\tpublicKey\030\002 \001(\014\022\014\n\004name\030\003 \001(\t\0221" + + "\n\021encryptionKeyPair\030\004 \001(\0132\026.signalservic" + + "e.KeyPair\022\017\n\007members\030\005 \003(\014\022\016\n\006admins\030\006 \003" + + "(\014\022U\n\010wrappers\030\007 \003(\0132C.signalservice.Dat" + + "aMessage.ClosedGroupControlMessage.KeyPa" + + "irWrapper\022\027\n\017expirationTimer\030\010 \001(\r\032=\n\016Ke", + "yPairWrapper\022\021\n\tpublicKey\030\001 \002(\014\022\030\n\020encry" + + "ptedKeyPair\030\002 \002(\014\"r\n\004Type\022\007\n\003NEW\020\001\022\027\n\023EN" + + "CRYPTION_KEY_PAIR\020\003\022\017\n\013NAME_CHANGE\020\004\022\021\n\r" + + "MEMBERS_ADDED\020\005\022\023\n\017MEMBERS_REMOVED\020\006\022\017\n\013" + + "MEMBER_LEFT\020\007\032\222\001\n\010Reaction\022\n\n\002id\030\001 \002(\004\022\016" + + "\n\006author\030\002 \002(\t\022\r\n\005emoji\030\003 \001(\t\022:\n\006action\030" + + "\004 \002(\0162*.signalservice.DataMessage.Reacti" + + "on.Action\"\037\n\006Action\022\t\n\005REACT\020\000\022\n\n\006REMOVE" + + "\020\001\"$\n\005Flags\022\033\n\027EXPIRATION_TIMER_UPDATE\020\002" + + "\"\352\001\n\013CallMessage\022-\n\004type\030\001 \002(\0162\037.signals", + "ervice.CallMessage.Type\022\014\n\004sdps\030\002 \003(\t\022\027\n" + + "\017sdpMLineIndexes\030\003 \003(\r\022\017\n\007sdpMids\030\004 \003(\t\022" + + "\014\n\004uuid\030\005 \002(\t\"f\n\004Type\022\r\n\tPRE_OFFER\020\006\022\t\n\005" + + "OFFER\020\001\022\n\n\006ANSWER\020\002\022\026\n\022PROVISIONAL_ANSWE" + + "R\020\003\022\022\n\016ICE_CANDIDATES\020\004\022\014\n\010END_CALL\020\005\"\245\004" + + "\n\024ConfigurationMessage\022E\n\014closedGroups\030\001" + + " \003(\0132/.signalservice.ConfigurationMessag" + + "e.ClosedGroup\022\022\n\nopenGroups\030\002 \003(\t\022\023\n\013dis" + + "playName\030\003 \001(\t\022\026\n\016profilePicture\030\004 \001(\t\022\022" + + "\n\nprofileKey\030\005 \001(\014\022=\n\010contacts\030\006 \003(\0132+.s", + "ignalservice.ConfigurationMessage.Contac" + + "t\032\233\001\n\013ClosedGroup\022\021\n\tpublicKey\030\001 \001(\014\022\014\n\004" + + "name\030\002 \001(\t\0221\n\021encryptionKeyPair\030\003 \001(\0132\026." + + "signalservice.KeyPair\022\017\n\007members\030\004 \003(\014\022\016" + + "\n\006admins\030\005 \003(\014\022\027\n\017expirationTimer\030\006 \001(\r\032" + + "\223\001\n\007Contact\022\021\n\tpublicKey\030\001 \002(\014\022\014\n\004name\030\002" + + " \002(\t\022\026\n\016profilePicture\030\003 \001(\t\022\022\n\nprofileK" + + "ey\030\004 \001(\014\022\022\n\nisApproved\030\005 \001(\010\022\021\n\tisBlocke" + + "d\030\006 \001(\010\022\024\n\014didApproveMe\030\007 \001(\010\",\n\026Message" + + "RequestResponse\022\022\n\nisApproved\030\001 \002(\010\"u\n\016R", + "eceiptMessage\0220\n\004type\030\001 \002(\0162\".signalserv" + + "ice.ReceiptMessage.Type\022\021\n\ttimestamp\030\002 \003" + + "(\004\"\036\n\004Type\022\014\n\010DELIVERY\020\000\022\010\n\004READ\020\001\"\354\001\n\021A" + + "ttachmentPointer\022\n\n\002id\030\001 \002(\006\022\023\n\013contentT" + + "ype\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\022\014\n\004size\030\004 \001(\r\022\021\n\t" + + "thumbnail\030\005 \001(\014\022\016\n\006digest\030\006 \001(\014\022\020\n\010fileN" + + "ame\030\007 \001(\t\022\r\n\005flags\030\010 \001(\r\022\r\n\005width\030\t \001(\r\022" + + "\016\n\006height\030\n \001(\r\022\017\n\007caption\030\013 \001(\t\022\013\n\003url\030" + + "e \001(\t\"\032\n\005Flags\022\021\n\rVOICE_MESSAGE\020\001\"\365\001\n\014Gr" + + "oupContext\022\n\n\002id\030\001 \001(\014\022.\n\004type\030\002 \001(\0162 .s", + "ignalservice.GroupContext.Type\022\014\n\004name\030\003" + + " \001(\t\022\017\n\007members\030\004 \003(\t\0220\n\006avatar\030\005 \001(\0132 ." + + "signalservice.AttachmentPointer\022\016\n\006admin" + + "s\030\006 \003(\t\"H\n\004Type\022\013\n\007UNKNOWN\020\000\022\n\n\006UPDATE\020\001" + + "\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\022\020\n\014REQUEST_INFO\020" + + "\004B3\n\034org.session.libsignal.protosB\023Signa" + + "lServiceProtos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -25968,21 +26882,27 @@ public final class SignalServiceProtos { internal_static_signalservice_Content_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_Content_descriptor, - new java.lang.String[] { "DataMessage", "CallMessage", "ReceiptMessage", "TypingMessage", "ConfigurationMessage", "DataExtractionNotification", "UnsendRequest", "MessageRequestResponse", }); - internal_static_signalservice_KeyPair_descriptor = + new java.lang.String[] { "DataMessage", "CallMessage", "ReceiptMessage", "TypingMessage", "ConfigurationMessage", "DataExtractionNotification", "UnsendRequest", "MessageRequestResponse", "ExpirationType", "ExpirationTimer", "LastDisappearingMessageChangeTimestamp", }); + internal_static_signalservice_SyncedExpiry_descriptor = getDescriptor().getMessageTypes().get(4); + internal_static_signalservice_SyncedExpiry_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_signalservice_SyncedExpiry_descriptor, + new java.lang.String[] { "ServerHash", "ExpirationTimestamp", }); + internal_static_signalservice_KeyPair_descriptor = + getDescriptor().getMessageTypes().get(5); internal_static_signalservice_KeyPair_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_KeyPair_descriptor, new java.lang.String[] { "PublicKey", "PrivateKey", }); internal_static_signalservice_DataExtractionNotification_descriptor = - getDescriptor().getMessageTypes().get(5); + getDescriptor().getMessageTypes().get(6); internal_static_signalservice_DataExtractionNotification_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_DataExtractionNotification_descriptor, new java.lang.String[] { "Type", "Timestamp", }); internal_static_signalservice_DataMessage_descriptor = - getDescriptor().getMessageTypes().get(6); + getDescriptor().getMessageTypes().get(7); internal_static_signalservice_DataMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_DataMessage_descriptor, @@ -26036,13 +26956,13 @@ public final class SignalServiceProtos { internal_static_signalservice_DataMessage_Reaction_descriptor, new java.lang.String[] { "Id", "Author", "Emoji", "Action", }); internal_static_signalservice_CallMessage_descriptor = - getDescriptor().getMessageTypes().get(7); + getDescriptor().getMessageTypes().get(8); internal_static_signalservice_CallMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_CallMessage_descriptor, new java.lang.String[] { "Type", "Sdps", "SdpMLineIndexes", "SdpMids", "Uuid", }); internal_static_signalservice_ConfigurationMessage_descriptor = - getDescriptor().getMessageTypes().get(8); + getDescriptor().getMessageTypes().get(9); internal_static_signalservice_ConfigurationMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_ConfigurationMessage_descriptor, @@ -26060,25 +26980,25 @@ public final class SignalServiceProtos { internal_static_signalservice_ConfigurationMessage_Contact_descriptor, new java.lang.String[] { "PublicKey", "Name", "ProfilePicture", "ProfileKey", "IsApproved", "IsBlocked", "DidApproveMe", }); internal_static_signalservice_MessageRequestResponse_descriptor = - getDescriptor().getMessageTypes().get(9); + getDescriptor().getMessageTypes().get(10); internal_static_signalservice_MessageRequestResponse_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_MessageRequestResponse_descriptor, new java.lang.String[] { "IsApproved", }); internal_static_signalservice_ReceiptMessage_descriptor = - getDescriptor().getMessageTypes().get(10); + getDescriptor().getMessageTypes().get(11); internal_static_signalservice_ReceiptMessage_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_ReceiptMessage_descriptor, new java.lang.String[] { "Type", "Timestamp", }); internal_static_signalservice_AttachmentPointer_descriptor = - getDescriptor().getMessageTypes().get(11); + getDescriptor().getMessageTypes().get(12); internal_static_signalservice_AttachmentPointer_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_AttachmentPointer_descriptor, new java.lang.String[] { "Id", "ContentType", "Key", "Size", "Thumbnail", "Digest", "FileName", "Flags", "Width", "Height", "Caption", "Url", }); internal_static_signalservice_GroupContext_descriptor = - getDescriptor().getMessageTypes().get(12); + getDescriptor().getMessageTypes().get(13); internal_static_signalservice_GroupContext_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_signalservice_GroupContext_descriptor, From 427b2d7b5fc7ee0a22d61601005a5de0b0ec75e3 Mon Sep 17 00:00:00 2001 From: ceokot Date: Mon, 24 Oct 2022 15:45:26 +1100 Subject: [PATCH 009/744] fix: Selected message theme colours and crash fixes (#1025) * Fixed a bug where message requests could incorrectly appear in the thread list (#1009) * New app theming (#1010) * feat: start new app theming feature * feat: add some theming colours * refactor: start refactoring themes and colours to use dynamic attributes * feat: adding more colours and switching over default colours to be theme based instead of hard-coded or day/night specific * refactor: take a look at ocean light and logo colour * feat: global search colours for light and dark ocean * feat: more styling * feat: adding themes to conversation activity and refactoring the base theme to apply over the top of the activity's theme so it retains noActionBar etc * feat: add dynamic accent color * docs: add todo for changing how accent colour is applied * feat: update new theming to use override primary style so that the regular colorAccent attribute can be used in existing layouts * feat: coordinating styles across layouts, fixing up pinned icons and naming for conversation list items * refactor: re-styling layouts to match new themes and attributes. Need to figure out action mode close button * refactor: remove @color/text and replace with ?android:textColorPrimary to override in themes * refactor: add context theme wrapper to bottom sheet dialog that references accent color * fix: input bar bug fix and preference activity themes * refactor: new settings menu options * fix: crash for PNModeActivity.kt refactor: move ordering in seed dialog to match designs, copy changes to match new settings menu * feat: add new appearance settings activity * refactor: title and VM changes * fix: correct override * feat: add theme appearance screen UI features and start VM implementation. re-add legacy theme utils to get default for migration * fix: compile errors and missing themes from emoji features * refactor: remove background shape alteration and old bottom sheet styles, re-add the theme mode attr * feat: appearance screen wired up, just need to refresh theme * feat: add theme state recreation and fix match system settings option * refactor: add bottom margin * feat: explore custom preference category * feat: add the customized session theme for CorrectedPreferenceFragment * feat: replace AppProtectionPreferenceFragment to extend ListSummaryPreferenceFragment * refactor: change drawable style and remove explicit dividers * refactor: remove divider in CorrectedPreferenceFragment * feat: add theme state check on resume, might be jarring currently * feat: add preference divider elements for settings menu * refactor: settings menu redesigns * refactor: change led preference to integer and refactor TextSecurePreferences.kt * feat: add scroll parcel to save/restore hierarchy on restart with appearance changes * feat: add the conversations blocked contacts and refactor preference order and copy * feat: add blocked contacts activity, basic layout and vm * feat: add unblock DB functions and storage protocol, start working on the DB query state flow, might have to just implement recipient on modified listener * feat: add blocked contacts and notif recipient listeners * feat: add recipient db reader * feat: add blocked contact interactions and fix a theming crash for notifications * feat: introduce better equals and hashcode implementations to recipient, replace home diff util content check with hashcode-based comparison * feat: add settings menu vectors * fix: preview compile error * refactor: migrating settings menu to new designs * feat: help menu * refactor: simplify link opening * refactor: remove space * feat: refactor preferences and start theming for light mode options * refactor: fixing dark and light modes with dialogs * refactor: popup dialogs use proper themes now * refactor: alert dialogs and media edit fragments use attribute references * refactor: use input bar button attribute instead color control normal in vector tint * refactor: transparency, dialog fixes, notification fix * refactor: attrs and styles for buttons * fix: use prominent button color on the outline button's border * fix: fix the trash * refactor: remove the appearance * refactor: avatar placeholder generation, chips and element border styles * refactor: use colors instead of style references * refactor: theming changes to match designs and feedback * refactor: the titles are bold and the categories are tertiary coloured now * fix: appearance settings match preferences, search bottom bar uses themed attributes * refactor: increase setting button height * Update clear all data dialog * Update seed dialog * refactor: more qa feedback changes * feat: add new TLs and fa-rIR TLs * Update notification content dialog * Fix message requests clear all button text color * feat: re-add screenshot observer * refactor: make send tint accent color * feat: add unread background differences * fix: change unread count indicator * build: upgrade build numbers * Fix message requests popupmenu background color * fix: crash from attr reference in color attribute * build: upgrade build number * fix: message bubbles, thumbnail backgrounds, search bar visibility with input bar, attachment buttons * fix: tertiary text for keyboard page search view * fix: emoji overflow colour differences * fix: reaction pill dialog background is now correct colour * Add style to reactions tab layout * fix: appearance activity reverting primary color at correct time * fix: show call privacy warning every time instead of just once * fix: gradient background(?) and audio autoplay disable * fix: crash in all media containing documents * fix: reaction dialog heading fixes * Add style to reactions tab layout * fix: remove gradient backgrounds * fix: adding new reaction normal text attribute to try correct the tab layout * fix: ocean dark unread/read colours * build; update build number * build: update build number * Fix ocean light theme pin color * Update classic dark unread indicator text color * Reduce group name text size on join community screen * Restore tab indicator color on join community and all media screens * Home adapter rename * Updated the HomeViewModel to cancel old executors when new ones are added (#1) * Updated the HomeViewModel to cancel old executors when new ones are added * Removed a seemingly unneeded update * Explicitly remove observers when the HomeActivity is paused (#2) Co-authored-by: jubb Co-authored-by: charles Co-authored-by: Morgan Pretty * Play fixes (#1017) * fix: Prevent crash from recipient modification listener * fix: Add message selection highlight color * Handle crash from fingerprint auth * Update message selection highlight colors * Handle call answer/hangup processing appropriately * Add proguard rule for ContextMenuList * Handle more calls intents Co-authored-by: charles Co-authored-by: Morgan Pretty Co-authored-by: jubb Co-authored-by: charles --- app/proguard/proguard.pro | 1 + .../securesms/PassphrasePromptActivity.java | 11 +++++------ .../conversation/v2/ConversationActivityV2.kt | 2 +- .../securesms/service/WebRtcCallService.kt | 3 ++- .../securesms/webrtc/CallMessageProcessor.kt | 4 ++-- app/src/main/res/values/themes.xml | 4 ++++ 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/proguard/proguard.pro b/app/proguard/proguard.pro index 863701970c..bcbc8dadaf 100644 --- a/app/proguard/proguard.pro +++ b/app/proguard/proguard.pro @@ -2,6 +2,7 @@ -keepattributes SourceFile,LineNumberTable -keep class org.whispersystems.** { *; } -keep class org.thoughtcrime.securesms.** { *; } +-keep class org.thoughtcrime.securesms.components.menu.** { *; } -keep class org.session.** { *; } -keepclassmembers class ** { public void onEvent*(**); diff --git a/app/src/main/java/org/thoughtcrime/securesms/PassphrasePromptActivity.java b/app/src/main/java/org/thoughtcrime/securesms/PassphrasePromptActivity.java index 7f7f6f75db..63b42c4936 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/PassphrasePromptActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/PassphrasePromptActivity.java @@ -148,12 +148,11 @@ public class PassphrasePromptActivity extends BaseActionBarActivity { // Finish and proceed with the next intent. Intent nextIntent = getIntent().getParcelableExtra("next_intent"); if (nextIntent != null) { - startActivity(nextIntent); -// try { -// startActivity(nextIntent); -// } catch (java.lang.SecurityException e) { -// Log.w(TAG, "Access permission not passed from PassphraseActivity, retry sharing."); -// } + try { + startActivity(nextIntent); + } catch (java.lang.SecurityException e) { + Log.w(TAG, "Access permission not passed from PassphraseActivity, retry sharing.", e); + } } finish(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 7fe583ddbc..a819c3fa22 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -660,7 +660,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe updateSubtitle() showOrHideInputIfNeeded() binding?.toolbarContent?.profilePictureView?.root?.update(threadRecipient) - binding!!.toolbarContent.conversationTitleView.text = when { + binding?.toolbarContent?.conversationTitleView?.text = when { threadRecipient.isLocalNumber -> getString(R.string.note_to_self) else -> threadRecipient.toShortString() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt index 079d7a21ad..0f10a93b0b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.kt @@ -12,6 +12,7 @@ import android.os.IBinder import android.os.ResultReceiver import android.telephony.PhoneStateListener import android.telephony.TelephonyManager +import androidx.core.content.ContextCompat import androidx.core.os.bundleOf import androidx.localbroadcastmanager.content.LocalBroadcastManager import dagger.hilt.android.AndroidEntryPoint @@ -199,7 +200,7 @@ class WebRtcCallService: Service(), CallManager.WebRtcListener { private val serviceExecutor = Executors.newSingleThreadExecutor() private val timeoutExecutor = Executors.newScheduledThreadPool(1) private val hangupOnCallAnswered = HangUpRtcOnPstnCallAnsweredListener { - startService(hangupIntent(this)) + ContextCompat.startForegroundService(this, hangupIntent(this)) } private var networkChangedReceiver: NetworkChangeReceiver? = null diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt index a66dd591f6..f007ace976 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt @@ -78,7 +78,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP private fun incomingHangup(callMessage: CallMessage) { val callId = callMessage.callId ?: return val hangupIntent = WebRtcCallService.remoteHangupIntent(context, callId) - context.startService(hangupIntent) + ContextCompat.startForegroundService(context, hangupIntent) } private fun incomingAnswer(callMessage: CallMessage) { @@ -91,7 +91,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP sdp = sdp, callId = callId ) - context.startService(answerIntent) + ContextCompat.startForegroundService(context, answerIntent) } private fun handleIceCandidates(callMessage: CallMessage) { diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 88f1a6a2f4..4c7dfd1db4 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -385,6 +385,7 @@ @color/classic_dark_1 @color/classic_dark_3 @color/classic_dark_4 + @color/classic_dark_1 @@ -548,6 +550,7 @@ @color/ocean_dark_4 ?colorPrimary @color/ocean_dark_4 + @color/ocean_dark_1 @@ -633,6 +636,7 @@ ?colorCellBackground @color/ocean_light_5 ?android:textColorPrimary + @color/ocean_light_5 From 76fff8bc74416b7fb0ad89d911a79101ef6a92f6 Mon Sep 17 00:00:00 2001 From: charles Date: Mon, 24 Oct 2022 15:53:14 +1100 Subject: [PATCH 010/744] release: increment build number --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 49ecd7a8f5..7e710ff7b5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -157,8 +157,8 @@ dependencies { testImplementation 'org.robolectric:shadows-multidex:4.4' } -def canonicalVersionCode = 309 -def canonicalVersionName = "1.16.0" +def canonicalVersionCode = 310 +def canonicalVersionName = "1.16.1" def postFixSize = 10 def abiPostFix = ['armeabi-v7a' : 1, From e6d854a4ea2e61ee6d27891c034c7071536c4a25 Mon Sep 17 00:00:00 2001 From: charles Date: Wed, 26 Oct 2022 17:52:47 +1100 Subject: [PATCH 011/744] Show disappearing messages setting menu on Note to Self conversation --- .../securesms/conversation/v2/menus/ConversationMenuHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 663dd2e255..6e23b47433 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -63,7 +63,7 @@ object ConversationMenuHelper { // Base menu (options that should always be present) inflater.inflate(R.menu.menu_conversation, menu) // Expiring messages - if (!isOpenGroup && (thread.hasApprovedMe() || thread.isClosedGroupRecipient)) { + if (!isOpenGroup && (thread.hasApprovedMe() || thread.isClosedGroupRecipient || thread.isLocalNumber)) { if (thread.expireMessages > 0) { inflater.inflate(R.menu.menu_conversation_expiration_on, menu) val item = menu.findItem(R.id.menu_expiring_messages) From 63f372b45c0a4223f5a776ad2db8a00221cb774c Mon Sep 17 00:00:00 2001 From: charles Date: Wed, 26 Oct 2022 19:27:22 +1100 Subject: [PATCH 012/744] Add expiration settings screen --- app/src/main/AndroidManifest.xml | 3 + .../expiration/ExpirationSettingsActivity.kt | 96 +++++++++++++++ .../conversation/v2/ConversationActivityV2.kt | 18 ++- .../layout/activity_expiration_settings.xml | 113 ++++++++++++++++++ app/src/main/res/values/arrays.xml | 36 ++++++ app/src/main/res/values/strings.xml | 15 +++ app/src/main/res/values/styles.xml | 4 + 7 files changed, 274 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/expiration/ExpirationSettingsActivity.kt create mode 100644 app/src/main/res/layout/activity_expiration_settings.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 681fc00c17..16a4418724 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -172,6 +172,9 @@ android:screenOrientation="portrait" /> + () + binding.scrollView.saveHierarchyState(scrollParcelArray) + outState.putSparseParcelableArray(SCROLL_PARCEL, scrollParcelArray) + } + + override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { + super.onCreate(savedInstanceState, ready) + binding = ActivityExpirationSettingsBinding.inflate(layoutInflater) + setContentView(binding.root) + + setUpToolbar() + + savedInstanceState?.let { bundle -> + val scrollStateParcel = bundle.getSparseParcelableArray(SCROLL_PARCEL) + if (scrollStateParcel != null) { + binding.scrollView.restoreHierarchyState(scrollStateParcel) + } + } + + val options = if (expirationType == ExpirationType.DELETE_AFTER_SEND) { + val values = resources.getIntArray(R.array.send_expiration_time_values).map(Int::toString) + val names = resources.getStringArray(R.array.send_expiration_time_names) + values.zip(names) { value, name -> RadioOption(value, name)} + } else { + listOf( + RadioOption("off", getString(R.string.expiration_off)), + RadioOption("read", getString(R.string.expiration_type_disappear_after_read)), + RadioOption("send", getString(R.string.expiration_type_disappear_after_send)) + ) + } + val optionAdapter = RadioOptionAdapter { + + } + binding.textViewDeleteType.isVisible = expirationType == null + binding.textViewTimer.isVisible = expirationType == null + binding.layoutTimer.isVisible = expirationType == null + binding.recyclerView.apply { + adapter = optionAdapter + addItemDecoration(ContextCompat.getDrawable(this@ExpirationSettingsActivity, R.drawable.conversation_menu_divider)!!.let { + DividerItemDecoration(this@ExpirationSettingsActivity, RecyclerView.VERTICAL).apply { + setDrawable(it) + } + }) + setHasFixedSize(true) + } + optionAdapter.submitList(options) + + } + + private fun setUpToolbar() { + setSupportActionBar(binding.toolbar) + val actionBar = supportActionBar ?: return + actionBar.title = getString(R.string.activity_expiration_settings_title) + actionBar.subtitle = if (expirationType == ExpirationType.DELETE_AFTER_SEND) { + getString(R.string.activity_expiration_settings_subtitle_sent) + } else { + getString(R.string.activity_expiration_settings_subtitle) + } + actionBar.setDisplayHomeAsUpEnabled(true) + actionBar.setHomeButtonEnabled(true) + } + companion object { + private const val SCROLL_PARCEL = "scroll_parcel" + const val EXTRA_EXPIRATION_TYPE = "expiration_type" + const val EXTRA_READ_ONLY = "read_only" + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 7fe583ddbc..685939c4ad 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -56,7 +56,6 @@ import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.mentions.Mention import org.session.libsession.messaging.mentions.MentionsManager import org.session.libsession.messaging.messages.control.DataExtractionNotification -import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsession.messaging.messages.signal.OutgoingMediaMessage import org.session.libsession.messaging.messages.signal.OutgoingTextMessage import org.session.libsession.messaging.messages.visible.Reaction @@ -78,18 +77,19 @@ import org.session.libsession.utilities.concurrent.SimpleTask import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.RecipientModifiedListener import org.session.libsignal.crypto.MnemonicCodec +import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType import org.session.libsignal.utilities.IdPrefix import org.session.libsignal.utilities.ListenableFuture import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.guava.Optional import org.session.libsignal.utilities.hexEncodedPrivateKey import org.thoughtcrime.securesms.ApplicationContext -import org.thoughtcrime.securesms.ExpirationDialog import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.attachments.ScreenshotObserver import org.thoughtcrime.securesms.audio.AudioRecorder import org.thoughtcrime.securesms.contacts.SelectContactsActivity.Companion.selectedContactsKey import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher +import org.thoughtcrime.securesms.conversation.expiration.ExpirationSettingsActivity import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnActionSelectedListener import org.thoughtcrime.securesms.conversation.v2.ConversationReactionOverlay.OnReactionSelectedListener import org.thoughtcrime.securesms.conversation.v2.dialogs.BlockedDialog @@ -154,6 +154,7 @@ import org.thoughtcrime.securesms.util.DateUtils import org.thoughtcrime.securesms.util.MediaUtil import org.thoughtcrime.securesms.util.SaveAttachmentTask import org.thoughtcrime.securesms.util.push +import org.thoughtcrime.securesms.util.show import org.thoughtcrime.securesms.util.toPx import java.util.Locale import java.util.concurrent.ExecutionException @@ -988,16 +989,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe val group = groupDb.getGroup(thread.address.toGroupString()).orNull() if (group?.isActive == false) { return } } - ExpirationDialog.show(this, thread.expireMessages) { expirationTime: Int -> - recipientDb.setExpireMessages(thread, expirationTime) - val message = ExpirationTimerUpdate(expirationTime) - message.recipient = thread.address.serialize() - message.sentTimestamp = System.currentTimeMillis() - val expiringMessageManager = ApplicationContext.getInstance(this).expiringMessageManager - expiringMessageManager.setExpirationTimer(message) - MessageSender.send(message, thread.address) - invalidateOptionsMenu() + val expirationIntent = Intent(this, ExpirationSettingsActivity::class.java) + if (thread.isLocalNumber || thread.isClosedGroupRecipient) { + expirationIntent.putExtra(ExpirationSettingsActivity.EXTRA_EXPIRATION_TYPE, ExpirationType.DELETE_AFTER_SEND_VALUE) } + show(expirationIntent, true) } override fun unblock() { diff --git a/app/src/main/res/layout/activity_expiration_settings.xml b/app/src/main/res/layout/activity_expiration_settings.xml new file mode 100644 index 0000000000..59d62fcc5c --- /dev/null +++ b/app/src/main/res/layout/activity_expiration_settings.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +