Use Glide for all contact photo caching

// FREEBIE
This commit is contained in:
Moxie Marlinspike
2017-10-16 13:11:42 -07:00
parent 10f224ede5
commit b80408bcb4
66 changed files with 931 additions and 946 deletions

View File

@@ -4,19 +4,21 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
public class AvatarImageView extends ImageView {
public class AvatarImageView extends AppCompatImageView {
private static final String TAG = AvatarImageView.class.getSimpleName();
@@ -45,17 +47,24 @@ public class AvatarImageView extends ImageView {
super.setOnClickListener(listener);
}
public void setAvatar(final @Nullable Recipient recipient, boolean quickContactEnabled) {
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) {
if (recipient != null) {
MaterialColor backgroundColor = recipient.getColor();
setImageDrawable(recipient.getContactPhoto().asDrawable(getContext(), backgroundColor.toConversationColor(getContext()), inverted));
requestManager.load(recipient.getContactPhoto())
.fallback(recipient.getFallbackContactPhotoDrawable(getContext(), inverted))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.circleCrop()
.into(this);
setAvatarClickHandler(recipient, quickContactEnabled);
} else {
setImageDrawable(ContactPhotoFactory.getDefaultContactPhoto(null).asDrawable(getContext(), ContactColors.UNKNOWN_COLOR.toConversationColor(getContext()), inverted));
setImageDrawable(new GeneratedContactPhoto("#").asDrawable(getContext(), ContactColors.UNKNOWN_COLOR.toConversationColor(getContext()), inverted));
super.setOnClickListener(listener);
}
}
public void clear(@NonNull GlideRequests glideRequests) {
glideRequests.clear(this);
}
private void setAvatarClickHandler(final Recipient recipient, boolean quickContactEnabled) {
if (!recipient.isGroupRecipient() && quickContactEnabled) {
super.setOnClickListener(v -> {
@@ -76,4 +85,5 @@ public class AvatarImageView extends ImageView {
super.setOnClickListener(listener);
}
}
}

View File

@@ -111,7 +111,7 @@ public class RecentPhotoViewRail extends FrameLayout implements LoaderManager.Lo
Key signature = new MediaStoreSignature(mimeType, dateModified, orientation);
GlideApp.with(getContext())
GlideApp.with(getContext().getApplicationContext())
.load(uri)
.signature(signature)
.diskCacheStrategy(DiskCacheStrategy.NONE)

View File

@@ -3,11 +3,8 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
@@ -19,19 +16,15 @@ import android.widget.FrameLayout;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
public class ThreadPhotoRailView extends FrameLayout {
public static final String ADDRESS_EXTRA = "address";
public static final String MASTER_SECRET_EXTRA = "master_secret";
@NonNull private final RecyclerView recyclerView;
@Nullable private OnItemClickedListener listener;
@@ -62,25 +55,28 @@ public class ThreadPhotoRailView extends FrameLayout {
}
}
public void setCursor(@Nullable Cursor cursor, @NonNull MasterSecret masterSecret) {
this.recyclerView.setAdapter(new ThreadPhotoRailAdapter(getContext(), masterSecret, cursor, this.listener));
public void setCursor(@NonNull MasterSecret masterSecret, @NonNull GlideRequests glideRequests, @Nullable Cursor cursor) {
this.recyclerView.setAdapter(new ThreadPhotoRailAdapter(getContext(), masterSecret, glideRequests, cursor, this.listener));
}
private static class ThreadPhotoRailAdapter extends CursorRecyclerViewAdapter<ThreadPhotoRailAdapter.ThreadPhotoViewHolder> {
private static final String TAG = ThreadPhotoRailAdapter.class.getName();
private final MasterSecret masterSecret;
@NonNull private final MasterSecret masterSecret;
@NonNull private final GlideRequests glideRequests;
@Nullable private OnItemClickedListener clickedListener;
private ThreadPhotoRailAdapter(@NonNull Context context,
@NonNull MasterSecret masterSecret,
@NonNull Cursor cursor,
@NonNull GlideRequests glideRequests,
@Nullable Cursor cursor,
@Nullable OnItemClickedListener listener)
{
super(context, cursor);
this.masterSecret = masterSecret;
this.glideRequests = glideRequests;
this.clickedListener = listener;
}
@@ -99,7 +95,7 @@ public class ThreadPhotoRailView extends FrameLayout {
Slide slide = MediaUtil.getSlideForAttachment(getContext(), mediaRecord.getAttachment());
if (slide != null) {
imageView.setImageResource(masterSecret, slide, false, false);
imageView.setImageResource(masterSecret, glideRequests, slide, false, false);
}
imageView.setOnClickListener(v -> {

View File

@@ -1,13 +1,9 @@
package org.thoughtcrime.securesms.components;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;
@@ -15,7 +11,6 @@ import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
@@ -25,7 +20,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.util.Util;
@@ -102,7 +97,9 @@ public class ThumbnailView extends FrameLayout {
this.backgroundColorHint = color;
}
public void setImageResource(@NonNull MasterSecret masterSecret, @NonNull Slide slide, boolean showControls, boolean isPreview) {
public void setImageResource(@NonNull MasterSecret masterSecret, @NonNull GlideRequests glideRequests,
@NonNull Slide slide, boolean showControls, boolean isPreview)
{
if (showControls) {
getTransferControls().setSlide(slide);
getTransferControls().setDownloadClickListener(new DownloadClickDispatcher());
@@ -131,31 +128,25 @@ public class ThumbnailView extends FrameLayout {
return;
}
if (!isContextValid()) {
Log.w(TAG, "Not loading slide, context is invalid");
return;
}
Log.w(TAG, "loading part with id " + slide.asAttachment().getDataUri()
+ ", progress " + slide.getTransferState() + ", fast preflight id: " +
slide.asAttachment().getFastPreflightId());
this.slide = slide;
if (slide.getThumbnailUri() != null) buildThumbnailGlideRequest(slide, masterSecret).into(image);
else if (slide.hasPlaceholder()) buildPlaceholderGlideRequest(slide).into(image);
else Glide.with(getContext()).clear(image);
if (slide.getThumbnailUri() != null) buildThumbnailGlideRequest(masterSecret, glideRequests, slide).into(image);
else if (slide.hasPlaceholder()) buildPlaceholderGlideRequest(glideRequests, slide).into(image);
else glideRequests.clear(image);
}
public void setImageResource(@NonNull MasterSecret masterSecret, @NonNull Uri uri) {
public void setImageResource(@NonNull MasterSecret masterSecret, @NonNull GlideRequests glideRequests, @NonNull Uri uri) {
if (transferControls.isPresent()) getTransferControls().setVisibility(View.GONE);
GlideApp.with(getContext())
.load(new DecryptableUri(masterSecret, uri))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.transform(new RoundedCorners(radius))
.transition(withCrossFade())
.into(image);
glideRequests.load(new DecryptableUri(masterSecret, uri))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.transform(new RoundedCorners(radius))
.transition(withCrossFade())
.into(image);
}
public void setThumbnailClickListener(SlideClickListener listener) {
@@ -166,9 +157,12 @@ public class ThumbnailView extends FrameLayout {
this.downloadClickListener = listener;
}
public void clear() {
if (isContextValid()) Glide.with(getContext()).clear(image);
if (transferControls.isPresent()) getTransferControls().clear();
public void clear(GlideRequests glideRequests) {
glideRequests.clear(image);
if (transferControls.isPresent()) {
getTransferControls().clear();
}
slide = null;
}
@@ -177,30 +171,21 @@ public class ThumbnailView extends FrameLayout {
getTransferControls().showProgressSpinner();
}
@TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
private boolean isContextValid() {
return !(getContext() instanceof Activity) ||
VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN_MR1 ||
!((Activity)getContext()).isDestroyed();
}
private RequestBuilder buildThumbnailGlideRequest(@NonNull Slide slide, @NonNull MasterSecret masterSecret) {
RequestBuilder builder = GlideApp.with(getContext())
.load(new DecryptableUri(masterSecret, slide.getThumbnailUri()))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.transform(new RoundedCorners(radius))
.transition(withCrossFade());
private RequestBuilder buildThumbnailGlideRequest(@NonNull MasterSecret masterSecret, @NonNull GlideRequests glideRequests, @NonNull Slide slide) {
RequestBuilder builder = glideRequests.load(new DecryptableUri(masterSecret, slide.getThumbnailUri()))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.transform(new RoundedCorners(radius))
.transition(withCrossFade());
if (slide.isInProgress()) return builder;
else return builder.apply(RequestOptions.errorOf(R.drawable.ic_missing_thumbnail_picture));
}
private RequestBuilder buildPlaceholderGlideRequest(Slide slide) {
return GlideApp.with(getContext())
.asBitmap()
.load(slide.getPlaceholderRes(getContext().getTheme()))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.fitCenter();
private RequestBuilder buildPlaceholderGlideRequest(@NonNull GlideRequests glideRequests, @NonNull Slide slide) {
return glideRequests.asBitmap()
.load(slide.getPlaceholderRes(getContext().getTheme()))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.fitCenter();
}
private class ThumbnailClickDispatcher implements View.OnClickListener {

View File

@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
@@ -21,7 +22,7 @@ import org.thoughtcrime.securesms.components.subsampling.AttachmentBitmapDecoder
import org.thoughtcrime.securesms.components.subsampling.AttachmentRegionDecoder;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.util.BitmapDecodingException;
import org.thoughtcrime.securesms.util.BitmapUtil;
@@ -59,7 +60,9 @@ public class ZoomingImageView extends FrameLayout {
this.subsamplingImageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_USE_EXIF);
}
public void setImageUri(final MasterSecret masterSecret, final Uri uri, final String contentType) {
public void setImageUri(@NonNull MasterSecret masterSecret, @NonNull GlideRequests glideRequests,
@NonNull Uri uri, @NonNull String contentType)
{
final Context context = getContext();
final int maxTextureSize = BitmapUtil.getMaxTextureSize();
@@ -84,7 +87,7 @@ public class ZoomingImageView extends FrameLayout {
if (dimensions == null || (dimensions.first <= maxTextureSize && dimensions.second <= maxTextureSize)) {
Log.w(TAG, "Loading in standard image view...");
setImageViewUri(masterSecret, uri);
setImageViewUri(masterSecret, glideRequests, uri);
} else {
Log.w(TAG, "Loading in subsampling image view...");
setSubsamplingImageViewUri(uri);
@@ -93,19 +96,18 @@ public class ZoomingImageView extends FrameLayout {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void setImageViewUri(MasterSecret masterSecret, Uri uri) {
private void setImageViewUri(@NonNull MasterSecret masterSecret, @NonNull GlideRequests glideRequests, @NonNull Uri uri) {
photoView.setVisibility(View.VISIBLE);
subsamplingImageView.setVisibility(View.GONE);
GlideApp.with(getContext())
.load(new DecryptableUri(masterSecret, uri))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.dontTransform()
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.into(photoView);
glideRequests.load(new DecryptableUri(masterSecret, uri))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.dontTransform()
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.into(photoView);
}
private void setSubsamplingImageViewUri(Uri uri) {
private void setSubsamplingImageViewUri(@NonNull Uri uri) {
subsamplingImageView.setVisibility(View.VISIBLE);
photoView.setVisibility(View.GONE);

View File

@@ -18,9 +18,6 @@
package org.thoughtcrime.securesms.components.webrtc;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
@@ -30,20 +27,19 @@ import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.service.WebRtcCallService;
@@ -285,24 +281,11 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
this.recipient = recipient;
this.recipient.addListener(this);
final Context context = getContext();
new AsyncTask<Void, Void, ContactPhoto>() {
@Override
protected ContactPhoto doInBackground(Void... params) {
DisplayMetrics metrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Uri contentUri = ContactsContract.Contacts.lookupContact(context.getContentResolver(),
recipient.getContactUri());
windowManager.getDefaultDisplay().getMetrics(metrics);
return ContactPhotoFactory.getContactPhoto(context, contentUri, recipient.getAddress(), null, metrics.widthPixels);
}
@Override
protected void onPostExecute(final ContactPhoto contactPhoto) {
WebRtcCallScreen.this.photo.setImageDrawable(contactPhoto.asCallCard(context));
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
GlideApp.with(getContext().getApplicationContext())
.load(recipient.getContactPhoto())
.fallback(recipient.getFallbackContactPhoto().asCallCard(getContext()))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(this.photo);
this.name.setText(recipient.getName());