mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-24 02:25:19 +00:00
Use promises instead of blocking the thread.
This commit is contained in:
parent
bdc0ed36eb
commit
789aa244b5
@ -91,7 +91,7 @@ public class TypingStatusSender {
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(threadId, typingStarted));
|
||||
return;
|
||||
}
|
||||
LokiStorageAPI.shared.getAllDevicePublicKeysAsync(recipient.getAddress().serialize()).success(devices -> {
|
||||
LokiStorageAPI.shared.getAllDevicePublicKeys(recipient.getAddress().serialize()).success(devices -> {
|
||||
for (String device : devices) {
|
||||
Recipient deviceRecipient = Recipient.from(context, Address.fromSerialized(device), false);
|
||||
long deviceThreadID = threadDatabase.getThreadIdIfExistsFor(deviceRecipient);
|
||||
|
@ -127,6 +127,7 @@ import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher;
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
||||
import org.thoughtcrime.securesms.crypto.SecurityEvent;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.Database;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.DraftDatabase;
|
||||
import org.thoughtcrime.securesms.database.DraftDatabase.Draft;
|
||||
@ -2192,7 +2193,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
if (threadID != this.threadId) {
|
||||
Recipient threadRecipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID);
|
||||
if (threadRecipient != null && !threadRecipient.isGroupRecipient()) {
|
||||
LokiStorageAPI.shared.getAllDevicePublicKeysAsync(threadRecipient.getAddress().serialize()).success(devices -> {
|
||||
LokiStorageAPI.shared.getAllDevicePublicKeys(threadRecipient.getAddress().serialize()).success(devices -> {
|
||||
// We should update our input if this thread is a part of the other threads device
|
||||
if (devices.contains(recipient.getAddress().serialize())) {
|
||||
this.updateInputPanel();
|
||||
@ -2212,10 +2213,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
return;
|
||||
}
|
||||
|
||||
task(() -> {
|
||||
// Run the functions below in a background thread since they are blocking
|
||||
return MultiDeviceUtilities.isFriendsWithAnyLinkedDevice(this, recipient) || !hasPendingFriendRequestWithAnyLinkedDevice();
|
||||
}).success(shouldEnableInput -> {
|
||||
// It could take a while before our promise resolves, so we assume the best case
|
||||
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(this).getFriendRequestStatus(threadId);
|
||||
boolean isPending = friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENDING || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED;
|
||||
setInputPanelEnabled(!isPending);
|
||||
|
||||
// This promise correctly updates the UI for multidevice
|
||||
MultiDeviceUtilities.shouldEnableUserInput(this, recipient).success(shouldEnableInput -> {
|
||||
setInputPanelEnabled(shouldEnableInput);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
@ -3054,20 +3058,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
updateInputPanel();
|
||||
}
|
||||
|
||||
public boolean hasPendingFriendRequestWithAnyLinkedDevice() {
|
||||
if (recipient.isGroupRecipient()) return false;
|
||||
|
||||
// This call will block the thread that is being run on! be careful
|
||||
Map<String, LokiThreadFriendRequestStatus> map = MultiDeviceUtilities.getAllDeviceFriendRequestStatuses(this, recipient.getAddress().serialize());
|
||||
for (LokiThreadFriendRequestStatus status : map.values()) {
|
||||
if (status == LokiThreadFriendRequestStatus.REQUEST_SENDING || status == LokiThreadFriendRequestStatus.REQUEST_SENT || status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isNoteToSelf() {
|
||||
return TextSecurePreferences.getLocalNumber(this).equalsIgnoreCase(recipient.getAddress().serialize());
|
||||
}
|
||||
|
@ -134,6 +134,7 @@ import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestS
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiServiceMessage;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadSessionResetStatus;
|
||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.SecureRandom;
|
||||
@ -1094,15 +1095,19 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
// it must be a friend request accepted message. Declining a friend request doesn't send a message.
|
||||
lokiThreadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS);
|
||||
// Update the last message if needed
|
||||
String primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(pubKey);
|
||||
long primaryDeviceThreadID = primaryDevice == null ? threadID : DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(primaryDevice), false));
|
||||
FriendRequestHandler.updateLastFriendRequestMessage(context, primaryDeviceThreadID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED);
|
||||
LokiStorageAPI.shared.getPrimaryDevicePublicKey(pubKey).success(primaryDevice -> {
|
||||
Util.runOnMain(() -> {
|
||||
long primaryDeviceThreadID = primaryDevice == null ? threadID : DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(primaryDevice), false));
|
||||
FriendRequestHandler.updateLastFriendRequestMessage(context, primaryDeviceThreadID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED);
|
||||
});
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
private void updateFriendRequestStatusIfNeeded(@NonNull SignalServiceEnvelope envelope, @NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) {
|
||||
if (!envelope.isFriendRequest() || isGroupChatMessage(message)) { return; }
|
||||
// This handles the case where another user sends us a regular message without authorisation
|
||||
boolean shouldBecomeFriends = MultiDeviceUtilities.shouldAutomaticallyBecomeFriendsWithDevice(content.getSender(), context);
|
||||
boolean shouldBecomeFriends = PromiseUtil.get(MultiDeviceUtilities.shouldAutomaticallyBecomeFriendsWithDevice(content.getSender(), context), false);
|
||||
if (shouldBecomeFriends) {
|
||||
// Become friends AND update the message they sent
|
||||
becomeFriendsWithContact(content.getSender());
|
||||
@ -1113,9 +1118,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
Recipient originalRecipient = getMessageDestination(content, message);
|
||||
Recipient primaryDeviceRecipient = getMessagePrimaryDestination(content, message);
|
||||
LokiThreadDatabase lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context);
|
||||
SmsDatabase smsMessageDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
MmsDatabase mmsMessageDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||
LokiMessageDatabase lokiMessageDatabase= DatabaseFactory.getLokiMessageDatabase(context);
|
||||
|
||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(originalRecipient);
|
||||
long primaryDeviceThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(primaryDeviceRecipient);
|
||||
@ -1532,7 +1534,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
private Recipient getPrimaryDeviceRecipient(String recipient) {
|
||||
try {
|
||||
String primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(recipient);
|
||||
String primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(recipient).get();
|
||||
String publicKey = (primaryDevice != null) ? primaryDevice : recipient;
|
||||
// If the public key matches our primary device then we need to forward the message to ourselves (Note to self)
|
||||
String ourPrimaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
|
||||
@ -1593,10 +1595,16 @@ 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 = MultiDeviceUtilities.isOneOfOurDevices(context, sender.getAddress());
|
||||
if (!isOurDevice) { Log.w(TAG, "Got a sync message from a device that is not ours!."); }
|
||||
return !isOurDevice;
|
||||
try {
|
||||
// We should ignore a sync message if the sender is not one of our devices
|
||||
boolean isOurDevice = MultiDeviceUtilities.isOneOfOurDevices(context, sender.getAddress()).get();
|
||||
if (!isOurDevice) {
|
||||
Log.w(TAG, "Got a sync message from a device that is not ours!.");
|
||||
}
|
||||
return !isOurDevice;
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -45,6 +45,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage;
|
||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
@ -281,7 +282,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
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 = LokiStorageAPI.shared.getPrimaryDevicePublicKey(address.getNumber());
|
||||
String primaryDevice = PromiseUtil.get(LokiStorageAPI.shared.getPrimaryDevicePublicKey(address.getNumber()), null);
|
||||
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);
|
||||
|
@ -32,6 +32,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage;
|
||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@ -232,7 +233,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
||||
LokiSyncMessage syncMessage = null;
|
||||
if (shouldSendSyncMessage) {
|
||||
// Set the sync message destination to the primary device, this way it will show that we sent a message to the primary device and not a secondary device
|
||||
String primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(address.getNumber());
|
||||
String primaryDevice = PromiseUtil.get(LokiStorageAPI.shared.getPrimaryDevicePublicKey(address.getNumber()), null);
|
||||
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);
|
||||
|
@ -20,6 +20,7 @@ import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage.Action;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -98,7 +99,10 @@ public class TypingSendJob extends BaseJob implements InjectableType {
|
||||
SignalServiceTypingMessage typingMessage = new SignalServiceTypingMessage(typing ? Action.STARTED : Action.STOPPED, System.currentTimeMillis(), groupId);
|
||||
|
||||
// Loki - Don't send typing indicators in group chats or to ourselves
|
||||
if (!recipient.isGroupRecipient() && !MultiDeviceUtilities.isOneOfOurDevices(context, recipient.getAddress())) {
|
||||
if (recipient.isGroupRecipient()) { return; }
|
||||
|
||||
boolean isOurDevice = PromiseUtil.get(MultiDeviceUtilities.isOneOfOurDevices(context, recipient.getAddress()), false);
|
||||
if (!isOurDevice) {
|
||||
messageSender.sendTyping(0, addresses, unidentifiedAccess, typingMessage);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import nl.komponents.kovenant.Promise
|
||||
import nl.komponents.kovenant.ui.alwaysUi
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import org.whispersystems.signalservice.loki.api.LokiStorageAPI
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
|
||||
@ -34,8 +35,10 @@ object FriendRequestHandler {
|
||||
if (type == ActionType.Sending) {
|
||||
// We only want to update message status if we aren't friends with another of their devices
|
||||
// This avoids spam in the ui where it would keep telling the user that they sent a friend request on every single message
|
||||
if (!isFriendsWithAnyLinkedDevice(context, recipient) && friendRequestStatus == LokiMessageFriendRequestStatus.NONE) {
|
||||
messageDatabase.setFriendRequestStatus(messageId, LokiMessageFriendRequestStatus.REQUEST_SENDING)
|
||||
isFriendsWithAnyLinkedDevice(context, recipient).successUi { isFriends ->
|
||||
if (!isFriends && friendRequestStatus == LokiMessageFriendRequestStatus.NONE) {
|
||||
messageDatabase.setFriendRequestStatus(messageId, LokiMessageFriendRequestStatus.REQUEST_SENDING)
|
||||
}
|
||||
}
|
||||
} else if (friendRequestStatus != LokiMessageFriendRequestStatus.NONE) {
|
||||
// Update the friend request status of the message if we have it
|
||||
@ -70,23 +73,25 @@ object FriendRequestHandler {
|
||||
// We only want to update the last message status if we're not friends with any of their linked devices
|
||||
// This ensures that we don't spam the UI with accept/decline messages
|
||||
val recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId) ?: return
|
||||
if (isFriendsWithAnyLinkedDevice(context, recipient)) { return }
|
||||
isFriendsWithAnyLinkedDevice(context, recipient).successUi { isFriends ->
|
||||
if (isFriends) { return@successUi }
|
||||
|
||||
// Since messages are forwarded to the primary device thread, we need to update it there
|
||||
val messageCount = smsMessageDatabase.getMessageCountForThread(threadId)
|
||||
val messageID = smsMessageDatabase.getIDForMessageAtIndex(threadId, messageCount - 1) // The message that was just received
|
||||
if (messageID < 0) { return }
|
||||
// Since messages are forwarded to the primary device thread, we need to update it there
|
||||
val messageCount = smsMessageDatabase.getMessageCountForThread(threadId)
|
||||
val messageID = smsMessageDatabase.getIDForMessageAtIndex(threadId, messageCount - 1) // The message that was just received
|
||||
if (messageID < 0) { return@successUi }
|
||||
|
||||
val messageDatabase = DatabaseFactory.getLokiMessageDatabase(context)
|
||||
val messageDatabase = DatabaseFactory.getLokiMessageDatabase(context)
|
||||
|
||||
// We need to go through and set all messages which are REQUEST_PENDING to NONE
|
||||
smsMessageDatabase.getAllMessageIDs(threadId)
|
||||
.filter { messageDatabase.getFriendRequestStatus(it) == LokiMessageFriendRequestStatus.REQUEST_PENDING }
|
||||
.forEach {
|
||||
messageDatabase.setFriendRequestStatus(it, LokiMessageFriendRequestStatus.NONE)
|
||||
}
|
||||
// We need to go through and set all messages which are REQUEST_PENDING to NONE
|
||||
smsMessageDatabase.getAllMessageIDs(threadId)
|
||||
.filter { messageDatabase.getFriendRequestStatus(it) == LokiMessageFriendRequestStatus.REQUEST_PENDING }
|
||||
.forEach {
|
||||
messageDatabase.setFriendRequestStatus(it, LokiMessageFriendRequestStatus.NONE)
|
||||
}
|
||||
|
||||
// Set the last message to pending
|
||||
messageDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_PENDING)
|
||||
// Set the last message to pending
|
||||
messageDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_PENDING)
|
||||
}
|
||||
}
|
||||
}
|
@ -3,9 +3,9 @@ package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import nl.komponents.kovenant.Promise
|
||||
import nl.komponents.kovenant.*
|
||||
import nl.komponents.kovenant.functional.bind
|
||||
import nl.komponents.kovenant.functional.map
|
||||
import nl.komponents.kovenant.toFailVoid
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||
import org.thoughtcrime.securesms.database.Address
|
||||
@ -20,28 +20,26 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
||||
import org.whispersystems.signalservice.loki.api.LokiStorageAPI
|
||||
import org.whispersystems.signalservice.loki.api.PairingAuthorisation
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus
|
||||
import org.whispersystems.signalservice.loki.utilities.recover
|
||||
import org.whispersystems.signalservice.loki.utilities.retryIfNeeded
|
||||
|
||||
/*
|
||||
All functions within this class, excluding the ones which return promises, BLOCK the thread! Don't run them on the main thread!
|
||||
*/
|
||||
|
||||
fun getAllDeviceFriendRequestStatuses(context: Context, hexEncodedPublicKey: String): Map<String, LokiThreadFriendRequestStatus> {
|
||||
fun getAllDeviceFriendRequestStatuses(context: Context, hexEncodedPublicKey: String): Promise<Map<String, LokiThreadFriendRequestStatus>, Exception> {
|
||||
val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context)
|
||||
val keys = LokiStorageAPI.shared.getAllDevicePublicKeys(hexEncodedPublicKey)
|
||||
val map = mutableMapOf<String, LokiThreadFriendRequestStatus>()
|
||||
for (devicePublicKey in keys) {
|
||||
val device = Recipient.from(context, Address.fromSerialized(devicePublicKey), false)
|
||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(device)
|
||||
val friendRequestStatus = if (threadID < 0) LokiThreadFriendRequestStatus.NONE else lokiThreadDatabase.getFriendRequestStatus(threadID)
|
||||
map[devicePublicKey] = friendRequestStatus
|
||||
}
|
||||
return map
|
||||
return LokiStorageAPI.shared.getAllDevicePublicKeys(hexEncodedPublicKey).map { keys ->
|
||||
val map = mutableMapOf<String, LokiThreadFriendRequestStatus>()
|
||||
for (devicePublicKey in keys) {
|
||||
val device = Recipient.from(context, Address.fromSerialized(devicePublicKey), false)
|
||||
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(device)
|
||||
val friendRequestStatus = if (threadID < 0) LokiThreadFriendRequestStatus.NONE else lokiThreadDatabase.getFriendRequestStatus(threadID)
|
||||
map[devicePublicKey] = friendRequestStatus
|
||||
}
|
||||
map
|
||||
}.recover { mutableMapOf() }
|
||||
}
|
||||
|
||||
fun getAllDevicePublicKeysWithFriendStatus(context: Context, hexEncodedPublicKey: String): Promise<Map<String, Boolean>, Unit> {
|
||||
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
return LokiStorageAPI.shared.getAllDevicePublicKeysAsync(hexEncodedPublicKey).map { keys ->
|
||||
return LokiStorageAPI.shared.getAllDevicePublicKeys(hexEncodedPublicKey).map { keys ->
|
||||
val devices = keys.toMutableSet()
|
||||
if (hexEncodedPublicKey != userHexEncodedPublicKey) {
|
||||
devices.remove(userHexEncodedPublicKey)
|
||||
@ -59,22 +57,31 @@ fun getFriendCount(context: Context, devices: Set<String>): Int {
|
||||
return getFriendPublicKeys(context, devices).count()
|
||||
}
|
||||
|
||||
fun shouldAutomaticallyBecomeFriendsWithDevice(publicKey: String, context: Context): Boolean {
|
||||
fun shouldAutomaticallyBecomeFriendsWithDevice(publicKey: String, context: Context): Promise<Boolean, Exception> {
|
||||
val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context)
|
||||
val storageAPI = LokiStorageAPI.shared
|
||||
|
||||
// If the public key doesn't have any other devices then go through regular friend request logic
|
||||
val primaryDevicePublicKey = storageAPI.getPrimaryDevicePublicKey(publicKey) ?: return false
|
||||
|
||||
// If this is one of our devices then we should become friends
|
||||
if (isOneOfOurDevices(context, publicKey)) {
|
||||
return true
|
||||
// If this public key is our primary device then we should become friends
|
||||
if (publicKey == TextSecurePreferences.getMasterHexEncodedPublicKey(context)) {
|
||||
return Promise.of(true)
|
||||
}
|
||||
|
||||
// If we are friends with the primary device then we should become friends
|
||||
val primaryDevice = Recipient.from(context, Address.fromSerialized(primaryDevicePublicKey), false)
|
||||
val primaryDeviceThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(primaryDevice)
|
||||
return primaryDeviceThreadID >= 0 && lokiThreadDatabase.getFriendRequestStatus(primaryDeviceThreadID) == LokiThreadFriendRequestStatus.FRIENDS
|
||||
return storageAPI.getPrimaryDevicePublicKey(publicKey).map { primaryDevicePublicKey ->
|
||||
// If the public key doesn't have any other devices then go through regular friend request logic
|
||||
if (primaryDevicePublicKey == null) {
|
||||
return@map false
|
||||
}
|
||||
|
||||
// If the primary device public key matches our primary device then we should become friends since this is our other device
|
||||
if (primaryDevicePublicKey == TextSecurePreferences.getMasterHexEncodedPublicKey(context)) {
|
||||
return@map true
|
||||
}
|
||||
|
||||
// If we are friends with the primary device then we should become friends
|
||||
val primaryDevice = Recipient.from(context, Address.fromSerialized(primaryDevicePublicKey), false)
|
||||
val primaryDeviceThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(primaryDevice)
|
||||
primaryDeviceThreadID >= 0 && lokiThreadDatabase.getFriendRequestStatus(primaryDeviceThreadID) == LokiThreadFriendRequestStatus.FRIENDS
|
||||
}
|
||||
}
|
||||
|
||||
fun sendPairingAuthorisationMessage(context: Context, contactHexEncodedPublicKey: String, authorisation: PairingAuthorisation): Promise<Unit, Exception> {
|
||||
@ -125,37 +132,55 @@ fun signAndSendPairingAuthorisationMessage(context: Context, pairingAuthorisatio
|
||||
|
||||
}
|
||||
|
||||
fun shouldSendSycMessage(context: Context, address: Address): Boolean {
|
||||
fun shouldSendSycMessage(context: Context, address: Address): Promise<Boolean, Exception> {
|
||||
if (address.isGroup || address.isEmail || address.isMmsGroup) {
|
||||
return false
|
||||
return Promise.of(false)
|
||||
}
|
||||
|
||||
// Don't send sync messages if it's one of our devices
|
||||
return !isOneOfOurDevices(context, address)
|
||||
return isOneOfOurDevices(context, address).map { !it }
|
||||
}
|
||||
|
||||
fun isOneOfOurDevices(context: Context, publicKey: String): Boolean {
|
||||
return isOneOfOurDevices(context, Address.fromSerialized(publicKey))
|
||||
}
|
||||
|
||||
fun isOneOfOurDevices(context: Context, address: Address): Boolean {
|
||||
fun isOneOfOurDevices(context: Context, address: Address): Promise<Boolean, Exception> {
|
||||
if (address.isGroup || address.isEmail || address.isMmsGroup) {
|
||||
return false
|
||||
return Promise.of(false)
|
||||
}
|
||||
|
||||
val ourPublicKey = TextSecurePreferences.getLocalNumber(context)
|
||||
val devices = LokiStorageAPI.shared.getAllDevicePublicKeys(ourPublicKey)
|
||||
return devices.contains(address.serialize())
|
||||
return LokiStorageAPI.shared.getAllDevicePublicKeys(ourPublicKey).map { devices ->
|
||||
devices.contains(address.serialize())
|
||||
}
|
||||
}
|
||||
|
||||
fun isFriendsWithAnyLinkedDevice(context: Context, recipient: Recipient): Boolean {
|
||||
if (recipient.isGroupRecipient) return true
|
||||
fun isFriendsWithAnyLinkedDevice(context: Context, recipient: Recipient): Promise<Boolean, Exception> {
|
||||
if (recipient.isGroupRecipient) { return Promise.of(true) }
|
||||
|
||||
val map = getAllDeviceFriendRequestStatuses(context, recipient.address.serialize())
|
||||
for (status in map.values) {
|
||||
if (status == LokiThreadFriendRequestStatus.FRIENDS) {
|
||||
return true
|
||||
return getAllDeviceFriendRequestStatuses(context, recipient.address.serialize()).map { map ->
|
||||
for (status in map.values) {
|
||||
if (status == LokiThreadFriendRequestStatus.FRIENDS) {
|
||||
return@map true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun hasPendingFriendRequestWithAnyLinkedDevice(context: Context, recipient: Recipient): Promise<Boolean, Exception> {
|
||||
if (recipient.isGroupRecipient) { return Promise.of(false) }
|
||||
|
||||
return getAllDeviceFriendRequestStatuses(context, recipient.address.serialize()).map { map ->
|
||||
for (status in map.values) {
|
||||
if (status == LokiThreadFriendRequestStatus.REQUEST_SENDING || status == LokiThreadFriendRequestStatus.REQUEST_SENT || status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
|
||||
return@map true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun shouldEnableUserInput(context: Context, recipient: Recipient): Promise<Boolean, Exception> {
|
||||
// Input should be enabled if we don't have any pending requests OR we're friends with any linked device
|
||||
return hasPendingFriendRequestWithAnyLinkedDevice(context, recipient).bind { hasPendingFriendRequest ->
|
||||
if (!hasPendingFriendRequest) Promise.of(true) else isFriendsWithAnyLinkedDevice(context, recipient)
|
||||
}.recover { true }
|
||||
}
|
||||
|
@ -61,12 +61,15 @@ import org.whispersystems.signalservice.api.push.ContactTokenDetails;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus;
|
||||
import org.whispersystems.signalservice.loki.utilities.PromiseUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import kotlin.Unit;
|
||||
import nl.komponents.kovenant.Kovenant;
|
||||
import nl.komponents.kovenant.Promise;
|
||||
|
||||
public class MessageSender {
|
||||
|
||||
@ -79,20 +82,24 @@ public class MessageSender {
|
||||
sendBackgroundMessage(context, contactHexEncodedPublicKey);
|
||||
|
||||
// Go through the other devices and only send background messages if we're friends or we have received friend request
|
||||
Set<String> devices = LokiStorageAPI.shared.getAllDevicePublicKeys(contactHexEncodedPublicKey);
|
||||
for (String device : devices) {
|
||||
// Don't send message to the device we already have sent to
|
||||
if (device.equals(contactHexEncodedPublicKey)) { continue; }
|
||||
Recipient recipient = Recipient.from(context, Address.fromSerialized(device), false);
|
||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient);
|
||||
if (threadID < 0) { continue; }
|
||||
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
|
||||
if (friendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
|
||||
sendBackgroundMessage(context, device);
|
||||
}
|
||||
LokiStorageAPI.shared.getAllDevicePublicKeys(contactHexEncodedPublicKey).success(devices -> {
|
||||
Util.runOnMain(() -> {
|
||||
for (String device : devices) {
|
||||
// Don't send message to the device we already have sent to
|
||||
if (device.equals(contactHexEncodedPublicKey)) { continue; }
|
||||
Recipient recipient = Recipient.from(context, Address.fromSerialized(device), false);
|
||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient);
|
||||
if (threadID < 0) { continue; }
|
||||
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
|
||||
if (friendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) {
|
||||
sendBackgroundMessage(context, device);
|
||||
}
|
||||
|
||||
// TODO: Do we want to send a custom FR Message if we're not friends and we haven't received a friend request?
|
||||
}
|
||||
// TODO: Do we want to send a custom FR Message if we're not friends and we haven't received a friend request?
|
||||
}
|
||||
});
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
public static void sendBackgroundMessage(Context context, String contactHexEncodedPublicKey) {
|
||||
@ -199,15 +206,19 @@ public class MessageSender {
|
||||
final int ttl) {
|
||||
String ourPublicKey = TextSecurePreferences.getLocalNumber(context);
|
||||
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
|
||||
Set<String> devices = LokiStorageAPI.shared.getAllDevicePublicKeys(ourPublicKey);
|
||||
for (String device : devices) {
|
||||
// Don't send to ourselves
|
||||
if (device.equals(ourPublicKey)) { continue; }
|
||||
LokiStorageAPI.shared.getAllDevicePublicKeys(ourPublicKey).success(devices -> {
|
||||
Util.runOnMain(() -> {
|
||||
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));
|
||||
}
|
||||
// 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) {
|
||||
@ -267,9 +278,8 @@ public class MessageSender {
|
||||
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
|
||||
|
||||
// Just send the message normally if it's a group message or we're sending to one of our devices
|
||||
// TODO: Test how badly this will block the thread
|
||||
String recipientPublicKey = recipient.getAddress().serialize();
|
||||
if (GeneralUtilitiesKt.isPublicChat(context, recipientPublicKey) || MultiDeviceUtilities.isOneOfOurDevices(context, recipient.getAddress())) {
|
||||
if (GeneralUtilitiesKt.isPublicChat(context, recipientPublicKey) || PromiseUtil.get(MultiDeviceUtilities.isOneOfOurDevices(context, recipient.getAddress()), false)) {
|
||||
if (type == MessageType.MEDIA) {
|
||||
PushMediaSendJob.enqueue(context, jobManager, messageId, recipient.getAddress(), false);
|
||||
} else {
|
||||
@ -292,13 +302,24 @@ public class MessageSender {
|
||||
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] && MultiDeviceUtilities.shouldSendSycMessage(context, address);
|
||||
if (type == MessageType.MEDIA) {
|
||||
PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address, shouldSendSyncMessage);
|
||||
} else {
|
||||
jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address, shouldSendSyncMessage));
|
||||
Promise<Boolean, Exception> promise = Promise.Companion.of(false, Kovenant.INSTANCE.getContext());
|
||||
if (!hasSentSyncMessage[0]) {
|
||||
promise = MultiDeviceUtilities.shouldSendSycMessage(context, address).success(value -> {
|
||||
hasSentSyncMessage[0] = value;
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
hasSentSyncMessage[0] = shouldSendSyncMessage;
|
||||
|
||||
promise.success(shouldSendSyncMessage -> {
|
||||
Util.runOnMain(() -> {
|
||||
if (type == MessageType.MEDIA) {
|
||||
PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address, shouldSendSyncMessage);
|
||||
} else {
|
||||
jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address, shouldSendSyncMessage));
|
||||
}
|
||||
});
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
} 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.
|
||||
|
Loading…
Reference in New Issue
Block a user