Improve wallpaper load speed.

This commit is contained in:
Greyson Parrelli 2022-03-16 13:45:23 -04:00 committed by Cody Henthorne
parent 63e48efdfe
commit d504bd593a
4 changed files with 86 additions and 17 deletions

View file

@ -159,7 +159,6 @@ public class ConversationIntents {
} }
public @Nullable ChatWallpaper getWallpaper() { public @Nullable ChatWallpaper getWallpaper() {
// TODO [greyson][wallpaper] Is it worth it to do this beforehand?
return Recipient.resolved(recipientId).getWallpaper(); return Recipient.resolved(recipientId).getWallpaper();
} }

View file

@ -163,6 +163,7 @@ import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask; import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog; import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import org.thoughtcrime.securesms.util.views.Stub; import org.thoughtcrime.securesms.util.views.Stub;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState; import org.whispersystems.signalservice.api.websocket.WebSocketConnectionState;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -1034,7 +1035,15 @@ public class ConversationListFragment extends MainFragment implements ActionMode
} }
private void handleCreateConversation(long threadId, Recipient recipient, int distributionType) { private void handleCreateConversation(long threadId, Recipient recipient, int distributionType) {
getNavigator().goToConversation(recipient.getId(), threadId, distributionType, -1); SimpleTask.run(getLifecycle(), () -> {
ChatWallpaper wallpaper = recipient.resolve().getWallpaper();
if (wallpaper != null && !wallpaper.prefetch(requireContext(), 250)) {
Log.w(TAG, "Failed to prefetch wallpaper.");
}
return null;
}, (nothing) -> {
getNavigator().goToConversation(recipient.getId(), threadId, distributionType, -1);
});
} }
private void startActionMode() { private void startActionMode() {

View file

@ -1,9 +1,11 @@
package org.thoughtcrime.securesms.wallpaper; package org.thoughtcrime.securesms.wallpaper;
import android.content.Context;
import android.os.Parcelable; import android.os.Parcelable;
import android.widget.ImageView; import android.widget.ImageView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import org.thoughtcrime.securesms.conversation.colors.ChatColors; import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsMapper; import org.thoughtcrime.securesms.conversation.colors.ChatColorsMapper;
@ -26,6 +28,11 @@ public interface ChatWallpaper extends Parcelable {
void loadInto(@NonNull ImageView imageView); void loadInto(@NonNull ImageView imageView);
@WorkerThread
default boolean prefetch(@NonNull Context context, long maxWaitTime) {
return true;
}
default boolean isPhoto() { default boolean isPhoto() {
return false; return false;
} }

View file

@ -1,9 +1,12 @@
package org.thoughtcrime.securesms.wallpaper; package org.thoughtcrime.securesms.wallpaper;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.util.LruCache;
import android.widget.ImageView; import android.widget.ImageView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -18,11 +21,26 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper; import org.thoughtcrime.securesms.database.model.databaseprotos.Wallpaper;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.util.ByteUnit;
import org.thoughtcrime.securesms.util.LRUCache;
import java.util.HashMap;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
final class UriChatWallpaper implements ChatWallpaper, Parcelable { final class UriChatWallpaper implements ChatWallpaper, Parcelable {
private static final LruCache<Uri, Bitmap> CACHE = new LruCache<Uri, Bitmap>((int) Runtime.getRuntime().maxMemory() / 8) {
@Override
protected int sizeOf(Uri key, Bitmap value) {
return value.getByteCount();
}
};
private static final String TAG = Log.tag(UriChatWallpaper.class); private static final String TAG = Log.tag(UriChatWallpaper.class);
private final Uri uri; private final Uri uri;
@ -45,22 +63,58 @@ final class UriChatWallpaper implements ChatWallpaper, Parcelable {
@Override @Override
public void loadInto(@NonNull ImageView imageView) { public void loadInto(@NonNull ImageView imageView) {
GlideApp.with(imageView) Bitmap cached = CACHE.get(uri);
.load(new DecryptableStreamUriLoader.DecryptableUri(uri)) if (cached != null) {
.addListener(new RequestListener<Drawable>() { Log.d(TAG, "Using cached value.");
@Override imageView.setImageBitmap(CACHE.get(uri));
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { } else {
Log.w(TAG, "Failed to load wallpaper " + uri); Log.d(TAG, "Not in cache. Fetching using Glide.");
return false; GlideApp.with(imageView)
} .load(new DecryptableStreamUriLoader.DecryptableUri(uri))
.addListener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
Log.w(TAG, "Failed to load wallpaper " + uri);
return false;
}
@Override @Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
Log.i(TAG, "Loaded wallpaper " + uri); Log.i(TAG, "Loaded wallpaper " + uri);
return false; return false;
} }
}) })
.into(imageView); .into(imageView);
}
}
@Override
public boolean prefetch(@NonNull Context context, long maxWaitTime) {
Bitmap cached = CACHE.get(uri);
if (cached != null) {
Log.d(TAG, "Already cached, skipping prefetch.");
return true;
}
long startTime = System.currentTimeMillis();
try {
Bitmap bitmap = GlideApp.with(context)
.asBitmap()
.load(new DecryptableStreamUriLoader.DecryptableUri(uri))
.submit()
.get(maxWaitTime, TimeUnit.MILLISECONDS);
CACHE.put(uri, bitmap);
Log.d(TAG, "Prefetched wallpaper in " + (System.currentTimeMillis() - startTime) + " ms.");
return true;
} catch (ExecutionException | InterruptedException e) {
Log.w(TAG, "Failed to prefetch wallpaper.", e);
} catch (TimeoutException e) {
Log.w(TAG, "Timed out waiting for prefetch.");
}
return false;
} }
@Override @Override