Skip to content

Commit

Permalink
Merge pull request #1495 from oxen-io/release-1.18.3
Browse files Browse the repository at this point in the history
Merge release-1.18.3 to master
  • Loading branch information
bemusementpark authored May 24, 2024
2 parents 1354bcc + 98f279f commit 455a1ed
Show file tree
Hide file tree
Showing 22 changed files with 106 additions and 76 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ configurations.all {
exclude module: "commons-logging"
}

def canonicalVersionCode = 370
def canonicalVersionName = "1.18.2"
def canonicalVersionCode = 372
def canonicalVersionName = "1.18.3"

def postFixSize = 10
def abiPostFix = ['armeabi-v7a' : 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.crypto.KeyPairUtilities;
import org.thoughtcrime.securesms.database.EmojiSearchDatabase;
import org.thoughtcrime.securesms.database.LastSentTimestampCache;
import org.thoughtcrime.securesms.database.LokiAPIDatabase;
import org.thoughtcrime.securesms.database.Storage;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
Expand Down Expand Up @@ -149,6 +150,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
@Inject TextSecurePreferences textSecurePreferences;
@Inject PushRegistry pushRegistry;
@Inject ConfigFactory configFactory;
@Inject LastSentTimestampCache lastSentTimestampCache;
CallMessageProcessor callMessageProcessor;
MessagingModuleConfiguration messagingModuleConfiguration;

Expand Down Expand Up @@ -218,7 +220,8 @@ public void onCreate() {
device,
messageDataProvider,
()-> KeyPairUtilities.INSTANCE.getUserED25519KeyPair(this),
configFactory
configFactory,
lastSentTimestampCache
);
callMessageProcessor = new CallMessageProcessor(this, textSecurePreferences, ProcessLifecycleOwner.get().getLifecycle(), storage);
Log.i(TAG, "onCreate()");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import android.text.TextUtils
import com.google.protobuf.ByteString
import org.greenrobot.eventbus.EventBus
import org.session.libsession.database.MessageDataProvider
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.messages.control.UnsendRequest
import org.session.libsession.messaging.sending_receiving.attachments.Attachment
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentState
Expand Down Expand Up @@ -185,22 +187,33 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper)
val messagingDatabase: MessagingDatabase = if (isSms) DatabaseComponent.get(context).smsDatabase()
else DatabaseComponent.get(context).mmsDatabase()

val (threadId, timestamp) = runCatching { messagingDatabase.getMessageRecord(messageID).run { threadId to timestamp } }.getOrNull() ?: (null to null)

messagingDatabase.deleteMessage(messageID)
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessage(messageID, isSms)
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessageServerHash(messageID, mms = !isSms)

threadId ?: return
timestamp ?: return
MessagingModuleConfiguration.shared.lastSentTimestampCache.delete(threadId, timestamp)
}

override fun deleteMessages(messageIDs: List<Long>, threadId: Long, isSms: Boolean) {

val messagingDatabase: MessagingDatabase = if (isSms) DatabaseComponent.get(context).smsDatabase()
else DatabaseComponent.get(context).mmsDatabase()

val messages = messageIDs.mapNotNull { runCatching { messagingDatabase.getMessageRecord(it) }.getOrNull() }

// Perform local delete
messagingDatabase.deleteMessages(messageIDs.toLongArray(), threadId)

// Perform online delete
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessages(messageIDs)
DatabaseComponent.get(context).lokiMessageDatabase().deleteMessageServerHashes(messageIDs, mms = !isSms)

val threadId = messages.firstOrNull()?.threadId
threadId?.let{ MessagingModuleConfiguration.shared.lastSentTimestampCache.delete(it, messages.map { it.timestamp }) }
}

override fun updateMessageAsDeleted(timestamp: Long, author: String): Long? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
}
},
onAttachmentNeedsDownload = { attachmentId, mmsId ->
// Start download (on IO thread)
lifecycleScope.launch(Dispatchers.IO) {
JobQueue.shared.add(AttachmentDownloadJob(attachmentId, mmsId))
}
Expand All @@ -335,8 +334,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
)
adapter.visibleMessageViewDelegate = this

