mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-24 02:25:19 +00:00
Message syncing.
This commit is contained in:
parent
98cfd93b97
commit
efad14fcdc
@ -20,13 +20,17 @@ import android.annotation.SuppressLint;
|
||||
import android.arch.lifecycle.DefaultLifecycleObserver;
|
||||
import android.arch.lifecycle.LifecycleOwner;
|
||||
import android.arch.lifecycle.ProcessLifecycleOwner;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.multidex.MultiDexApplication;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.google.android.gms.security.ProviderInstaller;
|
||||
@ -62,6 +66,7 @@ import org.thoughtcrime.securesms.logging.PersistentLogger;
|
||||
import org.thoughtcrime.securesms.logging.UncaughtExceptionLogger;
|
||||
import org.thoughtcrime.securesms.loki.BackgroundPollWorker;
|
||||
import org.thoughtcrime.securesms.loki.LokiAPIDatabase;
|
||||
import org.thoughtcrime.securesms.loki.LokiMessageSyncEvent;
|
||||
import org.thoughtcrime.securesms.loki.LokiPublicChatManager;
|
||||
import org.thoughtcrime.securesms.loki.LokiRSSFeedPoller;
|
||||
import org.thoughtcrime.securesms.loki.LokiUserDatabase;
|
||||
@ -77,6 +82,7 @@ import org.thoughtcrime.securesms.service.LocalBackupListener;
|
||||
import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
|
||||
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
||||
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;
|
||||
import org.webrtc.PeerConnectionFactory;
|
||||
@ -141,6 +147,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
private LokiPublicChatAPI lokiPublicChatAPI = null;
|
||||
public SignalCommunicationModule communicationModule;
|
||||
public MixpanelAPI mixpanel;
|
||||
private BroadcastReceiver syncMessageEventReceiver;
|
||||
|
||||
private volatile boolean isAppVisible;
|
||||
|
||||
@ -193,6 +200,22 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
if (setUpStorageAPIIfNeeded()) {
|
||||
LokiStorageAPI.Companion.getShared().updateUserDeviceMappings();
|
||||
}
|
||||
|
||||
// Loki - Event listener
|
||||
syncMessageEventReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// Send the sync message to our devices
|
||||
long messageID = intent.getLongExtra(LokiMessageSyncEvent.MESSAGE_ID, -1);
|
||||
long timestamp = intent.getLongExtra(LokiMessageSyncEvent.TIMESTAMP, -1);
|
||||
byte[] message = intent.getByteArrayExtra(LokiMessageSyncEvent.SYNC_MESSAGE);
|
||||
int ttl = intent.getIntExtra(LokiMessageSyncEvent.TTL, -1);
|
||||
if (messageID > 0 && timestamp > 0 && message != null && ttl > 0) {
|
||||
MessageSender.sendSyncMessageToOurDevices(context, messageID, timestamp, message, ttl);
|
||||
}
|
||||
}
|
||||
};
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(syncMessageEventReceiver, new IntentFilter(LokiMessageSyncEvent.MESSAGE_SYNC_EVENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -220,6 +243,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
||||
@Override
|
||||
public void onTerminate() {
|
||||
stopKovenant();
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(syncMessageEventReceiver);
|
||||
super.onTerminate();
|
||||
}
|
||||
|
||||
|
@ -47,8 +47,9 @@ import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
|
||||
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
||||
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.push.SecurityEventListener;
|
||||
import org.thoughtcrime.securesms.push.MessageSenderEventListener;
|
||||
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
|
||||
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.service.WebRtcCallService;
|
||||
@ -112,7 +113,8 @@ import network.loki.messenger.BuildConfig;
|
||||
StickerPackDownloadJob.class,
|
||||
MultiDeviceStickerPackOperationJob.class,
|
||||
MultiDeviceStickerPackSyncJob.class,
|
||||
LinkPreviewRepository.class})
|
||||
LinkPreviewRepository.class,
|
||||
PushMessageSyncSendJob.class})
|
||||
|
||||
public class SignalCommunicationModule {
|
||||
|
||||
@ -151,7 +153,7 @@ public class SignalCommunicationModule {
|
||||
TextSecurePreferences.isMultiDevice(context),
|
||||
Optional.fromNullable(IncomingMessageObserver.getPipe()),
|
||||
Optional.fromNullable(IncomingMessageObserver.getUnidentifiedPipe()),
|
||||
Optional.of(new SecurityEventListener(context)),
|
||||
Optional.of(new MessageSenderEventListener(context)),
|
||||
TextSecurePreferences.getLocalNumber(context),
|
||||
DatabaseFactory.getLokiAPIDatabase(context),
|
||||
DatabaseFactory.getLokiThreadDatabase(context),
|
||||
|
@ -24,6 +24,7 @@ public class Data {
|
||||
@JsonProperty private final Map<String, double[]> doubleArrays;
|
||||
@JsonProperty private final Map<String, Boolean> booleans;
|
||||
@JsonProperty private final Map<String, boolean[]> booleanArrays;
|
||||
@JsonProperty private final Map<String, byte[]> byteArrays;
|
||||
|
||||
public Data(@JsonProperty("strings") @NonNull Map<String, String> strings,
|
||||
@JsonProperty("stringArrays") @NonNull Map<String, String[]> stringArrays,
|
||||
@ -36,7 +37,8 @@ public class Data {
|
||||
@JsonProperty("doubles") @NonNull Map<String, Double> doubles,
|
||||
@JsonProperty("doubleArrays") @NonNull Map<String, double[]> doubleArrays,
|
||||
@JsonProperty("booleans") @NonNull Map<String, Boolean> booleans,
|
||||
@JsonProperty("booleanArrays") @NonNull Map<String, boolean[]> booleanArrays)
|
||||
@JsonProperty("booleanArrays") @NonNull Map<String, boolean[]> booleanArrays,
|
||||
@JsonProperty("byteArrays") @NonNull Map<String, byte[]> byteArrays)
|
||||
{
|
||||
this.strings = strings;
|
||||
this.stringArrays = stringArrays;
|
||||
@ -50,6 +52,7 @@ public class Data {
|
||||
this.doubleArrays = doubleArrays;
|
||||
this.booleans = booleans;
|
||||
this.booleanArrays = booleanArrays;
|
||||
this.byteArrays = byteArrays;
|
||||
}
|
||||
|
||||
public boolean hasString(@NonNull String key) {
|
||||
@ -201,6 +204,14 @@ public class Data {
|
||||
return booleanArrays.get(key);
|
||||
}
|
||||
|
||||
public boolean hasByteArray(@NonNull String key) {
|
||||
return byteArrays.containsKey(key);
|
||||
}
|
||||
|
||||
public byte[] getByteArray(@NonNull String key) {
|
||||
throwIfAbsent(byteArrays, key);
|
||||
return byteArrays.get(key);
|
||||
}
|
||||
|
||||
private void throwIfAbsent(@NonNull Map map, @NonNull String key) {
|
||||
if (!map.containsKey(key)) {
|
||||
@ -223,6 +234,7 @@ public class Data {
|
||||
private final Map<String, double[]> doubleArrays = new HashMap<>();
|
||||
private final Map<String, Boolean> booleans = new HashMap<>();
|
||||
private final Map<String, boolean[]> booleanArrays = new HashMap<>();
|
||||
private final Map<String, byte[]> byteArrays = new HashMap<>();
|
||||
|
||||
public Builder putString(@NonNull String key, @Nullable String value) {
|
||||
strings.put(key, value);
|
||||
@ -284,6 +296,11 @@ public class Data {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder putByteArray(@NonNull String key, @NonNull byte[] value) {
|
||||
byteArrays.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Data build() {
|
||||
return new Data(strings,
|
||||
stringArrays,
|
||||
@ -296,7 +313,8 @@ public class Data {
|
||||
doubles,
|
||||
doubleArrays,
|
||||
booleans,
|
||||
booleanArrays);
|
||||
booleanArrays,
|
||||
byteArrays);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraintObserver;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraint;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.SqlCipherMigrationConstraintObserver;
|
||||
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@ -70,6 +71,7 @@ public final class JobManagerFactories {
|
||||
put(TrimThreadJob.KEY, new TrimThreadJob.Factory());
|
||||
put(TypingSendJob.KEY, new TypingSendJob.Factory());
|
||||
put(UpdateApkJob.KEY, new UpdateApkJob.Factory());
|
||||
put(PushMessageSyncSendJob.KEY, new PushMessageSyncSendJob.Factory());
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -821,8 +821,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
|
||||
private long handleSynchronizeSentExpirationUpdate(@NonNull SentTranscriptMessage message) throws MmsException {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipient = getSyncMessageDestination(message);
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipient = getSyncMessagePrimaryDestination(message);
|
||||
|
||||
OutgoingExpirationUpdateMessage expirationUpdateMessage = new OutgoingExpirationUpdateMessage(recipient,
|
||||
message.getTimestamp(),
|
||||
@ -842,7 +842,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
throws MmsException
|
||||
{
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipients = getSyncMessageDestination(message);
|
||||
Recipient recipients = getSyncMessagePrimaryDestination(message);
|
||||
Optional<QuoteModel> quote = getValidatedQuote(message.getMessage().getQuote());
|
||||
Optional<Attachment> sticker = getStickerAttachment(message.getMessage().getSticker());
|
||||
Optional<List<Contact>> sharedContacts = getContacts(message.getMessage().getSharedContacts());
|
||||
@ -1172,7 +1172,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
throws MmsException
|
||||
{
|
||||
|
||||
Recipient recipient = getSyncMessageDestination(message);
|
||||
Recipient recipient = getSyncMessagePrimaryDestination(message);
|
||||
String body = message.getMessage().getBody().or("");
|
||||
long expiresInMillis = message.getMessage().getExpiresInSeconds() * 1000L;
|
||||
|
||||
@ -1523,35 +1523,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
private Recipient getMessagePrimaryDestination(SignalServiceContent content, SignalServiceDataMessage message) {
|
||||
if (message.getGroupInfo().isPresent()) {
|
||||
return Recipient.from(context, Address.fromSerialized(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false)), false);
|
||||
private Recipient getSyncMessagePrimaryDestination(SentTranscriptMessage message) {
|
||||
if (message.getMessage().getGroupInfo().isPresent()) {
|
||||
return getSyncMessageDestination(message);
|
||||
} else {
|
||||
SettableFuture<String> device = new SettableFuture<>();
|
||||
String contentSender = content.getSender();
|
||||
|
||||
// Get the primary device
|
||||
LokiStorageAPI.shared.getPrimaryDevicePublicKey(contentSender).success(primaryDevice -> {
|
||||
String publicKey = (primaryDevice != null) ? primaryDevice : contentSender;
|
||||
// If our the public key matches our primary device then we need to forward the message to ourselves (Note to self)
|
||||
String ourPrimaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||
if (ourPrimaryDevice != null && ourPrimaryDevice.equals(publicKey)) {
|
||||
publicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
}
|
||||
device.set(publicKey);
|
||||
return Unit.INSTANCE;
|
||||
}).fail(exception -> {
|
||||
device.set(contentSender);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
try {
|
||||
String primarySender = device.get();
|
||||
return Recipient.from(context, Address.fromSerialized(primarySender), false);
|
||||
} catch (Exception e) {
|
||||
Log.d("Loki", "Failed to get primary device public key for message. " + e.getMessage());
|
||||
return Recipient.from(context, Address.fromSerialized(content.getSender()), false);
|
||||
}
|
||||
return getPrimaryDeviceRecipient(message.getDestination().get());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1563,6 +1539,41 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
}
|
||||
|
||||
private Recipient getMessagePrimaryDestination(SignalServiceContent content, SignalServiceDataMessage message) {
|
||||
if (message.getGroupInfo().isPresent()) {
|
||||
return getMessageDestination(content, message);
|
||||
} else {
|
||||
return getPrimaryDeviceRecipient(content.getSender());
|
||||
}
|
||||
}
|
||||
|
||||
private Recipient getPrimaryDeviceRecipient(String recipient) {
|
||||
SettableFuture<String> device = new SettableFuture<>();
|
||||
|
||||
// Get the primary device
|
||||
LokiStorageAPI.shared.getPrimaryDevicePublicKey(recipient).success(primaryDevice -> {
|
||||
String publicKey = (primaryDevice != null) ? primaryDevice : recipient;
|
||||
// If our the public key matches our primary device then we need to forward the message to ourselves (Note to self)
|
||||
String ourPrimaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||
if (ourPrimaryDevice != null && ourPrimaryDevice.equals(publicKey)) {
|
||||
publicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
}
|
||||
device.set(publicKey);
|
||||
return Unit.INSTANCE;
|
||||
}).fail(exception -> {
|
||||
device.set(recipient);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
try {
|
||||
String primarySender = device.get();
|
||||
return Recipient.from(context, Address.fromSerialized(primarySender), false);
|
||||
} catch (Exception e) {
|
||||
Log.d("Loki", "Failed to get primary device public key for message. " + e.getMessage());
|
||||
return Recipient.from(context, Address.fromSerialized(recipient), false);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyTypingStoppedFromIncomingMessage(@NonNull Recipient conversationRecipient, @NonNull String sender, int device) {
|
||||
Recipient author = Recipient.from(context, Address.fromSerialized(sender), false);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(conversationRecipient);
|
||||
@ -1609,6 +1620,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
} else if (content.getCallMessage().isPresent() || content.getTypingMessage().isPresent()) {
|
||||
return sender.isBlocked();
|
||||
} else if (content.getSyncMessage().isPresent()) {
|
||||
// We should ignore a sync message if the sender is not one of our devices
|
||||
boolean isOurDevice = MultiDeviceUtilitiesKt.isOneOfOurDevices(context, sender.getAddress());
|
||||
if (!isOurDevice) { Log.w(TAG, "Got a sync message from a device that is not ours!."); }
|
||||
return !isOurDevice;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@ -42,6 +43,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSy
|
||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
@ -61,6 +63,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
private static final String KEY_DESTINATION = "destination";
|
||||
private static final String KEY_IS_FRIEND_REQUEST = "is_friend_request";
|
||||
private static final String KEY_CUSTOM_FR_MESSAGE = "custom_friend_request_message";
|
||||
private static final String KEY_SHOULD_SEND_SYNC_MESSAGE = "should_send_sync_message";
|
||||
|
||||
@Inject SignalServiceMessageSender messageSender;
|
||||
|
||||
@ -71,34 +74,36 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
private Address destination; // Destination to check whether this is another device we're sending to
|
||||
private boolean isFriendRequest; // Whether this is a friend request message
|
||||
private String customFriendRequestMessage; // If this isn't set then we use the message body
|
||||
private boolean shouldSendSyncMessage;
|
||||
|
||||
public PushMediaSendJob(long messageId, Address destination) { this(messageId, messageId, destination); }
|
||||
public PushMediaSendJob(long templateMessageId, long messageId, Address destination) { this(templateMessageId, messageId, destination, false, null); }
|
||||
public PushMediaSendJob(long templateMessageId, long messageId, Address destination, boolean isFriendRequest, String customFriendRequestMessage) {
|
||||
this(constructParameters(destination), templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage);
|
||||
public PushMediaSendJob(long templateMessageId, long messageId, Address destination) { this(templateMessageId, messageId, destination, false, null, false); }
|
||||
public PushMediaSendJob(long templateMessageId, long messageId, Address destination, boolean isFriendRequest, String customFriendRequestMessage, boolean shouldSendSyncMessage) {
|
||||
this(constructParameters(destination), templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage, shouldSendSyncMessage);
|
||||
}
|
||||
|
||||
private PushMediaSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isFriendRequest, String customFriendRequestMessage) {
|
||||
private PushMediaSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isFriendRequest, String customFriendRequestMessage, boolean shouldSendSyncMessage) {
|
||||
super(parameters);
|
||||
this.templateMessageId = templateMessageId;
|
||||
this.messageId = messageId;
|
||||
this.destination = destination;
|
||||
this.isFriendRequest = isFriendRequest;
|
||||
this.customFriendRequestMessage = customFriendRequestMessage;
|
||||
this.shouldSendSyncMessage = shouldSendSyncMessage;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Address destination) {
|
||||
enqueue(context, jobManager, messageId, messageId, destination);
|
||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Address destination, boolean shouldSendSyncMessage) {
|
||||
enqueue(context, jobManager, messageId, messageId, destination, shouldSendSyncMessage);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long templateMessageId, long messageId, @NonNull Address destination) {
|
||||
enqueue(context, jobManager, templateMessageId, messageId, destination, false, null);
|
||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long templateMessageId, long messageId, @NonNull Address destination, boolean shouldSendSyncMessage) {
|
||||
enqueue(context, jobManager, templateMessageId, messageId, destination, false, null, shouldSendSyncMessage);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long templateMessageId, long messageId, @NonNull Address destination, Boolean isFriendRequest, @Nullable String customFriendRequestMessage) {
|
||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long templateMessageId, long messageId, @NonNull Address destination, Boolean isFriendRequest, @Nullable String customFriendRequestMessage, boolean shouldSendSyncMessage) {
|
||||
try {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
|
||||
@ -111,10 +116,10 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
List<AttachmentUploadJob> attachmentJobs = Stream.of(attachments).map(a -> new AttachmentUploadJob(((DatabaseAttachment) a).getAttachmentId(), destination)).toList();
|
||||
|
||||
if (attachmentJobs.isEmpty()) {
|
||||
jobManager.add(new PushMediaSendJob(templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage));
|
||||
jobManager.add(new PushMediaSendJob(templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage, shouldSendSyncMessage));
|
||||
} else {
|
||||
jobManager.startChain(attachmentJobs)
|
||||
.then(new PushMediaSendJob(templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage))
|
||||
.then(new PushMediaSendJob(templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage, shouldSendSyncMessage))
|
||||
.enqueue();
|
||||
}
|
||||
|
||||
@ -128,10 +133,11 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
@Override
|
||||
public @NonNull Data serialize() {
|
||||
Data.Builder builder = new Data.Builder()
|
||||
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
|
||||
.putLong(KEY_MESSAGE_ID, messageId)
|
||||
.putString(KEY_DESTINATION, destination.serialize())
|
||||
.putBoolean(KEY_IS_FRIEND_REQUEST, isFriendRequest);
|
||||
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
|
||||
.putLong(KEY_MESSAGE_ID, messageId)
|
||||
.putString(KEY_DESTINATION, destination.serialize())
|
||||
.putBoolean(KEY_IS_FRIEND_REQUEST, isFriendRequest)
|
||||
.putBoolean(KEY_SHOULD_SEND_SYNC_MESSAGE, shouldSendSyncMessage);
|
||||
|
||||
if (customFriendRequestMessage != null) { builder.putString(KEY_CUSTOM_FR_MESSAGE, customFriendRequestMessage); }
|
||||
return builder.build();
|
||||
@ -271,7 +277,15 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
messageSender.sendMessage(messageId, syncMessage, syncAccess);
|
||||
return syncAccess.isPresent();
|
||||
} else {
|
||||
return messageSender.sendMessage(messageId, address, UnidentifiedAccessUtil.getAccessFor(context, recipient), mediaMessage).getSuccess().isUnidentified();
|
||||
LokiSyncMessage syncMessage = null;
|
||||
if (shouldSendSyncMessage) {
|
||||
// Set the sync message destination the primary device, this way it will show that we sent a message to the primary device and not a secondary device
|
||||
String primaryDevice = MultiDeviceUtilitiesKt.getPrimaryDevicePublicKey(address.getNumber());
|
||||
SignalServiceAddress primaryAddress = primaryDevice == null ? address : new SignalServiceAddress(primaryDevice);
|
||||
// We also need to use the original message id and not -1
|
||||
syncMessage = new LokiSyncMessage(primaryAddress, templateMessageId);
|
||||
}
|
||||
return messageSender.sendMessage(messageId, address, UnidentifiedAccessUtil.getAccessFor(context, recipient), mediaMessage, Optional.fromNullable(syncMessage)).getSuccess().isUnidentified();
|
||||
}
|
||||
} catch (UnregisteredUserException e) {
|
||||
warn(TAG, e);
|
||||
@ -292,8 +306,9 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
long messageID = data.getLong(KEY_MESSAGE_ID);
|
||||
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
|
||||
boolean isFriendRequest = data.getBoolean(KEY_IS_FRIEND_REQUEST);
|
||||
boolean shouldSendSyncMessage = data.getBoolean(KEY_SHOULD_SEND_SYNC_MESSAGE);
|
||||
String frMessage = data.hasString(KEY_CUSTOM_FR_MESSAGE) ? data.getString(KEY_CUSTOM_FR_MESSAGE) : null;
|
||||
return new PushMediaSendJob(parameters, templateMessageID, messageID, destination, isFriendRequest, frMessage);
|
||||
return new PushMediaSendJob(parameters, templateMessageID, messageID, destination, isFriendRequest, frMessage, shouldSendSyncMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
@ -29,6 +30,7 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@ -45,6 +47,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
private static final String KEY_DESTINATION = "destination";
|
||||
private static final String KEY_IS_FRIEND_REQUEST = "is_friend_request";
|
||||
private static final String KEY_CUSTOM_FR_MESSAGE = "custom_friend_request_message";
|
||||
private static final String KEY_SHOULD_SEND_SYNC_MESSAGE = "should_send_sync_message";
|
||||
|
||||
@Inject SignalServiceMessageSender messageSender;
|
||||
|
||||
@ -55,29 +58,32 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
private Address destination; // Destination to check whether this is another device we're sending to
|
||||
private boolean isFriendRequest; // Whether this is a friend request message
|
||||
private String customFriendRequestMessage; // If this isn't set then we use the message body
|
||||
private boolean shouldSendSyncMessage;
|
||||
|
||||
public PushTextSendJob(long messageId, Address destination) { this(messageId, messageId, destination); }
|
||||
public PushTextSendJob(long templateMessageId, long messageId, Address destination) { this(templateMessageId, messageId, destination, false, null); }
|
||||
public PushTextSendJob(long templateMessageId, long messageId, Address destination, boolean isFriendRequest, String customFriendRequestMessage) {
|
||||
this(constructParameters(destination), templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage);
|
||||
public PushTextSendJob(long messageId, Address destination) { this(messageId, messageId, destination, false); }
|
||||
public PushTextSendJob(long templateMessageId, long messageId, Address destination, boolean shouldSendSyncMessage) { this(templateMessageId, messageId, destination, false, null, shouldSendSyncMessage); }
|
||||
public PushTextSendJob(long templateMessageId, long messageId, Address destination, boolean isFriendRequest, String customFriendRequestMessage, boolean shouldSendSyncMessage) {
|
||||
this(constructParameters(destination), templateMessageId, messageId, destination, isFriendRequest, customFriendRequestMessage, shouldSendSyncMessage);
|
||||
}
|
||||
|
||||
private PushTextSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isFriendRequest, String customFriendRequestMessage) {
|
||||
private PushTextSendJob(@NonNull Job.Parameters parameters, long templateMessageId, long messageId, Address destination, boolean isFriendRequest, String customFriendRequestMessage, boolean shouldSendSyncMessage) {
|
||||
super(parameters);
|
||||
this.templateMessageId = templateMessageId;
|
||||
this.messageId = messageId;
|
||||
this.destination = destination;
|
||||
this.isFriendRequest = isFriendRequest;
|
||||
this.customFriendRequestMessage = customFriendRequestMessage;
|
||||
this.shouldSendSyncMessage = shouldSendSyncMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Data serialize() {
|
||||
Data.Builder builder = new Data.Builder()
|
||||
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
|
||||
.putLong(KEY_MESSAGE_ID, messageId)
|
||||
.putString(KEY_DESTINATION, destination.serialize())
|
||||
.putBoolean(KEY_IS_FRIEND_REQUEST, isFriendRequest);
|
||||
.putLong(KEY_TEMPLATE_MESSAGE_ID, templateMessageId)
|
||||
.putLong(KEY_MESSAGE_ID, messageId)
|
||||
.putString(KEY_DESTINATION, destination.serialize())
|
||||
.putBoolean(KEY_IS_FRIEND_REQUEST, isFriendRequest)
|
||||
.putBoolean(KEY_SHOULD_SEND_SYNC_MESSAGE, shouldSendSyncMessage);
|
||||
|
||||
if (customFriendRequestMessage != null) { builder.putString(KEY_CUSTOM_FR_MESSAGE, customFriendRequestMessage); }
|
||||
return builder.build();
|
||||
@ -222,7 +228,15 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
messageSender.sendMessage(messageId, syncMessage, syncAccess);
|
||||
return syncAccess.isPresent();
|
||||
} else {
|
||||
return messageSender.sendMessage(messageId, address, unidentifiedAccess, textSecureMessage).getSuccess().isUnidentified();
|
||||
LokiSyncMessage syncMessage = null;
|
||||
if (shouldSendSyncMessage) {
|
||||
// Set the sync message destination the primary device, this way it will show that we sent a message to the primary device and not a secondary device
|
||||
String primaryDevice = MultiDeviceUtilitiesKt.getPrimaryDevicePublicKey(address.getNumber());
|
||||
SignalServiceAddress primaryAddress = primaryDevice == null ? address : new SignalServiceAddress(primaryDevice);
|
||||
// We also need to use the original message id and not -1
|
||||
syncMessage = new LokiSyncMessage(primaryAddress, templateMessageId);
|
||||
}
|
||||
return messageSender.sendMessage(messageId, address, unidentifiedAccess, textSecureMessage, Optional.fromNullable(syncMessage)).getSuccess().isUnidentified();
|
||||
}
|
||||
} catch (UnregisteredUserException e) {
|
||||
warn(TAG, "Failure", e);
|
||||
@ -241,7 +255,8 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
Address destination = Address.fromSerialized(data.getString(KEY_DESTINATION));
|
||||
boolean isFriendRequest = data.getBoolean(KEY_IS_FRIEND_REQUEST);
|
||||
String frMessage = data.hasString(KEY_CUSTOM_FR_MESSAGE) ? data.getString(KEY_CUSTOM_FR_MESSAGE) : null;
|
||||
return new PushTextSendJob(parameters, templateMessageID, messageID, destination, isFriendRequest, frMessage);
|
||||
boolean shouldSendSyncMessage = data.getBoolean(KEY_SHOULD_SEND_SYNC_MESSAGE);
|
||||
return new PushTextSendJob(parameters, templateMessageID, messageID, destination, isFriendRequest, frMessage, shouldSendSyncMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
22
src/org/thoughtcrime/securesms/loki/LokiMessageSyncEvent.kt
Normal file
22
src/org/thoughtcrime/securesms/loki/LokiMessageSyncEvent.kt
Normal file
@ -0,0 +1,22 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.support.v4.content.LocalBroadcastManager
|
||||
|
||||
object LokiMessageSyncEvent {
|
||||
const val MESSAGE_SYNC_EVENT = "com.loki-network.messenger.MESSAGE_SYNC_EVENT"
|
||||
const val MESSAGE_ID = "message_id"
|
||||
const val TIMESTAMP = "timestamp"
|
||||
const val SYNC_MESSAGE = "sync_message"
|
||||
const val TTL = "ttl"
|
||||
|
||||
fun broadcastSecurityUpdateEvent(context: Context, messageID: Long, timestamp: Long, message: ByteArray, ttl: Int) {
|
||||
val intent = Intent(MESSAGE_SYNC_EVENT)
|
||||
intent.putExtra(MESSAGE_ID, messageID)
|
||||
intent.putExtra(TIMESTAMP, timestamp)
|
||||
intent.putExtra(SYNC_MESSAGE, message)
|
||||
intent.putExtra(TTL, ttl)
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(intent)
|
||||
}
|
||||
}
|
@ -138,3 +138,68 @@ fun signAndSendPairingAuthorisationMessage(context: Context, pairingAuthorisatio
|
||||
Log.w("Loki", "Failed to update device mapping")
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldSendSycMessage(context: Context, address: Address): Boolean {
|
||||
if (address.isGroup || address.isEmail || address.isMmsGroup) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Don't send sync messages if it's our address
|
||||
val publicKey = address.serialize()
|
||||
if (publicKey == TextSecurePreferences.getLocalNumber(context)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val storageAPI = LokiStorageAPI.shared
|
||||
val future = SettableFuture<Boolean>()
|
||||
storageAPI.getPrimaryDevicePublicKey(publicKey).success { primaryDevicePublicKey ->
|
||||
val isOurPrimaryDevice = primaryDevicePublicKey != null && TextSecurePreferences.getMasterHexEncodedPublicKey(context) == publicKey
|
||||
// Don't send sync message if the primary device is the same as ours
|
||||
future.set(!isOurPrimaryDevice)
|
||||
}.fail {
|
||||
future.set(false)
|
||||
}
|
||||
|
||||
return try {
|
||||
future.get()
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun isOneOfOurDevices(context: Context, address: Address): Boolean {
|
||||
if (address.isGroup || address.isEmail || address.isMmsGroup) {
|
||||
return false
|
||||
}
|
||||
|
||||
val ourPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
val storageAPI = LokiStorageAPI.shared
|
||||
val future = SettableFuture<Boolean>()
|
||||
storageAPI.getAllDevicePublicKeys(ourPublicKey).success {
|
||||
future.set(it.contains(address.serialize()))
|
||||
}.fail {
|
||||
future.set(false)
|
||||
}
|
||||
|
||||
return try {
|
||||
future.get()
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun getPrimaryDevicePublicKey(hexEncodedPublicKey: String): String? {
|
||||
val storageAPI = LokiStorageAPI.shared
|
||||
val future = SettableFuture<String?>()
|
||||
storageAPI.getPrimaryDevicePublicKey(hexEncodedPublicKey).success {
|
||||
future.set(it)
|
||||
}.fail {
|
||||
future.set(null)
|
||||
}
|
||||
|
||||
return try {
|
||||
future.get()
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import org.thoughtcrime.securesms.database.Address
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType
|
||||
import org.thoughtcrime.securesms.jobmanager.Data
|
||||
import org.thoughtcrime.securesms.jobmanager.Job
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint
|
||||
import org.thoughtcrime.securesms.jobs.BaseJob
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
class PushMessageSyncSendJob private constructor(
|
||||
parameters: Parameters,
|
||||
private val messageID: Long,
|
||||
private val recipient: Address,
|
||||
private val timestamp: Long,
|
||||
private val message: ByteArray,
|
||||
private val ttl: Int
|
||||
) : BaseJob(parameters), InjectableType {
|
||||
|
||||
companion object {
|
||||
const val KEY = "PushMessageSyncSendJob"
|
||||
|
||||
private val TAG = PushMessageSyncSendJob::class.java.simpleName
|
||||
|
||||
private val KEY_MESSAGE_ID = "message_id"
|
||||
private val KEY_RECIPIENT = "recipient"
|
||||
private val KEY_TIMESTAMP = "timestamp"
|
||||
private val KEY_MESSAGE = "message"
|
||||
private val KEY_TTL = "ttl"
|
||||
}
|
||||
|
||||
@Inject
|
||||
lateinit var messageSender: SignalServiceMessageSender
|
||||
|
||||
constructor(messageID: Long, recipient: Address, timestamp: Long, message: ByteArray, ttl: Int) : this(Parameters.Builder()
|
||||
.addConstraint(NetworkConstraint.KEY)
|
||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
||||
.setMaxAttempts(3)
|
||||
.build(),
|
||||
messageID, recipient, timestamp, message, ttl)
|
||||
|
||||
override fun serialize(): Data {
|
||||
return Data.Builder()
|
||||
.putLong(KEY_MESSAGE_ID, messageID)
|
||||
.putString(KEY_RECIPIENT, recipient.serialize())
|
||||
.putLong(KEY_TIMESTAMP, timestamp)
|
||||
.putByteArray(KEY_MESSAGE, message)
|
||||
.putInt(KEY_TTL, ttl)
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun getFactoryKey(): String {
|
||||
return KEY
|
||||
}
|
||||
|
||||
@Throws(IOException::class, UntrustedIdentityException::class)
|
||||
public override fun onRun() {
|
||||
// Don't send sync messages to a group
|
||||
if (recipient.isGroup || recipient.isEmail) { return }
|
||||
messageSender.lokiSendSyncMessage(messageID, SignalServiceAddress(recipient.toPhoneString()), timestamp, message, ttl)
|
||||
}
|
||||
|
||||
public override fun onShouldRetry(e: Exception): Boolean {
|
||||
// Loki - Disable since we have our own retrying when sending messages
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onCanceled() {}
|
||||
|
||||
class Factory : Job.Factory<PushMessageSyncSendJob> {
|
||||
override fun create(parameters: Parameters, data: Data): PushMessageSyncSendJob {
|
||||
try {
|
||||
return PushMessageSyncSendJob(parameters,
|
||||
data.getLong(KEY_MESSAGE_ID),
|
||||
Address.fromSerialized(data.getString(KEY_RECIPIENT)),
|
||||
data.getLong(KEY_TIMESTAMP),
|
||||
data.getByteArray(KEY_MESSAGE),
|
||||
data.getInt(KEY_TTL))
|
||||
} catch (e: IOException) {
|
||||
throw AssertionError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,20 +3,17 @@ package org.thoughtcrime.securesms.push;
|
||||
import android.content.Context;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.loki.LokiMessageSyncEvent;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
public class SecurityEventListener implements SignalServiceMessageSender.EventListener {
|
||||
public class MessageSenderEventListener implements SignalServiceMessageSender.EventListener {
|
||||
|
||||
private static final String TAG = SecurityEventListener.class.getSimpleName();
|
||||
private static final String TAG = MessageSenderEventListener.class.getSimpleName();
|
||||
|
||||
private final Context context;
|
||||
|
||||
public SecurityEventListener(Context context) {
|
||||
public MessageSenderEventListener(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
@ -24,4 +21,9 @@ public class SecurityEventListener implements SignalServiceMessageSender.EventLi
|
||||
public void onSecurityEvent(SignalServiceAddress textSecureAddress) {
|
||||
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSyncEvent(long messageID, long timestamp, byte[] message, int ttl) {
|
||||
LokiMessageSyncEvent.INSTANCE.broadcastSecurityUpdateEvent(context, messageID, timestamp, message, ttl);
|
||||
}
|
||||
}
|
@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.GeneralUtilitiesKt;
|
||||
import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt;
|
||||
import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.push.AccountManagerFactory;
|
||||
@ -149,6 +150,28 @@ public class MessageSender {
|
||||
return allocatedThreadId;
|
||||
}
|
||||
|
||||
public static void sendSyncMessageToOurDevices(final Context context,
|
||||
final long messageID,
|
||||
final long timestamp,
|
||||
final byte[] message,
|
||||
final int ttl) {
|
||||
String ourPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared();
|
||||
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
|
||||
|
||||
storageAPI.getAllDevicePublicKeys(ourPublicKey).success(devices -> {
|
||||
for (String device : devices) {
|
||||
// Don't send to ourselves
|
||||
if (device.equals(ourPublicKey)) { continue; }
|
||||
|
||||
// Create a send job for our device
|
||||
Address address = Address.fromSerialized(device);
|
||||
jobManager.add(new PushMessageSyncSendJob(messageID, address, timestamp, message, ttl));
|
||||
}
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
public static void resendGroupMessage(Context context, MessageRecord messageRecord, Address filterAddress) {
|
||||
if (!messageRecord.isMms()) throw new AssertionError("Not Group");
|
||||
sendGroupPush(context, messageRecord.getRecipient(), messageRecord.getId(), filterAddress);
|
||||
@ -204,22 +227,27 @@ public class MessageSender {
|
||||
jobManager.add(new PushTextSendJob(messageId, recipient.getAddress()));
|
||||
return;
|
||||
}
|
||||
boolean[] hasSentSyncMessage = { false };
|
||||
|
||||
MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, recipientPublicKey, storageAPI, (devicePublicKey, isFriend, friendCount) -> {
|
||||
Address address = Address.fromSerialized(devicePublicKey);
|
||||
long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L;
|
||||
|
||||
if (isFriend) {
|
||||
// Send a normal message if the user is friends with the recipient
|
||||
jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address));
|
||||
} else {
|
||||
// Send friend requests to non friends. If the user is friends with any
|
||||
// of the devices then send out a default friend request message.
|
||||
boolean isFriendsWithAny = (friendCount > 0);
|
||||
String defaultFriendRequestMessage = isFriendsWithAny ? "Accept this friend request to enable messages to be synced across devices" : null;
|
||||
jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address, true, defaultFriendRequestMessage));
|
||||
}
|
||||
Util.runOnMain(() -> {
|
||||
Address address = Address.fromSerialized(devicePublicKey);
|
||||
long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L;
|
||||
|
||||
if (isFriend) {
|
||||
// Send a normal message if the user is friends with the recipient
|
||||
// We should also send a sync message if we haven't already sent one
|
||||
boolean shouldSendSyncMessage = !hasSentSyncMessage[0] && MultiDeviceUtilitiesKt.shouldSendSycMessage(context, address);
|
||||
jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address, shouldSendSyncMessage));
|
||||
hasSentSyncMessage[0] = shouldSendSyncMessage;
|
||||
} else {
|
||||
// Send friend requests to non friends. If the user is friends with any
|
||||
// of the devices then send out a default friend request message.
|
||||
boolean isFriendsWithAny = (friendCount > 0);
|
||||
String defaultFriendRequestMessage = isFriendsWithAny ? "Accept this friend request to enable messages to be synced across devices" : null;
|
||||
jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address, true, defaultFriendRequestMessage, false));
|
||||
}
|
||||
});
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
@ -231,25 +259,31 @@ public class MessageSender {
|
||||
// Just send the message normally if it's a group message
|
||||
String recipientPublicKey = recipient.getAddress().serialize();
|
||||
if (GeneralUtilitiesKt.isPublicChat(context, recipientPublicKey)) {
|
||||
PushMediaSendJob.enqueue(context, jobManager, messageId, recipient.getAddress());
|
||||
PushMediaSendJob.enqueue(context, jobManager, messageId, recipient.getAddress(), false);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean[] hasSentSyncMessage = { false };
|
||||
|
||||
MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, recipientPublicKey, storageAPI, (devicePublicKey, isFriend, friendCount) -> {
|
||||
Address address = Address.fromSerialized(devicePublicKey);
|
||||
long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L;
|
||||
|
||||
if (isFriend) {
|
||||
// Send a normal message if the user is friends with the recipient
|
||||
PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address);
|
||||
} else {
|
||||
// Send friend requests to non friends. If the user is friends with any
|
||||
// of the devices then send out a default friend request message.
|
||||
boolean isFriendsWithAny = friendCount > 0;
|
||||
String defaultFriendRequestMessage = isFriendsWithAny ? "Accept this friend request to enable messages to be synced across devices" : null;
|
||||
PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address, true, defaultFriendRequestMessage);
|
||||
}
|
||||
Util.runOnMain(() -> {
|
||||
Address address = Address.fromSerialized(devicePublicKey);
|
||||
long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L;
|
||||
|
||||
if (isFriend) {
|
||||
// Send a normal message if the user is friends with the recipient
|
||||
// We should also send a sync message if we haven't already sent one
|
||||
boolean shouldSendSyncMessage = !hasSentSyncMessage[0] && MultiDeviceUtilitiesKt.shouldSendSycMessage(context, address);
|
||||
PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address, shouldSendSyncMessage);
|
||||
hasSentSyncMessage[0] = shouldSendSyncMessage;
|
||||
} else {
|
||||
// Send friend requests to non friends. If the user is friends with any
|
||||
// of the devices then send out a default friend request message.
|
||||
boolean isFriendsWithAny = friendCount > 0;
|
||||
String defaultFriendRequestMessage = isFriendsWithAny ? "Accept this friend request to enable messages to be synced across devices" : null;
|
||||
PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address, true, defaultFriendRequestMessage, false);
|
||||
}
|
||||
});
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user