From 7ff7c36e27b00204f933e858aff71c08e5ab2c6a Mon Sep 17 00:00:00 2001 From: Mikunj Date: Wed, 30 Oct 2019 09:59:11 +1100 Subject: [PATCH] Cleanup code. --- .../ApplicationPreferencesActivity.java | 4 +- .../components/TypingStatusSender.java | 13 +- .../conversation/ConversationActivity.java | 42 ++--- .../securesms/database/Address.java | 2 +- .../securesms/jobs/PushDecryptJob.java | 36 +--- .../securesms/jobs/PushMediaSendJob.java | 5 +- .../securesms/jobs/PushTextSendJob.java | 5 +- .../securesms/jobs/TypingSendJob.java | 4 +- .../securesms/loki/MultiDeviceUtilities.kt | 173 ++++-------------- .../notifications/MarkReadReceiver.java | 14 +- .../securesms/sms/MessageSender.java | 145 +++++++-------- 11 files changed, 156 insertions(+), 287 deletions(-) diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index 279db687a3..b7f5b797de 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -44,7 +44,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.loki.DeviceLinkingDialog; import org.thoughtcrime.securesms.loki.DeviceLinkingDialogDelegate; import org.thoughtcrime.securesms.loki.DeviceLinkingView; -import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt; +import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.loki.QRCodeDialog; import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment; import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment; @@ -394,7 +394,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA } @Override public void sendPairingAuthorizedMessage(@NotNull PairingAuthorisation pairingAuthorisation) { - MultiDeviceUtilitiesKt.signAndSendPairingAuthorisationMessage(context, pairingAuthorisation); + MultiDeviceUtilities.signAndSendPairingAuthorisationMessage(context, pairingAuthorisation); } @Override public void handleDeviceLinkAuthorized(@NotNull PairingAuthorisation pairingAuthorisation) {} @Override public void handleDeviceLinkingDialogDismissed() {} diff --git a/src/org/thoughtcrime/securesms/components/TypingStatusSender.java b/src/org/thoughtcrime/securesms/components/TypingStatusSender.java index b7526f1065..b813f5c63e 100644 --- a/src/org/thoughtcrime/securesms/components/TypingStatusSender.java +++ b/src/org/thoughtcrime/securesms/components/TypingStatusSender.java @@ -9,13 +9,14 @@ import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.jobs.TypingSendJob; -import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt; +import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.signalservice.loki.api.LokiStorageAPI; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; import kotlin.Unit; @@ -91,14 +92,14 @@ public class TypingStatusSender { return; } - MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, recipient.getAddress().serialize(), storageAPI, (devicePublicKey, isFriend, friendCount) -> { - Recipient device = Recipient.from(context, Address.fromSerialized(devicePublicKey), false); - long deviceThreadID = threadDatabase.getThreadIdIfExistsFor(device); + Set devices = LokiStorageAPI.shared.getAllDevicePublicKeys(recipient.getAddress().serialize()); + for (String device : devices) { + Recipient deviceRecipient = Recipient.from(context, Address.fromSerialized(device), false); + long deviceThreadID = threadDatabase.getThreadIdIfExistsFor(deviceRecipient); if (deviceThreadID > -1) { ApplicationContext.getInstance(context).getJobManager().add(new TypingSendJob(deviceThreadID, typingStarted)); } - return Unit.INSTANCE; - }); + } } private class StartRunnable implements Runnable { diff --git a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java index df45d35688..e3f6769fe3 100644 --- a/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -38,7 +38,6 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; -import android.os.Handler; import android.os.Vibrator; import android.provider.Browser; import android.provider.ContactsContract; @@ -128,7 +127,6 @@ 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; @@ -163,7 +161,7 @@ import org.thoughtcrime.securesms.loki.LokiMessageDatabase; import org.thoughtcrime.securesms.loki.LokiThreadDatabaseDelegate; import org.thoughtcrime.securesms.loki.LokiUserDatabase; import org.thoughtcrime.securesms.loki.MentionCandidateSelectionView; -import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt; +import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.mediasend.MediaSendActivity; import org.thoughtcrime.securesms.mms.AttachmentManager; @@ -228,9 +226,6 @@ import org.thoughtcrime.securesms.util.concurrent.SettableFuture; import org.thoughtcrime.securesms.util.views.Stub; import org.whispersystems.libsignal.InvalidMessageException; import org.whispersystems.libsignal.util.guava.Optional; -import org.whispersystems.signalservice.api.SignalServiceMessageSender; -import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; -import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.loki.api.LokiAPI; import org.whispersystems.signalservice.loki.api.LokiStorageAPI; import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus; @@ -246,6 +241,7 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; @@ -2195,7 +2191,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity Recipient threadRecipient = DatabaseFactory.getThreadDatabase(this).getRecipientForThreadId(threadID); if (threadRecipient != null && !threadRecipient.isGroupRecipient()) { // We should update our input if this thread is a part of the other threads device - Set devices = MultiDeviceUtilitiesKt.getAllDevicePublicKeys(threadRecipient.getAddress().serialize(), LokiStorageAPI.Companion.getShared()); + Set devices = LokiStorageAPI.shared.getAllDevicePublicKeys(threadRecipient.getAddress().serialize()); shouldUpdateInputPanel = devices.contains(recipient.getAddress().serialize()); } else { shouldUpdateInputPanel = false; @@ -2216,13 +2212,13 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity inputMethodManager.showSoftInput(inputPanel.composeText, 0); } boolean hasPendingFriendRequest = !recipient.isGroupRecipient() && hasPendingFriendRequestWithAnyLinkedDevice(); - boolean isFriendsWithAnyLinkedDevices = MultiDeviceUtilitiesKt.isFriendsWithAnyLinkedDevice(this, recipient); + boolean isFriendsWithAnyLinkedDevices = MultiDeviceUtilities.isFriendsWithAnyLinkedDevice(this, recipient); boolean shouldEnableInput = isFriendsWithAnyLinkedDevices || !hasPendingFriendRequest; updateToggleButtonState(); inputPanel.setEnabled(shouldEnableInput); int hintID = shouldEnableInput ? R.string.activity_conversation_default_hint : R.string.activity_conversation_pending_friend_request_hint; inputPanel.setHint(getResources().getString(hintID)); - if (!shouldEnableInput) { + if (shouldEnableInput) { inputPanel.composeText.requestFocus(); InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); inputMethodManager.showSoftInput(inputPanel.composeText, 0); @@ -3050,31 +3046,15 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity public boolean hasPendingFriendRequestWithAnyLinkedDevice() { if (recipient.isGroupRecipient()) return false; - SettableFuture future = new SettableFuture<>(); - LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared(); - MultiDeviceUtilitiesKt.getAllDeviceFriendRequestStatus(this, recipient.getAddress().serialize(), storageAPI).success(map -> { - for (LokiThreadFriendRequestStatus status : map.values()) { - // Break out of the loop as soon as one of the device has a pending friend request - if (status == LokiThreadFriendRequestStatus.REQUEST_SENDING || status == LokiThreadFriendRequestStatus.REQUEST_SENT || status == LokiThreadFriendRequestStatus.REQUEST_RECEIVED) { - future.set(true); - break; - } + Map 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; } - - // If we reached this and we haven't set anything on the future then it means that we don't have a pending request - if (!future.isDone()) { future.set(false); } - return Unit.INSTANCE; - }).fail(e -> { - future.set(false); - return Unit.INSTANCE; - }); - - try { - return future.get(); - } catch (Exception e) { - return false; } + + return false; } // endregion } diff --git a/src/org/thoughtcrime/securesms/database/Address.java b/src/org/thoughtcrime/securesms/database/Address.java index ed20c6fbbb..d063025cfa 100644 --- a/src/org/thoughtcrime/securesms/database/Address.java +++ b/src/org/thoughtcrime/securesms/database/Address.java @@ -61,7 +61,7 @@ public class Address implements Parcelable, Comparable
{ private Address(@NonNull String address, Boolean isPublicChat) { if (address == null) throw new AssertionError(address); - this.address = address; + this.address = address.toLowerCase(); this.isPublicChat = isPublicChat; } diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index ba8aab96d4..60c846da20 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -72,7 +72,7 @@ import org.thoughtcrime.securesms.loki.LokiMessageDatabase; import org.thoughtcrime.securesms.loki.LokiPreKeyBundleDatabase; import org.thoughtcrime.securesms.loki.LokiPreKeyRecordDatabase; import org.thoughtcrime.securesms.loki.LokiThreadDatabase; -import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt; +import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.mms.IncomingMediaMessage; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage; @@ -780,11 +780,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType { return; } - // Don't insert friend request if we're already friends with a one of the users other device - if (message.isFriendRequest() && MultiDeviceUtilitiesKt.isFriendsWithAnyLinkedDevice(context, primaryDeviceRecipient)) { - return; - } - Optional insertResult; try { @@ -828,8 +823,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } private long handleSynchronizeSentExpirationUpdate(@NonNull SentTranscriptMessage message) throws MmsException { - MmsDatabase database = DatabaseFactory.getMmsDatabase(context); - Recipient recipient = getSyncMessagePrimaryDestination(message); + MmsDatabase database = DatabaseFactory.getMmsDatabase(context); + Recipient recipient = getSyncMessagePrimaryDestination(message); OutgoingExpirationUpdateMessage expirationUpdateMessage = new OutgoingExpirationUpdateMessage(recipient, message.getTimestamp(), @@ -1099,7 +1094,7 @@ 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 = MultiDeviceUtilitiesKt.getPrimaryDevicePublicKey(pubKey); + 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); } @@ -1107,7 +1102,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { private void updateFriendRequestStatusIfNeeded(@NonNull SignalServiceEnvelope envelope, @NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) { if (!envelope.isFriendRequest()) { return; } // This handles the case where another user sends us a regular message without authorisation - boolean shouldBecomeFriends = MultiDeviceUtilitiesKt.shouldAutomaticallyBecomeFriendsWithDevice(content.getSender(), context); + boolean shouldBecomeFriends = MultiDeviceUtilities.shouldAutomaticallyBecomeFriendsWithDevice(content.getSender(), context); if (shouldBecomeFriends) { // Become friends AND update the message they sent becomeFriendsWithContact(content.getSender()); @@ -1536,26 +1531,15 @@ public class PushDecryptJob extends BaseJob implements InjectableType { } private Recipient getPrimaryDeviceRecipient(String recipient) { - SettableFuture device = new SettableFuture<>(); - - // Get the primary device - LokiStorageAPI.shared.getPrimaryDevicePublicKey(recipient).success(primaryDevice -> { + try { + String primaryDevice = LokiStorageAPI.shared.getPrimaryDevicePublicKey(recipient); 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) + // 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); 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); + return Recipient.from(context, Address.fromSerialized(publicKey), 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); @@ -1610,7 +1594,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { 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()); + 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; } diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index eab4072ddd..9a10d5f797 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -22,7 +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.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.recipients.Recipient; @@ -43,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.api.LokiStorageAPI; import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage; import java.io.FileNotFoundException; @@ -280,7 +281,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 = MultiDeviceUtilitiesKt.getPrimaryDevicePublicKey(address.getNumber()); + String primaryDevice = LokiStorageAPI.shared.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); diff --git a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index 0585d6e586..7c93b82c8b 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -14,7 +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.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.service.ExpiringMessageManager; @@ -30,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.api.LokiStorageAPI; import org.whispersystems.signalservice.loki.messaging.LokiSyncMessage; import java.io.IOException; @@ -231,7 +232,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 = MultiDeviceUtilitiesKt.getPrimaryDevicePublicKey(address.getNumber()); + String primaryDevice = LokiStorageAPI.shared.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); diff --git a/src/org/thoughtcrime/securesms/jobs/TypingSendJob.java b/src/org/thoughtcrime/securesms/jobs/TypingSendJob.java index e5379894dd..023afda792 100644 --- a/src/org/thoughtcrime/securesms/jobs/TypingSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/TypingSendJob.java @@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt; +import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; @@ -98,7 +98,7 @@ 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() && !MultiDeviceUtilitiesKt.isOneOfOurDevices(context, recipient.getAddress())) { + if (!recipient.isGroupRecipient() && !MultiDeviceUtilities.isOneOfOurDevices(context, recipient.getAddress())) { messageSender.sendTyping(0, addresses, unidentifiedAccess, typingMessage); } } diff --git a/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt b/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt index 72811df37c..d3c8b17cad 100644 --- a/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt @@ -1,11 +1,9 @@ +@file:JvmName("MultiDeviceUtilities") package org.thoughtcrime.securesms.loki import android.content.Context import android.os.Handler import nl.komponents.kovenant.Promise -import nl.komponents.kovenant.deferred -import nl.komponents.kovenant.functional.bind -import nl.komponents.kovenant.functional.map import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.crypto.IdentityKeyUtil import org.thoughtcrime.securesms.database.Address @@ -13,7 +11,6 @@ import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.logging.Log import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.TextSecurePreferences -import org.thoughtcrime.securesms.util.concurrent.SettableFuture import org.whispersystems.libsignal.util.guava.Optional import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage @@ -23,85 +20,53 @@ import org.whispersystems.signalservice.loki.api.PairingAuthorisation import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus import org.whispersystems.signalservice.loki.utilities.retryIfNeeded -fun getAllDeviceFriendRequestStatus(context: Context, hexEncodedPublicKey: String, storageAPI: LokiStorageAPI): Promise, Exception> { +fun getAllDeviceFriendRequestStatuses(context: Context, hexEncodedPublicKey: String): Map { val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context) - return storageAPI.getAllDevicePublicKeys(hexEncodedPublicKey).map { keys -> - val map = mutableMapOf() - - 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.put(devicePublicKey, friendRequestStatus); - } - - map + val keys = LokiStorageAPI.shared.getAllDevicePublicKeys(hexEncodedPublicKey) + val map = mutableMapOf() + 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 } -fun getAllDevicePublicKeys(context: Context, hexEncodedPublicKey: String, storageAPI: LokiStorageAPI, block: (devicePublicKey: String, isFriend: Boolean, friendCount: Int) -> Unit) { +fun getAllDevicePublicKeysWithFriendStatus(context: Context, hexEncodedPublicKey: String): Map { val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) - val devices = getAllDevicePublicKeys(hexEncodedPublicKey, storageAPI).toMutableSet() + val devices = LokiStorageAPI.shared.getAllDevicePublicKeys(hexEncodedPublicKey).toMutableSet() if (hexEncodedPublicKey != userHexEncodedPublicKey) { devices.remove(userHexEncodedPublicKey) } val friends = getFriendPublicKeys(context, devices) + val map = mutableMapOf() for (device in devices) { - block(device, friends.contains(device), friends.count()) + map[device] = friends.contains(device) } + return map } -fun getAllDevicePublicKeys(hexEncodedPublicKey: String, storageAPI: LokiStorageAPI): Set { - val future = SettableFuture>() - storageAPI.getAllDevicePublicKeys(hexEncodedPublicKey).success { future.set(it) }.fail { future.setException(it) } - return try { - future.get() - } catch (e: Exception) { - setOf() - } +fun getFriendCount(context: Context, devices: Set): Int { + return getFriendPublicKeys(context, devices).count() } fun shouldAutomaticallyBecomeFriendsWithDevice(publicKey: String, context: Context): Boolean { val lokiThreadDatabase = DatabaseFactory.getLokiThreadDatabase(context) val storageAPI = LokiStorageAPI.shared - val future = SettableFuture() - storageAPI.getPrimaryDevicePublicKey(publicKey).success { primaryDevicePublicKey -> - if (primaryDevicePublicKey == null) { - // If the public key doesn't have any other devices then go through regular friend request logic - future.set(false) - return@success - } - // If we are the primary device and the public key is our secondary device then we should become friends - val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context) - if (primaryDevicePublicKey == userHexEncodedPublicKey) { - storageAPI.getSecondaryDevicePublicKeys(userHexEncodedPublicKey).success { secondaryDevices -> - future.set(secondaryDevices.contains(publicKey)) - }.fail { - future.set(false) - } - return@success - } - // If we share the same primary device then we should become friends - val ourPrimaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context) - if (ourPrimaryDevice != null && ourPrimaryDevice == primaryDevicePublicKey) { - future.set(true) - return@success - } - // If we are friends with the primary device then we should become friends - val primaryDevice = Recipient.from(context, Address.fromSerialized(primaryDevicePublicKey), false) - val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(primaryDevice) - if (threadID < 0) { - future.set(false) - return@success - } - future.set(lokiThreadDatabase.getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS) + + // 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 } - return try { - future.get() - } catch (e: Exception) { - false - } + // 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 } fun sendPairingAuthorisationMessage(context: Context, contactHexEncodedPublicKey: String, authorisation: PairingAuthorisation): Promise { @@ -157,27 +122,12 @@ fun shouldSendSycMessage(context: Context, address: Address): Boolean { return false } - // Don't send sync messages if it's our address - val publicKey = address.serialize() - if (publicKey == TextSecurePreferences.getLocalNumber(context)) { - return false - } + // Don't send sync messages if it's one of our devices + return !isOneOfOurDevices(context, address) +} - val storageAPI = LokiStorageAPI.shared - val future = SettableFuture() - 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, publicKey: String): Boolean { + return isOneOfOurDevices(context, Address.fromSerialized(publicKey)) } fun isOneOfOurDevices(context: Context, address: Address): Boolean { @@ -186,61 +136,18 @@ fun isOneOfOurDevices(context: Context, address: Address): Boolean { } val ourPublicKey = TextSecurePreferences.getLocalNumber(context) - val storageAPI = LokiStorageAPI.shared - val future = SettableFuture() - 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() - storageAPI.getPrimaryDevicePublicKey(hexEncodedPublicKey).success { - future.set(it) - }.fail { - future.set(null) - } - - return try { - future.get() - } catch (e: Exception) { - null - } + val devices = LokiStorageAPI.shared.getAllDevicePublicKeys(ourPublicKey) + return devices.contains(address.serialize()) } fun isFriendsWithAnyLinkedDevice(context: Context, recipient: Recipient): Boolean { if (recipient.isGroupRecipient) return true - val future = SettableFuture() - val storageAPI = LokiStorageAPI.shared - getAllDeviceFriendRequestStatus(context, recipient.address.serialize(), storageAPI).success { map -> - for (status in map.values) { - if (status == LokiThreadFriendRequestStatus.FRIENDS) { - future.set(true) - break - } + val map = getAllDeviceFriendRequestStatuses(context, recipient.address.serialize()) + for (status in map.values) { + if (status == LokiThreadFriendRequestStatus.FRIENDS) { + return true } - - if (!future.isDone) { - future.set(false) - } - }.fail { e -> - future.set(false) } - - try { - return future.get() - } catch (e: Exception) { - return false - } - + return false } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java b/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java index 9d403bad9a..ff5a1477ee 100644 --- a/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java +++ b/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java @@ -20,7 +20,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId; import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob; import org.thoughtcrime.securesms.jobs.SendReadReceiptJob; import org.thoughtcrime.securesms.logging.Log; -import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt; +import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.service.ExpiringMessageManager; import org.whispersystems.signalservice.loki.api.LokiStorageAPI; @@ -90,17 +90,17 @@ public class MarkReadReceiver extends BroadcastReceiver { .collect(Collectors.groupingBy(SyncMessageId::getAddress)); for (Address address : addressMap.keySet()) { - LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared(); - List timestamps = Stream.of(addressMap.get(address)).map(SyncMessageId::getTimetamp).toList(); - MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, address.serialize(), storageAPI, (devicePublicKey, isFriend, friendCount) -> { + Map devices = MultiDeviceUtilities.getAllDevicePublicKeysWithFriendStatus(context, address.serialize()); + for (Map.Entry entry : devices.entrySet()) { + String device = entry.getKey(); + boolean isFriend = entry.getValue(); // Loki - This also prevents read receipts from being sent in group chats as they don't maintain a friend request status if (isFriend) { - ApplicationContext.getInstance(context).getJobManager().add(new SendReadReceiptJob(Address.fromSerialized(devicePublicKey), timestamps)); + ApplicationContext.getInstance(context).getJobManager().add(new SendReadReceiptJob(Address.fromSerialized(device), timestamps)); } - return Unit.INSTANCE; - }); + } } } diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index 58334eeb48..660da23c4d 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -44,7 +44,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.loki.FriendRequestHandler; import org.thoughtcrime.securesms.loki.GeneralUtilitiesKt; -import org.thoughtcrime.securesms.loki.MultiDeviceUtilitiesKt; +import org.thoughtcrime.securesms.loki.MultiDeviceUtilities; import org.thoughtcrime.securesms.loki.PushMessageSyncSendJob; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; @@ -63,6 +63,8 @@ import org.whispersystems.signalservice.loki.api.LokiStorageAPI; import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus; import java.io.IOException; +import java.util.Map; +import java.util.Set; import kotlin.Unit; @@ -75,24 +77,20 @@ 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 - LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared(); - storageAPI.getAllDevicePublicKeys(contactHexEncodedPublicKey).success(devices -> { - 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? + Set 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); } - return Unit.INSTANCE; - }); + // TODO: Do we want to send a custom FR Message if we're not friends and we haven't received a friend request? + } } public static void sendBackgroundMessage(Context context, String contactHexEncodedPublicKey) { @@ -198,20 +196,16 @@ public class MessageSender { final byte[] message, final int ttl) { String ourPublicKey = TextSecurePreferences.getLocalNumber(context); - LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared(); JobManager jobManager = ApplicationContext.getInstance(context).getJobManager(); + Set devices = LokiStorageAPI.shared.getAllDevicePublicKeys(ourPublicKey); + for (String device : devices) { + // Don't send to ourselves + if (device.equals(ourPublicKey)) { continue; } - 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; - }); + // Create a send job for our device + Address address = Address.fromSerialized(device); + jobManager.add(new PushMessageSyncSendJob(messageID, address, timestamp, message, ttl)); + } } public static void resendGroupMessage(Context context, MessageRecord messageRecord, Address filterAddress) { @@ -260,7 +254,6 @@ public class MessageSender { } private static void sendTextPush(Context context, Recipient recipient, long messageId) { - LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared(); JobManager jobManager = ApplicationContext.getInstance(context).getJobManager(); // Just send the message normally if it's a group message @@ -271,39 +264,40 @@ public class MessageSender { } // Note to self - boolean isNoteToSelf = MultiDeviceUtilitiesKt.isOneOfOurDevices(context, recipient.getAddress()); + boolean isNoteToSelf = MultiDeviceUtilities.isOneOfOurDevices(context, recipient.getAddress()); if (isNoteToSelf) { jobManager.add(new PushTextSendJob(messageId, recipient.getAddress())); return; } - boolean[] hasSentSyncMessage = { false }; + boolean hasSentSyncMessage = false; - MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, recipientPublicKey, storageAPI, (devicePublicKey, isFriend, friendCount) -> { - Util.runOnMain(() -> { - Address address = Address.fromSerialized(devicePublicKey); - long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L; + Map devices = MultiDeviceUtilities.getAllDevicePublicKeysWithFriendStatus(context, recipientPublicKey); + int friendCount = MultiDeviceUtilities.getFriendCount(context, devices.keySet()); + for (Map.Entry entry : devices.entrySet()) { + String devicePublicKey = entry.getKey(); + boolean isFriend = entry.getValue(); - 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; - }); + 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 && MultiDeviceUtilities.shouldSendSycMessage(context, address); + jobManager.add(new PushTextSendJob(messageId, messageIDToUse, address, shouldSendSyncMessage)); + hasSentSyncMessage = 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)); + } + } } private static void sendMediaPush(Context context, Recipient recipient, long messageId) { - LokiStorageAPI storageAPI = LokiStorageAPI.Companion.getShared(); JobManager jobManager = ApplicationContext.getInstance(context).getJobManager(); // Just send the message normally if it's a group message @@ -314,36 +308,37 @@ public class MessageSender { } // Note to self - boolean isNoteToSelf = MultiDeviceUtilitiesKt.isOneOfOurDevices(context, recipient.getAddress()); + boolean isNoteToSelf = MultiDeviceUtilities.isOneOfOurDevices(context, recipient.getAddress()); if (isNoteToSelf) { jobManager.add(new PushTextSendJob(messageId, recipient.getAddress())); return; } - boolean[] hasSentSyncMessage = { false }; + boolean hasSentSyncMessage = false; - MultiDeviceUtilitiesKt.getAllDevicePublicKeys(context, recipientPublicKey, storageAPI, (devicePublicKey, isFriend, friendCount) -> { - Util.runOnMain(() -> { - Address address = Address.fromSerialized(devicePublicKey); - long messageIDToUse = recipientPublicKey.equals(devicePublicKey) ? messageId : -1L; + Map devices = MultiDeviceUtilities.getAllDevicePublicKeysWithFriendStatus(context, recipientPublicKey); + int friendCount = MultiDeviceUtilities.getFriendCount(context, devices.keySet()); + for (Map.Entry entry : devices.entrySet()) { + String devicePublicKey = entry.getKey(); + boolean isFriend = entry.getValue(); - 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; - }); + 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 && MultiDeviceUtilities.shouldSendSycMessage(context, address); + PushMediaSendJob.enqueue(context, jobManager, messageId, messageIDToUse, address, shouldSendSyncMessage); + hasSentSyncMessage = 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); + } + } } private static void sendGroupPush(Context context, Recipient recipient, long messageId, Address filterAddress) {