// Register an AdapterDataObserver to scroll us to the bottom of the RecyclerView if we're
// already near the the bottom and the data changes.
// Register an AdapterDataObserver to scroll us to the bottom of the RecyclerView for if
// we're already near the the bottom and the data changes.
adapter.registerAdapterDataObserver(ConversationAdapterDataObserver(binding?.conversationRecyclerView!!, adapter))

adapter
Expand All @@ -360,6 +359,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
private var currentLastVisibleRecyclerViewIndex: Int = RecyclerView.NO_POSITION
private var recyclerScrollState: Int = RecyclerView.SCROLL_STATE_IDLE


// region Settings
companion object {
// Extras
Expand All @@ -374,7 +374,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
const val PICK_GIF = 10
const val PICK_FROM_LIBRARY = 12
const val INVITE_CONTACTS = 124

}
// endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@ import kotlinx.coroutines.launch
import network.loki.messenger.R
import network.loki.messenger.databinding.ViewVisibleMessageBinding
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.conversation.v2.messages.ControlMessageView
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView
import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageViewDelegate
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter
import org.thoughtcrime.securesms.database.MmsSmsColumns
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.mms.GlideRequests
Expand Down Expand Up @@ -59,7 +57,6 @@ class ConversationAdapter(
private val contactCache = SparseArray<Contact>(100)
private val contactLoadedCache = SparseBooleanArray(100)
private val lastSeen = AtomicLong(originalLastSeen)
private var lastSentMessageId: Long = -1L

init {
lifecycleCoroutineScope.launch(IO) {
Expand Down Expand Up @@ -139,8 +136,7 @@ class ConversationAdapter(
senderId,
lastSeen.get(),
visibleMessageViewDelegate,
onAttachmentNeedsDownload,
lastSentMessageId
onAttachmentNeedsDownload
)

if (!message.isDeleted) {
Expand Down Expand Up @@ -209,20 +205,6 @@ class ConversationAdapter(
return messageDB.readerFor(cursor).current
}

private fun getLastSentMessageId(cursor: Cursor): Long {
// If we don't move to first (or at least step backwards) we can step off the end of the
// cursor and any query will return an "Index = -1" error.
val cursorHasContent = cursor.moveToFirst()
if (cursorHasContent) {
val thisThreadId = cursor.getLong(4) // Column index 4 is "thread_id"
if (thisThreadId != -1L) {
val thisUsersSessionId = TextSecurePreferences.getLocalNumber(context)
return messageDB.getLastSentMessageFromSender(thisThreadId, thisUsersSessionId)
}
}
return -1L
}

override fun changeCursor(cursor: Cursor?) {
super.changeCursor(cursor)

Expand All @@ -243,11 +225,6 @@ class ConversationAdapter(
toDeselect.iterator().forEach { (pos, record) ->
onDeselect(record, pos)
}

// This value gets updated here ONLY when the cursor changes, and the value is then passed
// through to `VisibleMessageView.bind` each time we bind via `onBindItemViewHolder`, above.
// If there are no messages then lastSentMessageId is assigned the value -1L.
if (cursor != null) { lastSentMessageId = getLastSentMessageId(cursor) }
}

fun findLastSeenItemPosition(lastSeenTimestamp: Long): Int? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2

import android.content.Context
import android.database.Cursor
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.util.AbstractCursorLoader

Expand All @@ -12,6 +13,7 @@ class ConversationLoader(
) : AbstractCursorLoader(context) {

override fun getCursor(): Cursor {
MessagingModuleConfiguration.shared.lastSentTimestampCache.refresh(threadID)
return DatabaseComponent.get(context).mmsSmsDatabase().getConversation(threadID, reverse)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.view.marginBottom
import dagger.hilt.android.AndroidEntryPoint
Expand All @@ -32,13 +31,12 @@ import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.contacts.Contact.ContactContext
import org.session.libsession.messaging.open_groups.OpenGroupApi
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsession.utilities.ViewUtil
import org.session.libsession.utilities.getColorFromAttr
import org.session.libsession.utilities.modifyLayoutParams
import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2
import org.thoughtcrime.securesms.database.LastSentTimestampCache
import org.thoughtcrime.securesms.database.LokiAPIDatabase
import org.thoughtcrime.securesms.database.LokiThreadDatabase
import org.thoughtcrime.securesms.database.MmsDatabase
Expand Down Expand Up @@ -73,6 +71,7 @@ class VisibleMessageView : LinearLayout {
@Inject lateinit var mmsSmsDb: MmsSmsDatabase
@Inject lateinit var smsDb: SmsDatabase
@Inject lateinit var mmsDb: MmsDatabase
@Inject lateinit var lastSentTimestampCache: LastSentTimestampCache

private val binding by lazy { ViewVisibleMessageBinding.bind(this) }
private val swipeToReplyIcon = ContextCompat.getDrawable(context, R.drawable.ic_baseline_reply_24)!!.mutate()
Expand Down Expand Up @@ -134,8 +133,7 @@ class VisibleMessageView : LinearLayout {
senderSessionID: String,
lastSeen: Long,
delegate: VisibleMessageViewDelegate? = null,
onAttachmentNeedsDownload: (Long, Long) -> Unit,
lastSentMessageId: Long
onAttachmentNeedsDownload: (Long, Long) -> Unit
) {
replyDisabled = message.isOpenGroupInvitation
val threadID = message.threadId
Expand Down Expand Up @@ -303,10 +301,6 @@ class VisibleMessageView : LinearLayout {

// --- If we got here then we know the message is outgoing ---

val thisUsersSessionId = TextSecurePreferences.getLocalNumber(context)
val lastSentMessageId = mmsSmsDb.getLastSentMessageFromSender(message.threadId, thisUsersSessionId)
val isLastSentMessage = lastSentMessageId == message.id

// ----- Case ii.) Message is outgoing but NOT scheduled to disappear -----
if (!scheduledToDisappear) {
// If this isn't a disappearing message then we never show the timer
Expand All @@ -319,9 +313,11 @@ class VisibleMessageView : LinearLayout {
} else {
// ..but if the message HAS been successfully sent or read then only display the delivery status
// text and image if this is the last sent message.
binding.messageStatusTextView.isVisible = isLastSentMessage
binding.messageStatusImageView.isVisible = isLastSentMessage
if (isLastSentMessage) { binding.messageStatusImageView.bringToFront() }
val lastSentTimestamp = lastSentTimestampCache.getTimestamp(message.threadId)
val isLastSent = lastSentTimestamp == message.timestamp
binding.messageStatusTextView.isVisible = isLastSent
binding.messageStatusImageView.isVisible = isLastSent
if (isLastSent) { binding.messageStatusImageView.bringToFront() }
}
}
else // ----- Case iii.) Message is outgoing AND scheduled to disappear -----
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package org.thoughtcrime.securesms.crypto

import android.content.Context
import com.goterl.lazysodium.LazySodiumAndroid
import com.goterl.lazysodium.SodiumAndroid
import com.goterl.lazysodium.utils.Key
import com.goterl.lazysodium.utils.KeyPair
import org.session.libsession.messaging.utilities.SodiumUtilities.sodium
import org.session.libsignal.crypto.ecc.DjbECPrivateKey
import org.session.libsignal.crypto.ecc.DjbECPublicKey
import org.session.libsignal.crypto.ecc.ECKeyPair
Expand All @@ -13,8 +12,6 @@ import org.session.libsignal.utilities.Hex

object KeyPairUtilities {

private val sodium by lazy { LazySodiumAndroid(SodiumAndroid()) }

fun generate(): KeyPairGenerationResult {
val seed = sodium.randomBytesBuf(16)
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.thoughtcrime.securesms.database

import org.session.libsession.messaging.LastSentTimestampCache
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class LastSentTimestampCache @Inject constructor(
val mmsSmsDatabase: MmsSmsDatabase
): LastSentTimestampCache {

private val map = mutableMapOf<Long, Long>()

@Synchronized
override fun getTimestamp(threadId: Long): Long? = map[threadId]

@Synchronized
override fun submitTimestamp(threadId: Long, timestamp: Long) {
if (map[threadId]?.let { timestamp <= it } == true) return

map[threadId] = timestamp
}

@Synchronized
override fun delete(threadId: Long, timestamps: List<Long>) {
if (map[threadId]?.let { it !in timestamps } == true) return
map.remove(threadId)
refresh(threadId)
}

@Synchronized
override fun refresh(threadId: Long) {
if (map[threadId]?.let { it > 0 } == true) return
val lastOutgoingTimestamp = mmsSmsDatabase.getLastOutgoingTimestamp(threadId)
if (lastOutgoingTimestamp <= 0) return
map[threadId] = lastOutgoingTimestamp
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ public interface MmsSmsColumns {
public static final String THREAD_ID = "thread_id";
public static final String READ = "read";
public static final String BODY = "body";

// This is the address of the message recipient, which may be a single user, a group, or a community!
// It is NOT the address of the sender of any given message!
public static final String ADDRESS = "address";

public static final String ADDRESS_DEVICE_ID = "address_device_id";
public static final String DELIVERY_RECEIPT_COUNT = "delivery_receipt_count";
public static final String READ_RECEIPT_COUNT = "read_receipt_count";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,24 +295,21 @@ public Set<Long> getAllMessageIdsFromSenderInThread(long threadId, String serial
return identifiedMessages;
}

public long getLastSentMessageFromSender(long threadId, String serializedAuthor) {

// Early exit
boolean isOwnNumber = Util.isOwnNumber(context, serializedAuthor);
if (!isOwnNumber) {
Log.i(TAG, "Asked to find last sent message but sender isn't us - returning null.");
return -1;
}

public long getLastOutgoingTimestamp(long threadId) {
String order = MmsSmsColumns.NORMALIZED_DATE_SENT + " DESC";
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;

// Try everything with resources so that they auto-close on end of scope
try (Cursor cursor = queryTables(PROJECTION, selection, order, null)) {
try (MmsSmsDatabase.Reader reader = readerFor(cursor)) {
MessageRecord messageRecord;
long attempts = 0;
long maxAttempts = 20;
while ((messageRecord = reader.getNext()) != null) {
if (messageRecord.isOutgoing()) { return messageRecord.id; }
// Note: We rely on the message order to get us the most recent outgoing message - so we
// take the first outgoing message we find as the last outgoing message.
if (messageRecord.isOutgoing()) return messageRecord.getTimestamp();
if (attempts++ > maxAttempts) break;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.session.libsession.messaging.jobs.MessageReceiveParameters
import org.session.libsession.messaging.sending_receiving.notifications.PushNotificationMetadata
import org.session.libsession.messaging.utilities.MessageWrapper
import org.session.libsession.messaging.utilities.SodiumUtilities
import org.session.libsession.messaging.utilities.SodiumUtilities.sodium
import org.session.libsession.utilities.bencode.Bencode
import org.session.libsession.utilities.bencode.BencodeList
import org.session.libsession.utilities.bencode.BencodeString
Expand All @@ -28,7 +29,6 @@ import javax.inject.Inject
private const val TAG = "PushHandler"

class PushReceiver @Inject constructor(@ApplicationContext val context: Context) {
private val sodium = LazySodiumAndroid(SodiumAndroid())
private val json = Json { ignoreUnknownKeys = true }

fun onPush(dataMap: Map<String, String>?) {
Expand Down
Loading

0 comments on commit 455a1ed

Please sign in to comment.