mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Implement Stories feature behind flag.
Co-Authored-By: Greyson Parrelli <37311915+greyson-signal@users.noreply.github.com> Co-Authored-By: Rashad Sookram <95182499+rashad-signal@users.noreply.github.com>
This commit is contained in:
@@ -41,7 +41,10 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServicePreview;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceTextAttachment;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
|
||||
import org.whispersystems.signalservice.api.messages.calls.AnswerMessage;
|
||||
import org.whispersystems.signalservice.api.messages.calls.CallingResponse;
|
||||
@@ -102,8 +105,11 @@ import org.whispersystems.signalservice.internal.push.SignalServiceProtos.DataMe
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContextV2;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.NullMessage;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Preview;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.ReceiptMessage;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.StoryMessage;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.TextAttachment;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.TypingMessage;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.Verified;
|
||||
import org.whispersystems.signalservice.internal.push.StaleDevices;
|
||||
@@ -219,22 +225,8 @@ public class SignalServiceMessageSender {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a typing indicator.
|
||||
*
|
||||
* @param recipient The destination
|
||||
* @param message The typing indicator to deliver
|
||||
* Sends a typing indicator using client-side fanout. Doesn't bother with return results, since these are best-effort.
|
||||
*/
|
||||
public void sendTyping(SignalServiceAddress recipient,
|
||||
Optional<UnidentifiedAccessPair> unidentifiedAccess,
|
||||
SignalServiceTypingMessage message)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
Content content = createTypingContent(message);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.absent());
|
||||
|
||||
sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), message.getTimestamp(), envelopeContent, true, null);
|
||||
}
|
||||
|
||||
public void sendTyping(List<SignalServiceAddress> recipients,
|
||||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess,
|
||||
SignalServiceTypingMessage message,
|
||||
@@ -248,7 +240,7 @@ public class SignalServiceMessageSender {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a typing indicator a group. Doesn't bother with return results, since these are best-effort.
|
||||
* Send a typing indicator to a group using sender key. Doesn't bother with return results, since these are best-effort.
|
||||
*/
|
||||
public void sendGroupTyping(DistributionId distributionId,
|
||||
List<SignalServiceAddress> recipients,
|
||||
@@ -257,7 +249,35 @@ public class SignalServiceMessageSender {
|
||||
throws IOException, UntrustedIdentityException, InvalidKeyException, NoSessionException, InvalidRegistrationIdException
|
||||
{
|
||||
Content content = createTypingContent(message);
|
||||
sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp(), content, ContentHint.IMPLICIT, message.getGroupId().orNull(), true, SenderKeyGroupEvents.EMPTY);
|
||||
sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp(), content, ContentHint.IMPLICIT, message.getGroupId(), true, SenderKeyGroupEvents.EMPTY);
|
||||
}
|
||||
|
||||
public List<SendMessageResult> sendStory(List<SignalServiceAddress> recipients,
|
||||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess,
|
||||
SignalServiceStoryMessage message,
|
||||
long timestamp)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
Content content = createStoryContent(message);
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.RESENDABLE, Optional.absent());
|
||||
|
||||
return sendMessage(recipients, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, envelopeContent, false, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a typing indicator to a group using sender key. Doesn't bother with return results, since these are best-effort.
|
||||
* @return
|
||||
*/
|
||||
public List<SendMessageResult> sendGroupStory(DistributionId distributionId,
|
||||
Optional<byte[]> groupId,
|
||||
List<SignalServiceAddress> recipients,
|
||||
List<UnidentifiedAccess> unidentifiedAccess,
|
||||
SignalServiceStoryMessage message,
|
||||
long timestamp)
|
||||
throws IOException, UntrustedIdentityException, InvalidKeyException, NoSessionException, InvalidRegistrationIdException
|
||||
{
|
||||
Content content = createStoryContent(message);
|
||||
return sendGroupMessage(distributionId, recipients, unidentifiedAccess, timestamp, content, ContentHint.RESENDABLE, groupId, false, SenderKeyGroupEvents.EMPTY);
|
||||
}
|
||||
|
||||
|
||||
@@ -297,7 +317,7 @@ public class SignalServiceMessageSender {
|
||||
throws IOException, UntrustedIdentityException, InvalidKeyException, NoSessionException, InvalidRegistrationIdException
|
||||
{
|
||||
Content content = createCallContent(message);
|
||||
return sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp().get(), content, ContentHint.IMPLICIT, message.getGroupId().get(), false, SenderKeyGroupEvents.EMPTY);
|
||||
return sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp().get(), content, ContentHint.IMPLICIT, message.getGroupId(), false, SenderKeyGroupEvents.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -369,12 +389,12 @@ public class SignalServiceMessageSender {
|
||||
List<SignalServiceAddress> recipients,
|
||||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess,
|
||||
SenderKeyDistributionMessage message,
|
||||
byte[] groupId)
|
||||
Optional<byte[]> groupId)
|
||||
throws IOException
|
||||
{
|
||||
ByteString distributionBytes = ByteString.copyFrom(message.serialize());
|
||||
Content content = Content.newBuilder().setSenderKeyDistributionMessage(distributionBytes).build();
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, Optional.of(groupId));
|
||||
EnvelopeContent envelopeContent = EnvelopeContent.encrypted(content, ContentHint.IMPLICIT, groupId);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
|
||||
Log.d(TAG, "[" + timestamp + "] Sending SKDM to " + recipients.size() + " recipients for DistributionId " + distributionId);
|
||||
@@ -421,7 +441,7 @@ public class SignalServiceMessageSender {
|
||||
|
||||
Content content = createMessageContent(message);
|
||||
Optional<byte[]> groupId = message.getGroupId();
|
||||
List<SendMessageResult> results = sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp(), content, contentHint, groupId.orNull(), false, sendEvents);
|
||||
List<SendMessageResult> results = sendGroupMessage(distributionId, recipients, unidentifiedAccess, message.getTimestamp(), content, contentHint, groupId, false, sendEvents);
|
||||
|
||||
sendEvents.onMessageSent();
|
||||
|
||||
@@ -725,6 +745,33 @@ public class SignalServiceMessageSender {
|
||||
return container.setTypingMessage(builder).build();
|
||||
}
|
||||
|
||||
private Content createStoryContent(SignalServiceStoryMessage message) throws IOException {
|
||||
Content.Builder container = Content.newBuilder();
|
||||
StoryMessage.Builder builder = StoryMessage.newBuilder();
|
||||
|
||||
if (message.getProfileKey().isPresent()) {
|
||||
builder.setProfileKey(ByteString.copyFrom(message.getProfileKey().get()));
|
||||
}
|
||||
|
||||
if (message.getGroupContext().isPresent()) {
|
||||
builder.setGroup(createGroupContent(message.getGroupContext().get()));
|
||||
}
|
||||
|
||||
if (message.getFileAttachment().isPresent()) {
|
||||
if (message.getFileAttachment().get().isStream()) {
|
||||
builder.setFileAttachment(createAttachmentPointer(message.getFileAttachment().get().asStream()));
|
||||
} else {
|
||||
builder.setFileAttachment(createAttachmentPointer(message.getFileAttachment().get().asPointer()));
|
||||
}
|
||||
}
|
||||
|
||||
if (message.getTextAttachment().isPresent()) {
|
||||
builder.setTextAttachment(createTextAttachment(message.getTextAttachment().get()));
|
||||
}
|
||||
|
||||
return container.setStoryMessage(builder).build();
|
||||
}
|
||||
|
||||
private Content createReceiptContent(SignalServiceReceiptMessage message) {
|
||||
Content.Builder container = Content.newBuilder();
|
||||
ReceiptMessage.Builder builder = ReceiptMessage.newBuilder();
|
||||
@@ -832,22 +879,8 @@ public class SignalServiceMessageSender {
|
||||
}
|
||||
|
||||
if (message.getPreviews().isPresent()) {
|
||||
for (SignalServiceDataMessage.Preview preview : message.getPreviews().get()) {
|
||||
DataMessage.Preview.Builder previewBuilder = DataMessage.Preview.newBuilder();
|
||||
previewBuilder.setTitle(preview.getTitle());
|
||||
previewBuilder.setDescription(preview.getDescription());
|
||||
previewBuilder.setDate(preview.getDate());
|
||||
previewBuilder.setUrl(preview.getUrl());
|
||||
|
||||
if (preview.getImage().isPresent()) {
|
||||
if (preview.getImage().get().isStream()) {
|
||||
previewBuilder.setImage(createAttachmentPointer(preview.getImage().get().asStream()));
|
||||
} else {
|
||||
previewBuilder.setImage(createAttachmentPointer(preview.getImage().get().asPointer()));
|
||||
}
|
||||
}
|
||||
|
||||
builder.addPreview(previewBuilder.build());
|
||||
for (SignalServicePreview preview : message.getPreviews().get()) {
|
||||
builder.addPreview(createPreview(preview));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -936,6 +969,24 @@ public class SignalServiceMessageSender {
|
||||
return enforceMaxContentSize(container.setDataMessage(builder).build());
|
||||
}
|
||||
|
||||
private Preview createPreview(SignalServicePreview preview) throws IOException {
|
||||
Preview.Builder previewBuilder = Preview.newBuilder()
|
||||
.setTitle(preview.getTitle())
|
||||
.setDescription(preview.getDescription())
|
||||
.setDate(preview.getDate())
|
||||
.setUrl(preview.getUrl());
|
||||
|
||||
if (preview.getImage().isPresent()) {
|
||||
if (preview.getImage().get().isStream()) {
|
||||
previewBuilder.setImage(createAttachmentPointer(preview.getImage().get().asStream()));
|
||||
} else {
|
||||
previewBuilder.setImage(createAttachmentPointer(preview.getImage().get().asPointer()));
|
||||
}
|
||||
}
|
||||
|
||||
return previewBuilder.build();
|
||||
}
|
||||
|
||||
private Content createCallContent(SignalServiceCallMessage callMessage) {
|
||||
Content.Builder container = Content.newBuilder();
|
||||
CallMessage.Builder builder = CallMessage.newBuilder();
|
||||
@@ -1700,7 +1751,7 @@ public class SignalServiceMessageSender {
|
||||
long timestamp,
|
||||
Content content,
|
||||
ContentHint contentHint,
|
||||
byte[] groupId,
|
||||
Optional<byte[]> groupId,
|
||||
boolean online,
|
||||
SenderKeyGroupEvents sendEvents)
|
||||
throws IOException, UntrustedIdentityException, NoSessionException, InvalidKeyException, InvalidRegistrationIdException
|
||||
@@ -1922,6 +1973,54 @@ public class SignalServiceMessageSender {
|
||||
return createAttachmentPointer(uploadAttachment(attachment));
|
||||
}
|
||||
|
||||
private TextAttachment createTextAttachment(SignalServiceTextAttachment attachment) throws IOException {
|
||||
TextAttachment.Builder builder = TextAttachment.newBuilder();
|
||||
|
||||
if (attachment.getStyle().isPresent()) {
|
||||
switch (attachment.getStyle().get()) {
|
||||
case DEFAULT:
|
||||
builder.setTextStyle(TextAttachment.Style.DEFAULT);
|
||||
break;
|
||||
case REGULAR:
|
||||
builder.setTextStyle(TextAttachment.Style.REGULAR);
|
||||
break;
|
||||
case BOLD:
|
||||
builder.setTextStyle(TextAttachment.Style.BOLD);
|
||||
break;
|
||||
case SERIF:
|
||||
builder.setTextStyle(TextAttachment.Style.SERIF);
|
||||
break;
|
||||
case SCRIPT:
|
||||
builder.setTextStyle(TextAttachment.Style.SCRIPT);
|
||||
break;
|
||||
case CONDENSED:
|
||||
builder.setTextStyle(TextAttachment.Style.CONDENSED);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unknown type: " + attachment.getStyle().get());
|
||||
}
|
||||
}
|
||||
|
||||
TextAttachment.Gradient.Builder gradientBuilder = TextAttachment.Gradient.newBuilder();
|
||||
|
||||
if (attachment.getBackgroundGradient().isPresent()) {
|
||||
SignalServiceTextAttachment.Gradient gradient = attachment.getBackgroundGradient().get();
|
||||
|
||||
if (gradient.getStartColor().isPresent()) gradientBuilder.setStartColor(gradient.getStartColor().get());
|
||||
if (gradient.getEndColor().isPresent()) gradientBuilder.setEndColor(gradient.getEndColor().get());
|
||||
if (gradient.getAngle().isPresent()) gradientBuilder.setAngle(gradient.getAngle().get());
|
||||
|
||||
builder.setGradient(gradientBuilder.build());
|
||||
}
|
||||
|
||||
if (attachment.getText().isPresent()) builder.setText(attachment.getText().get());
|
||||
if (attachment.getTextForegroundColor().isPresent()) builder.setTextForegroundColor(attachment.getTextForegroundColor().get());
|
||||
if (attachment.getTextBackgroundColor().isPresent()) builder.setTextBackgroundColor(attachment.getTextBackgroundColor().get());
|
||||
if (attachment.getPreview().isPresent()) builder.setPreview(createPreview(attachment.getPreview().get()));
|
||||
if (attachment.getBackgroundColor().isPresent()) builder.setColor(attachment.getBackgroundColor().get());
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private OutgoingPushMessageList getEncryptedMessages(PushServiceSocket socket,
|
||||
SignalServiceAddress recipient,
|
||||
|
||||
@@ -144,10 +144,13 @@ public class AccountAttributes {
|
||||
@JsonProperty
|
||||
private boolean changeNumber;
|
||||
|
||||
@JsonProperty
|
||||
private boolean stories;
|
||||
|
||||
@JsonCreator
|
||||
public Capabilities() {}
|
||||
|
||||
public Capabilities(boolean uuid, boolean gv2, boolean storage, boolean gv1Migration, boolean senderKey, boolean announcementGroup, boolean changeNumber) {
|
||||
public Capabilities(boolean uuid, boolean gv2, boolean storage, boolean gv1Migration, boolean senderKey, boolean announcementGroup, boolean changeNumber, boolean stories) {
|
||||
this.uuid = uuid;
|
||||
this.gv2 = gv2;
|
||||
this.storage = storage;
|
||||
@@ -155,6 +158,7 @@ public class AccountAttributes {
|
||||
this.senderKey = senderKey;
|
||||
this.announcementGroup = announcementGroup;
|
||||
this.changeNumber = changeNumber;
|
||||
this.stories = stories;
|
||||
}
|
||||
|
||||
public boolean isUuid() {
|
||||
@@ -184,5 +188,9 @@ public class AccountAttributes {
|
||||
public boolean isChangeNumber() {
|
||||
return changeNumber;
|
||||
}
|
||||
|
||||
public boolean isStories() {
|
||||
return stories;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public class SignalServiceCipher {
|
||||
SenderCertificate senderCertificate,
|
||||
byte[] unpaddedMessage,
|
||||
ContentHint contentHint,
|
||||
byte[] groupId)
|
||||
Optional<byte[]> groupId)
|
||||
throws NoSessionException, UntrustedIdentityException, InvalidKeyException, InvalidRegistrationIdException
|
||||
{
|
||||
PushTransportDetails transport = new PushTransportDetails();
|
||||
@@ -105,7 +105,7 @@ public class SignalServiceCipher {
|
||||
UnidentifiedSenderMessageContent messageContent = new UnidentifiedSenderMessageContent(message,
|
||||
senderCertificate,
|
||||
contentHint.getType(),
|
||||
Optional.of(groupId));
|
||||
groupId);
|
||||
|
||||
return sessionCipher.multiRecipientEncrypt(destinations, messageContent);
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ public final class SignalServiceContent {
|
||||
private final Optional<SignalServiceTypingMessage> typingMessage;
|
||||
private final Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage;
|
||||
private final Optional<DecryptionErrorMessage> decryptionErrorMessage;
|
||||
private final Optional<SignalServiceStoryMessage> storyMessage;
|
||||
|
||||
private SignalServiceContent(SignalServiceDataMessage message,
|
||||
Optional<SenderKeyDistributionMessage> senderKeyDistributionMessage,
|
||||
@@ -114,6 +115,7 @@ public final class SignalServiceContent {
|
||||
this.typingMessage = Optional.absent();
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.absent();
|
||||
this.storyMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceSyncMessage synchronizeMessage,
|
||||
@@ -145,6 +147,7 @@ public final class SignalServiceContent {
|
||||
this.typingMessage = Optional.absent();
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.absent();
|
||||
this.storyMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceCallMessage callMessage,
|
||||
@@ -176,6 +179,7 @@ public final class SignalServiceContent {
|
||||
this.typingMessage = Optional.absent();
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.absent();
|
||||
this.storyMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceReceiptMessage receiptMessage,
|
||||
@@ -207,6 +211,7 @@ public final class SignalServiceContent {
|
||||
this.typingMessage = Optional.absent();
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.absent();
|
||||
this.storyMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(DecryptionErrorMessage errorMessage,
|
||||
@@ -238,6 +243,7 @@ public final class SignalServiceContent {
|
||||
this.typingMessage = Optional.absent();
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.of(errorMessage);
|
||||
this.storyMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceTypingMessage typingMessage,
|
||||
@@ -269,6 +275,7 @@ public final class SignalServiceContent {
|
||||
this.typingMessage = Optional.of(typingMessage);
|
||||
this.senderKeyDistributionMessage = senderKeyDistributionMessage;
|
||||
this.decryptionErrorMessage = Optional.absent();
|
||||
this.storyMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(SenderKeyDistributionMessage senderKeyDistributionMessage,
|
||||
@@ -299,6 +306,38 @@ public final class SignalServiceContent {
|
||||
this.typingMessage = Optional.absent();
|
||||
this.senderKeyDistributionMessage = Optional.of(senderKeyDistributionMessage);
|
||||
this.decryptionErrorMessage = Optional.absent();
|
||||
this.storyMessage = Optional.absent();
|
||||
}
|
||||
|
||||
private SignalServiceContent(SignalServiceStoryMessage storyMessage,
|
||||
SignalServiceAddress sender,
|
||||
int senderDevice,
|
||||
long timestamp,
|
||||
long serverReceivedTimestamp,
|
||||
long serverDeliveredTimestamp,
|
||||
boolean needsReceipt,
|
||||
String serverUuid,
|
||||
Optional<byte[]> groupId,
|
||||
SignalServiceContentProto serializedState)
|
||||
{
|
||||
this.sender = sender;
|
||||
this.senderDevice = senderDevice;
|
||||
this.timestamp = timestamp;
|
||||
this.serverReceivedTimestamp = serverReceivedTimestamp;
|
||||
this.serverDeliveredTimestamp = serverDeliveredTimestamp;
|
||||
this.needsReceipt = needsReceipt;
|
||||
this.serverUuid = serverUuid;
|
||||
this.groupId = groupId;
|
||||
this.serializedState = serializedState;
|
||||
|
||||
this.message = Optional.absent();
|
||||
this.synchronizeMessage = Optional.absent();
|
||||
this.callMessage = Optional.absent();
|
||||
this.readMessage = Optional.absent();
|
||||
this.typingMessage = Optional.absent();
|
||||
this.senderKeyDistributionMessage = Optional.absent();
|
||||
this.decryptionErrorMessage = Optional.absent();
|
||||
this.storyMessage = Optional.of(storyMessage);
|
||||
}
|
||||
|
||||
public Optional<SignalServiceDataMessage> getDataMessage() {
|
||||
@@ -321,6 +360,10 @@ public final class SignalServiceContent {
|
||||
return typingMessage;
|
||||
}
|
||||
|
||||
public Optional<SignalServiceStoryMessage> getStoryMessage() {
|
||||
return storyMessage;
|
||||
}
|
||||
|
||||
public Optional<SenderKeyDistributionMessage> getSenderKeyDistributionMessage() {
|
||||
return senderKeyDistributionMessage;
|
||||
}
|
||||
@@ -496,6 +539,17 @@ public final class SignalServiceContent {
|
||||
metadata.getServerGuid(),
|
||||
metadata.getGroupId(),
|
||||
serviceContentProto);
|
||||
} else if (message.hasStoryMessage()) {
|
||||
return new SignalServiceContent(createStoryMessage(message.getStoryMessage()),
|
||||
metadata.getSender(),
|
||||
metadata.getSenderDevice(),
|
||||
metadata.getTimestamp(),
|
||||
metadata.getServerReceivedTimestamp(),
|
||||
metadata.getServerDeliveredTimestamp(),
|
||||
false,
|
||||
metadata.getServerGuid(),
|
||||
metadata.getGroupId(),
|
||||
serviceContentProto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,7 +577,7 @@ public final class SignalServiceContent {
|
||||
boolean isGroupV2 = groupInfoV2 != null;
|
||||
SignalServiceDataMessage.Quote quote = createQuote(content, isGroupV2);
|
||||
List<SharedContact> sharedContacts = createSharedContacts(content);
|
||||
List<SignalServiceDataMessage.Preview> previews = createPreviews(content);
|
||||
List<SignalServicePreview> previews = createPreviews(content);
|
||||
List<SignalServiceDataMessage.Mention> mentions = createMentions(content.getBodyRangesList(), content.getBody(), isGroupV2);
|
||||
SignalServiceDataMessage.Sticker sticker = createSticker(content);
|
||||
SignalServiceDataMessage.Reaction reaction = createReaction(content);
|
||||
@@ -898,6 +952,20 @@ public final class SignalServiceContent {
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
private static SignalServiceStoryMessage createStoryMessage(SignalServiceProtos.StoryMessage content) throws InvalidMessageStructureException {
|
||||
byte[] profileKey = content.hasProfileKey() ? content.getProfileKey().toByteArray() : null;
|
||||
|
||||
if (content.hasFileAttachment()) {
|
||||
return SignalServiceStoryMessage.forFileAttachment(profileKey,
|
||||
createGroupV2Info(content),
|
||||
createAttachmentPointer(content.getFileAttachment()));
|
||||
} else {
|
||||
return SignalServiceStoryMessage.forTextAttachment(profileKey,
|
||||
createGroupV2Info(content),
|
||||
createTextAttachment(content.getTextAttachment()));
|
||||
}
|
||||
}
|
||||
|
||||
private static SignalServiceDataMessage.Quote createQuote(SignalServiceProtos.DataMessage content, boolean isGroupV2)
|
||||
throws InvalidMessageStructureException
|
||||
{
|
||||
@@ -925,28 +993,32 @@ public final class SignalServiceContent {
|
||||
}
|
||||
}
|
||||
|
||||
private static List<SignalServiceDataMessage.Preview> createPreviews(SignalServiceProtos.DataMessage content) throws InvalidMessageStructureException {
|
||||
private static List<SignalServicePreview> createPreviews(SignalServiceProtos.DataMessage content) throws InvalidMessageStructureException {
|
||||
if (content.getPreviewCount() <= 0) return null;
|
||||
|
||||
List<SignalServiceDataMessage.Preview> results = new LinkedList<>();
|
||||
List<SignalServicePreview> results = new LinkedList<>();
|
||||
|
||||
for (SignalServiceProtos.DataMessage.Preview preview : content.getPreviewList()) {
|
||||
SignalServiceAttachment attachment = null;
|
||||
|
||||
if (preview.hasImage()) {
|
||||
attachment = createAttachmentPointer(preview.getImage());
|
||||
}
|
||||
|
||||
results.add(new SignalServiceDataMessage.Preview(preview.getUrl(),
|
||||
preview.getTitle(),
|
||||
preview.getDescription(),
|
||||
preview.getDate(),
|
||||
Optional.fromNullable(attachment)));
|
||||
for (SignalServiceProtos.Preview preview : content.getPreviewList()) {
|
||||
results.add(createPreview(preview));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static SignalServicePreview createPreview(SignalServiceProtos.Preview preview) throws InvalidMessageStructureException {
|
||||
SignalServiceAttachment attachment = null;
|
||||
|
||||
if (preview.hasImage()) {
|
||||
attachment = createAttachmentPointer(preview.getImage());
|
||||
}
|
||||
|
||||
return new SignalServicePreview(preview.getUrl(),
|
||||
preview.getTitle(),
|
||||
preview.getDescription(),
|
||||
preview.getDate(),
|
||||
Optional.fromNullable(attachment));
|
||||
}
|
||||
|
||||
private static List<SignalServiceDataMessage.Mention> createMentions(List<SignalServiceProtos.DataMessage.BodyRange> bodyRanges, String body, boolean isGroupV2)
|
||||
throws InvalidMessageStructureException
|
||||
{
|
||||
@@ -1173,13 +1245,73 @@ public final class SignalServiceContent {
|
||||
|
||||
private static SignalServiceAttachmentPointer createAttachmentPointer(SignalServiceProtos.AttachmentPointer pointer) throws InvalidMessageStructureException {
|
||||
return AttachmentPointerUtil.createSignalAttachmentPointer(pointer);
|
||||
|
||||
}
|
||||
|
||||
private static SignalServiceGroupV2 createGroupV2Info(SignalServiceProtos.DataMessage content) throws InvalidMessageStructureException {
|
||||
if (!content.hasGroupV2()) return null;
|
||||
private static SignalServiceTextAttachment createTextAttachment(SignalServiceProtos.TextAttachment attachment) throws InvalidMessageStructureException {
|
||||
SignalServiceTextAttachment.Style style = null;
|
||||
if (attachment.hasTextStyle()) {
|
||||
switch (attachment.getTextStyle()) {
|
||||
case DEFAULT:
|
||||
style = SignalServiceTextAttachment.Style.DEFAULT;
|
||||
break;
|
||||
case REGULAR:
|
||||
style = SignalServiceTextAttachment.Style.REGULAR;
|
||||
break;
|
||||
case BOLD:
|
||||
style = SignalServiceTextAttachment.Style.BOLD;
|
||||
break;
|
||||
case SERIF:
|
||||
style = SignalServiceTextAttachment.Style.SERIF;
|
||||
break;
|
||||
case SCRIPT:
|
||||
style = SignalServiceTextAttachment.Style.SCRIPT;
|
||||
break;
|
||||
case CONDENSED:
|
||||
style = SignalServiceTextAttachment.Style.CONDENSED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Optional<String> text = Optional.fromNullable(attachment.hasText() ? attachment.getText() : null);
|
||||
Optional<Integer> textForegroundColor = Optional.fromNullable(attachment.hasTextForegroundColor() ? attachment.getTextForegroundColor() : null);
|
||||
Optional<Integer> textBackgroundColor = Optional.fromNullable(attachment.hasTextBackgroundColor() ? attachment.getTextBackgroundColor() : null);
|
||||
Optional<SignalServicePreview> preview = Optional.fromNullable(attachment.hasPreview() ? createPreview(attachment.getPreview()) : null);
|
||||
|
||||
if (attachment.hasGradient()) {
|
||||
SignalServiceProtos.TextAttachment.Gradient attachmentGradient = attachment.getGradient();
|
||||
|
||||
Integer startColor = attachmentGradient.hasStartColor() ? attachmentGradient.getStartColor() : null;
|
||||
Integer endColor = attachmentGradient.hasEndColor() ? attachmentGradient.getEndColor() : null;
|
||||
Integer angle = attachmentGradient.hasAngle() ? attachmentGradient.getAngle() : null;
|
||||
SignalServiceTextAttachment.Gradient gradient = new SignalServiceTextAttachment.Gradient(Optional.fromNullable(startColor),
|
||||
Optional.fromNullable(endColor),
|
||||
Optional.fromNullable(angle));
|
||||
|
||||
return SignalServiceTextAttachment.forGradientBackground(text, Optional.fromNullable(style), textForegroundColor, textBackgroundColor, preview, gradient);
|
||||
} else {
|
||||
return SignalServiceTextAttachment.forSolidBackground(text, Optional.fromNullable(style), textForegroundColor, textBackgroundColor, preview, attachment.getColor());
|
||||
}
|
||||
}
|
||||
|
||||
private static SignalServiceGroupV2 createGroupV2Info(SignalServiceProtos.StoryMessage storyMessage) throws InvalidMessageStructureException {
|
||||
if (!storyMessage.hasGroup()) {
|
||||
return null;
|
||||
}
|
||||
return createGroupV2Info(storyMessage.getGroup());
|
||||
}
|
||||
|
||||
private static SignalServiceGroupV2 createGroupV2Info(SignalServiceProtos.DataMessage dataMessage) throws InvalidMessageStructureException {
|
||||
if (!dataMessage.hasGroupV2()) {
|
||||
return null;
|
||||
}
|
||||
return createGroupV2Info(dataMessage.getGroupV2());
|
||||
}
|
||||
|
||||
private static SignalServiceGroupV2 createGroupV2Info(SignalServiceProtos.GroupContextV2 groupV2) throws InvalidMessageStructureException {
|
||||
if (groupV2 == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SignalServiceProtos.GroupContextV2 groupV2 = content.getGroupV2();
|
||||
if (!groupV2.hasMasterKey()) {
|
||||
throw new InvalidMessageStructureException("No GV2 master key on message");
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class SignalServiceDataMessage {
|
||||
private final boolean profileKeyUpdate;
|
||||
private final Optional<Quote> quote;
|
||||
private final Optional<List<SharedContact>> contacts;
|
||||
private final Optional<List<Preview>> previews;
|
||||
private final Optional<List<SignalServicePreview>> previews;
|
||||
private final Optional<List<Mention>> mentions;
|
||||
private final Optional<Sticker> sticker;
|
||||
private final boolean viewOnce;
|
||||
@@ -66,7 +66,7 @@ public class SignalServiceDataMessage {
|
||||
boolean profileKeyUpdate,
|
||||
Quote quote,
|
||||
List<SharedContact> sharedContacts,
|
||||
List<Preview> previews,
|
||||
List<SignalServicePreview> previews,
|
||||
List<Mention> mentions,
|
||||
Sticker sticker,
|
||||
boolean viewOnce,
|
||||
@@ -217,7 +217,7 @@ public class SignalServiceDataMessage {
|
||||
return contacts;
|
||||
}
|
||||
|
||||
public Optional<List<Preview>> getPreviews() {
|
||||
public Optional<List<SignalServicePreview>> getPreviews() {
|
||||
return previews;
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ public class SignalServiceDataMessage {
|
||||
|
||||
private List<SignalServiceAttachment> attachments = new LinkedList<>();
|
||||
private List<SharedContact> sharedContacts = new LinkedList<>();
|
||||
private List<Preview> previews = new LinkedList<>();
|
||||
private List<SignalServicePreview> previews = new LinkedList<>();
|
||||
private List<Mention> mentions = new LinkedList<>();
|
||||
|
||||
private long timestamp;
|
||||
@@ -378,7 +378,7 @@ public class SignalServiceDataMessage {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withPreviews(List<Preview> previews) {
|
||||
public Builder withPreviews(List<SignalServicePreview> previews) {
|
||||
this.previews.addAll(previews);
|
||||
return this;
|
||||
}
|
||||
@@ -495,42 +495,6 @@ public class SignalServiceDataMessage {
|
||||
}
|
||||
}
|
||||
|
||||
public static class Preview {
|
||||
private final String url;
|
||||
private final String title;
|
||||
private final String description;
|
||||
private final long date;
|
||||
private final Optional<SignalServiceAttachment> image;
|
||||
|
||||
public Preview(String url, String title, String description, long date, Optional<SignalServiceAttachment> image) {
|
||||
this.url = url;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.date = date;
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public long getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public Optional<SignalServiceAttachment> getImage() {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Sticker {
|
||||
private final byte[] packId;
|
||||
private final byte[] packKey;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.whispersystems.signalservice.api.messages;
|
||||
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
public class SignalServicePreview {
|
||||
private final String url;
|
||||
private final String title;
|
||||
private final String description;
|
||||
private final long date;
|
||||
private final Optional<SignalServiceAttachment> image;
|
||||
|
||||
public SignalServicePreview(String url, String title, String description, long date, Optional<SignalServiceAttachment> image) {
|
||||
this.url = url;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.date = date;
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public long getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public Optional<SignalServiceAttachment> getImage() {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.whispersystems.signalservice.api.messages;
|
||||
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
public class SignalServiceStoryMessage {
|
||||
private final Optional<byte[]> profileKey;
|
||||
private final Optional<SignalServiceGroupV2> groupContext;
|
||||
private final Optional<SignalServiceAttachment> fileAttachment;
|
||||
private final Optional<SignalServiceTextAttachment> textAttachment;
|
||||
|
||||
private SignalServiceStoryMessage(byte[] profileKey,
|
||||
SignalServiceGroupV2 groupContext,
|
||||
SignalServiceAttachment fileAttachment,
|
||||
SignalServiceTextAttachment textAttachment) {
|
||||
this.profileKey = Optional.fromNullable(profileKey);
|
||||
this.groupContext = Optional.fromNullable(groupContext);
|
||||
this.fileAttachment = Optional.fromNullable(fileAttachment);
|
||||
this.textAttachment = Optional.fromNullable(textAttachment);
|
||||
}
|
||||
|
||||
public static SignalServiceStoryMessage forFileAttachment(byte[] profileKey,
|
||||
SignalServiceGroupV2 groupContext,
|
||||
SignalServiceAttachment fileAttachment) {
|
||||
return new SignalServiceStoryMessage(profileKey, groupContext, fileAttachment, null);
|
||||
}
|
||||
|
||||
public static SignalServiceStoryMessage forTextAttachment(byte[] profileKey,
|
||||
SignalServiceGroupV2 groupContext,
|
||||
SignalServiceTextAttachment textAttachment) {
|
||||
return new SignalServiceStoryMessage(profileKey, groupContext, null, textAttachment);
|
||||
}
|
||||
|
||||
public Optional<byte[]> getProfileKey() {
|
||||
return profileKey;
|
||||
}
|
||||
|
||||
public Optional<SignalServiceGroupV2> getGroupContext() {
|
||||
return groupContext;
|
||||
}
|
||||
|
||||
public Optional<SignalServiceAttachment> getFileAttachment() {
|
||||
return fileAttachment;
|
||||
}
|
||||
|
||||
public Optional<SignalServiceTextAttachment> getTextAttachment() {
|
||||
return textAttachment;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.whispersystems.signalservice.api.messages;
|
||||
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
public class SignalServiceTextAttachment {
|
||||
|
||||
private final Optional<String> text;
|
||||
private final Optional<Style> style;
|
||||
private final Optional<Integer> textForegroundColor;
|
||||
private final Optional<Integer> textBackgroundColor;
|
||||
private final Optional<SignalServicePreview> preview;
|
||||
private final Optional<Gradient> backgroundGradient;
|
||||
private final Optional<Integer> backgroundColor;
|
||||
|
||||
private SignalServiceTextAttachment(Optional<String> text,
|
||||
Optional<Style> style,
|
||||
Optional<Integer> textForegroundColor,
|
||||
Optional<Integer> textBackgroundColor,
|
||||
Optional<SignalServicePreview> preview,
|
||||
Optional<Gradient> backgroundGradient,
|
||||
Optional<Integer> backgroundColor) {
|
||||
this.text = text;
|
||||
this.style = style;
|
||||
this.textForegroundColor = textForegroundColor;
|
||||
this.textBackgroundColor = textBackgroundColor;
|
||||
this.preview = preview;
|
||||
this.backgroundGradient = backgroundGradient;
|
||||
this.backgroundColor = backgroundColor;
|
||||
}
|
||||
|
||||
public static SignalServiceTextAttachment forGradientBackground(Optional<String> text,
|
||||
Optional<Style> style,
|
||||
Optional<Integer> textForegroundColor,
|
||||
Optional<Integer> textBackgroundColor,
|
||||
Optional<SignalServicePreview> preview,
|
||||
Gradient backgroundGradient) {
|
||||
return new SignalServiceTextAttachment(text,
|
||||
style,
|
||||
textForegroundColor,
|
||||
textBackgroundColor,
|
||||
preview,
|
||||
Optional.of(backgroundGradient),
|
||||
Optional.absent());
|
||||
}
|
||||
|
||||
public static SignalServiceTextAttachment forSolidBackground(Optional<String> text,
|
||||
Optional<Style> style,
|
||||
Optional<Integer> textForegroundColor,
|
||||
Optional<Integer> textBackgroundColor,
|
||||
Optional<SignalServicePreview> preview,
|
||||
int backgroundColor) {
|
||||
return new SignalServiceTextAttachment(text,
|
||||
style,
|
||||
textForegroundColor,
|
||||
textBackgroundColor,
|
||||
preview,
|
||||
Optional.absent(),
|
||||
Optional.of(backgroundColor));
|
||||
}
|
||||
|
||||
public Optional<String> getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public Optional<Style> getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
public Optional<Integer> getTextForegroundColor() {
|
||||
return textForegroundColor;
|
||||
}
|
||||
|
||||
public Optional<Integer> getTextBackgroundColor() {
|
||||
return textBackgroundColor;
|
||||
}
|
||||
|
||||
public Optional<SignalServicePreview> getPreview() {
|
||||
return preview;
|
||||
}
|
||||
|
||||
public Optional<Gradient> getBackgroundGradient() {
|
||||
return backgroundGradient;
|
||||
}
|
||||
|
||||
public Optional<Integer> getBackgroundColor() {
|
||||
return backgroundColor;
|
||||
}
|
||||
|
||||
public static class Gradient {
|
||||
private final Optional<Integer> startColor;
|
||||
private final Optional<Integer> endColor;
|
||||
private final Optional<Integer> angle;
|
||||
|
||||
public Gradient(Optional<Integer> startColor, Optional<Integer> endColor, Optional<Integer> angle) {
|
||||
this.startColor = startColor;
|
||||
this.endColor = endColor;
|
||||
this.angle = angle;
|
||||
}
|
||||
|
||||
public Optional<Integer> getStartColor() {
|
||||
return startColor;
|
||||
}
|
||||
|
||||
public Optional<Integer> getEndColor() {
|
||||
return endColor;
|
||||
}
|
||||
|
||||
public Optional<Integer> getAngle() {
|
||||
return angle;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Style {
|
||||
DEFAULT,
|
||||
REGULAR,
|
||||
BOLD,
|
||||
SERIF,
|
||||
SCRIPT,
|
||||
CONDENSED,
|
||||
}
|
||||
}
|
||||
@@ -193,6 +193,9 @@ public class SignalServiceProfile {
|
||||
@JsonProperty
|
||||
private boolean changeNumber;
|
||||
|
||||
@JsonProperty
|
||||
private boolean stories;
|
||||
|
||||
@JsonCreator
|
||||
public Capabilities() {}
|
||||
|
||||
@@ -219,6 +222,10 @@ public class SignalServiceProfile {
|
||||
public boolean isChangeNumber() {
|
||||
return changeNumber;
|
||||
}
|
||||
|
||||
public boolean isStories() {
|
||||
return stories;
|
||||
}
|
||||
}
|
||||
|
||||
public ProfileKeyCredentialResponse getProfileKeyCredentialResponse() {
|
||||
|
||||
@@ -118,6 +118,10 @@ public final class SignalContactRecord implements SignalRecord {
|
||||
diff.add("MuteUntil");
|
||||
}
|
||||
|
||||
if (shouldHideStory() != that.shouldHideStory()) {
|
||||
diff.add("HideStory");
|
||||
}
|
||||
|
||||
if (!Objects.equals(this.hasUnknownFields(), that.hasUnknownFields())) {
|
||||
diff.add("UnknownFields");
|
||||
}
|
||||
@@ -184,6 +188,10 @@ public final class SignalContactRecord implements SignalRecord {
|
||||
return proto.getMutedUntilTimestamp();
|
||||
}
|
||||
|
||||
public boolean shouldHideStory() {
|
||||
return proto.getHideStory();
|
||||
}
|
||||
|
||||
ContactRecord toProto() {
|
||||
return proto;
|
||||
}
|
||||
@@ -274,6 +282,11 @@ public final class SignalContactRecord implements SignalRecord {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setHideStory(boolean hideStory) {
|
||||
builder.setHideStory(hideStory);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static ContactRecord.Builder parseUnknowns(byte[] serializedUnknowns) {
|
||||
try {
|
||||
return ContactRecord.parseFrom(serializedUnknowns).toBuilder();
|
||||
|
||||
@@ -78,6 +78,10 @@ public final class SignalGroupV2Record implements SignalRecord {
|
||||
diff.add("NotifyForMentionsWhenMuted");
|
||||
}
|
||||
|
||||
if (shouldHideStory() != that.shouldHideStory()) {
|
||||
diff.add("HideStory");
|
||||
}
|
||||
|
||||
if (!Objects.equals(this.hasUnknownFields(), that.hasUnknownFields())) {
|
||||
diff.add("UnknownFields");
|
||||
}
|
||||
@@ -132,6 +136,9 @@ public final class SignalGroupV2Record implements SignalRecord {
|
||||
return !proto.getDontNotifyForMentionsIfMuted();
|
||||
}
|
||||
|
||||
public boolean shouldHideStory() {
|
||||
return proto.getHideStory();
|
||||
}
|
||||
|
||||
GroupV2Record toProto() {
|
||||
return proto;
|
||||
@@ -201,6 +208,11 @@ public final class SignalGroupV2Record implements SignalRecord {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setHideStory(boolean hideStory) {
|
||||
builder.setHideStory(hideStory);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static GroupV2Record.Builder parseUnknowns(byte[] serializedUnknowns) {
|
||||
try {
|
||||
return GroupV2Record.parseFrom(serializedUnknowns).toBuilder();
|
||||
|
||||
@@ -45,6 +45,7 @@ message Content {
|
||||
optional TypingMessage typingMessage = 6;
|
||||
optional bytes senderKeyDistributionMessage = 7;
|
||||
optional bytes decryptionErrorMessage = 8;
|
||||
optional StoryMessage storyMessage = 9;
|
||||
}
|
||||
|
||||
message CallMessage {
|
||||
@@ -218,14 +219,6 @@ message DataMessage {
|
||||
optional string organization = 7;
|
||||
}
|
||||
|
||||
message Preview {
|
||||
optional string url = 1;
|
||||
optional string title = 2;
|
||||
optional AttachmentPointer image = 3;
|
||||
optional string description = 4;
|
||||
optional uint64 date = 5;
|
||||
}
|
||||
|
||||
message Sticker {
|
||||
optional bytes packId = 1;
|
||||
optional bytes packKey = 2;
|
||||
@@ -356,6 +349,50 @@ message TypingMessage {
|
||||
optional bytes groupId = 3;
|
||||
}
|
||||
|
||||
message StoryMessage {
|
||||
optional bytes profileKey = 1;
|
||||
optional GroupContextV2 group = 2;
|
||||
oneof attachment {
|
||||
AttachmentPointer fileAttachment = 3;
|
||||
TextAttachment textAttachment = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message Preview {
|
||||
optional string url = 1;
|
||||
optional string title = 2;
|
||||
optional AttachmentPointer image = 3;
|
||||
optional string description = 4;
|
||||
optional uint64 date = 5;
|
||||
}
|
||||
|
||||
message TextAttachment {
|
||||
enum Style {
|
||||
DEFAULT = 0;
|
||||
REGULAR = 1;
|
||||
BOLD = 2;
|
||||
SERIF = 3;
|
||||
SCRIPT = 4;
|
||||
CONDENSED = 5;
|
||||
}
|
||||
|
||||
message Gradient {
|
||||
optional uint32 startColor = 1;
|
||||
optional uint32 endColor = 2;
|
||||
optional uint32 angle = 3; // degrees
|
||||
}
|
||||
|
||||
optional string text = 1;
|
||||
optional Style textStyle = 2;
|
||||
optional uint32 textForegroundColor = 3; // integer representation of hex color
|
||||
optional uint32 textBackgroundColor = 4;
|
||||
optional Preview preview = 5;
|
||||
oneof background {
|
||||
Gradient gradient = 6;
|
||||
uint32 color = 7;
|
||||
}
|
||||
}
|
||||
|
||||
message Verified {
|
||||
enum State {
|
||||
DEFAULT = 0;
|
||||
|
||||
@@ -82,6 +82,7 @@ message ContactRecord {
|
||||
bool archived = 11;
|
||||
bool markedUnread = 12;
|
||||
uint64 mutedUntilTimestamp = 13;
|
||||
bool hideStory = 14;
|
||||
}
|
||||
|
||||
message GroupV1Record {
|
||||
@@ -101,6 +102,7 @@ message GroupV2Record {
|
||||
bool markedUnread = 5;
|
||||
uint64 mutedUntilTimestamp = 6;
|
||||
bool dontNotifyForMentionsIfMuted = 7;
|
||||
bool hideStory = 8;
|
||||
}
|
||||
|
||||
message Payments {
|
||||
|
||||
@@ -16,7 +16,7 @@ public final class AccountAttributesTest {
|
||||
"reglock1234",
|
||||
new byte[10],
|
||||
false,
|
||||
new AccountAttributes.Capabilities(true, true, true, true, true, true, true),
|
||||
new AccountAttributes.Capabilities(true, true, true, true, true, true, true, true),
|
||||
false,
|
||||
null));
|
||||
assertEquals("{\"signalingKey\":\"skey\"," +
|
||||
@@ -29,19 +29,19 @@ public final class AccountAttributesTest {
|
||||
"\"unidentifiedAccessKey\":\"AAAAAAAAAAAAAA==\"," +
|
||||
"\"unrestrictedUnidentifiedAccess\":false," +
|
||||
"\"discoverableByPhoneNumber\":false," +
|
||||
"\"capabilities\":{\"uuid\":true,\"storage\":true,\"senderKey\":true,\"announcementGroup\":true,\"changeNumber\":true,\"gv2-3\":true,\"gv1-migration\":true}," +
|
||||
"\"capabilities\":{\"uuid\":true,\"storage\":true,\"senderKey\":true,\"announcementGroup\":true,\"changeNumber\":true,\"stories\":true,\"gv2-3\":true,\"gv1-migration\":true}," +
|
||||
"\"name\":null}", json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gv2_true() {
|
||||
String json = JsonUtil.toJson(new AccountAttributes.Capabilities(false, true, false, false, false, false, false));
|
||||
assertEquals("{\"uuid\":false,\"storage\":false,\"senderKey\":false,\"announcementGroup\":false,\"changeNumber\":false,\"gv2-3\":true,\"gv1-migration\":false}", json);
|
||||
String json = JsonUtil.toJson(new AccountAttributes.Capabilities(false, true, false, false, false, false, false, false));
|
||||
assertEquals("{\"uuid\":false,\"storage\":false,\"senderKey\":false,\"announcementGroup\":false,\"changeNumber\":false,\"stories\":false,\"gv2-3\":true,\"gv1-migration\":false}", json);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gv2_false() {
|
||||
String json = JsonUtil.toJson(new AccountAttributes.Capabilities(false, false, false, false, false, false, false));
|
||||
assertEquals("{\"uuid\":false,\"storage\":false,\"senderKey\":false,\"announcementGroup\":false,\"changeNumber\":false,\"gv2-3\":false,\"gv1-migration\":false}", json);
|
||||
String json = JsonUtil.toJson(new AccountAttributes.Capabilities(false, false, false, false, false, false, false, false));
|
||||
assertEquals("{\"uuid\":false,\"storage\":false,\"senderKey\":false,\"announcementGroup\":false,\"changeNumber\":false,\"stories\":false,\"gv2-3\":false,\"gv1-migration\":false}", json);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user