Merge pull request #570 from oxen-io/performance

Batch Conversation Updates
This commit is contained in:
Niels Andriesse 2021-05-27 15:21:14 +10:00 committed by GitHub
commit 877bd68b2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 60 additions and 42 deletions

View File

@ -21,6 +21,7 @@ import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
@ -47,7 +48,6 @@ import org.session.libsignal.utilities.ThreadUtils;
import org.signal.aesgcmprovider.AesGcmProvider; import org.signal.aesgcmprovider.AesGcmProvider;
import org.thoughtcrime.securesms.components.TypingStatusSender; import org.thoughtcrime.securesms.components.TypingStatusSender;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule; import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule;
import org.thoughtcrime.securesms.jobmanager.DependencyInjector; import org.thoughtcrime.securesms.jobmanager.DependencyInjector;
@ -120,14 +120,12 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
private ProfileManager profileManager; private ProfileManager profileManager;
private ObjectGraph objectGraph; private ObjectGraph objectGraph;
private PersistentLogger persistentLogger; private PersistentLogger persistentLogger;
// Loki
public MessageNotifier messageNotifier = null; public MessageNotifier messageNotifier = null;
public Poller poller = null; public Poller poller = null;
public Broadcaster broadcaster = null; public Broadcaster broadcaster = null;
public SignalCommunicationModule communicationModule; public SignalCommunicationModule communicationModule;
private Job firebaseInstanceIdJob; private Job firebaseInstanceIdJob;
private Handler threadNotificationHandler; private Handler conversationListNotificationHandler;
private volatile boolean isAppVisible; private volatile boolean isAppVisible;
@ -135,8 +133,8 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
return (ApplicationContext) context.getApplicationContext(); return (ApplicationContext) context.getApplicationContext();
} }
public Handler getThreadNotificationHandler() { public Handler getConversationListNotificationHandler() {
return this.threadNotificationHandler; return this.conversationListNotificationHandler;
} }
@Override @Override
@ -153,7 +151,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
AppContext.INSTANCE.configureKovenant(); AppContext.INSTANCE.configureKovenant();
messageNotifier = new OptimizedMessageNotifier(new DefaultMessageNotifier()); messageNotifier = new OptimizedMessageNotifier(new DefaultMessageNotifier());
broadcaster = new Broadcaster(this); broadcaster = new Broadcaster(this);
threadNotificationHandler = new Handler(Looper.getMainLooper()); conversationListNotificationHandler = new Handler(Looper.getMainLooper());
LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this); LokiAPIDatabase apiDB = DatabaseFactory.getLokiAPIDatabase(this);
MessagingModuleConfiguration.Companion.configure(this, MessagingModuleConfiguration.Companion.configure(this,
DatabaseFactory.getStorage(this), DatabaseFactory.getStorage(this),

View File

@ -0,0 +1,37 @@
package org.thoughtcrime.securesms.database
import android.annotation.SuppressLint
import android.content.Context
import android.os.Handler
import android.os.Looper
import org.session.libsession.utilities.Debouncer
import org.thoughtcrime.securesms.ApplicationContext
class ConversationNotificationDebouncer(private val context: Context) {
private val threadIDs = mutableSetOf<Long>()
private val handler = Handler(Looper.getMainLooper())
private val debouncer = Debouncer(handler, 250);
companion object {
@SuppressLint("StaticFieldLeak")
lateinit var shared: ConversationNotificationDebouncer
fun get(context: Context): ConversationNotificationDebouncer {
if (::shared.isInitialized) { return shared }
shared = ConversationNotificationDebouncer(context)
return shared
}
}
fun notify(threadID: Long) {
threadIDs.add(threadID)
debouncer.publish { publish() }
}
private fun publish() {
for (threadID in threadIDs) {
context.contentResolver.notifyChange(DatabaseContentProviders.Conversation.getUriForThread(threadID), null)
}
threadIDs.clear()
}
}

View File

@ -35,13 +35,13 @@ public abstract class Database {
protected SQLCipherOpenHelper databaseHelper; protected SQLCipherOpenHelper databaseHelper;
protected final Context context; protected final Context context;
private final Debouncer threadNotificationDebouncer; private final Debouncer conversationListNotificationDebouncer;
@SuppressLint("WrongConstant") @SuppressLint("WrongConstant")
public Database(Context context, SQLCipherOpenHelper databaseHelper) { public Database(Context context, SQLCipherOpenHelper databaseHelper) {
this.context = context; this.context = context;
this.databaseHelper = databaseHelper; this.databaseHelper = databaseHelper;
this.threadNotificationDebouncer = new Debouncer(ApplicationContext.getInstance(context).getThreadNotificationHandler(), 250); this.conversationListNotificationDebouncer = new Debouncer(ApplicationContext.getInstance(context).getConversationListNotificationHandler(), 250);
} }
protected void notifyConversationListeners(Set<Long> threadIds) { protected void notifyConversationListeners(Set<Long> threadIds) {
@ -50,11 +50,11 @@ public abstract class Database {
} }
protected void notifyConversationListeners(long threadId) { protected void notifyConversationListeners(long threadId) {
context.getContentResolver().notifyChange(DatabaseContentProviders.Conversation.getUriForThread(threadId), null); ConversationNotificationDebouncer.Companion.get(context).notify(threadId);
} }
protected void notifyConversationListListeners() { protected void notifyConversationListListeners() {
threadNotificationDebouncer.publish(()->context.getContentResolver().notifyChange(DatabaseContentProviders.ConversationList.CONTENT_URI, null)); conversationListNotificationDebouncer.publish(()->context.getContentResolver().notifyChange(DatabaseContentProviders.ConversationList.CONTENT_URI, null));
} }
protected void notifyStickerListeners() { protected void notifyStickerListeners() {

View File

@ -3,8 +3,8 @@ package org.thoughtcrime.securesms.database
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import org.session.libsession.database.StorageProtocol import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.jobs.*
import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.*
import org.session.libsession.messaging.messages.control.ConfigurationMessage import org.session.libsession.messaging.messages.control.ConfigurationMessage
import org.session.libsession.messaging.messages.signal.* import org.session.libsession.messaging.messages.signal.*
import org.session.libsession.messaging.messages.signal.IncomingTextMessage import org.session.libsession.messaging.messages.signal.IncomingTextMessage
@ -16,20 +16,15 @@ import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAt
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.Address.Companion.fromSerialized
import org.session.libsession.utilities.GroupRecord
import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.messaging.utilities.UpdateMessageData import org.session.libsession.messaging.utilities.UpdateMessageData
import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.*
import org.session.libsession.utilities.IdentityKeyUtil import org.session.libsession.utilities.Address.Companion.fromSerialized
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.ProfileKeyUtil
import org.session.libsignal.crypto.ecc.ECKeyPair import org.session.libsignal.crypto.ecc.ECKeyPair
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.utilities.guava.Optional
import org.session.libsignal.messages.SignalServiceAttachmentPointer import org.session.libsignal.messages.SignalServiceAttachmentPointer
import org.session.libsignal.messages.SignalServiceGroup import org.session.libsignal.messages.SignalServiceGroup
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.utilities.guava.Optional
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob
@ -100,7 +95,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
override fun persist(message: VisibleMessage, quotes: QuoteModel?, linkPreview: List<LinkPreview?>, groupPublicKey: String?, openGroupID: String?, attachments: List<Attachment>): Long? { override fun persist(message: VisibleMessage, quotes: QuoteModel?, linkPreview: List<LinkPreview?>, groupPublicKey: String?, openGroupID: String?, attachments: List<Attachment>): Long? {
var messageID: Long? = null var messageID: Long? = null
val senderAddress = Address.fromSerialized(message.sender!!) val senderAddress = Address.fromSerialized(message.sender!!)
val isUserSender = message.sender!! == getUserPublicKey() val isUserSender = (message.sender!! == getUserPublicKey())
val group: Optional<SignalServiceGroup> = when { val group: Optional<SignalServiceGroup> = when {
openGroupID != null -> Optional.of(SignalServiceGroup(openGroupID.toByteArray(), SignalServiceGroup.GroupType.PUBLIC_CHAT)) openGroupID != null -> Optional.of(SignalServiceGroup(openGroupID.toByteArray(), SignalServiceGroup.GroupType.PUBLIC_CHAT))
groupPublicKey != null -> { groupPublicKey != null -> {
@ -120,7 +115,6 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
senderAddress senderAddress
} }
val targetRecipient = Recipient.from(context, targetAddress, false) val targetRecipient = Recipient.from(context, targetAddress, false)
if (message.isMediaMessage() || attachments.isNotEmpty()) { if (message.isMediaMessage() || attachments.isNotEmpty()) {
val quote: Optional<QuoteModel> = if (quotes != null) Optional.of(quotes) else Optional.absent() val quote: Optional<QuoteModel> = if (quotes != null) Optional.of(quotes) else Optional.absent()
val linkPreviews: Optional<List<LinkPreview>> = if (linkPreview.isEmpty()) Optional.absent() else Optional.of(linkPreview.mapNotNull { it!! }) val linkPreviews: Optional<List<LinkPreview>> = if (linkPreview.isEmpty()) Optional.absent() else Optional.of(linkPreview.mapNotNull { it!! })

View File

@ -51,17 +51,12 @@ import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.mms.GlideRequests
import java.io.IOException import java.io.IOException
class HomeActivity : PassphraseRequiredActionBarActivity(), class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickListener, SeedReminderViewDelegate, NewConversationButtonSetViewDelegate {
ConversationClickListener,
SeedReminderViewDelegate,
NewConversationButtonSetViewDelegate {
private lateinit var glide: GlideRequests private lateinit var glide: GlideRequests
private var broadcastReceiver: BroadcastReceiver? = null private var broadcastReceiver: BroadcastReceiver? = null
private val publicKey: String private val publicKey: String
get() { get() = TextSecurePreferences.getLocalNumber(this)!!
return TextSecurePreferences.getLocalNumber(this)!!
}
// region Lifecycle // region Lifecycle
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) { override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {

View File

@ -35,13 +35,8 @@ class ConversationView : LinearLayout {
setUpViewHierarchy() setUpViewHierarchy()
} }
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
setUpViewHierarchy()
}
private fun setUpViewHierarchy() { private fun setUpViewHierarchy() {
LayoutInflater.from(context) LayoutInflater.from(context).inflate(R.layout.view_conversation, this)
.inflate(R.layout.view_conversation, this)
} }
// endregion // endregion
@ -75,7 +70,7 @@ class ConversationView : LinearLayout {
typingIndicatorView.visibility = if (isTyping) View.VISIBLE else View.GONE typingIndicatorView.visibility = if (isTyping) View.VISIBLE else View.GONE
statusIndicatorImageView.visibility = View.VISIBLE statusIndicatorImageView.visibility = View.VISIBLE
when { when {
!thread.isOutgoing || thread.isVerificationStatusChange -> statusIndicatorImageView.visibility = View.GONE !thread.isOutgoing -> statusIndicatorImageView.visibility = View.GONE
thread.isFailed -> statusIndicatorImageView.setImageResource(R.drawable.ic_error) thread.isFailed -> statusIndicatorImageView.setImageResource(R.drawable.ic_error)
thread.isPending -> statusIndicatorImageView.setImageResource(R.drawable.ic_circle_dot_dot_dot) thread.isPending -> statusIndicatorImageView.setImageResource(R.drawable.ic_circle_dot_dot_dot)
thread.isRemoteRead -> statusIndicatorImageView.setImageResource(R.drawable.ic_filled_circle_check) thread.isRemoteRead -> statusIndicatorImageView.setImageResource(R.drawable.ic_filled_circle_check)

View File

@ -12,8 +12,8 @@ import org.session.libsession.messaging.messages.visible.Attachment
import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.messages.visible.VisibleMessage
import org.session.libsession.messaging.open_groups.OpenGroupV2 import org.session.libsession.messaging.open_groups.OpenGroupV2
import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId import org.session.libsession.messaging.sending_receiving.attachments.AttachmentId
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachment
import org.session.libsession.messaging.sending_receiving.data_extraction.DataExtractionNotificationInfoMessage
import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview
import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel
import org.session.libsession.utilities.Address import org.session.libsession.utilities.Address

View File

@ -12,7 +12,6 @@ import android.os.Handler;
* See http://rxmarbles.com/#debounce * See http://rxmarbles.com/#debounce
*/ */
public class Debouncer { public class Debouncer {
private final Handler handler; private final Handler handler;
private final long threshold; private final long threshold;