refactor: performance experiments

This commit is contained in:
jubb 2021-07-29 17:02:58 +10:00
parent 9d9f543c3b
commit 0ed7b28b6b
12 changed files with 72 additions and 57 deletions

View File

@ -35,7 +35,6 @@ dependencies {
implementation 'androidx.gridlayout:gridlayout:1.0.0' implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.exifinterface:exifinterface:1.2.0' implementation 'androidx.exifinterface:exifinterface:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.3.1' implementation 'androidx.lifecycle:lifecycle-common-java8:2.3.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
@ -96,7 +95,7 @@ dependencies {
} }
implementation 'com.codewaves.stickyheadergrid:stickyheadergrid:0.9.4' implementation 'com.codewaves.stickyheadergrid:stickyheadergrid:0.9.4'
implementation 'com.github.dmytrodanylyk.circular-progress-button:library:1.1.3-S2' implementation 'com.github.dmytrodanylyk.circular-progress-button:library:1.1.3-S2'
implementation 'net.zetetic:android-database-sqlcipher:4.4.3' implementation 'org.signal:android-database-sqlcipher:3.5.9-S3'
implementation ('com.googlecode.ez-vcard:ez-vcard:0.9.11') { implementation ('com.googlecode.ez-vcard:ez-vcard:0.9.11') {
exclude group: 'com.fasterxml.jackson.core' exclude group: 'com.fasterxml.jackson.core'
exclude group: 'org.freemarker' exclude group: 'org.freemarker'
@ -214,7 +213,6 @@ android {
buildTypes { buildTypes {
release { release {
debuggable true
minifyEnabled false minifyEnabled false
} }
debug { debug {

View File

@ -15,6 +15,7 @@
*/ */
package org.thoughtcrime.securesms; package org.thoughtcrime.securesms;
import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.AsyncTask; import android.os.AsyncTask;
@ -26,7 +27,6 @@ import androidx.annotation.NonNull;
import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner; import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.multidex.MultiDexApplication;
import org.conscrypt.Conscrypt; import org.conscrypt.Conscrypt;
import org.session.libsession.avatars.AvatarHelper; import org.session.libsession.avatars.AvatarHelper;
@ -104,7 +104,7 @@ import static nl.komponents.kovenant.android.KovenantAndroid.stopKovenant;
* *
* @author Moxie Marlinspike * @author Moxie Marlinspike
*/ */
public class ApplicationContext extends MultiDexApplication implements DependencyInjector, DefaultLifecycleObserver { public class ApplicationContext extends Application implements DependencyInjector, DefaultLifecycleObserver {
public static final String PREFERENCES_NAME = "SecureSMS-Preferences"; public static final String PREFERENCES_NAME = "SecureSMS-Preferences";
@ -180,12 +180,15 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
Log.i(TAG, "App is now visible."); Log.i(TAG, "App is now visible.");
KeyCachingService.onAppForegrounded(this); KeyCachingService.onAppForegrounded(this);
if (poller != null) { ThreadUtils.queue(()->{
poller.setCaughtUp(false); if (poller != null) {
} poller.setCaughtUp(false);
startPollingIfNeeded(); }
OpenGroupManager.INSTANCE.startPolling(); startPollingIfNeeded();
OpenGroupManager.INSTANCE.startPolling();
});
} }
@Override @Override

View File

@ -1206,7 +1206,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val sortedMessages = messages.sortedBy { it.dateSent } val sortedMessages = messages.sortedBy { it.dateSent }
val builder = StringBuilder() val builder = StringBuilder()
for (message in sortedMessages) { for (message in sortedMessages) {
val body = MentionUtilities.highlightMentions(message.body, message.threadId, this) val body = MentionUtilities.highlightMentions(message.body, this)
if (TextUtils.isEmpty(body)) { continue } if (TextUtils.isEmpty(body)) { continue }
val formattedTimestamp = DateUtils.getDisplayFormattedTimeSpanString(this, Locale.getDefault(), message.timestamp) val formattedTimestamp = DateUtils.getDisplayFormattedTimeSpanString(this, Locale.getDefault(), message.timestamp)
builder.append("$formattedTimestamp: $body").append('\n') builder.append("$formattedTimestamp: $body").append('\n')

View File

@ -10,7 +10,6 @@ import androidx.annotation.ColorInt
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.text.toSpannable import androidx.core.text.toSpannable
import androidx.core.view.isVisible import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.view_link_preview.view.*
import kotlinx.android.synthetic.main.view_quote.view.* import kotlinx.android.synthetic.main.view_quote.view.*
import network.loki.messenger.R import network.loki.messenger.R
import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.contacts.Contact
@ -120,7 +119,7 @@ class QuoteView : LinearLayout {
} }
quoteViewAuthorTextView.isVisible = thread.isGroupRecipient quoteViewAuthorTextView.isVisible = thread.isGroupRecipient
// Body // Body
quoteViewBodyTextView.text = if (isOpenGroupInvitation) resources.getString(R.string.open_group_invitation_view__open_group_invitation) else MentionUtilities.highlightMentions((body ?: "").toSpannable(), threadID, context); quoteViewBodyTextView.text = if (isOpenGroupInvitation) resources.getString(R.string.open_group_invitation_view__open_group_invitation) else MentionUtilities.highlightMentions((body ?: "").toSpannable(), context);
quoteViewBodyTextView.setTextColor(getTextColor(isOutgoingMessage)) quoteViewBodyTextView.setTextColor(getTextColor(isOutgoingMessage))
// Accent line / attachment preview // Accent line / attachment preview
val hasAttachments = (attachments != null && attachments.asAttachments().isNotEmpty()) && !isOriginalMissing val hasAttachments = (attachments != null && attachments.asAttachments().isNotEmpty()) && !isOriginalMissing

View File

@ -223,7 +223,7 @@ class VisibleMessageContentView : LinearLayout {
body.setSpan(replacementSpan, start, end, flags) body.setSpan(replacementSpan, start, end, flags)
} }
body = MentionUtilities.highlightMentions(body, message.isOutgoing, message.threadId, context) body = MentionUtilities.highlightMentions(body, message.isOutgoing, context)
body = SearchUtil.getHighlightedSpan(Locale.getDefault(), StyleFactory { BackgroundColorSpan(Color.WHITE) }, body, searchQuery) body = SearchUtil.getHighlightedSpan(Locale.getDefault(), StyleFactory { BackgroundColorSpan(Color.WHITE) }, body, searchQuery)
body = SearchUtil.getHighlightedSpan(Locale.getDefault(), StyleFactory { ForegroundColorSpan(Color.BLACK) }, body, searchQuery) body = SearchUtil.getHighlightedSpan(Locale.getDefault(), StyleFactory { ForegroundColorSpan(Color.BLACK) }, body, searchQuery)

View File

@ -19,15 +19,13 @@ import java.util.regex.Pattern
object MentionUtilities { object MentionUtilities {
@JvmStatic @JvmStatic
fun highlightMentions(text: CharSequence, threadID: Long, context: Context): String { fun highlightMentions(text: CharSequence, context: Context): String {
return highlightMentions(text, false, threadID, context).toString() // isOutgoingMessage is irrelevant return highlightMentions(text, false, context).toString() // isOutgoingMessage is irrelevant
} }
@JvmStatic @JvmStatic
fun highlightMentions(text: CharSequence, isOutgoingMessage: Boolean, threadID: Long, context: Context): SpannableString { fun highlightMentions(text: CharSequence, isOutgoingMessage: Boolean, context: Context): SpannableString {
@Suppress("NAME_SHADOWING") var text = text @Suppress("NAME_SHADOWING") var text = text
val threadDB = DatabaseFactory.getThreadDatabase(context)
val isOpenGroup = threadDB.getRecipientForThreadId(threadID)?.isOpenGroupRecipient ?: false
val pattern = Pattern.compile("@[0-9a-fA-F]*") val pattern = Pattern.compile("@[0-9a-fA-F]*")
var matcher = pattern.matcher(text) var matcher = pattern.matcher(text)
val mentions = mutableListOf<Tuple2<Range<Int>, String>>() val mentions = mutableListOf<Tuple2<Range<Int>, String>>()
@ -40,8 +38,7 @@ object MentionUtilities {
TextSecurePreferences.getProfileName(context) TextSecurePreferences.getProfileName(context)
} else { } else {
val contact = DatabaseFactory.getSessionContactDatabase(context).getContactWithSessionID(publicKey) val contact = DatabaseFactory.getSessionContactDatabase(context).getContactWithSessionID(publicKey)
@Suppress("NAME_SHADOWING") val context = if (isOpenGroup) Contact.ContactContext.OPEN_GROUP else Contact.ContactContext.REGULAR contact?.displayName(Contact.ContactContext.REGULAR)
contact?.displayName(context)
} }
if (userDisplayName != null) { if (userDisplayName != null) {
text = text.subSequence(0, matcher.start()).toString() + "@" + userDisplayName + text.subSequence(matcher.end(), text.length) text = text.subSequence(0, matcher.start()).toString() + "@" + userDisplayName + text.subSequence(matcher.end(), text.length)

View File

@ -69,7 +69,7 @@ class ConversationView : LinearLayout {
} }
muteIndicatorImageView.setImageResource(drawableRes) muteIndicatorImageView.setImageResource(drawableRes)
val rawSnippet = thread.getDisplayBody(context) val rawSnippet = thread.getDisplayBody(context)
val snippet = highlightMentions(rawSnippet, thread.threadId, context) val snippet = highlightMentions(rawSnippet, context)
snippetTextView.text = snippet snippetTextView.text = snippet
snippetTextView.typeface = if (unreadCount > 0) Typeface.DEFAULT_BOLD else Typeface.DEFAULT snippetTextView.typeface = if (unreadCount > 0) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE snippetTextView.visibility = if (isTyping) View.GONE else View.VISIBLE

View File

@ -12,6 +12,7 @@ import android.text.SpannableString
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.core.view.isVisible
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.loader.app.LoaderManager import androidx.loader.app.LoaderManager
@ -19,9 +20,11 @@ import androidx.loader.content.Loader
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_home.* import kotlinx.android.synthetic.main.activity_home.*
import kotlinx.android.synthetic.main.seed_reminder_stub.view.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import network.loki.messenger.R import network.loki.messenger.R
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
@ -63,8 +66,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
// region Lifecycle // region Lifecycle
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) { override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
super.onCreate(savedInstanceState, isReady) super.onCreate(savedInstanceState, isReady)
// Double check that the long poller is up
(applicationContext as ApplicationContext).startPollingIfNeeded()
// Set content view // Set content view
setContentView(R.layout.activity_home) setContentView(R.layout.activity_home)
// Set custom toolbar // Set custom toolbar
@ -79,14 +80,18 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
// Set up seed reminder view // Set up seed reminder view
val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this) val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this)
if (!hasViewedSeed) { if (!hasViewedSeed) {
val seedReminderViewTitle = SpannableString("You're almost finished! 80%") // Intentionally not yet translated seedReminderStub.isVisible = true
seedReminderViewTitle.setSpan(ForegroundColorSpan(resources.getColorWithID(R.color.accent, theme)), 24, 27, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) seedReminderStub.apply {
seedReminderView.title = seedReminderViewTitle val seedReminderView = this.seedReminderView
seedReminderView.subtitle = resources.getString(R.string.view_seed_reminder_subtitle_1) val seedReminderViewTitle = SpannableString("You're almost finished! 80%") // Intentionally not yet translated
seedReminderView.setProgress(80, false) seedReminderViewTitle.setSpan(ForegroundColorSpan(resources.getColorWithID(R.color.accent, theme)), 24, 27, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
seedReminderView.delegate = this seedReminderView.title = seedReminderViewTitle
seedReminderView.subtitle = resources.getString(R.string.view_seed_reminder_subtitle_1)
seedReminderView.setProgress(80, false)
seedReminderView.delegate = this@HomeActivity
}
} else { } else {
seedReminderView.visibility = View.GONE seedReminderStub.isVisible = false
} }
// Set up recycler view // Set up recycler view
val cursor = DatabaseFactory.getThreadDatabase(this).conversationList val cursor = DatabaseFactory.getThreadDatabase(this).conversationList
@ -126,24 +131,30 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
this.broadcastReceiver = broadcastReceiver this.broadcastReceiver = broadcastReceiver
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter("blockedContactsChanged")) LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, IntentFilter("blockedContactsChanged"))
lifecycleScope.launchWhenResumed { lifecycleScope.launchWhenResumed {
// update things based on TextSecurePrefs (profile info etc) launch(Dispatchers.IO) {
// Set up typing observer // Double check that the long poller is up
ApplicationContext.getInstance(this@HomeActivity).typingStatusRepository.typingThreads.observe(this@HomeActivity, Observer<Set<Long>> { threadIDs -> (applicationContext as ApplicationContext).startPollingIfNeeded()
val adapter = recyclerView.adapter as HomeAdapter // update things based on TextSecurePrefs (profile info etc)
adapter.typingThreadIDs = threadIDs ?: setOf() // Set up typing observer
}) withContext(Dispatchers.Main) {
// Set up remaining components if needed ApplicationContext.getInstance(this@HomeActivity).typingStatusRepository.typingThreads.observe(this@HomeActivity, Observer<Set<Long>> { threadIDs ->
val application = ApplicationContext.getInstance(this@HomeActivity) val adapter = recyclerView.adapter as HomeAdapter
application.registerForFCMIfNeeded(false) adapter.typingThreadIDs = threadIDs ?: setOf()
val userPublicKey = TextSecurePreferences.getLocalNumber(this@HomeActivity) })
if (userPublicKey != null) { updateProfileButton()
OpenGroupManager.startPolling() TextSecurePreferences.events.filter { it == TextSecurePreferences.PROFILE_NAME_PREF }.collect {
JobQueue.shared.resumePendingJobs() updateProfileButton()
} }
updateProfileButton() }
IP2Country.configureIfNeeded(this@HomeActivity) // Set up remaining components if needed
TextSecurePreferences.events.filter { it == TextSecurePreferences.PROFILE_NAME_PREF }.collect { val application = ApplicationContext.getInstance(this@HomeActivity)
updateProfileButton() application.registerForFCMIfNeeded(false)
val userPublicKey = TextSecurePreferences.getLocalNumber(this@HomeActivity)
if (userPublicKey != null) {
OpenGroupManager.startPolling()
JobQueue.shared.resumePendingJobs()
}
IP2Country.configureIfNeeded(this@HomeActivity)
} }
} }
EventBus.getDefault().register(this@HomeActivity) EventBus.getDefault().register(this@HomeActivity)
@ -158,7 +169,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), ConversationClickLis
profileButton.update() profileButton.update()
val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this) val hasViewedSeed = TextSecurePreferences.getHasViewedSeed(this)
if (hasViewedSeed) { if (hasViewedSeed) {
seedReminderView.visibility = View.GONE seedReminderStub.visibility = View.GONE
} }
if (TextSecurePreferences.getConfigurationMessageSynced(this)) { if (TextSecurePreferences.getConfigurationMessageSynced(this)) {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {

View File

@ -83,7 +83,7 @@ public class LongMessageActivity extends PassphraseRequiredActionBarActivity {
} }
String trimmedBody = getTrimmedBody(message.get().getFullBody()); String trimmedBody = getTrimmedBody(message.get().getFullBody());
String mentionBody = MentionUtilities.highlightMentions(trimmedBody, message.get().getMessageRecord().getThreadId(), this); String mentionBody = MentionUtilities.highlightMentions(trimmedBody, this);
textBody.setText(mentionBody); textBody.setText(mentionBody);
textBody.setMovementMethod(LinkMovementMethod.getInstance()); textBody.setMovementMethod(LinkMovementMethod.getInstance());

View File

@ -324,7 +324,7 @@ public class DefaultMessageNotifier implements MessageNotifier {
builder.setThread(notifications.get(0).getRecipient()); builder.setThread(notifications.get(0).getRecipient());
builder.setMessageCount(notificationState.getMessageCount()); builder.setMessageCount(notificationState.getMessageCount());
builder.setPrimaryMessageBody(recipient, notifications.get(0).getIndividualRecipient(), builder.setPrimaryMessageBody(recipient, notifications.get(0).getIndividualRecipient(),
MentionUtilities.highlightMentions(notifications.get(0).getText(), notifications.get(0).getThreadId(), context), MentionUtilities.highlightMentions(notifications.get(0).getText(), context),
notifications.get(0).getSlideDeck()); notifications.get(0).getSlideDeck());
builder.setContentIntent(notifications.get(0).getPendingIntent(context)); builder.setContentIntent(notifications.get(0).getPendingIntent(context));
builder.setDeleteIntent(notificationState.getDeleteIntent(context)); builder.setDeleteIntent(notificationState.getDeleteIntent(context));
@ -400,13 +400,13 @@ public class DefaultMessageNotifier implements MessageNotifier {
while(iterator.hasPrevious()) { while(iterator.hasPrevious()) {
NotificationItem item = iterator.previous(); NotificationItem item = iterator.previous();
builder.addMessageBody(item.getIndividualRecipient(), item.getRecipient(), builder.addMessageBody(item.getIndividualRecipient(), item.getRecipient(),
MentionUtilities.highlightMentions(item.getText(), item.getThreadId(), context)); MentionUtilities.highlightMentions(item.getText(), context));
} }
if (signal) { if (signal) {
builder.setAlarms(notificationState.getRingtone(context), notificationState.getVibrate()); builder.setAlarms(notificationState.getRingtone(context), notificationState.getVibrate());
builder.setTicker(notifications.get(0).getIndividualRecipient(), builder.setTicker(notifications.get(0).getIndividualRecipient(),
MentionUtilities.highlightMentions(notifications.get(0).getText(), notifications.get(0).getThreadId(), context)); MentionUtilities.highlightMentions(notifications.get(0).getText(), context));
} }
Notification notification = builder.build(); Notification notification = builder.build();

View File

@ -70,10 +70,11 @@
android:background="?android:dividerHorizontal" android:background="?android:dividerHorizontal"
android:elevation="1dp" /> android:elevation="1dp" />
<org.thoughtcrime.securesms.onboarding.SeedReminderView <ViewStub
android:id="@+id/seedReminderView" android:id="@+id/seedReminderStub"
android:layout="@layout/seed_reminder_stub"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"/>
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.onboarding.SeedReminderView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/seedReminderView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />