From 9ea2a6c8e4ac2ec5919ed13deb0d1bdf60545c39 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Tue, 29 Oct 2019 11:23:30 +1100 Subject: [PATCH] More fixes for friend request UI for multi device. Remove old FR pending states on new incoming friend request. Always update the last friend request message state and not a new message. --- .../securesms/database/SmsDatabase.java | 18 +++++++ .../securesms/jobs/PushDecryptJob.java | 26 +++------- .../securesms/loki/FriendRequestHandler.kt | 51 +++++++++++++++++-- .../securesms/loki/MultiDeviceUtilities.kt | 11 ++-- .../push/MessageSenderEventListener.java | 6 +-- .../securesms/sms/MessageSender.java | 7 ++- 6 files changed, 84 insertions(+), 35 deletions(-) diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java index 4fdcfdcc6a..112ddc463b 100644 --- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -47,6 +47,7 @@ import org.whispersystems.libsignal.util.guava.Optional; import java.io.IOException; import java.security.SecureRandom; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -193,6 +194,23 @@ public class SmsDatabase extends MessagingDatabase { return -1; } + public Set getAllMessageIDs(long threadID) { + SQLiteDatabase database = databaseHelper.getReadableDatabase(); + Cursor cursor = null; + Set messageIDs = new HashSet<>(); + try { + cursor = database.query(TABLE_NAME, null, THREAD_ID + " = ?", new String[] { threadID + "" }, null, null, null); + while (cursor != null && cursor.moveToNext()) { + messageIDs.add(cursor.getLong(0)); + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + return messageIDs; + } + public void markAsEndSession(long id) { updateTypeBitmask(id, Types.KEY_EXCHANGE_MASK, Types.END_SESSION_BIT); } diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 4fa07ac425..f3ba69fe73 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -66,6 +66,7 @@ import org.thoughtcrime.securesms.linkpreview.Link; import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil; import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.loki.FriendRequestHandler; import org.thoughtcrime.securesms.loki.LokiAPIUtilities; import org.thoughtcrime.securesms.loki.LokiMessageDatabase; import org.thoughtcrime.securesms.loki.LokiPreKeyBundleDatabase; @@ -961,11 +962,6 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // Ignore the message if the body is empty if (textMessage.getMessageBody().length() == 0) { 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; - } - // Insert the message into the database Optional insertResult = database.insertMessageInbox(textMessage); @@ -1103,14 +1099,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 - // TODO: Fix this logic to update the last friend request message - SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context); - LokiMessageDatabase lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context); - int messageCount = smsDatabase.getMessageCountForThread(threadID); - long messageID = smsDatabase.getIDForMessageAtIndex(threadID, messageCount - 1); - if (messageID > -1 && lokiMessageDatabase.getFriendRequestStatus(messageID) != LokiMessageFriendRequestStatus.REQUEST_ACCEPTED) { - lokiMessageDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED); - } + FriendRequestHandler.updateLastFriendRequestMessage(context, threadID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED); } private void updateFriendRequestStatusIfNeeded(@NonNull SignalServiceEnvelope envelope, @NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message) { @@ -1134,7 +1123,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(originalRecipient); long primaryDeviceThreadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(primaryDeviceRecipient); LokiThreadFriendRequestStatus threadFriendRequestStatus = lokiThreadDatabase.getFriendRequestStatus(threadID); - int messageCount = smsMessageDatabase.getMessageCountForThread(primaryDeviceThreadID); + if (threadFriendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) { // This can happen if Alice sent Bob a friend request, Bob declined, but then Bob changed his // mind and sent a friend request to Alice. In this case we want Alice to auto-accept the request @@ -1148,9 +1137,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // `REQUEST_SENT`. lokiThreadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.FRIENDS); // Since messages are forwarded to the primary device thread, we need to update it there - // TODO: Fix this logic to update the last friend request message - long messageID = smsMessageDatabase.getIDForMessageAtIndex(primaryDeviceThreadID, messageCount - 2); // The message before the one that was just received - lokiMessageDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED); + FriendRequestHandler.updateLastFriendRequestMessage(context, primaryDeviceThreadID, LokiMessageFriendRequestStatus.REQUEST_ACCEPTED); // Accept the friend request MessageSender.sendBackgroundMessage(context, content.getSender()); } else if (threadFriendRequestStatus != LokiThreadFriendRequestStatus.FRIENDS) { @@ -1160,10 +1147,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType { // request. Alice's thread's friend request status is reset to // `REQUEST_RECEIVED`. lokiThreadDatabase.setFriendRequestStatus(threadID, LokiThreadFriendRequestStatus.REQUEST_RECEIVED); + // Since messages are forwarded to the primary device thread, we need to update it there - long smsMessageID = smsMessageDatabase.getIDForMessageAtIndex(primaryDeviceThreadID, messageCount - 1); // The message that was just received - long messageID = smsMessageID != -1 ? smsMessageID : mmsMessageDatabase.getIDForMessageAtIndex(primaryDeviceThreadID, 0); - lokiMessageDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_PENDING); + FriendRequestHandler.receivedIncomingFriendRequestMessage(context, primaryDeviceThreadID); } } } diff --git a/src/org/thoughtcrime/securesms/loki/FriendRequestHandler.kt b/src/org/thoughtcrime/securesms/loki/FriendRequestHandler.kt index d68bc09bdd..70a0850f36 100644 --- a/src/org/thoughtcrime/securesms/loki/FriendRequestHandler.kt +++ b/src/org/thoughtcrime/securesms/loki/FriendRequestHandler.kt @@ -14,7 +14,7 @@ object FriendRequestHandler { enum class ActionType { Sending, Sent, Failed } @JvmStatic - fun handleFriendRequest(context: Context, type: ActionType, messageId: Long, threadId: Long) { + fun updateFriendRequestState(context: Context, type: ActionType, messageId: Long, threadId: Long) { // Update thread status // Note: Do we need to only update these if we're not friends? if (threadId >= 0) { @@ -30,14 +30,14 @@ object FriendRequestHandler { val recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId) if (recipient != null && messageId >= 0) { val messageDatabase = DatabaseFactory.getLokiMessageDatabase(context) - val messageFriendRequestStatus = messageDatabase.getFriendRequestStatus(messageId) - if (type == ActionType.Sending && messageFriendRequestStatus == LokiMessageFriendRequestStatus.NONE) { + val friendRequestStatus = messageDatabase.getFriendRequestStatus(messageId) + 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)) { + if (!isFriendsWithAnyLinkedDevice(context, recipient) && friendRequestStatus == LokiMessageFriendRequestStatus.NONE) { messageDatabase.setFriendRequestStatus(messageId, LokiMessageFriendRequestStatus.REQUEST_SENDING) } - } else if (messageFriendRequestStatus != LokiMessageFriendRequestStatus.NONE) { + } else if (friendRequestStatus != LokiMessageFriendRequestStatus.NONE) { // Update the friend request status of the message if we have it val messageFriendRequestStatus = when (type) { ActionType.Failed -> LokiMessageFriendRequestStatus.REQUEST_FAILED @@ -48,4 +48,45 @@ object FriendRequestHandler { } } } + + @JvmStatic + fun updateLastFriendRequestMessage(context: Context, threadId: Long, status: LokiMessageFriendRequestStatus) { + if (threadId < 0) { return } + + val messages = DatabaseFactory.getSmsDatabase(context).getAllMessageIDs(threadId) + val lokiMessageDatabase = DatabaseFactory.getLokiMessageDatabase(context) + val lastMessage = messages.find { + val friendRequestStatus = lokiMessageDatabase.getFriendRequestStatus(it) + friendRequestStatus == LokiMessageFriendRequestStatus.REQUEST_PENDING + } ?: return + + DatabaseFactory.getLokiMessageDatabase(context).setFriendRequestStatus(lastMessage, status) + } + + @JvmStatic + fun receivedIncomingFriendRequestMessage(context: Context, threadId: Long) { + val smsMessageDatabase = DatabaseFactory.getSmsDatabase(context) + + // 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 } + + // 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 } + + 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) + } + + // Set the last message to pending + messageDatabase.setFriendRequestStatus(messageID, LokiMessageFriendRequestStatus.REQUEST_PENDING) + } } \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt b/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt index dcbe57652d..1fbb4a480f 100644 --- a/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt +++ b/src/org/thoughtcrime/securesms/loki/MultiDeviceUtilities.kt @@ -1,6 +1,7 @@ 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 @@ -134,9 +135,13 @@ fun signAndSendPairingAuthorisationMessage(context: Context, pairingAuthorisatio Log.d("Loki", "Failed to send pairing authorization message to ${pairingAuthorisation.secondaryDevicePublicKey}.") } DatabaseFactory.getLokiAPIDatabase(context).insertOrUpdatePairingAuthorisation(signedPairingAuthorisation) - LokiStorageAPI.shared.updateUserDeviceMappings().fail { exception -> - Log.w("Loki", "Failed to update device mapping") - } + // Call function after a short delay + Handler().postDelayed({ + LokiStorageAPI.shared.updateUserDeviceMappings().fail { + Log.w("Loki", "Failed to update device mapping") + } + }, 100) + } fun shouldSendSycMessage(context: Context, address: Address): Boolean { diff --git a/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java b/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java index ec8357b232..5cd99e5fcb 100644 --- a/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java +++ b/src/org/thoughtcrime/securesms/push/MessageSenderEventListener.java @@ -29,14 +29,14 @@ public class MessageSenderEventListener implements SignalServiceMessageSender.Ev } @Override public void onFriendRequestSending(long messageID, long threadID) { - FriendRequestHandler.handleFriendRequest(context, FriendRequestHandler.ActionType.Sending, messageID, threadID); + FriendRequestHandler.updateFriendRequestState(context, FriendRequestHandler.ActionType.Sending, messageID, threadID); } @Override public void onFriendRequestSent(long messageID, long threadID) { - FriendRequestHandler.handleFriendRequest(context, FriendRequestHandler.ActionType.Sent, messageID, threadID); + FriendRequestHandler.updateFriendRequestState(context, FriendRequestHandler.ActionType.Sent, messageID, threadID); } @Override public void onFriendRequestSendingFail(long messageID, long threadID) { - FriendRequestHandler.handleFriendRequest(context, FriendRequestHandler.ActionType.Failed, messageID, threadID); + FriendRequestHandler.updateFriendRequestState(context, FriendRequestHandler.ActionType.Failed, messageID, threadID); } } diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index e6e9fa254c..027dd4fd24 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -60,7 +60,6 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage; 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.LokiMessageFriendRequestStatus; import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus; import java.io.IOException; @@ -132,7 +131,7 @@ public class MessageSender { // Loki - Set the message's friend request status as soon as it has hit the database if (message.isFriendRequest) { - FriendRequestHandler.handleFriendRequest(context, FriendRequestHandler.ActionType.Sending, messageId, allocatedThreadId); + FriendRequestHandler.updateFriendRequestState(context, FriendRequestHandler.ActionType.Sending, messageId, allocatedThreadId); } sendTextMessage(context, recipient, forceSms, keyExchange, messageId); @@ -168,7 +167,7 @@ public class MessageSender { long messageID = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener); // Loki - Set the message's friend request status as soon as it has hit the database if (message.isFriendRequest) { - FriendRequestHandler.handleFriendRequest(context, FriendRequestHandler.ActionType.Sending, messageID, allocatedThreadId); + FriendRequestHandler.updateFriendRequestState(context, FriendRequestHandler.ActionType.Sending, messageID, allocatedThreadId); } sendMediaMessage(context, recipient, forceSms, messageID, message.getExpiresIn()); } catch (Exception e) { @@ -181,7 +180,7 @@ public class MessageSender { long messageID = database.insertMessageOutbox(message, allocatedThreadId, forceSms, insertListener); // Loki - Set the message's friend request status as soon as it has hit the database if (message.isFriendRequest) { - FriendRequestHandler.handleFriendRequest(context, FriendRequestHandler.ActionType.Sending, messageID, allocatedThreadId); + FriendRequestHandler.updateFriendRequestState(context, FriendRequestHandler.ActionType.Sending, messageID, allocatedThreadId); } sendMediaMessage(context, recipient, forceSms, messageID, message.getExpiresIn()); } catch (MmsException e) {