mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-25 01:07:47 +00:00
Merge pull request #570 from oxen-io/performance
Batch Conversation Updates
This commit is contained in:
commit
877bd68b2d
@ -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),
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
@ -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() {
|
||||||
|
@ -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!! })
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user