mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-30 13:35:18 +00:00
Support for group update messages from paired devices.
Fixes #3566 // FREEBIE
This commit is contained in:
parent
4ffb1ea95e
commit
5fd9874ab6
@ -559,7 +559,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
|||||||
.setType(GroupContext.Type.QUIT)
|
.setType(GroupContext.Type.QUIT)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(getRecipients(), context, null);
|
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(getRecipients(), context, null, System.currentTimeMillis());
|
||||||
MessageSender.send(self, masterSecret, outgoingMessage, threadId, false);
|
MessageSender.send(self, masterSecret, outgoingMessage, threadId, false);
|
||||||
DatabaseFactory.getGroupDatabase(self).remove(groupId, TextSecurePreferences.getLocalNumber(self));
|
DatabaseFactory.getGroupDatabase(self).remove(groupId, TextSecurePreferences.getLocalNumber(self));
|
||||||
initializeEnabledCheck();
|
initializeEnabledCheck();
|
||||||
|
@ -476,7 +476,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity {
|
|||||||
|
|
||||||
Uri avatarUri = SingleUseBlobProvider.getInstance().createUri(avatar);
|
Uri avatarUri = SingleUseBlobProvider.getInstance().createUri(avatar);
|
||||||
Attachment avatarAttachment = new UriAttachment(avatarUri, ContentType.IMAGE_JPEG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length);
|
Attachment avatarAttachment = new UriAttachment(avatarUri, ContentType.IMAGE_JPEG, AttachmentDatabase.TRANSFER_PROGRESS_DONE, avatar.length);
|
||||||
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, context, avatarAttachment);
|
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(groupRecipient, context, avatarAttachment, System.currentTimeMillis());
|
||||||
long threadId = MessageSender.send(this, masterSecret, outgoingMessage, -1, false);
|
long threadId = MessageSender.send(this, masterSecret, outgoingMessage, -1, false);
|
||||||
|
|
||||||
return new Pair<>(threadId, groupRecipient);
|
return new Pair<>(threadId, groupRecipient);
|
||||||
|
@ -3,35 +3,39 @@ package org.thoughtcrime.securesms.groups;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
import org.thoughtcrime.securesms.ApplicationContext;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
import org.thoughtcrime.securesms.database.EncryptingSmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||||
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
import org.thoughtcrime.securesms.jobs.AvatarDownloadJob;
|
||||||
|
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||||
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
|
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||||
import org.whispersystems.textsecure.api.messages.TextSecureAttachment;
|
import org.whispersystems.textsecure.api.messages.TextSecureAttachment;
|
||||||
|
import org.whispersystems.textsecure.api.messages.TextSecureDataMessage;
|
||||||
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
|
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
|
||||||
import org.whispersystems.textsecure.api.messages.TextSecureGroup;
|
import org.whispersystems.textsecure.api.messages.TextSecureGroup;
|
||||||
import org.whispersystems.textsecure.api.messages.TextSecureDataMessage;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import ws.com.google.android.mms.MmsException;
|
||||||
|
|
||||||
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||||
import static org.whispersystems.textsecure.internal.push.TextSecureProtos.AttachmentPointer;
|
import static org.whispersystems.textsecure.internal.push.TextSecureProtos.AttachmentPointer;
|
||||||
import static org.whispersystems.textsecure.internal.push.TextSecureProtos.GroupContext;
|
import static org.whispersystems.textsecure.internal.push.TextSecureProtos.GroupContext;
|
||||||
@ -43,7 +47,8 @@ public class GroupMessageProcessor {
|
|||||||
public static void process(@NonNull Context context,
|
public static void process(@NonNull Context context,
|
||||||
@NonNull MasterSecretUnion masterSecret,
|
@NonNull MasterSecretUnion masterSecret,
|
||||||
@NonNull TextSecureEnvelope envelope,
|
@NonNull TextSecureEnvelope envelope,
|
||||||
@NonNull TextSecureDataMessage message)
|
@NonNull TextSecureDataMessage message,
|
||||||
|
boolean outgoing)
|
||||||
{
|
{
|
||||||
if (!message.getGroupInfo().isPresent() || message.getGroupInfo().get().getGroupId() == null) {
|
if (!message.getGroupInfo().isPresent() || message.getGroupInfo().get().getGroupId() == null) {
|
||||||
Log.w(TAG, "Received group message with no id! Ignoring...");
|
Log.w(TAG, "Received group message with no id! Ignoring...");
|
||||||
@ -56,11 +61,11 @@ public class GroupMessageProcessor {
|
|||||||
GroupRecord record = database.getGroup(id);
|
GroupRecord record = database.getGroup(id);
|
||||||
|
|
||||||
if (record != null && group.getType() == TextSecureGroup.Type.UPDATE) {
|
if (record != null && group.getType() == TextSecureGroup.Type.UPDATE) {
|
||||||
handleGroupUpdate(context, masterSecret, envelope, group, record);
|
handleGroupUpdate(context, masterSecret, envelope, group, record, outgoing);
|
||||||
} else if (record == null && group.getType() == TextSecureGroup.Type.UPDATE) {
|
} else if (record == null && group.getType() == TextSecureGroup.Type.UPDATE) {
|
||||||
handleGroupCreate(context, masterSecret, envelope, group);
|
handleGroupCreate(context, masterSecret, envelope, group, outgoing);
|
||||||
} else if (record != null && group.getType() == TextSecureGroup.Type.QUIT) {
|
} else if (record != null && group.getType() == TextSecureGroup.Type.QUIT) {
|
||||||
handleGroupLeave(context, masterSecret, envelope, group, record);
|
handleGroupLeave(context, masterSecret, envelope, group, record, outgoing);
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Received unknown type, ignoring...");
|
Log.w(TAG, "Received unknown type, ignoring...");
|
||||||
}
|
}
|
||||||
@ -69,7 +74,8 @@ public class GroupMessageProcessor {
|
|||||||
private static void handleGroupCreate(@NonNull Context context,
|
private static void handleGroupCreate(@NonNull Context context,
|
||||||
@NonNull MasterSecretUnion masterSecret,
|
@NonNull MasterSecretUnion masterSecret,
|
||||||
@NonNull TextSecureEnvelope envelope,
|
@NonNull TextSecureEnvelope envelope,
|
||||||
@NonNull TextSecureGroup group)
|
@NonNull TextSecureGroup group,
|
||||||
|
boolean outgoing)
|
||||||
{
|
{
|
||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
byte[] id = group.getGroupId();
|
byte[] id = group.getGroupId();
|
||||||
@ -82,14 +88,15 @@ public class GroupMessageProcessor {
|
|||||||
avatar != null && avatar.isPointer() ? avatar.asPointer() : null,
|
avatar != null && avatar.isPointer() ? avatar.asPointer() : null,
|
||||||
envelope.getRelay());
|
envelope.getRelay());
|
||||||
|
|
||||||
storeMessage(context, masterSecret, envelope, group, builder.build());
|
storeMessage(context, masterSecret, envelope, group, builder.build(), outgoing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handleGroupUpdate(@NonNull Context context,
|
private static void handleGroupUpdate(@NonNull Context context,
|
||||||
@NonNull MasterSecretUnion masterSecret,
|
@NonNull MasterSecretUnion masterSecret,
|
||||||
@NonNull TextSecureEnvelope envelope,
|
@NonNull TextSecureEnvelope envelope,
|
||||||
@NonNull TextSecureGroup group,
|
@NonNull TextSecureGroup group,
|
||||||
@NonNull GroupRecord groupRecord)
|
@NonNull GroupRecord groupRecord,
|
||||||
|
boolean outgoing)
|
||||||
{
|
{
|
||||||
|
|
||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
@ -132,14 +139,15 @@ public class GroupMessageProcessor {
|
|||||||
|
|
||||||
if (!groupRecord.isActive()) database.setActive(id, true);
|
if (!groupRecord.isActive()) database.setActive(id, true);
|
||||||
|
|
||||||
storeMessage(context, masterSecret, envelope, group, builder.build());
|
storeMessage(context, masterSecret, envelope, group, builder.build(), outgoing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handleGroupLeave(@NonNull Context context,
|
private static void handleGroupLeave(@NonNull Context context,
|
||||||
@NonNull MasterSecretUnion masterSecret,
|
@NonNull MasterSecretUnion masterSecret,
|
||||||
@NonNull TextSecureEnvelope envelope,
|
@NonNull TextSecureEnvelope envelope,
|
||||||
@NonNull TextSecureGroup group,
|
@NonNull TextSecureGroup group,
|
||||||
@NonNull GroupRecord record)
|
@NonNull GroupRecord record,
|
||||||
|
boolean outgoing)
|
||||||
{
|
{
|
||||||
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
GroupDatabase database = DatabaseFactory.getGroupDatabase(context);
|
||||||
byte[] id = group.getGroupId();
|
byte[] id = group.getGroupId();
|
||||||
@ -150,8 +158,9 @@ public class GroupMessageProcessor {
|
|||||||
|
|
||||||
if (members.contains(envelope.getSource())) {
|
if (members.contains(envelope.getSource())) {
|
||||||
database.remove(id, envelope.getSource());
|
database.remove(id, envelope.getSource());
|
||||||
|
if (outgoing) database.setActive(id, false);
|
||||||
|
|
||||||
storeMessage(context, masterSecret, envelope, group, builder.build());
|
storeMessage(context, masterSecret, envelope, group, builder.build(), outgoing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,20 +169,35 @@ public class GroupMessageProcessor {
|
|||||||
@NonNull MasterSecretUnion masterSecret,
|
@NonNull MasterSecretUnion masterSecret,
|
||||||
@NonNull TextSecureEnvelope envelope,
|
@NonNull TextSecureEnvelope envelope,
|
||||||
@NonNull TextSecureGroup group,
|
@NonNull TextSecureGroup group,
|
||||||
@NonNull GroupContext storage)
|
@NonNull GroupContext storage,
|
||||||
|
boolean outgoing)
|
||||||
{
|
{
|
||||||
if (group.getAvatar().isPresent()) {
|
if (group.getAvatar().isPresent()) {
|
||||||
ApplicationContext.getInstance(context).getJobManager()
|
ApplicationContext.getInstance(context).getJobManager()
|
||||||
.add(new AvatarDownloadJob(context, group.getGroupId()));
|
.add(new AvatarDownloadJob(context, group.getGroupId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context);
|
try {
|
||||||
String body = Base64.encodeBytes(storage.toByteArray());
|
if (outgoing) {
|
||||||
IncomingTextMessage incoming = new IncomingTextMessage(envelope.getSource(), envelope.getSourceDevice(), envelope.getTimestamp(), body, Optional.of(group));
|
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||||
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);
|
Recipients recipients = RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(group.getGroupId()), false);
|
||||||
|
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(recipients, storage, null, envelope.getTimestamp());
|
||||||
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||||
|
long messageId = mmsDatabase.insertMessageOutbox(masterSecret, outgoingMessage, threadId, false);
|
||||||
|
|
||||||
Pair<Long, Long> messageAndThreadId = smsDatabase.insertMessageInbox(masterSecret, groupMessage);
|
mmsDatabase.markAsSent(messageId);
|
||||||
MessageNotifier.updateNotification(context, masterSecret.getMasterSecret().orNull(), messageAndThreadId.second);
|
} else {
|
||||||
|
EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context);
|
||||||
|
String body = Base64.encodeBytes(storage.toByteArray());
|
||||||
|
IncomingTextMessage incoming = new IncomingTextMessage(envelope.getSource(), envelope.getSourceDevice(), envelope.getTimestamp(), body, Optional.of(group));
|
||||||
|
IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body);
|
||||||
|
|
||||||
|
Pair<Long, Long> messageAndThreadId = smsDatabase.insertMessageInbox(masterSecret, groupMessage);
|
||||||
|
MessageNotifier.updateNotification(context, masterSecret.getMasterSecret().orNull(), messageAndThreadId.second);
|
||||||
|
}
|
||||||
|
} catch (MmsException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GroupContext.Builder createGroupContext(TextSecureGroup group) {
|
private static GroupContext.Builder createGroupContext(TextSecureGroup group) {
|
||||||
|
@ -143,7 +143,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
} else if (content.getSyncMessage().isPresent()) {
|
} else if (content.getSyncMessage().isPresent()) {
|
||||||
TextSecureSyncMessage syncMessage = content.getSyncMessage().get();
|
TextSecureSyncMessage syncMessage = content.getSyncMessage().get();
|
||||||
|
|
||||||
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(masterSecret, syncMessage.getSent().get(), smsMessageId);
|
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(masterSecret, envelope, syncMessage.getSent().get(), smsMessageId);
|
||||||
else if (syncMessage.getRequest().isPresent()) handleSynchronizeRequestMessage(masterSecret, syncMessage.getRequest().get());
|
else if (syncMessage.getRequest().isPresent()) handleSynchronizeRequestMessage(masterSecret, syncMessage.getRequest().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
@NonNull TextSecureDataMessage message,
|
@NonNull TextSecureDataMessage message,
|
||||||
@NonNull Optional<Long> smsMessageId)
|
@NonNull Optional<Long> smsMessageId)
|
||||||
{
|
{
|
||||||
GroupMessageProcessor.process(context, masterSecret, envelope, message);
|
GroupMessageProcessor.process(context, masterSecret, envelope, message, false);
|
||||||
|
|
||||||
if (smsMessageId.isPresent()) {
|
if (smsMessageId.isPresent()) {
|
||||||
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
||||||
@ -214,11 +214,14 @@ public class PushDecryptJob extends ContextJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleSynchronizeSentMessage(@NonNull MasterSecretUnion masterSecret,
|
private void handleSynchronizeSentMessage(@NonNull MasterSecretUnion masterSecret,
|
||||||
|
@NonNull TextSecureEnvelope envelope,
|
||||||
@NonNull SentTranscriptMessage message,
|
@NonNull SentTranscriptMessage message,
|
||||||
@NonNull Optional<Long> smsMessageId)
|
@NonNull Optional<Long> smsMessageId)
|
||||||
throws MmsException
|
throws MmsException
|
||||||
{
|
{
|
||||||
if (message.getMessage().getAttachments().isPresent()) {
|
if (message.getMessage().isGroupUpdate()) {
|
||||||
|
GroupMessageProcessor.process(context, masterSecret, envelope, message.getMessage(), true);
|
||||||
|
} else if (message.getMessage().getAttachments().isPresent()) {
|
||||||
handleSynchronizeSentMediaMessage(masterSecret, message, smsMessageId);
|
handleSynchronizeSentMediaMessage(masterSecret, message, smsMessageId);
|
||||||
} else {
|
} else {
|
||||||
handleSynchronizeSentTextMessage(masterSecret, message, smsMessageId);
|
handleSynchronizeSentTextMessage(masterSecret, message, smsMessageId);
|
||||||
|
@ -31,7 +31,8 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
|
|||||||
|
|
||||||
public OutgoingGroupMediaMessage(@NonNull Recipients recipients,
|
public OutgoingGroupMediaMessage(@NonNull Recipients recipients,
|
||||||
@NonNull GroupContext group,
|
@NonNull GroupContext group,
|
||||||
@Nullable final Attachment avatar)
|
@Nullable final Attachment avatar,
|
||||||
|
long sentTimeMillis)
|
||||||
{
|
{
|
||||||
super(recipients, Base64.encodeBytes(group.toByteArray()),
|
super(recipients, Base64.encodeBytes(group.toByteArray()),
|
||||||
new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}},
|
new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}},
|
||||||
|
Loading…
Reference in New Issue
Block a user