mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-28 20:45:17 +00:00
fix: fix up the duplicate thread creation in the message receive handler
This commit is contained in:
parent
6d37fb29ab
commit
2ebd6ebf64
@ -3,37 +3,30 @@ package org.thoughtcrime.securesms.conversation.v2
|
||||
import android.Manifest
|
||||
import android.animation.FloatEvaluator
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.*
|
||||
import android.content.res.Resources
|
||||
import android.database.Cursor
|
||||
import android.graphics.Rect
|
||||
import android.graphics.Typeface
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.*
|
||||
import android.provider.MediaStore
|
||||
import android.text.SpannableString
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.SpannedString
|
||||
import android.text.TextUtils
|
||||
import android.text.style.StyleSpan
|
||||
import android.util.Pair
|
||||
import android.util.TypedValue
|
||||
import android.view.ActionMode
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.view.*
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.Toast
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.DimenRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.text.set
|
||||
import androidx.core.text.toSpannable
|
||||
import androidx.core.view.drawToBitmap
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
@ -79,12 +72,8 @@ import org.session.libsession.messaging.sending_receiving.link_preview.LinkPrevi
|
||||
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
|
||||
import org.session.libsession.messaging.utilities.SessionId
|
||||
import org.session.libsession.snode.SnodeAPI
|
||||
import org.session.libsession.utilities.Address
|
||||
import org.session.libsession.utilities.*
|
||||
import org.session.libsession.utilities.Address.Companion.fromSerialized
|
||||
import org.session.libsession.utilities.GroupUtil
|
||||
import org.session.libsession.utilities.MediaTypes
|
||||
import org.session.libsession.utilities.Stub
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsession.utilities.concurrent.SimpleTask
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.session.libsession.utilities.recipients.RecipientModifiedListener
|
||||
@ -117,25 +106,10 @@ import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView
|
||||
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageViewDelegate
|
||||
import org.thoughtcrime.securesms.conversation.v2.search.SearchBottomBar
|
||||
import org.thoughtcrime.securesms.conversation.v2.search.SearchViewModel
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionManagerUtilities
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.MentionUtilities
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.ResendMessageUtilities
|
||||
import org.thoughtcrime.securesms.conversation.v2.utilities.*
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
|
||||
import org.thoughtcrime.securesms.crypto.MnemonicUtilities
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase
|
||||
import org.thoughtcrime.securesms.database.LokiAPIDatabase
|
||||
import org.thoughtcrime.securesms.database.LokiMessageDatabase
|
||||
import org.thoughtcrime.securesms.database.LokiThreadDatabase
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase
|
||||
import org.thoughtcrime.securesms.database.ReactionDatabase
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase
|
||||
import org.thoughtcrime.securesms.database.SessionContactDatabase
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase
|
||||
import org.thoughtcrime.securesms.database.Storage
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||
import org.thoughtcrime.securesms.database.*
|
||||
import org.thoughtcrime.securesms.database.model.MessageId
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||
@ -148,26 +122,13 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel.LinkPreviewState
|
||||
import org.thoughtcrime.securesms.mediasend.Media
|
||||
import org.thoughtcrime.securesms.mediasend.MediaSendActivity
|
||||
import org.thoughtcrime.securesms.mms.AudioSlide
|
||||
import org.thoughtcrime.securesms.mms.GifSlide
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.mms.ImageSlide
|
||||
import org.thoughtcrime.securesms.mms.MediaConstraints
|
||||
import org.thoughtcrime.securesms.mms.Slide
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck
|
||||
import org.thoughtcrime.securesms.mms.VideoSlide
|
||||
import org.thoughtcrime.securesms.mms.*
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.reactions.ReactionsDialogFragment
|
||||
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiDialogFragment
|
||||
import org.thoughtcrime.securesms.util.ActivityDispatcher
|
||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
import org.thoughtcrime.securesms.util.DateUtils
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask
|
||||
import org.thoughtcrime.securesms.util.push
|
||||
import org.thoughtcrime.securesms.util.toPx
|
||||
import org.thoughtcrime.securesms.util.*
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.Locale
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutionException
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
@ -401,6 +362,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
|
||||
updateUnreadCountIndicator()
|
||||
updateSubtitle()
|
||||
updatePlaceholder()
|
||||
setUpBlockedBanner()
|
||||
binding!!.searchBottomBar.setEventListener(this)
|
||||
showOrHideInputIfNeeded()
|
||||
@ -984,6 +946,37 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
updateUnreadCountIndicator()
|
||||
}
|
||||
|
||||
private fun updatePlaceholder() {
|
||||
val recipient = viewModel.recipient
|
||||
?: return Log.w("Loki", "recipient was null in placeholder update")
|
||||
val binding = binding ?: return
|
||||
val openGroup = viewModel.openGroup
|
||||
val (textResource, insertParam) = when {
|
||||
recipient.isLocalNumber -> R.string.activity_conversation_empty_state_note_to_self to null
|
||||
openGroup != null && !openGroup.canWrite -> R.string.activity_conversation_empty_state_read_only to recipient.toShortString()
|
||||
else -> R.string.activity_conversation_empty_state_default to recipient.toShortString()
|
||||
}
|
||||
val showPlaceholder = adapter.itemCount == 0
|
||||
binding.placeholderText.isVisible = showPlaceholder
|
||||
if (showPlaceholder) {
|
||||
if (insertParam != null) {
|
||||
val span = getText(textResource) as SpannedString
|
||||
val annotations = span.getSpans(0, span.length, StyleSpan::class.java)
|
||||
val boldSpan = annotations.first()
|
||||
val spannedParam = insertParam.toSpannable()
|
||||
spannedParam[0 until spannedParam.length] = StyleSpan(boldSpan.style)
|
||||
val originalStart = span.getSpanStart(boldSpan)
|
||||
val originalEnd = span.getSpanEnd(boldSpan)
|
||||
val newString = SpannableStringBuilder(span)
|
||||
.replace(originalStart, originalEnd, spannedParam)
|
||||
binding.placeholderText.text = newString
|
||||
} else {
|
||||
binding.placeholderText.setText(textResource)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun showOrHideScrollToBottomButton(show: Boolean = true) {
|
||||
binding?.scrollToBottomButton?.isVisible = show && !isScrolledToBottom && adapter.itemCount > 0
|
||||
}
|
||||
|
@ -98,7 +98,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
||||
|
||||
// TODO: maybe add time here from formation / creation message
|
||||
override fun threadCreated(address: Address, threadId: Long) {
|
||||
Log.d("Loki-DBG", "creating thread for $address")
|
||||
Log.d("Loki-DBG", "creating thread for $address\nExecution context:\n${Thread.currentThread().stackTrace.joinToString("\n")}")
|
||||
|
||||
val volatile = configFactory.convoVolatile ?: return
|
||||
if (address.isGroup) {
|
||||
val groups = configFactory.userGroups ?: return
|
||||
@ -136,7 +137,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
||||
}
|
||||
|
||||
override fun threadDeleted(address: Address, threadId: Long) {
|
||||
Log.d("Loki-DBG", "deleting thread for $address")
|
||||
Log.d("Loki-DBG", "deleting thread for $address\nExecution context:\n${Thread.currentThread().stackTrace.joinToString("\n")}")
|
||||
val volatile = configFactory.convoVolatile ?: return
|
||||
if (address.isGroup) {
|
||||
val groups = configFactory.userGroups ?: return
|
||||
@ -460,11 +461,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
||||
val extracted = convos.all()
|
||||
for (conversation in extracted) {
|
||||
val threadId = when (conversation) {
|
||||
is Conversation.OneToOne -> getOrCreateThreadIdFor(fromSerialized(conversation.sessionId))
|
||||
is Conversation.LegacyGroup -> getOrCreateThreadIdFor("", conversation.groupId,null)
|
||||
is Conversation.Community -> getOrCreateThreadIdFor("",null, "${conversation.baseCommunityInfo.baseUrl}.${conversation.baseCommunityInfo.room}")
|
||||
is Conversation.OneToOne -> getThreadIdFor(conversation.sessionId, null, null, createThread = false)
|
||||
is Conversation.LegacyGroup -> getThreadIdFor("", conversation.groupId,null, createThread = false)
|
||||
is Conversation.Community -> getThreadIdFor("",null, "${conversation.baseCommunityInfo.baseUrl}.${conversation.baseCommunityInfo.room}", createThread = false)
|
||||
}
|
||||
if (threadId >= 0) {
|
||||
if (threadId != null) {
|
||||
markConversationAsRead(threadId, conversation.lastRead)
|
||||
updateThread(threadId, false)
|
||||
}
|
||||
@ -981,17 +982,19 @@ class Storage(context: Context, helper: SQLCipherOpenHelper, private val configF
|
||||
return DatabaseComponent.get(context).threadDatabase().getOrCreateThreadIdFor(recipient)
|
||||
}
|
||||
|
||||
override fun getOrCreateThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?): Long {
|
||||
override fun getThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?, createThread: Boolean): Long? {
|
||||
val database = DatabaseComponent.get(context).threadDatabase()
|
||||
return if (!openGroupID.isNullOrEmpty()) {
|
||||
val recipient = Recipient.from(context, fromSerialized(GroupUtil.getEncodedOpenGroupID(openGroupID.toByteArray())), false)
|
||||
database.getThreadIdIfExistsFor(recipient)
|
||||
database.getThreadIdIfExistsFor(recipient).let { if (it == -1L) null else it }
|
||||
} else if (!groupPublicKey.isNullOrEmpty()) {
|
||||
val recipient = Recipient.from(context, fromSerialized(GroupUtil.doubleEncodeGroupID(groupPublicKey)), false)
|
||||
database.getOrCreateThreadIdFor(recipient)
|
||||
if (createThread) database.getOrCreateThreadIdFor(recipient)
|
||||
else database.getThreadIdIfExistsFor(recipient).let { if (it == -1L) null else it }
|
||||
} else {
|
||||
val recipient = Recipient.from(context, fromSerialized(publicKey), false)
|
||||
database.getOrCreateThreadIdFor(recipient)
|
||||
if (createThread) database.getOrCreateThreadIdFor(recipient)
|
||||
else database.getThreadIdIfExistsFor(recipient).let { if (it == -1L) null else it }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,6 +202,19 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:padding="@dimen/medium_spacing"
|
||||
android:textSize="@dimen/small_font_size"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textAlignment="center"
|
||||
android:id="@+id/placeholderText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/blockedBanner"
|
||||
android:elevation="8dp"
|
||||
tools:text="@string/activity_conversation_empty_state_default"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/messageRequestBar"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -1013,4 +1013,9 @@
|
||||
<string name="giphy_permission_title">Search GIFs?</string>
|
||||
<string name="giphy_permission_message">Session will connect to Giphy to provide search results. You will not have full metadata protection when sending GIFs.</string>
|
||||
<string name="activity_home_outdated_client_config">Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.</string>
|
||||
|
||||
<string name="activity_conversation_empty_state_read_only">There are no messages in <b>%s</b>.</string>
|
||||
<string name="activity_conversation_empty_state_note_to_self">You have no messages in Note to Self.</string>
|
||||
<string name="activity_conversation_empty_state_default">You have no messages from <b>%s</b>.\nSend a message to start the conversation!</string>
|
||||
|
||||
</resources>
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 3817b543f5f862b58afd50c285fbccc26bc82ee0
|
||||
Subproject commit 057318136c69f582b7fd78a39ee26686d1d5a3ec
|
@ -155,7 +155,7 @@ interface StorageProtocol {
|
||||
|
||||
// Thread
|
||||
fun getOrCreateThreadIdFor(address: Address): Long
|
||||
fun getOrCreateThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?): Long
|
||||
fun getThreadIdFor(publicKey: String, groupPublicKey: String?, openGroupID: String?, createThread: Boolean): Long?
|
||||
fun getThreadId(publicKeyOrOpenGroupID: String): Long?
|
||||
fun getThreadId(openGroup: OpenGroup): Long?
|
||||
fun getThreadId(address: Address): Long?
|
||||
|
@ -10,6 +10,7 @@ import nl.komponents.kovenant.task
|
||||
import org.session.libsession.database.StorageProtocol
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.messaging.messages.Message
|
||||
import org.session.libsession.messaging.messages.control.ClosedGroupControlMessage
|
||||
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||
import org.session.libsession.messaging.messages.control.UnsendRequest
|
||||
import org.session.libsession.messaging.messages.visible.ParsedMessage
|
||||
@ -61,13 +62,29 @@ class BatchMessageReceiveJob(
|
||||
private val OPEN_GROUP_ID_KEY = "open_group_id"
|
||||
}
|
||||
|
||||
private fun getThreadId(message: Message, storage: StorageProtocol): Long {
|
||||
private fun shouldCreateThread(parsedMessage: ParsedMessage): Boolean {
|
||||
val message = parsedMessage.message
|
||||
return message is VisibleMessage
|
||||
|| !message.isSenderSelf
|
||||
// TODO: sort out which messages should create threads: message requests? group creation threads? visible messages? others? calls?
|
||||
|
||||
// || (message is ClosedGroupControlMessage && message.kind is ClosedGroupControlMessage.Kind.New) // this was creating threads for self send messages (i.e. synced group creation)
|
||||
// if (message is ClosedGroupControlMessage && message.kind is ClosedGroupControlMessage.Kind.New) {
|
||||
// return true
|
||||
// }
|
||||
// if (parsedMessage.message.isSenderSelf ) {
|
||||
// // all the cases where we should add a self send creating the thread, i.e. group invite? visible message?
|
||||
// }
|
||||
// !parsedMessage.message.isSenderSelf || parsedMessage.message is VisibleMessage
|
||||
}
|
||||
|
||||
private fun getThreadId(message: Message, storage: StorageProtocol, shouldCreateThread: Boolean): Long? {
|
||||
val senderOrSync = when (message) {
|
||||
is VisibleMessage -> message.syncTarget ?: message.sender!!
|
||||
is ExpirationTimerUpdate -> message.syncTarget ?: message.sender!!
|
||||
else -> message.sender!!
|
||||
}
|
||||
return storage.getOrCreateThreadIdFor(senderOrSync, message.groupPublicKey, openGroupID)
|
||||
return storage.getThreadIdFor(senderOrSync, message.groupPublicKey, openGroupID, createThread = shouldCreateThread)
|
||||
}
|
||||
|
||||
override suspend fun execute(dispatcherName: String) {
|
||||
@ -88,9 +105,9 @@ class BatchMessageReceiveJob(
|
||||
try {
|
||||
val (message, proto) = MessageReceiver.parse(data, openGroupMessageServerID, openGroupPublicKey = serverPublicKey)
|
||||
message.serverHash = serverHash
|
||||
val threadID = getThreadId(message, storage)
|
||||
val parsedParams = ParsedMessage(messageParameters, message, proto)
|
||||
if (!threadMap.containsKey(threadID)) {
|
||||
val threadID = getThreadId(message, storage, shouldCreateThread(parsedParams))
|
||||
if (threadID != null && !threadMap.containsKey(threadID)) {
|
||||
threadMap[threadID] = mutableListOf(parsedParams)
|
||||
} else {
|
||||
threadMap[threadID]!! += parsedParams
|
||||
|
@ -11,6 +11,7 @@ abstract class Message {
|
||||
var receivedTimestamp: Long? = null
|
||||
var recipient: String? = null
|
||||
var sender: String? = null
|
||||
var isSenderSelf: Boolean = false
|
||||
var groupPublicKey: String? = null
|
||||
var openGroupServerMessageID: Long? = null
|
||||
var serverHash: String? = null
|
||||
|
@ -149,6 +149,9 @@ object MessageReceiver {
|
||||
if (!message.isSelfSendValid && (sender == userPublicKey || isUserBlindedSender)) {
|
||||
throw Error.SelfSend
|
||||
}
|
||||
if (sender == userPublicKey || isUserBlindedSender) {
|
||||
message.isSenderSelf = true
|
||||
}
|
||||
// Guard against control messages in open groups
|
||||
if (isOpenGroupMessage && message !is VisibleMessage) {
|
||||
throw Error.InvalidMessage
|
||||
|
@ -440,7 +440,7 @@ object MessageSender {
|
||||
}
|
||||
|
||||
fun sendNonDurably(message: Message, address: Address): Promise<Unit, Exception> {
|
||||
val threadID = MessagingModuleConfiguration.shared.storage.getOrCreateThreadIdFor(address)
|
||||
val threadID = MessagingModuleConfiguration.shared.storage.getThreadId(address)
|
||||
message.threadID = threadID
|
||||
val destination = Destination.from(address)
|
||||
return send(message, destination)
|
||||
|
@ -232,11 +232,9 @@ fun MessageReceiver.handleVisibleMessage(
|
||||
// Get or create thread
|
||||
// FIXME: In case this is an open group this actually * doesn't * create the thread if it doesn't yet
|
||||
// exist. This is intentional, but it's very non-obvious.
|
||||
val threadID = storage.getOrCreateThreadIdFor(message.syncTarget ?: messageSender!!, message.groupPublicKey, openGroupID)
|
||||
if (threadID < 0) {
|
||||
val threadID = storage.getThreadIdFor(message.syncTarget ?: messageSender!!, message.groupPublicKey, openGroupID, createThread = true)
|
||||
// Thread doesn't exist; should only be reached in a case where we are processing open group messages for a no longer existent thread
|
||||
throw MessageReceiver.Error.NoThread
|
||||
}
|
||||
?: throw MessageReceiver.Error.NoThread
|
||||
val threadRecipient = storage.getRecipientForThread(threadID)
|
||||
val userBlindedKey = openGroupID?.let {
|
||||
val openGroup = storage.getOpenGroup(threadID) ?: return@let null
|
||||
|
Loading…
Reference in New Issue
Block a user