kopia lustrzana https://github.com/ryukoposting/Signal-Android
Improve conversation list cold start performance.
rodzic
10e8c6d795
commit
f3693c966a
|
@ -73,6 +73,7 @@ import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger;
|
|||
import org.thoughtcrime.securesms.logging.PersistentLogger;
|
||||
import org.thoughtcrime.securesms.messageprocessingalarm.MessageProcessReceiver;
|
||||
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.SignalGlideComponents;
|
||||
import org.thoughtcrime.securesms.mms.SignalGlideModule;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
|
@ -176,6 +177,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
|||
.addBlocking("feature-flags", FeatureFlags::init)
|
||||
.addBlocking("ring-rtc", this::initializeRingRtc)
|
||||
.addBlocking("glide", () -> SignalGlideModule.setRegisterGlideComponents(new SignalGlideComponents()))
|
||||
.addNonBlocking(() -> GlideApp.get(this))
|
||||
.addNonBlocking(this::checkIsGooglePayReady)
|
||||
.addNonBlocking(this::cleanAvatarStorage)
|
||||
.addNonBlocking(this::initializeRevealableMessageManager)
|
||||
|
@ -212,6 +214,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
|||
.addPostRender(PnpInitializeDevicesJob::enqueueIfNecessary)
|
||||
.addPostRender(() -> ApplicationDependencies.getExoPlayerPool().getPoolStats().getMaxUnreserved())
|
||||
.addPostRender(() -> SignalDatabase.groupCallRings().removeOldRings())
|
||||
.addPostRender(() -> ApplicationDependencies.getRecipientCache().warmUp())
|
||||
.execute();
|
||||
|
||||
Log.d(TAG, "onCreate() took " + (System.currentTimeMillis() - startTime) + " ms");
|
||||
|
@ -231,7 +234,6 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
|||
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
FeatureFlags.refreshIfNecessary();
|
||||
ApplicationDependencies.getRecipientCache().warmUp();
|
||||
RetrieveProfileJob.enqueueRoutineFetchIfNecessary(this);
|
||||
executePendingContactSync();
|
||||
KeyCachingService.onAppForegrounded(this);
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.content.Intent;
|
|||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
@ -37,6 +38,8 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
|||
private VoiceNoteMediaController mediaController;
|
||||
private ConversationListTabsViewModel conversationListTabsViewModel;
|
||||
|
||||
private boolean onFirstRender = false;
|
||||
|
||||
public static @NonNull Intent clearTop(@NonNull Context context) {
|
||||
Intent intent = new Intent(context, MainActivity.class);
|
||||
|
||||
|
@ -53,6 +56,21 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
|||
super.onCreate(savedInstanceState, ready);
|
||||
|
||||
setContentView(R.layout.main_activity);
|
||||
final View content = findViewById(android.R.id.content);
|
||||
content.getViewTreeObserver().addOnPreDrawListener(
|
||||
new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
// Use pre draw listener to delay drawing frames till conversation list is ready
|
||||
if (onFirstRender) {
|
||||
content.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
mediaController = new VoiceNoteMediaController(this, true);
|
||||
|
||||
|
@ -158,6 +176,10 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
|||
}
|
||||
}
|
||||
|
||||
public void onFirstRender() {
|
||||
onFirstRender = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull VoiceNoteMediaController getVoiceNoteMediaController() {
|
||||
return mediaController;
|
||||
|
|
|
@ -82,6 +82,7 @@ import org.signal.core.util.Stopwatch;
|
|||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.MainActivity;
|
||||
import org.thoughtcrime.securesms.MainFragment;
|
||||
import org.thoughtcrime.securesms.MainNavigator;
|
||||
import org.thoughtcrime.securesms.MuteDialog;
|
||||
|
@ -850,7 +851,11 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
}
|
||||
|
||||
private void updateSearchToolbarHint(@NonNull ConversationFilterRequest conversationFilterRequest) {
|
||||
requireCallback().getSearchToolbar().get().setSearchInputHint(
|
||||
Stub<Material3SearchToolbar> searchToolbar = requireCallback().getSearchToolbar();
|
||||
if (!searchToolbar.resolved()) {
|
||||
return;
|
||||
}
|
||||
searchToolbar.get().setSearchInputHint(
|
||||
conversationFilterRequest.getFilter() == ConversationFilter.OFF ? R.string.SearchToolbar_search : R.string.SearchToolbar_search_unread_chats
|
||||
);
|
||||
}
|
||||
|
@ -887,13 +892,14 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
startupStopwatch.split("data-set");
|
||||
SignalLocalMetrics.ColdStart.onConversationListDataLoaded();
|
||||
defaultAdapter.unregisterAdapterDataObserver(this);
|
||||
list.post(() -> {
|
||||
AppStartup.getInstance().onCriticalRenderEventEnd();
|
||||
startupStopwatch.split("first-render");
|
||||
startupStopwatch.stop(TAG);
|
||||
mediaControllerOwner.getVoiceNoteMediaController().finishPostpone();
|
||||
if (getContext() != null) {
|
||||
ConversationFragment.prepare(getContext());
|
||||
if (requireActivity() instanceof MainActivity) {
|
||||
((MainActivity) requireActivity()).onFirstRender();
|
||||
}
|
||||
list.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
|
||||
@Override
|
||||
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||
list.removeOnLayoutChangeListener(this);
|
||||
list.post(ConversationListFragment.this::onFirstRender);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -968,6 +974,17 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
});
|
||||
}
|
||||
|
||||
private void onFirstRender() {
|
||||
AppStartup.getInstance().onCriticalRenderEventEnd();
|
||||
startupStopwatch.split("first-render");
|
||||
startupStopwatch.stop(TAG);
|
||||
mediaControllerOwner.getVoiceNoteMediaController().finishPostpone();
|
||||
requireCallback().getSearchToolbar().get();
|
||||
if (getContext() != null) {
|
||||
ConversationFragment.prepare(getContext());
|
||||
}
|
||||
}
|
||||
|
||||
private void onConversationListChanged(@NonNull List<Conversation> conversations) {
|
||||
LinearLayoutManager layoutManager = (LinearLayoutManager) list.getLayoutManager();
|
||||
int firstVisibleItem = layoutManager != null ? layoutManager.findFirstCompletelyVisibleItemPosition() : -1;
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.database.MergeCursor
|
|||
import android.net.Uri
|
||||
import androidx.core.content.contentValuesOf
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.helper.StringUtil
|
||||
import org.signal.core.util.CursorUtil
|
||||
import org.signal.core.util.SqlUtil
|
||||
|
@ -59,6 +60,7 @@ import org.thoughtcrime.securesms.recipients.RecipientUtil
|
|||
import org.thoughtcrime.securesms.storage.StorageSyncHelper
|
||||
import org.thoughtcrime.securesms.util.ConversationUtil
|
||||
import org.thoughtcrime.securesms.util.JsonUtils
|
||||
import org.thoughtcrime.securesms.util.JsonUtils.SaneJSONObject
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.isScheduled
|
||||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
|
@ -1743,9 +1745,21 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
|
|||
val extraString = cursor.getString(cursor.getColumnIndexOrThrow(SNIPPET_EXTRAS))
|
||||
val extra: Extra? = if (extraString != null) {
|
||||
try {
|
||||
JsonUtils.fromJson(extraString, Extra::class.java)
|
||||
} catch (e: IOException) {
|
||||
Log.w(TAG, "Failed to decode extras!")
|
||||
val jsonObject = SaneJSONObject(JSONObject(extraString))
|
||||
Extra(
|
||||
isViewOnce = jsonObject.getBoolean("isRevealable"),
|
||||
isSticker = jsonObject.getBoolean("isSticker"),
|
||||
stickerEmoji = jsonObject.getString("stickerEmoji"),
|
||||
isAlbum = jsonObject.getBoolean("isAlbum"),
|
||||
isRemoteDelete = jsonObject.getBoolean("isRemoteDelete"),
|
||||
isMessageRequestAccepted = jsonObject.getBoolean("isMessageRequestAccepted"),
|
||||
isGv2Invite = jsonObject.getBoolean("isGv2Invite"),
|
||||
groupAddedBy = jsonObject.getString("groupAddedBy"),
|
||||
individualRecipientId = jsonObject.getString("individualRecipientId")!!,
|
||||
bodyRanges = jsonObject.getString("bodyRanges"),
|
||||
isScheduled = jsonObject.getBoolean("isScheduled")
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -87,6 +87,7 @@ public class ApplicationDependencies {
|
|||
private static final Object LOCK = new Object();
|
||||
private static final Object FRAME_RATE_TRACKER_LOCK = new Object();
|
||||
private static final Object JOB_MANAGER_LOCK = new Object();
|
||||
private static final Object SIGNAL_HTTP_CLIENT_LOCK = new Object();
|
||||
|
||||
private static Application application;
|
||||
private static Provider provider;
|
||||
|
@ -544,7 +545,7 @@ public class ApplicationDependencies {
|
|||
|
||||
public static @NonNull OkHttpClient getSignalOkHttpClient() {
|
||||
if (signalOkHttpClient == null) {
|
||||
synchronized (LOCK) {
|
||||
synchronized (SIGNAL_HTTP_CLIENT_LOCK) {
|
||||
if (signalOkHttpClient == null) {
|
||||
try {
|
||||
OkHttpClient baseClient = ApplicationDependencies.getOkHttpClient();
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import android.net.Uri
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
|
||||
|
@ -142,7 +143,6 @@ object EmojiFiles {
|
|||
private fun getDirectory(context: Context): File = File(context.getEmojiDirectory(), this.uuid.toString()).apply { mkdir() }
|
||||
|
||||
companion object {
|
||||
|
||||
private val objectMapper = ObjectMapper().registerKotlinModule()
|
||||
|
||||
@JvmStatic
|
||||
|
@ -150,7 +150,12 @@ object EmojiFiles {
|
|||
fun readVersion(context: Context, skipValidation: Boolean = false): Version? {
|
||||
val version = try {
|
||||
getInputStream(context, context.getVersionFile()).use {
|
||||
objectMapper.readValue(it, Version::class.java)
|
||||
val tree: JsonNode = objectMapper.readTree(it)
|
||||
Version(
|
||||
version = tree["version"].asInt(),
|
||||
uuid = objectMapper.convertValue(tree["uuid"], UUID::class.java),
|
||||
density = tree["density"].asText()
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Could not read current emoji version from disk.", e)
|
||||
|
@ -222,8 +227,15 @@ object EmojiFiles {
|
|||
@JvmStatic
|
||||
fun read(context: Context, version: Version): NameCollection {
|
||||
try {
|
||||
getInputStream(context, context.getNameFile(version.uuid)).use {
|
||||
return objectMapper.readValue(it)
|
||||
getInputStream(context, context.getNameFile(version.uuid)).use { inputStream ->
|
||||
val tree: JsonNode = objectMapper.readTree(inputStream)
|
||||
val elements = tree["names"].elements().asSequence().map {
|
||||
Name(
|
||||
name = it["name"].asText(),
|
||||
uuid = objectMapper.convertValue(it["uuid"], UUID::class.java)
|
||||
)
|
||||
}.toList()
|
||||
return NameCollection(objectMapper.convertValue(tree["versionUuid"], UUID::class.java), elements)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return NameCollection(version.uuid, listOf())
|
||||
|
|
|
@ -11,6 +11,8 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class JsonUtils {
|
||||
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
@ -54,7 +56,7 @@ public class JsonUtils {
|
|||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String getString(String name) throws JSONException {
|
||||
public @Nullable String getString(String name) throws JSONException {
|
||||
if (delegate.isNull(name)) return null;
|
||||
else return delegate.getString(name);
|
||||
}
|
||||
|
@ -63,6 +65,10 @@ public class JsonUtils {
|
|||
return delegate.getLong(name);
|
||||
}
|
||||
|
||||
public boolean getBoolean(String name) throws JSONException {
|
||||
return delegate.getBoolean(name);
|
||||
}
|
||||
|
||||
public boolean isNull(String name) {
|
||||
return delegate.isNull(name);
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue