diff --git a/src/org/thoughtcrime/securesms/BindableConversationItem.java b/src/org/thoughtcrime/securesms/BindableConversationItem.java index 9a9b64254f..9bc527a3e8 100644 --- a/src/org/thoughtcrime/securesms/BindableConversationItem.java +++ b/src/org/thoughtcrime/securesms/BindableConversationItem.java @@ -4,6 +4,7 @@ import android.support.annotation.NonNull; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.model.MessageRecord; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import java.util.Locale; @@ -12,6 +13,7 @@ import java.util.Set; public interface BindableConversationItem extends Unbindable { void bind(@NonNull MasterSecret masterSecret, @NonNull MessageRecord messageRecord, + @NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull Set batchSelected, @NonNull Recipient recipients); diff --git a/src/org/thoughtcrime/securesms/BindableConversationListItem.java b/src/org/thoughtcrime/securesms/BindableConversationListItem.java index 1da1ac2864..8aff5c79ee 100644 --- a/src/org/thoughtcrime/securesms/BindableConversationListItem.java +++ b/src/org/thoughtcrime/securesms/BindableConversationListItem.java @@ -4,6 +4,7 @@ import android.support.annotation.NonNull; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.model.ThreadRecord; +import org.thoughtcrime.securesms.mms.GlideRequests; import java.util.Locale; import java.util.Set; @@ -11,5 +12,6 @@ import java.util.Set; public interface BindableConversationListItem extends Unbindable { public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread, - @NonNull Locale locale, @NonNull Set selectedThreads, boolean batchMode); + @NonNull GlideRequests glideRequests, @NonNull Locale locale, + @NonNull Set selectedThreads, boolean batchMode); } diff --git a/src/org/thoughtcrime/securesms/BlockedContactsActivity.java b/src/org/thoughtcrime/securesms/BlockedContactsActivity.java index 426071195b..02b08dfe4f 100644 --- a/src/org/thoughtcrime/securesms/BlockedContactsActivity.java +++ b/src/org/thoughtcrime/securesms/BlockedContactsActivity.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.database.Cursor; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v4.app.ListFragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; @@ -19,6 +20,8 @@ import android.widget.ListView; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.loaders.BlockedContactsLoader; +import org.thoughtcrime.securesms.mms.GlideApp; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.preferences.BlockedContactListItem; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.DynamicLanguage; @@ -72,7 +75,7 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); - setListAdapter(new BlockedContactAdapter(getActivity(), null)); + setListAdapter(new BlockedContactAdapter(getActivity(), GlideApp.with(this), null)); getLoaderManager().initLoader(0, null, this); } @@ -112,8 +115,11 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity private static class BlockedContactAdapter extends CursorAdapter { - public BlockedContactAdapter(Context context, Cursor c) { + private final GlideRequests glideRequests; + + BlockedContactAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests, @Nullable Cursor c) { super(context, c); + this.glideRequests = glideRequests; } @Override @@ -127,7 +133,7 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity String address = cursor.getString(1); Recipient recipient = Recipient.from(context, Address.fromSerialized(address), true); - ((BlockedContactListItem) view).set(recipient); + ((BlockedContactListItem) view).set(glideRequests, recipient); } } diff --git a/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java b/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java index 15cdcc22aa..211f0a860c 100644 --- a/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java +++ b/src/org/thoughtcrime/securesms/ContactSelectionListFragment.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2015 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -37,6 +37,7 @@ import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter; import org.thoughtcrime.securesms.contacts.ContactSelectionListItem; import org.thoughtcrime.securesms.contacts.ContactsCursorLoader; import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; +import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.util.StickyHeaderDecoration; import org.thoughtcrime.securesms.util.ViewUtil; @@ -119,6 +120,7 @@ public class ContactSelectionListFragment extends Fragment private void initializeCursor() { ContactSelectionListAdapter adapter = new ContactSelectionListAdapter(getActivity(), + GlideApp.with(this), null, new ListClickListener(), isMulti()); diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index 6913cd8601..29dc68b255 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -117,6 +117,8 @@ import org.thoughtcrime.securesms.jobs.RetrieveProfileJob; import org.thoughtcrime.securesms.mms.AttachmentManager; import org.thoughtcrime.securesms.mms.AttachmentManager.MediaType; import org.thoughtcrime.securesms.mms.AudioSlide; +import org.thoughtcrime.securesms.mms.GlideApp; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.LocationSlide; import org.thoughtcrime.securesms.mms.MediaConstraints; import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage; @@ -208,6 +210,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity private static final int SMS_DEFAULT = 10; private MasterSecret masterSecret; + private GlideRequests glideRequests; protected ComposeText composeText; private AnimatingToggle buttonToggle; private SendButton sendButton; @@ -287,7 +290,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity if (!Util.isEmpty(composeText) || attachmentManager.isAttachmentPresent()) { saveDraft(); - attachmentManager.clear(false); + attachmentManager.clear(glideRequests, false); composeText.setText(""); } @@ -323,7 +326,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity initializeIdentityRecords(); composeText.setTransport(sendButton.getSelectedTransport()); - titleView.setTitle(recipient); + titleView.setTitle(glideRequests, recipient); setActionBarColor(recipient.getColor()); setBlockedUserState(recipient, isSecureText, isDefaultSms); setGroupShareProfileReminder(recipient); @@ -409,9 +412,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity addAttachmentContactInfo(data.getData()); break; case GROUP_EDIT: - recipient = Recipient.from(this, (Address)data.getParcelableExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA), true); + recipient = Recipient.from(this, data.getParcelableExtra(GroupCreateActivity.GROUP_ADDRESS_EXTRA), true); recipient.addListener(this); - titleView.setTitle(recipient); + titleView.setTitle(glideRequests, recipient); setBlockedUserState(recipient, isSecureText, isDefaultSms); supportInvalidateOptionsMenu(); break; @@ -1239,6 +1242,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1); archived = getIntent().getBooleanExtra(IS_ARCHIVED_EXTRA, false); distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT); + glideRequests = GlideApp.with(this); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { LinearLayout conversationContainer = ViewUtil.findById(this, R.id.conversation_container); @@ -1263,7 +1267,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity @Override public void onModified(final Recipient recipient) { Util.runOnMain(() -> { - titleView.setTitle(recipient); + titleView.setTitle(glideRequests, recipient); titleView.setVerified(identityRecords.isVerified()); setBlockedUserState(recipient, isSecureText, isDefaultSms); setActionBarColor(recipient.getColor()); @@ -1338,7 +1342,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity private void setMedia(@Nullable Uri uri, @NonNull MediaType mediaType) { if (uri == null) return; - attachmentManager.setMedia(masterSecret, uri, mediaType, getCurrentMediaConstraints()); + attachmentManager.setMedia(masterSecret, glideRequests, uri, mediaType, getCurrentMediaConstraints()); } private void addAttachmentContactInfo(Uri contactUri) { @@ -1631,7 +1635,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity outgoingMessage = new OutgoingSecureMediaMessage(outgoingMessage); } - attachmentManager.clear(false); + attachmentManager.clear(glideRequests, false); composeText.setText(""); final long id = fragment.stageOutgoingMessage(outgoingMessage); diff --git a/src/org/thoughtcrime/securesms/ConversationAdapter.java b/src/org/thoughtcrime/securesms/ConversationAdapter.java index 8cc0b01c01..2b899a932f 100644 --- a/src/org/thoughtcrime/securesms/ConversationAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationAdapter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.MmsSmsDatabase; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.Conversions; @@ -92,6 +93,7 @@ public class ConversationAdapter private final @Nullable ItemClickListener clickListener; private final @NonNull MasterSecret masterSecret; + private final @NonNull GlideRequests glideRequests; private final @NonNull Locale locale; private final @NonNull Recipient recipient; private final @NonNull MmsSmsDatabase db; @@ -130,7 +132,7 @@ public class ConversationAdapter } - public interface ItemClickListener { + interface ItemClickListener { void onItemClick(MessageRecord item); void onItemLongClick(MessageRecord item); } @@ -141,6 +143,7 @@ public class ConversationAdapter super(context, cursor); try { this.masterSecret = null; + this.glideRequests = null; this.locale = null; this.clickListener = null; this.recipient = null; @@ -155,6 +158,7 @@ public class ConversationAdapter public ConversationAdapter(@NonNull Context context, @NonNull MasterSecret masterSecret, + @NonNull GlideRequests glideRequests, @NonNull Locale locale, @Nullable ItemClickListener clickListener, @Nullable Cursor cursor, @@ -164,6 +168,7 @@ public class ConversationAdapter try { this.masterSecret = masterSecret; + this.glideRequests = glideRequests; this.locale = locale; this.clickListener = clickListener; this.recipient = recipient; @@ -188,7 +193,7 @@ public class ConversationAdapter @Override protected void onBindItemViewHolder(ViewHolder viewHolder, @NonNull MessageRecord messageRecord) { long start = System.currentTimeMillis(); - viewHolder.getView().bind(masterSecret, messageRecord, locale, batchSelected, recipient); + viewHolder.getView().bind(masterSecret, messageRecord, glideRequests, locale, batchSelected, recipient); Log.w(TAG, "Bind time: " + (System.currentTimeMillis() - start)); } @@ -196,22 +201,16 @@ public class ConversationAdapter public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) { long start = System.currentTimeMillis(); final V itemView = ViewUtil.inflate(inflater, parent, getLayoutForViewType(viewType)); - itemView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - if (clickListener != null) { - clickListener.onItemClick(itemView.getMessageRecord()); - } + itemView.setOnClickListener(view -> { + if (clickListener != null) { + clickListener.onItemClick(itemView.getMessageRecord()); } }); - itemView.setOnLongClickListener(new OnLongClickListener() { - @Override - public boolean onLongClick(View view) { - if (clickListener != null) { - clickListener.onItemLongClick(itemView.getMessageRecord()); - } - return true; + itemView.setOnLongClickListener(view -> { + if (clickListener != null) { + clickListener.onItemLongClick(itemView.getMessageRecord()); } + return true; }); Log.w(TAG, "Inflate time: " + (System.currentTimeMillis() - start)); return new ViewHolder(itemView); diff --git a/src/org/thoughtcrime/securesms/ConversationFragment.java b/src/org/thoughtcrime/securesms/ConversationFragment.java index 9e4e91ee76..fa617634da 100644 --- a/src/org/thoughtcrime/securesms/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/ConversationFragment.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2015 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -60,6 +60,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.loaders.ConversationLoader; import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord; +import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.profiles.UnknownSenderView; @@ -69,7 +70,6 @@ import org.thoughtcrime.securesms.sms.OutgoingTextMessage; import org.thoughtcrime.securesms.util.SaveAttachmentTask; import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment; import org.thoughtcrime.securesms.util.StickyHeaderDecoration; -import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; @@ -122,12 +122,7 @@ public class ConversationFragment extends Fragment scrollToBottomButton = ViewUtil.findById(view, R.id.scroll_to_bottom_button); scrollDateHeader = ViewUtil.findById(view, R.id.scroll_date_header); - scrollToBottomButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(final View view) { - scrollToBottom(); - } - }); + scrollToBottomButton.setOnClickListener(v -> scrollToBottom()); final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, true); list.setHasFixedSize(false); @@ -185,7 +180,7 @@ public class ConversationFragment extends Fragment } private void initializeResources() { - this.recipient = Recipient.from(getActivity(), (Address) getActivity().getIntent().getParcelableExtra(ConversationActivity.ADDRESS_EXTRA), true); + this.recipient = Recipient.from(getActivity(), getActivity().getIntent().getParcelableExtra(ConversationActivity.ADDRESS_EXTRA), true); this.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1); this.lastSeen = this.getActivity().getIntent().getLongExtra(ConversationActivity.LAST_SEEN_EXTRA, -1); this.firstLoad = true; @@ -197,7 +192,7 @@ public class ConversationFragment extends Fragment private void initializeListAdapter() { if (this.recipient != null && this.threadId != -1) { - ConversationAdapter adapter = new ConversationAdapter(getActivity(), masterSecret, locale, selectionClickListener, null, this.recipient); + ConversationAdapter adapter = new ConversationAdapter(getActivity(), masterSecret, GlideApp.with(this), locale, selectionClickListener, null, this.recipient); list.setAdapter(adapter); list.addItemDecoration(new StickyHeaderDecoration(adapter, false, false)); diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java index d44ce04f20..14e439acd8 100644 --- a/src/org/thoughtcrime/securesms/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/ConversationItem.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -39,7 +39,6 @@ import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; -import android.view.ViewStub; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -67,6 +66,7 @@ import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob; import org.thoughtcrime.securesms.jobs.MmsDownloadJob; import org.thoughtcrime.securesms.jobs.MmsSendJob; import org.thoughtcrime.securesms.jobs.SmsSendJob; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.SlideClickListener; @@ -107,6 +107,7 @@ public class ConversationItem extends LinearLayout private Locale locale; private boolean groupThread; private Recipient recipient; + private GlideRequests glideRequests; protected View bodyBubble; private TextView bodyText; @@ -155,22 +156,22 @@ public class ConversationItem extends LinearLayout initializeAttributes(); - this.bodyText = (TextView) findViewById(R.id.conversation_item_body); - this.dateText = (TextView) findViewById(R.id.conversation_item_date); - this.simInfoText = (TextView) findViewById(R.id.sim_info); - this.indicatorText = (TextView) findViewById(R.id.indicator_text); - this.groupSender = (TextView) findViewById(R.id.group_message_sender); - this.groupSenderProfileName = (TextView) findViewById(R.id.group_message_sender_profile); - this.insecureImage = (ImageView) findViewById(R.id.insecure_indicator); - this.deliveryStatusIndicator = (DeliveryStatusView) findViewById(R.id.delivery_status); - this.alertView = (AlertView) findViewById(R.id.indicators_parent); - this.contactPhoto = (AvatarImageView) findViewById(R.id.contact_photo); - this.bodyBubble = findViewById(R.id.body_bubble); - this.mediaThumbnailStub = new Stub<>((ViewStub) findViewById(R.id.image_view_stub)); - this.audioViewStub = new Stub<>((ViewStub) findViewById(R.id.audio_view_stub)); - this.documentViewStub = new Stub<>((ViewStub) findViewById(R.id.document_view_stub)); - this.expirationTimer = (ExpirationTimerView) findViewById(R.id.expiration_indicator); - this.groupSenderHolder = findViewById(R.id.group_sender_holder); + this.bodyText = findViewById(R.id.conversation_item_body); + this.dateText = findViewById(R.id.conversation_item_date); + this.simInfoText = findViewById(R.id.sim_info); + this.indicatorText = findViewById(R.id.indicator_text); + this.groupSender = findViewById(R.id.group_message_sender); + this.groupSenderProfileName = findViewById(R.id.group_message_sender_profile); + this.insecureImage = findViewById(R.id.insecure_indicator); + this.deliveryStatusIndicator = findViewById(R.id.delivery_status); + this.alertView = findViewById(R.id.indicators_parent); + this.contactPhoto = findViewById(R.id.contact_photo); + this.bodyBubble = findViewById(R.id.body_bubble); + this.mediaThumbnailStub = new Stub<>(findViewById(R.id.image_view_stub)); + this.audioViewStub = new Stub<>(findViewById(R.id.audio_view_stub)); + this.documentViewStub = new Stub<>(findViewById(R.id.document_view_stub)); + this.expirationTimer = findViewById(R.id.expiration_indicator); + this.groupSenderHolder = findViewById(R.id.group_sender_holder); setOnClickListener(new ClickListener(null)); @@ -183,6 +184,7 @@ public class ConversationItem extends LinearLayout @Override public void bind(@NonNull MasterSecret masterSecret, @NonNull MessageRecord messageRecord, + @NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull Set batchSelected, @NonNull Recipient conversationRecipient) @@ -190,6 +192,7 @@ public class ConversationItem extends LinearLayout this.masterSecret = masterSecret; this.messageRecord = messageRecord; this.locale = locale; + this.glideRequests = glideRequests; this.batchSelected = batchSelected; this.conversationRecipient = conversationRecipient; this.groupThread = conversationRecipient.isGroupRecipient(); @@ -386,7 +389,7 @@ public class ConversationItem extends LinearLayout if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE); //noinspection ConstantConditions - mediaThumbnailStub.get().setImageResource(masterSecret, + mediaThumbnailStub.get().setImageResource(masterSecret, glideRequests, ((MmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide(), showControls, false); mediaThumbnailStub.get().setThumbnailClickListener(new ThumbnailClickListener()); @@ -409,7 +412,7 @@ public class ConversationItem extends LinearLayout if (messageRecord.isOutgoing() || !groupThread) { contactPhoto.setVisibility(View.GONE); } else { - contactPhoto.setAvatar(recipient, true); + contactPhoto.setAvatar(glideRequests, recipient, true); contactPhoto.setVisibility(View.VISIBLE); } } diff --git a/src/org/thoughtcrime/securesms/ConversationListAdapter.java b/src/org/thoughtcrime/securesms/ConversationListAdapter.java index 8c3dd8e3bc..f6b7fd5a37 100644 --- a/src/org/thoughtcrime/securesms/ConversationListAdapter.java +++ b/src/org/thoughtcrime/securesms/ConversationListAdapter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -23,17 +23,15 @@ import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnLongClickListener; import android.view.ViewGroup; import org.thoughtcrime.securesms.crypto.MasterCipher; import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.model.ThreadRecord; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.util.Conversions; import java.security.MessageDigest; @@ -48,18 +46,19 @@ import java.util.Set; * * @author Moxie Marlinspike */ -public class ConversationListAdapter extends CursorRecyclerViewAdapter { +class ConversationListAdapter extends CursorRecyclerViewAdapter { private static final int MESSAGE_TYPE_SWITCH_ARCHIVE = 1; private static final int MESSAGE_TYPE_THREAD = 2; - private final ThreadDatabase threadDatabase; - private final MasterSecret masterSecret; - private final MasterCipher masterCipher; - private final Locale locale; - private final LayoutInflater inflater; - private final ItemClickListener clickListener; - private final @NonNull MessageDigest digest; + private final @NonNull ThreadDatabase threadDatabase; + private final @NonNull MasterSecret masterSecret; + private final @NonNull MasterCipher masterCipher; + private final @NonNull GlideRequests glideRequests; + private final @NonNull Locale locale; + private final @NonNull LayoutInflater inflater; + private final @Nullable ItemClickListener clickListener; + private final @NonNull MessageDigest digest; private final Set batchSet = Collections.synchronizedSet(new HashSet()); private boolean batchMode = false; @@ -82,16 +81,18 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter { + if (clickListener != null) clickListener.onSwitchToArchive(); }); return new ViewHolder(action); @@ -121,19 +119,13 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter { + if (clickListener != null) clickListener.onItemClick(item); }); - item.setOnLongClickListener(new OnLongClickListener() { - @Override - public boolean onLongClick(View view) { - if (clickListener != null) clickListener.onItemLongClick(item); - return true; - } + item.setOnLongClickListener(view -> { + if (clickListener != null) clickListener.onItemLongClick(item); + return true; }); return new ViewHolder(item); @@ -147,7 +139,7 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter selectedThreads; private Recipient recipient; private long threadId; + private GlideRequests glideRequests; private TextView subjectView; private FromTextView fromView; private TextView dateView; @@ -98,13 +100,13 @@ public class ConversationListItem extends RelativeLayout @Override protected void onFinishInflate() { super.onFinishInflate(); - this.subjectView = (TextView) findViewById(R.id.subject); - this.fromView = (FromTextView) findViewById(R.id.from); - this.dateView = (TextView) findViewById(R.id.date); - this.deliveryStatusIndicator = (DeliveryStatusView) findViewById(R.id.delivery_status); - this.alertView = (AlertView) findViewById(R.id.indicators_parent); - this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image); - this.thumbnailView = (ThumbnailView) findViewById(R.id.thumbnail); + this.subjectView = findViewById(R.id.subject); + this.fromView = findViewById(R.id.from); + this.dateView = findViewById(R.id.date); + this.deliveryStatusIndicator = findViewById(R.id.delivery_status); + this.alertView = findViewById(R.id.indicators_parent); + this.contactPhotoImage = findViewById(R.id.contact_photo_image); + this.thumbnailView = findViewById(R.id.thumbnail); this.archivedView = ViewUtil.findById(this, R.id.archived); thumbnailView.setClickable(false); @@ -112,12 +114,15 @@ public class ConversationListItem extends RelativeLayout ViewUtil.setTextViewGravityStart(this.subjectView, getContext()); } + @Override public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread, - @NonNull Locale locale, @NonNull Set selectedThreads, boolean batchMode) + @NonNull GlideRequests glideRequests, @NonNull Locale locale, + @NonNull Set selectedThreads, boolean batchMode) { this.selectedThreads = selectedThreads; this.recipient = thread.getRecipient(); this.threadId = thread.getThreadId(); + this.glideRequests = glideRequests; this.read = thread.isRead(); this.distributionType = thread.getDistributionType(); this.lastSeen = thread.getLastSeen(); @@ -145,7 +150,7 @@ public class ConversationListItem extends RelativeLayout setBatchState(batchMode); setBackground(thread); setRippleColor(recipient); - this.contactPhotoImage.setAvatar(recipient, true); + this.contactPhotoImage.setAvatar(glideRequests, recipient, true); } @Override @@ -180,7 +185,7 @@ public class ConversationListItem extends RelativeLayout private void setThumbnailSnippet(MasterSecret masterSecret, ThreadRecord thread) { if (thread.getSnippetUri() != null) { this.thumbnailView.setVisibility(View.VISIBLE); - this.thumbnailView.setImageResource(masterSecret, thread.getSnippetUri()); + this.thumbnailView.setImageResource(masterSecret, glideRequests, thread.getSnippetUri()); LayoutParams subjectParams = (RelativeLayout.LayoutParams)this.subjectView.getLayoutParams(); subjectParams.addRule(RelativeLayout.LEFT_OF, R.id.thumbnail); @@ -238,7 +243,7 @@ public class ConversationListItem extends RelativeLayout public void onModified(final Recipient recipient) { Util.runOnMain(() -> { fromView.setText(recipient, read); - contactPhotoImage.setAvatar(recipient, true); + contactPhotoImage.setAvatar(glideRequests, recipient, true); setRippleColor(recipient); }); } @@ -250,7 +255,7 @@ public class ConversationListItem extends RelativeLayout private final View deliveryStatusView; private final View dateView; - public ThumbnailPositioner(View thumbnailView, View archivedView, View deliveryStatusView, View dateView) { + ThumbnailPositioner(View thumbnailView, View archivedView, View deliveryStatusView, View dateView) { this.thumbnailView = thumbnailView; this.archivedView = archivedView; this.deliveryStatusView = deliveryStatusView; diff --git a/src/org/thoughtcrime/securesms/ConversationListItemAction.java b/src/org/thoughtcrime/securesms/ConversationListItemAction.java index 6b49f7360e..42afdec57c 100644 --- a/src/org/thoughtcrime/securesms/ConversationListItemAction.java +++ b/src/org/thoughtcrime/securesms/ConversationListItemAction.java @@ -10,6 +10,7 @@ import android.widget.TextView; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.model.ThreadRecord; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.util.ViewUtil; import java.util.Locale; @@ -39,7 +40,7 @@ public class ConversationListItemAction extends LinearLayout implements Bindable } @Override - public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread, @NonNull Locale locale, @NonNull Set selectedThreads, boolean batchMode) { + public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread, @NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull Set selectedThreads, boolean batchMode) { this.description.setText(getContext().getString(R.string.ConversationListItemAction_archived_conversations_d, thread.getCount())); } diff --git a/src/org/thoughtcrime/securesms/ConversationTitleView.java b/src/org/thoughtcrime/securesms/ConversationTitleView.java index cad04fa5b2..8ad71522c2 100644 --- a/src/org/thoughtcrime/securesms/ConversationTitleView.java +++ b/src/org/thoughtcrime/securesms/ConversationTitleView.java @@ -15,6 +15,7 @@ import com.annimon.stream.Collectors; import com.annimon.stream.Stream; import org.thoughtcrime.securesms.components.AvatarImageView; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.ViewUtil; @@ -56,7 +57,7 @@ public class ConversationTitleView extends RelativeLayout { ViewUtil.setTextViewGravityStart(this.subtitle, getContext()); } - public void setTitle(@Nullable Recipient recipient) { + public void setTitle(@NonNull GlideRequests glideRequests, @Nullable Recipient recipient) { if (recipient == null) setComposeTitle(); else setRecipientTitle(recipient); @@ -69,7 +70,7 @@ public class ConversationTitleView extends RelativeLayout { } if (recipient != null) { - this.avatar.setAvatar(recipient, false); + this.avatar.setAvatar(glideRequests, recipient, false); } } diff --git a/src/org/thoughtcrime/securesms/ConversationUpdateItem.java b/src/org/thoughtcrime/securesms/ConversationUpdateItem.java index 32ef9ea068..4f6560b10c 100644 --- a/src/org/thoughtcrime/securesms/ConversationUpdateItem.java +++ b/src/org/thoughtcrime/securesms/ConversationUpdateItem.java @@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.IdentityDatabase; import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; import org.thoughtcrime.securesms.database.model.MessageRecord; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.util.DateUtils; @@ -69,6 +70,7 @@ public class ConversationUpdateItem extends LinearLayout @Override public void bind(@NonNull MasterSecret masterSecret, @NonNull MessageRecord messageRecord, + @NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull Set batchSelected, @NonNull Recipient conversationRecipient) diff --git a/src/org/thoughtcrime/securesms/CreateProfileActivity.java b/src/org/thoughtcrime/securesms/CreateProfileActivity.java index 002496a555..308e62c44a 100644 --- a/src/org/thoughtcrime/securesms/CreateProfileActivity.java +++ b/src/org/thoughtcrime/securesms/CreateProfileActivity.java @@ -17,7 +17,6 @@ import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.Log; -import android.util.Pair; import android.view.KeyEvent; import android.view.View; import android.view.ViewAnimationUtils; @@ -33,12 +32,12 @@ import com.soundcloud.android.crop.Crop; import org.thoughtcrime.securesms.components.InputAwareLayout; import org.thoughtcrime.securesms.components.emoji.EmojiDrawer; import org.thoughtcrime.securesms.components.emoji.EmojiToggle; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; +import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobs.MultiDeviceProfileKeyUpdateJob; +import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.profiles.AvatarHelper; import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints; import org.thoughtcrime.securesms.profiles.SystemProfileUtil; @@ -56,6 +55,7 @@ import org.whispersystems.signalservice.api.util.StreamDetails; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; +import java.security.SecureRandom; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ExecutionException; @@ -135,8 +135,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje if (data != null && data.getBooleanExtra("delete", false)) { avatarBytes = null; - avatar.setImageDrawable(ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp) - .asDrawable(this, getResources().getColor(R.color.grey_400))); + avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(this, getResources().getColor(R.color.grey_400))); } else { new Crop(inputFile).output(outputFile).asSquare().start(this); } @@ -145,13 +144,30 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje break; case Crop.REQUEST_CROP: if (resultCode == Activity.RESULT_OK) { - try { - avatarBytes = BitmapUtil.createScaledBytes(this, Crop.getOutput(data), new ProfileMediaConstraints()); - avatar.setImageDrawable(ContactPhotoFactory.getGroupContactPhoto(avatarBytes).asDrawable(this, 0)); - } catch (BitmapDecodingException e) { - Log.w(TAG, e); - Toast.makeText(this, R.string.CreateProfileActivity_error_setting_profile_photo, Toast.LENGTH_LONG).show(); - } + new AsyncTask() { + @Override + protected byte[] doInBackground(Void... params) { + try { + return BitmapUtil.createScaledBytes(CreateProfileActivity.this, Crop.getOutput(data), new ProfileMediaConstraints()); + } catch (BitmapDecodingException e) { + Log.w(TAG, e); + return null; + } + } + + @Override + protected void onPostExecute(byte[] result) { + if (result != null) { + avatarBytes = result; + GlideApp.with(CreateProfileActivity.this) + .load(avatarBytes) + .circleCrop() + .into(avatar); + } else { + Toast.makeText(CreateProfileActivity.this, R.string.CreateProfileActivity_error_setting_profile_photo, Toast.LENGTH_LONG).show(); + } + } + }.execute(); } break; } @@ -170,8 +186,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje this.reveal = ViewUtil.findById(this, R.id.reveal); this.nextIntent = getIntent().getParcelableExtra(NEXT_INTENT); - this.avatar.setImageDrawable(ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp) - .asDrawable(this, getResources().getColor(R.color.grey_400))); + this.avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(this, getResources().getColor(R.color.grey_400))); this.avatar.setOnClickListener(view -> { try { @@ -251,12 +266,11 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje Address ourAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)); if (AvatarHelper.getAvatarFile(this, ourAddress).exists() && AvatarHelper.getAvatarFile(this, ourAddress).length() > 0) { - new AsyncTask>() { + new AsyncTask() { @Override - protected Pair doInBackground(Void... params) { + protected byte[] doInBackground(Void... params) { try { - byte[] data =Util.readFully(AvatarHelper.getInputStreamFor(CreateProfileActivity.this, ourAddress)); - return new Pair<>(data, ContactPhotoFactory.getSignalAvatarContactPhoto(CreateProfileActivity.this, ourAddress, null, getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size))); + return Util.readFully(AvatarHelper.getInputStreamFor(CreateProfileActivity.this, ourAddress)); } catch (IOException e) { Log.w(TAG, e); return null; @@ -264,10 +278,13 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje } @Override - protected void onPostExecute(Pair result) { + protected void onPostExecute(byte[] result) { if (result != null) { - avatarBytes = result.first; - avatar.setImageDrawable(result.second.asDrawable(CreateProfileActivity.this, 0)); + avatarBytes = result; + GlideApp.with(CreateProfileActivity.this) + .load(result) + .circleCrop() + .into(avatar); } } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -277,7 +294,10 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje public void onSuccess(byte[] result) { if (result != null) { avatarBytes = result; - avatar.setImageDrawable(ContactPhotoFactory.getGroupContactPhoto(result).asDrawable(CreateProfileActivity.this, 0)); + GlideApp.with(CreateProfileActivity.this) + .load(result) + .circleCrop() + .into(avatar); } } @@ -376,6 +396,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje try { accountManager.setProfileAvatar(profileKey, avatar); AvatarHelper.setAvatar(CreateProfileActivity.this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), avatarBytes); + TextSecurePreferences.setProfileAvatarId(CreateProfileActivity.this, new SecureRandom().nextInt()); } catch (IOException e) { Log.w(TAG, e); return false; diff --git a/src/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/org/thoughtcrime/securesms/GroupCreateActivity.java index df5c9c7084..ab4323be58 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -38,9 +38,7 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; -import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; -import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.SimpleTarget; import com.bumptech.glide.request.transition.Transition; import com.soundcloud.android.crop.Crop; @@ -49,7 +47,7 @@ import org.thoughtcrime.securesms.components.PushRecipientsPanel; import org.thoughtcrime.securesms.components.PushRecipientsPanel.RecipientsPanelChangedListener; import org.thoughtcrime.securesms.contacts.RecipientsEditor; import org.thoughtcrime.securesms.contacts.avatars.ContactColors; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; +import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -193,8 +191,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity recipientsEditor.setHint(R.string.recipients_panel__add_members); recipientsPanel.setPanelChangeListener(this); findViewById(R.id.contacts_button).setOnClickListener(new AddRecipientButtonListener()); - avatar.setImageDrawable(ContactPhotoFactory.getDefaultGroupPhoto() - .asDrawable(this, ContactColors.UNKNOWN_COLOR.toConversationColor(this))); + avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_group_white_24dp).asDrawable(this, ContactColors.UNKNOWN_COLOR.toConversationColor(this))); avatar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { diff --git a/src/org/thoughtcrime/securesms/MediaGalleryAdapter.java b/src/org/thoughtcrime/securesms/MediaGalleryAdapter.java index cff52c73e7..8fcd2f449b 100644 --- a/src/org/thoughtcrime/securesms/MediaGalleryAdapter.java +++ b/src/org/thoughtcrime/securesms/MediaGalleryAdapter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2015 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -18,6 +18,7 @@ package org.thoughtcrime.securesms; import android.content.Context; import android.content.Intent; +import android.support.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -30,16 +31,19 @@ import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord; import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.util.MediaUtil; import java.util.Locale; -public class MediaGalleryAdapter extends StickyHeaderGridAdapter { +class MediaGalleryAdapter extends StickyHeaderGridAdapter { + private static final String TAG = MediaGalleryAdapter.class.getSimpleName(); private final Context context; private final MasterSecret masterSecret; + private final GlideRequests glideRequests; private final Locale locale; private final Address address; @@ -50,7 +54,7 @@ public class MediaGalleryAdapter extends StickyHeaderGridAdapter { ViewHolder(View v) { super(v); - imageView = (ThumbnailView) v.findViewById(R.id.image); + imageView = v.findViewById(R.id.image); } } @@ -59,16 +63,19 @@ public class MediaGalleryAdapter extends StickyHeaderGridAdapter { HeaderHolder(View itemView) { super(itemView); - textView = (TextView) itemView.findViewById(R.id.text); + textView = itemView.findViewById(R.id.text); } } - public MediaGalleryAdapter(Context context, MasterSecret masterSecret, BucketedThreadMedia media, Locale locale, Address address) { - this.context = context; - this.masterSecret = masterSecret; - this.locale = locale; - this.media = media; - this.address = address; + MediaGalleryAdapter(@NonNull Context context, @NonNull MasterSecret masterSecret, @NonNull GlideRequests glideRequests, + BucketedThreadMedia media, Locale locale, Address address) + { + this.context = context; + this.masterSecret = masterSecret; + this.glideRequests = glideRequests; + this.locale = locale; + this.media = media; + this.address = address; } public void setMedia(BucketedThreadMedia media) { @@ -98,7 +105,7 @@ public class MediaGalleryAdapter extends StickyHeaderGridAdapter { Slide slide = MediaUtil.getSlideForAttachment(context, mediaRecord.getAttachment()); if (slide != null) { - thumbnailView.setImageResource(masterSecret, slide, false, false); + thumbnailView.setImageResource(masterSecret, glideRequests, slide, false, false); } thumbnailView.setOnClickListener(new OnMediaClickListener(mediaRecord)); diff --git a/src/org/thoughtcrime/securesms/MediaOverviewActivity.java b/src/org/thoughtcrime/securesms/MediaOverviewActivity.java index ee25d48535..38adf7b72d 100644 --- a/src/org/thoughtcrime/securesms/MediaOverviewActivity.java +++ b/src/org/thoughtcrime/securesms/MediaOverviewActivity.java @@ -45,6 +45,7 @@ import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader; import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia; import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader; +import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme; @@ -204,7 +205,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity this.noMedia = ViewUtil.findById(view, R.id.no_images); this.gridManager = new StickyHeaderGridLayoutManager(getResources().getInteger(R.integer.media_overview_cols)); - this.recyclerView.setAdapter(new MediaGalleryAdapter(getContext(), masterSecret, new BucketedThreadMedia(getContext()), locale, recipient.getAddress())); + this.recyclerView.setAdapter(new MediaGalleryAdapter(getContext(), masterSecret, GlideApp.with(this), new BucketedThreadMedia(getContext()), locale, recipient.getAddress())); this.recyclerView.setLayoutManager(gridManager); this.recyclerView.setHasFixedSize(true); diff --git a/src/org/thoughtcrime/securesms/MediaPreviewActivity.java b/src/org/thoughtcrime/securesms/MediaPreviewActivity.java index 0ed3ec45a2..d11cef8973 100644 --- a/src/org/thoughtcrime/securesms/MediaPreviewActivity.java +++ b/src/org/thoughtcrime/securesms/MediaPreviewActivity.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2014 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -17,7 +17,6 @@ package org.thoughtcrime.securesms; import android.annotation.TargetApi; -import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.AsyncTask; @@ -36,6 +35,7 @@ import android.widget.Toast; import org.thoughtcrime.securesms.components.ZoomingImageView; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.VideoSlide; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; @@ -143,8 +143,8 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im } private void initializeViews() { - image = (ZoomingImageView) findViewById(R.id.image); - video = (VideoPlayer) findViewById(R.id.video_player); + image = findViewById(R.id.image); + video = findViewById(R.id.video_player); } private void initializeResources() { @@ -177,7 +177,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im if (mediaType != null && mediaType.startsWith("image/")) { image.setVisibility(View.VISIBLE); video.setVisibility(View.GONE); - image.setImageUri(masterSecret, mediaUri, mediaType); + image.setImageUri(masterSecret, GlideApp.with(this), mediaUri, mediaType); } else if (mediaType != null && mediaType.startsWith("video/")) { image.setVisibility(View.GONE); video.setVisibility(View.VISIBLE); @@ -210,13 +210,10 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im } private void saveToDisk() { - SaveAttachmentTask.showWarningDialog(this, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this, masterSecret, image); - long saveDate = (date > 0) ? date : System.currentTimeMillis(); - saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaUri, mediaType, saveDate, null)); - } + SaveAttachmentTask.showWarningDialog(this, (dialogInterface, i) -> { + SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this, masterSecret, image); + long saveDate = (date > 0) ? date : System.currentTimeMillis(); + saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaUri, mediaType, saveDate, null)); }); } diff --git a/src/org/thoughtcrime/securesms/MessageDetailsActivity.java b/src/org/thoughtcrime/securesms/MessageDetailsActivity.java index c27c661f75..f7d22a47ce 100644 --- a/src/org/thoughtcrime/securesms/MessageDetailsActivity.java +++ b/src/org/thoughtcrime/securesms/MessageDetailsActivity.java @@ -47,6 +47,8 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.loaders.MessageDetailsLoader; import org.thoughtcrime.securesms.database.model.MessageRecord; +import org.thoughtcrime.securesms.mms.GlideApp; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; @@ -78,6 +80,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity public final static String ADDRESS_EXTRA = "address"; private MasterSecret masterSecret; + private GlideRequests glideRequests; private long threadId; private boolean isPushGroup; private ConversationItem conversationItem; @@ -166,6 +169,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity masterSecret = getIntent().getParcelableExtra(MASTER_SECRET_EXTRA); threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1); isPushGroup = getIntent().getBooleanExtra(IS_PUSH_GROUP_EXTRA, false); + glideRequests = GlideApp.with(this); itemParent = (ViewGroup) header.findViewById(R.id.item_container); recipientsList = (ListView ) findViewById(R.id.recipients_list); metadataContainer = header.findViewById(R.id.metadata_container); @@ -249,9 +253,8 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity toFromRes = R.string.message_details_header__from; } toFrom.setText(toFromRes); - conversationItem.bind(masterSecret, messageRecord, dynamicLanguage.getCurrentLocale(), new HashSet<>(), recipient); - recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, masterSecret, messageRecord, - recipients, isPushGroup)); + conversationItem.bind(masterSecret, messageRecord, glideRequests, dynamicLanguage.getCurrentLocale(), new HashSet<>(), recipient); + recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, masterSecret, glideRequests, messageRecord, recipients, isPushGroup)); } private void inflateMessageViewIfAbsent(MessageRecord messageRecord) { diff --git a/src/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java b/src/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java index 2dc520fbf0..93bc3d387d 100644 --- a/src/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java +++ b/src/org/thoughtcrime/securesms/MessageDetailsRecipientAdapter.java @@ -1,6 +1,7 @@ package org.thoughtcrime.securesms; import android.content.Context; +import android.support.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -9,6 +10,7 @@ import android.widget.BaseAdapter; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.model.MessageRecord; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.Conversions; @@ -20,18 +22,21 @@ class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView. private final Context context; private final MasterSecret masterSecret; + private final GlideRequests glideRequests; private final MessageRecord record; private final List members; private final boolean isPushGroup; - MessageDetailsRecipientAdapter(Context context, MasterSecret masterSecret, MessageRecord record, - List members, boolean isPushGroup) + MessageDetailsRecipientAdapter(@NonNull Context context, @NonNull MasterSecret masterSecret, + @NonNull GlideRequests glideRequests, @NonNull MessageRecord record, + @NonNull List members, boolean isPushGroup) { - this.context = context; - this.masterSecret = masterSecret; - this.record = record; - this.isPushGroup = isPushGroup; - this.members = members; + this.context = context; + this.masterSecret = masterSecret; + this.glideRequests = glideRequests; + this.record = record; + this.isPushGroup = isPushGroup; + this.members = members; } @Override @@ -61,7 +66,7 @@ class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView. RecipientDeliveryStatus member = members.get(position); - ((MessageRecipientListItem)convertView).set(masterSecret, record, member, isPushGroup); + ((MessageRecipientListItem)convertView).set(masterSecret, glideRequests, record, member, isPushGroup); return convertView; } diff --git a/src/org/thoughtcrime/securesms/MessageRecipientListItem.java b/src/org/thoughtcrime/securesms/MessageRecipientListItem.java index 82883c38f4..98a4c2b4d8 100644 --- a/src/org/thoughtcrime/securesms/MessageRecipientListItem.java +++ b/src/org/thoughtcrime/securesms/MessageRecipientListItem.java @@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; import org.thoughtcrime.securesms.database.documents.NetworkFailure; import org.thoughtcrime.securesms.database.model.MessageRecord; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.sms.MessageSender; @@ -51,6 +52,7 @@ public class MessageRecipientListItem extends RelativeLayout private final static String TAG = MessageRecipientListItem.class.getSimpleName(); private RecipientDeliveryStatus member; + private GlideRequests glideRequests; private FromTextView fromView; private TextView errorDescription; private TextView actionDescription; @@ -70,25 +72,27 @@ public class MessageRecipientListItem extends RelativeLayout @Override protected void onFinishInflate() { super.onFinishInflate(); - this.fromView = (FromTextView) findViewById(R.id.from); - this.errorDescription = (TextView) findViewById(R.id.error_description); - this.actionDescription = (TextView) findViewById(R.id.action_description); - this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image); - this.conflictButton = (Button) findViewById(R.id.conflict_button); - this.resendButton = (Button) findViewById(R.id.resend_button); - this.deliveryStatusView = (DeliveryStatusView) findViewById(R.id.delivery_status); + this.fromView = findViewById(R.id.from); + this.errorDescription = findViewById(R.id.error_description); + this.actionDescription = findViewById(R.id.action_description); + this.contactPhotoImage = findViewById(R.id.contact_photo_image); + this.conflictButton = findViewById(R.id.conflict_button); + this.resendButton = findViewById(R.id.resend_button); + this.deliveryStatusView = findViewById(R.id.delivery_status); } public void set(final MasterSecret masterSecret, + final GlideRequests glideRequests, final MessageRecord record, final RecipientDeliveryStatus member, final boolean isPushGroup) { - this.member = member; + this.glideRequests = glideRequests; + this.member = member; member.getRecipient().addListener(this); fromView.setText(member.getRecipient()); - contactPhotoImage.setAvatar(member.getRecipient(), false); + contactPhotoImage.setAvatar(glideRequests, member.getRecipient(), false); setIssueIndicators(masterSecret, record, isPushGroup); } @@ -177,7 +181,7 @@ public class MessageRecipientListItem extends RelativeLayout public void onModified(final Recipient recipient) { Util.runOnMain(() -> { fromView.setText(recipient); - contactPhotoImage.setAvatar(recipient, false); + contactPhotoImage.setAvatar(glideRequests, recipient, false); }); } @@ -187,7 +191,7 @@ public class MessageRecipientListItem extends RelativeLayout private final MessageRecord record; private final NetworkFailure failure; - public ResendAsyncTask(MasterSecret masterSecret, MessageRecord record, NetworkFailure failure) { + ResendAsyncTask(MasterSecret masterSecret, MessageRecord record, NetworkFailure failure) { this.context = getContext().getApplicationContext(); this.masterSecret = masterSecret; this.record = record; diff --git a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java index 6201458ecb..4025b185d2 100644 --- a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java +++ b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java @@ -13,7 +13,6 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; -import android.provider.ContactsContract; import android.provider.Settings; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -27,7 +26,6 @@ import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceCategory; import android.support.v7.widget.Toolbar; -import android.util.DisplayMetrics; import android.util.Log; import android.view.MenuItem; import android.view.View; @@ -35,11 +33,11 @@ import android.view.WindowManager; import android.widget.ImageView; import android.widget.TextView; +import com.bumptech.glide.load.engine.DiskCacheStrategy; + import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.color.MaterialColors; import org.thoughtcrime.securesms.components.ThreadPhotoRailView; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.Address; @@ -52,9 +50,11 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState; import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader; import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob; import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob; +import org.thoughtcrime.securesms.mms.GlideApp; +import org.thoughtcrime.securesms.mms.GlideRequests; +import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment; import org.thoughtcrime.securesms.preferences.widgets.AdvancedRingtonePreference; import org.thoughtcrime.securesms.preferences.widgets.ColorPickerPreference; -import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.util.DynamicLanguage; @@ -88,6 +88,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi private ImageView avatar; private MasterSecret masterSecret; + private GlideRequests glideRequests; private Address address; private TextView threadPhotoRailLabel; private ThreadPhotoRailView threadPhotoRailView; @@ -103,8 +104,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi @Override public void onCreate(Bundle instanceState, @NonNull MasterSecret masterSecret) { setContentView(R.layout.recipient_preference_activity); - this.masterSecret = masterSecret; - this.address = getIntent().getParcelableExtra(ADDRESS_EXTRA); + this.masterSecret = masterSecret; + this.glideRequests = GlideApp.with(this); + this.address = getIntent().getParcelableExtra(ADDRESS_EXTRA); Recipient recipient = Recipient.from(this, address, true); @@ -208,39 +210,17 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi } private void setHeader(@NonNull Recipient recipient) { - new AsyncTask() { - @Override - protected @NonNull ContactPhoto doInBackground(Void... params) { - DisplayMetrics metrics = new DisplayMetrics(); - WindowManager windowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE); - Uri contentUri = ContactsContract.Contacts.lookupContact(getContentResolver(), recipient.getContactUri()); - windowManager.getDefaultDisplay().getMetrics(metrics); + glideRequests.load(recipient.getContactPhoto()) + .fallback(recipient.getFallbackContactPhoto().asCallCard(this)) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .into(this.avatar); - if (recipient.isGroupRecipient()) { - Optional groupRecord = DatabaseFactory.getGroupDatabase(RecipientPreferenceActivity.this).getGroup(recipient.getAddress().toGroupString()); + if (recipient.getContactPhoto() == null) this.avatar.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + else this.avatar.setScaleType(ImageView.ScaleType.CENTER_CROP); - if (groupRecord.isPresent() && groupRecord.get().getAvatar() != null) { - return ContactPhotoFactory.getGroupContactPhoto(groupRecord.get().getAvatar()); - } else { - return ContactPhotoFactory.getDefaultGroupPhoto(); - } - } else { - return ContactPhotoFactory.getContactPhoto(RecipientPreferenceActivity.this, contentUri, - recipient.getAddress(), recipient.getName(), - metrics.widthPixels); - } - } - - protected void onPostExecute(@NonNull ContactPhoto contactPhoto) { - if (contactPhoto.isGenerated() || contactPhoto.isResource()) avatar.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - else avatar.setScaleType(ImageView.ScaleType.CENTER_CROP); - - avatar.setImageDrawable(contactPhoto.asCallCard(RecipientPreferenceActivity.this)); - avatar.setBackgroundColor(recipient.getColor().toActionBarColor(RecipientPreferenceActivity.this)); - toolbarLayout.setTitle(recipient.toShortString()); - toolbarLayout.setContentScrimColor(recipient.getColor().toActionBarColor(RecipientPreferenceActivity.this)); - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + this.avatar.setBackgroundColor(recipient.getColor().toActionBarColor(this)); + this.toolbarLayout.setTitle(recipient.toShortString()); + this.toolbarLayout.setContentScrimColor(recipient.getColor().toActionBarColor(this)); } @Override @@ -263,7 +243,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi this.threadPhotoRailView.setVisibility(View.GONE); } - this.threadPhotoRailView.setCursor(data, masterSecret); + this.threadPhotoRailView.setCursor(masterSecret, glideRequests, data); Bundle bundle = new Bundle(); bundle.putParcelable(ADDRESS_EXTRA, address); @@ -272,7 +252,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi @Override public void onLoaderReset(Loader loader) { - this.threadPhotoRailView.setCursor(null, masterSecret); + this.threadPhotoRailView.setCursor(masterSecret, glideRequests, null); } public static class RecipientPreferenceFragment @@ -325,9 +305,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi } private void initializeRecipients() { - this.recipient = Recipient.from(getActivity(), - (Address)getArguments().getParcelable(ADDRESS_EXTRA), - true); + this.recipient = Recipient.from(getActivity(), getArguments().getParcelable(ADDRESS_EXTRA), true); this.recipient.addListener(this); @@ -335,7 +313,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi @Override public void onReceive(Context context, Intent intent) { recipient.removeListener(RecipientPreferenceFragment.this); - recipient = Recipient.from(getActivity(), (Address)getArguments().getParcelable(ADDRESS_EXTRA), true); + recipient = Recipient.from(getActivity(), getArguments().getParcelable(ADDRESS_EXTRA), true); onModified(recipient); } }; @@ -508,12 +486,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi } private void handleMute() { - MuteDialog.show(getActivity(), new MuteDialog.MuteSelectionListener() { - @Override - public void onMuted(long until) { - setMuted(recipient, until); - } - }); + MuteDialog.show(getActivity(), until -> setMuted(recipient, until)); setSummaries(recipient); } diff --git a/src/org/thoughtcrime/securesms/ShareFragment.java b/src/org/thoughtcrime/securesms/ShareFragment.java index 3405037fef..44ac290d7a 100644 --- a/src/org/thoughtcrime/securesms/ShareFragment.java +++ b/src/org/thoughtcrime/securesms/ShareFragment.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2014 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -30,6 +30,7 @@ import android.widget.ListView; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.loaders.ConversationListLoader; +import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.recipients.Recipient; /** @@ -78,7 +79,7 @@ public class ShareFragment extends ListFragment implements LoaderManager.LoaderC } private void initializeListAdapter() { - this.setListAdapter(new ShareListAdapter(getActivity(), null, masterSecret)); + this.setListAdapter(new ShareListAdapter(getActivity(), masterSecret, GlideApp.with(this), null)); getListView().setRecyclerListener((ShareListAdapter) getListAdapter()); getLoaderManager().restartLoader(0, null, this); } diff --git a/src/org/thoughtcrime/securesms/ShareListAdapter.java b/src/org/thoughtcrime/securesms/ShareListAdapter.java index a5ed412233..a43fffae71 100644 --- a/src/org/thoughtcrime/securesms/ShareListAdapter.java +++ b/src/org/thoughtcrime/securesms/ShareListAdapter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2014 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -18,37 +18,42 @@ package org.thoughtcrime.securesms; import android.content.Context; import android.database.Cursor; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; +import org.thoughtcrime.securesms.crypto.MasterCipher; +import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.model.ThreadRecord; -import org.thoughtcrime.securesms.crypto.MasterCipher; -import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.mms.GlideRequests; /** * A CursorAdapter for building a list of open conversations * * @author Jake McGinty */ -public class ShareListAdapter extends CursorAdapter implements AbsListView.RecyclerListener { +class ShareListAdapter extends CursorAdapter implements AbsListView.RecyclerListener { private final ThreadDatabase threadDatabase; + private final GlideRequests glideRequests; private final MasterCipher masterCipher; - private final Context context; private final LayoutInflater inflater; - public ShareListAdapter(Context context, Cursor cursor, MasterSecret masterSecret) { + ShareListAdapter(@NonNull Context context, @Nullable MasterSecret masterSecret, + @NonNull GlideRequests glideRequests, @Nullable Cursor cursor) + { super(context, cursor, 0); if (masterSecret != null) this.masterCipher = new MasterCipher(masterSecret); else this.masterCipher = null; - this.context = context; + this.glideRequests = glideRequests; this.threadDatabase = DatabaseFactory.getThreadDatabase(context); this.inflater = LayoutInflater.from(context); } @@ -64,7 +69,7 @@ public class ShareListAdapter extends CursorAdapter implements AbsListView.Recyc ThreadDatabase.Reader reader = threadDatabase.readerFor(cursor, masterCipher); ThreadRecord record = reader.getCurrent(); - ((ShareListItem)view).set(record); + ((ShareListItem)view).set(glideRequests, record); } } diff --git a/src/org/thoughtcrime/securesms/ShareListItem.java b/src/org/thoughtcrime/securesms/ShareListItem.java index 4ef1cbef31..97b577ffae 100644 --- a/src/org/thoughtcrime/securesms/ShareListItem.java +++ b/src/org/thoughtcrime/securesms/ShareListItem.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2014 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -18,13 +18,14 @@ package org.thoughtcrime.securesms; import android.content.Context; import android.content.res.TypedArray; -import android.os.Handler; +import android.support.annotation.NonNull; import android.util.AttributeSet; import android.widget.RelativeLayout; import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.FromTextView; import org.thoughtcrime.securesms.database.model.ThreadRecord; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.util.Util; @@ -39,10 +40,11 @@ public class ShareListItem extends RelativeLayout { private final static String TAG = ShareListItem.class.getSimpleName(); - private Context context; - private Recipient recipient; - private long threadId; - private FromTextView fromView; + private Context context; + private GlideRequests glideRequests; + private Recipient recipient; + private long threadId; + private FromTextView fromView; private AvatarImageView contactPhotoImage; @@ -61,11 +63,12 @@ public class ShareListItem extends RelativeLayout @Override protected void onFinishInflate() { super.onFinishInflate(); - this.fromView = (FromTextView) findViewById(R.id.from); - this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image); + this.fromView = findViewById(R.id.from); + this.contactPhotoImage = findViewById(R.id.contact_photo_image); } - public void set(ThreadRecord thread) { + public void set(@NonNull GlideRequests glideRequests, @NonNull ThreadRecord thread) { + this.glideRequests = glideRequests; this.recipient = thread.getRecipient(); this.threadId = thread.getThreadId(); this.distributionType = thread.getDistributionType(); @@ -74,7 +77,7 @@ public class ShareListItem extends RelativeLayout this.fromView.setText(recipient); setBackground(); - this.contactPhotoImage.setAvatar(this.recipient, false); + this.contactPhotoImage.setAvatar(glideRequests, this.recipient, false); } public void unbind() { @@ -106,7 +109,7 @@ public class ShareListItem extends RelativeLayout public void onModified(final Recipient recipient) { Util.runOnMain(() -> { fromView.setText(recipient); - contactPhotoImage.setAvatar(recipient, false); + contactPhotoImage.setAvatar(glideRequests, recipient, false); }); } } diff --git a/src/org/thoughtcrime/securesms/components/AvatarImageView.java b/src/org/thoughtcrime/securesms/components/AvatarImageView.java index 992d1c3cb5..8f17c786bb 100644 --- a/src/org/thoughtcrime/securesms/components/AvatarImageView.java +++ b/src/org/thoughtcrime/securesms/components/AvatarImageView.java @@ -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); } } + } diff --git a/src/org/thoughtcrime/securesms/components/RecentPhotoViewRail.java b/src/org/thoughtcrime/securesms/components/RecentPhotoViewRail.java index cca2462ecd..2024325bf8 100644 --- a/src/org/thoughtcrime/securesms/components/RecentPhotoViewRail.java +++ b/src/org/thoughtcrime/securesms/components/RecentPhotoViewRail.java @@ -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) diff --git a/src/org/thoughtcrime/securesms/components/ThreadPhotoRailView.java b/src/org/thoughtcrime/securesms/components/ThreadPhotoRailView.java index 35f9f02fb9..44b55504f1 100644 --- a/src/org/thoughtcrime/securesms/components/ThreadPhotoRailView.java +++ b/src/org/thoughtcrime/securesms/components/ThreadPhotoRailView.java @@ -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 { 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 -> { diff --git a/src/org/thoughtcrime/securesms/components/ThumbnailView.java b/src/org/thoughtcrime/securesms/components/ThumbnailView.java index dacf71af41..db0007317e 100644 --- a/src/org/thoughtcrime/securesms/components/ThumbnailView.java +++ b/src/org/thoughtcrime/securesms/components/ThumbnailView.java @@ -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 { diff --git a/src/org/thoughtcrime/securesms/components/ZoomingImageView.java b/src/org/thoughtcrime/securesms/components/ZoomingImageView.java index 3ff0fc02fd..80886b3fda 100644 --- a/src/org/thoughtcrime/securesms/components/ZoomingImageView.java +++ b/src/org/thoughtcrime/securesms/components/ZoomingImageView.java @@ -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); diff --git a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java index 2a0f1fb1ab..0aaa4e3eb7 100644 --- a/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java +++ b/src/org/thoughtcrime/securesms/components/webrtc/WebRtcCallScreen.java @@ -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() { - @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()); diff --git a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java index 92aa9eae99..ae6f659453 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java @@ -29,16 +29,17 @@ import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.TextView; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.RecyclerViewFastScroller.FastScrollAdapter; -import org.thoughtcrime.securesms.util.StickyHeaderDecoration.StickyHeaderAdapter; import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter.HeaderViewHolder; import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter.ViewHolder; +import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; +import org.thoughtcrime.securesms.mms.GlideRequests; +import org.thoughtcrime.securesms.util.StickyHeaderDecoration.StickyHeaderAdapter; import org.thoughtcrime.securesms.util.Util; import java.util.HashMap; @@ -62,6 +63,7 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter selectedContacts = new HashMap<>(); @@ -70,11 +72,8 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter { + if (clickListener != null) clickListener.onItemClick(getView()); }); } @@ -90,14 +89,16 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter { - contactPhotoImage.setAvatar(recipient, false); + contactPhotoImage.setAvatar(glideRequests, recipient, false); nameView.setText(recipient.toShortString()); }); } diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/BitmapContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/BitmapContactPhoto.java deleted file mode 100644 index c39f1d014f..0000000000 --- a/src/org/thoughtcrime/securesms/contacts/avatars/BitmapContactPhoto.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.thoughtcrime.securesms.contacts.avatars; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.widget.ImageView; - -import com.makeramen.roundedimageview.RoundedDrawable; - -public class BitmapContactPhoto implements ContactPhoto { - - private final Bitmap bitmap; - - BitmapContactPhoto(Bitmap bitmap) { - this.bitmap = bitmap; - } - - @Override - public Drawable asDrawable(Context context, int color) { - return asDrawable(context, color, false); - } - - @Override - public Drawable asDrawable(Context context, int color, boolean inverted) { - return RoundedDrawable.fromBitmap(bitmap) - .setScaleType(ImageView.ScaleType.CENTER_CROP) - .setOval(true); - } - - @Override - public Drawable asCallCard(Context context) { - return new BitmapDrawable(context.getResources(), bitmap); - } - - @Override - public boolean isGenerated() { - return false; - } - - @Override - public boolean isResource() { - return false; - } -} diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhoto.java index 0065962207..d1c633efe8 100644 --- a/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhoto.java +++ b/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhoto.java @@ -1,14 +1,16 @@ package org.thoughtcrime.securesms.contacts.avatars; + import android.content.Context; -import android.graphics.drawable.Drawable; -public interface ContactPhoto { - public Drawable asDrawable(Context context, int color); - public Drawable asDrawable(Context context, int color, boolean inverted); - public Drawable asCallCard(Context context); - public boolean isGenerated(); - public boolean isResource(); +import com.bumptech.glide.load.Key; + +import java.io.IOException; +import java.io.InputStream; + +public interface ContactPhoto extends Key { + + InputStream openInputStream(Context context) throws IOException; } diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhotoFactory.java b/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhotoFactory.java deleted file mode 100644 index 9904361778..0000000000 --- a/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhotoFactory.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.thoughtcrime.securesms.contacts.avatars; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.support.annotation.DrawableRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.annotation.WorkerThread; -import android.text.TextUtils; -import android.util.Log; - -import com.bumptech.glide.load.engine.DiskCacheStrategy; - -import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.database.Address; -import org.thoughtcrime.securesms.mms.ContactPhotoUriLoader.ContactPhotoUri; -import org.thoughtcrime.securesms.mms.GlideApp; -import org.thoughtcrime.securesms.profiles.AvatarPhotoUriLoader.AvatarPhotoUri; - -import java.util.concurrent.ExecutionException; - -public class ContactPhotoFactory { - - private static final String TAG = ContactPhotoFactory.class.getSimpleName(); - - public static ContactPhoto getLoadingPhoto() { - return new TransparentContactPhoto(); - } - - public static ContactPhoto getDefaultContactPhoto(@Nullable String name) { - if (!TextUtils.isEmpty(name)) return new GeneratedContactPhoto(name); - else return new GeneratedContactPhoto("#"); - } - - public static ContactPhoto getResourceContactPhoto(@DrawableRes int resourceId) { - return new ResourceContactPhoto(resourceId); - } - - public static ContactPhoto getDefaultGroupPhoto() { - return new ResourceContactPhoto(R.drawable.ic_group_white_24dp, R.drawable.ic_group_large); - } - - public static ContactPhoto getContactPhoto(@NonNull Context context, @Nullable Uri uri, @NonNull Address address, @Nullable String name) { - int targetSize = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size); - return getContactPhoto(context, uri, address, name, targetSize); - } - - @WorkerThread - public static ContactPhoto getContactPhoto(@NonNull Context context, - @Nullable Uri uri, - @NonNull Address address, - @Nullable String name, - int targetSize) - { - if (uri == null) return getSignalAvatarContactPhoto(context, address, name, targetSize); - - try { - Bitmap bitmap = GlideApp.with(context) - .asBitmap() - .load(new ContactPhotoUri(uri)) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .centerCrop() - .submit(targetSize, targetSize) - .get(); - return new BitmapContactPhoto(bitmap); - } catch (ExecutionException e) { - return getSignalAvatarContactPhoto(context, address, name, targetSize); - } catch (InterruptedException e) { - throw new AssertionError(e); - } - } - - public static ContactPhoto getGroupContactPhoto(@Nullable byte[] avatar) { - if (avatar == null) return getDefaultGroupPhoto(); - - return new BitmapContactPhoto(BitmapFactory.decodeByteArray(avatar, 0, avatar.length)); - } - - @WorkerThread - public static ContactPhoto getSignalAvatarContactPhoto(@NonNull Context context, - @NonNull Address address, - @Nullable String name, - int targetSize) - { - try { - Bitmap bitmap = GlideApp.with(context) - .asBitmap() - .load(new AvatarPhotoUri(address)) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) - .centerCrop() - .submit(targetSize, targetSize) - .get(); - - return new BitmapContactPhoto(bitmap); - } catch (IllegalArgumentException e) { - Log.w(TAG, e); - // XXX This is a temporary fix for #7016 until we upgrade to Glide 4 as a next step - return getDefaultContactPhoto(name); - } catch (ExecutionException e) { - return getDefaultContactPhoto(name); - } catch (InterruptedException e) { - throw new AssertionError(e); - } - } -} diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/FallbackContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/FallbackContactPhoto.java new file mode 100644 index 0000000000..8d8bf0ed89 --- /dev/null +++ b/src/org/thoughtcrime/securesms/contacts/avatars/FallbackContactPhoto.java @@ -0,0 +1,12 @@ +package org.thoughtcrime.securesms.contacts.avatars; + +import android.content.Context; +import android.graphics.drawable.Drawable; + +public interface FallbackContactPhoto { + + public Drawable asDrawable(Context context, int color); + public Drawable asDrawable(Context context, int color, boolean inverted); + public Drawable asCallCard(Context context); + +} diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/GeneratedContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/GeneratedContactPhoto.java index eec9c81ab6..61e6f06f66 100644 --- a/src/org/thoughtcrime/securesms/contacts/avatars/GeneratedContactPhoto.java +++ b/src/org/thoughtcrime/securesms/contacts/avatars/GeneratedContactPhoto.java @@ -11,11 +11,15 @@ import com.amulyakhare.textdrawable.TextDrawable; import org.thoughtcrime.securesms.R; -public class GeneratedContactPhoto implements ContactPhoto { +import java.util.regex.Pattern; + +public class GeneratedContactPhoto implements FallbackContactPhoto { + + private static final Pattern PATTERN = Pattern.compile("[^\\p{L}\\p{Nd}\\p{P}\\p{S}]+"); private final String name; - GeneratedContactPhoto(@NonNull String name) { + public GeneratedContactPhoto(@NonNull String name) { this.name = name; } @@ -38,7 +42,7 @@ public class GeneratedContactPhoto implements ContactPhoto { } private String getCharacter(String name) { - String cleanedName = name.replaceFirst("[^\\p{L}\\p{Nd}\\p{P}\\p{S}]+", ""); + String cleanedName = PATTERN.matcher(name).replaceFirst(""); if (cleanedName.isEmpty()) { return "#"; @@ -52,14 +56,4 @@ public class GeneratedContactPhoto implements ContactPhoto { return AppCompatResources.getDrawable(context, R.drawable.ic_person_large); } - - @Override - public boolean isGenerated() { - return true; - } - - @Override - public boolean isResource() { - return false; - } } diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/GroupRecordContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/GroupRecordContactPhoto.java new file mode 100644 index 0000000000..8b46f3e401 --- /dev/null +++ b/src/org/thoughtcrime/securesms/contacts/avatars/GroupRecordContactPhoto.java @@ -0,0 +1,59 @@ +package org.thoughtcrime.securesms.contacts.avatars; + + +import android.content.Context; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.database.DatabaseFactory; +import org.thoughtcrime.securesms.database.GroupDatabase; +import org.thoughtcrime.securesms.util.Conversions; +import org.whispersystems.libsignal.util.guava.Optional; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; + +public class GroupRecordContactPhoto implements ContactPhoto { + + private final @NonNull Address address; + private final long avatarId; + + public GroupRecordContactPhoto(@NonNull Address address, long avatarId) { + this.address = address; + this.avatarId = avatarId; + } + + @Override + public InputStream openInputStream(Context context) throws IOException { + GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); + Optional groupRecord = groupDatabase.getGroup(address.toGroupString()); + + if (groupRecord.isPresent() && groupRecord.get().getAvatar() != null) { + return new ByteArrayInputStream(groupRecord.get().getAvatar()); + } + + throw new IOException("Couldn't load avatar for group: " + address.toGroupString()); + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) { + messageDigest.update(address.serialize().getBytes()); + messageDigest.update(Conversions.longToByteArray(avatarId)); + } + + @Override + public boolean equals(Object other) { + if (other == null || !(other instanceof GroupRecordContactPhoto)) return false; + + GroupRecordContactPhoto that = (GroupRecordContactPhoto)other; + return this.address.equals(that.address) && this.avatarId == that.avatarId; + } + + @Override + public int hashCode() { + return this.address.hashCode() ^ (int) avatarId; + } + +} diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/ProfileContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/ProfileContactPhoto.java new file mode 100644 index 0000000000..3b099ef07d --- /dev/null +++ b/src/org/thoughtcrime/securesms/contacts/avatars/ProfileContactPhoto.java @@ -0,0 +1,49 @@ +package org.thoughtcrime.securesms.contacts.avatars; + + +import android.content.Context; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.profiles.AvatarHelper; +import org.thoughtcrime.securesms.util.Conversions; + +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; + +public class ProfileContactPhoto implements ContactPhoto { + + private final @NonNull Address address; + private final @NonNull String avatarObject; + + public ProfileContactPhoto(@NonNull Address address, @NonNull String avatarObject) { + this.address = address; + this.avatarObject = avatarObject; + } + + @Override + public InputStream openInputStream(Context context) throws IOException { + return AvatarHelper.getInputStreamFor(context, address); + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) { + messageDigest.update(address.serialize().getBytes()); + messageDigest.update(avatarObject.getBytes()); + } + + @Override + public boolean equals(Object other) { + if (other == null || !(other instanceof ProfileContactPhoto)) return false; + + ProfileContactPhoto that = (ProfileContactPhoto)other; + + return this.address.equals(that.address) && this.avatarObject.equals(that.avatarObject); + } + + @Override + public int hashCode() { + return address.hashCode() ^ avatarObject.hashCode(); + } +} diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/ResourceContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/ResourceContactPhoto.java index 130f0b7fa2..edb902c356 100644 --- a/src/org/thoughtcrime/securesms/contacts/avatars/ResourceContactPhoto.java +++ b/src/org/thoughtcrime/securesms/contacts/avatars/ResourceContactPhoto.java @@ -12,16 +12,16 @@ import android.widget.ImageView; import com.amulyakhare.textdrawable.TextDrawable; import com.makeramen.roundedimageview.RoundedDrawable; -public class ResourceContactPhoto implements ContactPhoto { +public class ResourceContactPhoto implements FallbackContactPhoto { private final int resourceId; private final int callCardResourceId; - ResourceContactPhoto(@DrawableRes int resourceId) { + public ResourceContactPhoto(@DrawableRes int resourceId) { this(resourceId, resourceId); } - ResourceContactPhoto(@DrawableRes int resourceId, @DrawableRes int callCardResourceId) { + public ResourceContactPhoto(@DrawableRes int resourceId, @DrawableRes int callCardResourceId) { this.resourceId = resourceId; this.callCardResourceId = callCardResourceId; } @@ -50,16 +50,6 @@ public class ResourceContactPhoto implements ContactPhoto { return AppCompatResources.getDrawable(context, callCardResourceId); } - @Override - public boolean isGenerated() { - return false; - } - - @Override - public boolean isResource() { - return true; - } - private static class ExpandingLayerDrawable extends LayerDrawable { public ExpandingLayerDrawable(Drawable[] layers) { super(layers); diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/SystemContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/SystemContactPhoto.java new file mode 100644 index 0000000000..00553fe56a --- /dev/null +++ b/src/org/thoughtcrime/securesms/contacts/avatars/SystemContactPhoto.java @@ -0,0 +1,54 @@ +package org.thoughtcrime.securesms.contacts.avatars; + + +import android.content.Context; +import android.net.Uri; +import android.support.annotation.NonNull; + +import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.util.Conversions; + +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.security.MessageDigest; + +public class SystemContactPhoto implements ContactPhoto { + + private final @NonNull Address address; + private final @NonNull Uri contactPhotoUri; + private final long lastModifiedTime; + + public SystemContactPhoto(@NonNull Address address, @NonNull Uri contactPhotoUri, long lastModifiedTime) { + this.address = address; + this.contactPhotoUri = contactPhotoUri; + this.lastModifiedTime = lastModifiedTime; + } + + @Override + public InputStream openInputStream(Context context) throws FileNotFoundException { + return context.getContentResolver().openInputStream(contactPhotoUri); + + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) { + messageDigest.update(address.serialize().getBytes()); + messageDigest.update(contactPhotoUri.toString().getBytes()); + messageDigest.update(Conversions.longToByteArray(lastModifiedTime)); + } + + @Override + public boolean equals(Object other) { + if (other == null || !(other instanceof SystemContactPhoto)) return false; + + SystemContactPhoto that = (SystemContactPhoto)other; + + return this.address.equals(that.address) && this.contactPhotoUri.equals(that.contactPhotoUri) && this.lastModifiedTime == that.lastModifiedTime; + } + + @Override + public int hashCode() { + return address.hashCode() ^ contactPhotoUri.hashCode() ^ (int)lastModifiedTime; + } + +} diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/TransparentContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/TransparentContactPhoto.java index 9623995512..33c2064b1f 100644 --- a/src/org/thoughtcrime/securesms/contacts/avatars/TransparentContactPhoto.java +++ b/src/org/thoughtcrime/securesms/contacts/avatars/TransparentContactPhoto.java @@ -8,9 +8,9 @@ import com.makeramen.roundedimageview.RoundedDrawable; import org.thoughtcrime.securesms.R; -public class TransparentContactPhoto implements ContactPhoto { +public class TransparentContactPhoto implements FallbackContactPhoto { - TransparentContactPhoto() {} + public TransparentContactPhoto() {} @Override public Drawable asDrawable(Context context, int color) { @@ -27,13 +27,4 @@ public class TransparentContactPhoto implements ContactPhoto { return ContextCompat.getDrawable(context, R.drawable.ic_contact_picture_large); } - @Override - public boolean isGenerated() { - return false; - } - - @Override - public boolean isResource() { - return false; - } } diff --git a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java index 989a429924..1926d6a156 100644 --- a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java +++ b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java @@ -13,7 +13,6 @@ import android.util.Log; import com.annimon.stream.Stream; import org.thoughtcrime.securesms.color.MaterialColor; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.Base64; import org.whispersystems.libsignal.util.Pair; @@ -467,7 +466,7 @@ public class RecipientDatabase extends Database { } public Optional getDefaultSubscriptionId() { - return defaultSubscriptionId != -1 ? Optional.of(defaultSubscriptionId) : Optional.absent(); + return defaultSubscriptionId != -1 ? Optional.of(defaultSubscriptionId) : Optional.absent(); } public int getExpireMessages() { diff --git a/src/org/thoughtcrime/securesms/giph/ui/GiphyAdapter.java b/src/org/thoughtcrime/securesms/giph/ui/GiphyAdapter.java index 5ebffa4bad..144100df0b 100644 --- a/src/org/thoughtcrime/securesms/giph/ui/GiphyAdapter.java +++ b/src/org/thoughtcrime/securesms/giph/ui/GiphyAdapter.java @@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.giph.model.GiphyImage; import org.thoughtcrime.securesms.mms.GlideApp; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; @@ -33,12 +34,14 @@ import java.util.List; import java.util.concurrent.ExecutionException; -public class GiphyAdapter extends RecyclerView.Adapter { +class GiphyAdapter extends RecyclerView.Adapter { private static final String TAG = GiphyAdapter.class.getSimpleName(); + private final Context context; + private final GlideRequests glideRequests; + private List images; - private Context context; private OnItemClickListener listener; class GiphyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, RequestListener { @@ -73,7 +76,6 @@ public class GiphyAdapter extends RecyclerView.Adapter images) { - this.context = context.getApplicationContext(); - this.images = images; + GiphyAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests, @NonNull List images) { + this.context = context.getApplicationContext(); + this.glideRequests = glideRequests; + this.images = images; } public void setImages(@NonNull List images) { @@ -145,21 +148,19 @@ public class GiphyAdapter extends RecyclerView.Adapter()); + this.giphyAdapter = new GiphyAdapter(getActivity(), GlideApp.with(this), new LinkedList<>()); this.giphyAdapter.setListener(this); this.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); diff --git a/src/org/thoughtcrime/securesms/profiles/AvatarPhotoUriFetcher.java b/src/org/thoughtcrime/securesms/glide/ContactPhotoFetcher.java similarity index 65% rename from src/org/thoughtcrime/securesms/profiles/AvatarPhotoUriFetcher.java rename to src/org/thoughtcrime/securesms/glide/ContactPhotoFetcher.java index b028e3e77b..29a5d1d674 100644 --- a/src/org/thoughtcrime/securesms/profiles/AvatarPhotoUriFetcher.java +++ b/src/org/thoughtcrime/securesms/glide/ContactPhotoFetcher.java @@ -1,4 +1,4 @@ -package org.thoughtcrime.securesms.profiles; +package org.thoughtcrime.securesms.glide; import android.content.Context; @@ -8,27 +8,27 @@ import com.bumptech.glide.Priority; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.data.DataFetcher; -import org.thoughtcrime.securesms.database.Address; +import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; import java.io.IOException; import java.io.InputStream; -class AvatarPhotoUriFetcher implements DataFetcher { +class ContactPhotoFetcher implements DataFetcher { - private final Context context; - private final Address address; + private final Context context; + private final ContactPhoto contactPhoto; private InputStream inputStream; - AvatarPhotoUriFetcher(@NonNull Context context, @NonNull Address address) { - this.context = context.getApplicationContext(); - this.address = address; + ContactPhotoFetcher(@NonNull Context context, @NonNull ContactPhoto contactPhoto) { + this.context = context.getApplicationContext(); + this.contactPhoto = contactPhoto; } @Override public void loadData(Priority priority, DataCallback callback) { try { - inputStream = AvatarHelper.getInputStreamFor(context, address); + inputStream = contactPhoto.openInputStream(context); callback.onDataReady(inputStream); } catch (IOException e) { callback.onLoadFailed(e); diff --git a/src/org/thoughtcrime/securesms/glide/ContactPhotoLoader.java b/src/org/thoughtcrime/securesms/glide/ContactPhotoLoader.java new file mode 100644 index 0000000000..5bdedf979d --- /dev/null +++ b/src/org/thoughtcrime/securesms/glide/ContactPhotoLoader.java @@ -0,0 +1,50 @@ +package org.thoughtcrime.securesms.glide; + +import android.content.Context; +import android.support.annotation.Nullable; + +import com.bumptech.glide.load.Options; +import com.bumptech.glide.load.model.ModelLoader; +import com.bumptech.glide.load.model.ModelLoaderFactory; +import com.bumptech.glide.load.model.MultiModelLoaderFactory; + +import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; + +import java.io.InputStream; + +public class ContactPhotoLoader implements ModelLoader { + + private final Context context; + + private ContactPhotoLoader(Context context) { + this.context = context; + } + + @Nullable + @Override + public LoadData buildLoadData(ContactPhoto contactPhoto, int width, int height, Options options) { + return new LoadData<>(contactPhoto, new ContactPhotoFetcher(context, contactPhoto)); + } + + @Override + public boolean handles(ContactPhoto contactPhoto) { + return true; + } + + public static class Factory implements ModelLoaderFactory { + + private final Context context; + + public Factory(Context context) { + this.context = context.getApplicationContext(); + } + + @Override + public ModelLoader build(MultiModelLoaderFactory multiFactory) { + return new ContactPhotoLoader(context); + } + + @Override + public void teardown() {} + } +} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java index 573372014a..f4f12e706a 100644 --- a/src/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java +++ b/src/org/thoughtcrime/securesms/jobs/RetrieveProfileAvatarJob.java @@ -5,8 +5,7 @@ import android.content.Context; import android.text.TextUtils; import android.util.Log; -import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; +import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.dependencies.InjectableType; @@ -85,8 +84,8 @@ public class RetrieveProfileAvatarJob extends ContextJob implements InjectableTy database.setProfileAvatar(recipient, profileAvatar); - if (recipient.resolve().getContactPhoto().isGenerated()) { - recipient.setContactPhoto(ContactPhotoFactory.getSignalAvatarContactPhoto(context, recipient.getAddress(), recipient.getName(), context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size))); + if (recipient.resolve().getContactPhoto() == null) { + recipient.setContactPhoto(new ProfileContactPhoto(recipient.getAddress(), profileAvatar)); } } diff --git a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java index 1577a3bb7b..4afd5b068d 100644 --- a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java +++ b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -108,14 +108,14 @@ public class AttachmentManager { } - public void clear(boolean animate) { + public void clear(@NonNull GlideRequests glideRequests, boolean animate) { if (attachmentViewStub.resolved()) { if (animate) { ViewUtil.fadeOut(attachmentViewStub.get(), 200).addListener(new Listener() { @Override public void onSuccess(Boolean result) { - thumbnail.clear(); + thumbnail.clear(glideRequests); attachmentViewStub.get().setVisibility(View.GONE); attachmentListener.onAttachmentChanged(); } @@ -125,7 +125,7 @@ public class AttachmentManager { } }); } else { - thumbnail.clear(); + thumbnail.clear(glideRequests); attachmentViewStub.get().setVisibility(View.GONE); attachmentListener.onAttachmentChanged(); } @@ -200,6 +200,7 @@ public class AttachmentManager { } public void setMedia(@NonNull final MasterSecret masterSecret, + @NonNull final GlideRequests glideRequests, @NonNull final Uri uri, @NonNull final MediaType mediaType, @NonNull final MediaConstraints constraints) @@ -209,7 +210,7 @@ public class AttachmentManager { new AsyncTask() { @Override protected void onPreExecute() { - thumbnail.clear(); + thumbnail.clear(glideRequests); thumbnail.showProgressSpinner(); attachmentViewStub.get().setVisibility(View.VISIBLE); } @@ -254,7 +255,7 @@ public class AttachmentManager { documentView.setDocument((DocumentSlide) slide, false); removableMediaView.display(documentView, false); } else { - thumbnail.setImageResource(masterSecret, slide, false, true); + thumbnail.setImageResource(masterSecret, glideRequests, slide, false, true); removableMediaView.display(thumbnail, mediaType == MediaType.IMAGE); } @@ -433,7 +434,7 @@ public class AttachmentManager { @Override public void onClick(View v) { cleanup(); - clear(true); + clear(GlideApp.with(context.getApplicationContext()), true); } } diff --git a/src/org/thoughtcrime/securesms/mms/ContactPhotoUriLoader.java b/src/org/thoughtcrime/securesms/mms/ContactPhotoUriLoader.java deleted file mode 100644 index 2bc51bfc35..0000000000 --- a/src/org/thoughtcrime/securesms/mms/ContactPhotoUriLoader.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.thoughtcrime.securesms.mms; - -import android.content.Context; -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import com.bumptech.glide.load.Key; -import com.bumptech.glide.load.Options; -import com.bumptech.glide.load.data.StreamLocalUriFetcher; -import com.bumptech.glide.load.model.ModelLoader; -import com.bumptech.glide.load.model.ModelLoaderFactory; -import com.bumptech.glide.load.model.MultiModelLoaderFactory; - -import org.thoughtcrime.securesms.mms.ContactPhotoUriLoader.ContactPhotoUri; - -import java.io.InputStream; -import java.security.MessageDigest; - -public class ContactPhotoUriLoader implements ModelLoader { - - private final Context context; - - private ContactPhotoUriLoader(Context context) { - this.context = context; - } - - @Nullable - @Override - public LoadData buildLoadData(ContactPhotoUri contactPhotoUri, int width, int height, Options options) { - return new LoadData<>(contactPhotoUri, new StreamLocalUriFetcher(context.getContentResolver(), contactPhotoUri.uri)); - } - - @Override - public boolean handles(ContactPhotoUri contactPhotoUri) { - return true; - } - - static class Factory implements ModelLoaderFactory { - - private final Context context; - - Factory(Context context) { - this.context = context.getApplicationContext(); - } - - @Override - public ModelLoader build(MultiModelLoaderFactory multiFactory) { - return new ContactPhotoUriLoader(context); - } - - @Override - public void teardown() { - // Do nothing. - } - } - - public static class ContactPhotoUri implements Key { - public @NonNull Uri uri; - - public ContactPhotoUri(@NonNull Uri uri) { - this.uri = uri; - } - - @Override - public void updateDiskCacheKey(MessageDigest messageDigest) { - messageDigest.update(uri.toString().getBytes()); - } - - @Override - public boolean equals(Object other) { - if (other == null || !(other instanceof ContactPhotoUri)) return false; - - return this.uri.equals(((ContactPhotoUri)other).uri); - } - - public int hashCode() { - return uri.hashCode(); - } - } -} - diff --git a/src/org/thoughtcrime/securesms/mms/SignalGlideModule.java b/src/org/thoughtcrime/securesms/mms/SignalGlideModule.java index 495d659aee..8637d7536b 100644 --- a/src/org/thoughtcrime/securesms/mms/SignalGlideModule.java +++ b/src/org/thoughtcrime/securesms/mms/SignalGlideModule.java @@ -12,12 +12,11 @@ import com.bumptech.glide.load.engine.cache.DiskCacheAdapter; import com.bumptech.glide.load.model.GlideUrl; import com.bumptech.glide.module.AppGlideModule; +import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; +import org.thoughtcrime.securesms.glide.ContactPhotoLoader; import org.thoughtcrime.securesms.glide.OkHttpUrlLoader; import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel; -import org.thoughtcrime.securesms.mms.ContactPhotoUriLoader.ContactPhotoUri; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri; -import org.thoughtcrime.securesms.profiles.AvatarPhotoUriLoader; -import org.thoughtcrime.securesms.profiles.AvatarPhotoUriLoader.AvatarPhotoUri; import java.io.InputStream; @@ -37,11 +36,10 @@ public class SignalGlideModule extends AppGlideModule { @Override public void registerComponents(Context context, Glide glide, Registry registry) { + registry.append(ContactPhoto.class, InputStream.class, new ContactPhotoLoader.Factory(context)); registry.append(DecryptableUri.class, InputStream.class, new DecryptableStreamUriLoader.Factory(context)); - registry.append(ContactPhotoUri.class, InputStream.class, new ContactPhotoUriLoader.Factory(context)); registry.append(AttachmentModel.class, InputStream.class, new AttachmentStreamUriLoader.Factory()); registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory()); - registry.append(AvatarPhotoUri.class, InputStream.class, new AvatarPhotoUriLoader.Factory(context)); } public static class NoopDiskCacheFactory implements DiskCache.Factory { diff --git a/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java b/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java index 653b2f837d..b6ae08ba25 100644 --- a/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java +++ b/src/org/thoughtcrime/securesms/notifications/SingleRecipientNotificationBuilder.java @@ -13,12 +13,15 @@ import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat.Action; import android.support.v4.app.RemoteInput; import android.text.SpannableStringBuilder; +import android.util.Log; import com.bumptech.glide.load.engine.DiskCacheStrategy; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.contacts.avatars.ContactColors; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; +import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader; import org.thoughtcrime.securesms.mms.GlideApp; @@ -64,13 +67,29 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil addPerson(recipient.getContactUri().toString()); } - setLargeIcon(recipient.getContactPhoto() - .asDrawable(context, recipient.getColor() - .toConversationColor(context))); + ContactPhoto contactPhoto = recipient.getContactPhoto(); + FallbackContactPhoto fallbackContactPhoto = recipient.getFallbackContactPhoto(); + + if (contactPhoto != null) { + try { + setLargeIcon(GlideApp.with(context.getApplicationContext()) + .load(contactPhoto) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .circleCrop() + .submit(context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width), + context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height)) + .get()); + } catch (InterruptedException | ExecutionException e) { + Log.w(TAG, e); + setLargeIcon(fallbackContactPhoto.asDrawable(context, recipient.getColor().toConversationColor(context))); + } + } else { + setLargeIcon(fallbackContactPhoto.asDrawable(context, recipient.getColor().toConversationColor(context))); + } + } else { setContentTitle(context.getString(R.string.SingleRecipientNotificationBuilder_signal)); - setLargeIcon(ContactPhotoFactory.getDefaultContactPhoto("Unknown") - .asDrawable(context, ContactColors.UNKNOWN_COLOR.toConversationColor(context))); + setLargeIcon(new GeneratedContactPhoto("Unknown").asDrawable(context, ContactColors.UNKNOWN_COLOR.toConversationColor(context))); } } @@ -225,7 +244,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil @SuppressWarnings("ConstantConditions") Uri uri = slideDeck.getThumbnailSlide().getThumbnailUri(); - return GlideApp.with(context) + return GlideApp.with(context.getApplicationContext()) .asBitmap() .load(new DecryptableStreamUriLoader.DecryptableUri(masterSecret, uri)) .diskCacheStrategy(DiskCacheStrategy.NONE) diff --git a/src/org/thoughtcrime/securesms/preferences/BlockedContactListItem.java b/src/org/thoughtcrime/securesms/preferences/BlockedContactListItem.java index 8a9e7a4d73..68366fbfb3 100644 --- a/src/org/thoughtcrime/securesms/preferences/BlockedContactListItem.java +++ b/src/org/thoughtcrime/securesms/preferences/BlockedContactListItem.java @@ -1,12 +1,14 @@ package org.thoughtcrime.securesms.preferences; import android.content.Context; +import android.support.annotation.NonNull; import android.util.AttributeSet; import android.widget.RelativeLayout; import android.widget.TextView; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.AvatarImageView; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.util.Util; @@ -15,6 +17,7 @@ public class BlockedContactListItem extends RelativeLayout implements RecipientM private AvatarImageView contactPhotoImage; private TextView nameView; + private GlideRequests glideRequests; private Recipient recipient; public BlockedContactListItem(Context context) { @@ -32,12 +35,13 @@ public class BlockedContactListItem extends RelativeLayout implements RecipientM @Override public void onFinishInflate() { super.onFinishInflate(); - this.contactPhotoImage = (AvatarImageView)findViewById(R.id.contact_photo_image); - this.nameView = (TextView) findViewById(R.id.name); + this.contactPhotoImage = findViewById(R.id.contact_photo_image); + this.nameView = findViewById(R.id.name); } - public void set(Recipient recipients) { - this.recipient = recipients; + public void set(@NonNull GlideRequests glideRequests, @NonNull Recipient recipients) { + this.glideRequests = glideRequests; + this.recipient = recipients; onModified(recipients); recipients.addListener(this); @@ -48,12 +52,9 @@ public class BlockedContactListItem extends RelativeLayout implements RecipientM final AvatarImageView contactPhotoImage = this.contactPhotoImage; final TextView nameView = this.nameView; - Util.runOnMain(new Runnable() { - @Override - public void run() { - contactPhotoImage.setAvatar(recipients, false); - nameView.setText(recipients.toShortString()); - } + Util.runOnMain(() -> { + contactPhotoImage.setAvatar(glideRequests, recipients, false); + nameView.setText(recipients.toShortString()); }); } diff --git a/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java b/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java index 1da84a41d6..e2afb38192 100644 --- a/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java +++ b/src/org/thoughtcrime/securesms/preferences/widgets/ProfilePreference.java @@ -2,26 +2,23 @@ package org.thoughtcrime.securesms.preferences.widgets; import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; import android.os.Build; -import android.support.annotation.NonNull; import android.support.annotation.RequiresApi; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceViewHolder; -import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.AttributeSet; -import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import com.bumptech.glide.load.engine.DiskCacheStrategy; + import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; +import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto; import org.thoughtcrime.securesms.database.Address; -import org.thoughtcrime.securesms.profiles.AvatarHelper; +import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.util.ViewUtil; public class ProfilePreference extends Preference { @@ -70,24 +67,12 @@ public class ProfilePreference extends Preference { final Address localAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(getContext())); final String profileName = TextSecurePreferences.getProfileName(getContext()); - new AsyncTask() { - @Override - protected @NonNull Drawable doInBackground(Void... params) { - if (AvatarHelper.getAvatarFile(getContext(), localAddress).exists()) { - return ContactPhotoFactory.getSignalAvatarContactPhoto(getContext(), localAddress, profileName, - getContext().getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size)) - .asDrawable(getContext(), 0); - } else { - return ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp) - .asDrawable(getContext(), getContext().getResources().getColor(R.color.grey_400)); - } - } - - @Override - protected void onPostExecute(@NonNull Drawable contactPhoto) { - avatarView.setImageDrawable(contactPhoto); - } - }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + GlideApp.with(getContext().getApplicationContext()) + .load(new ProfileContactPhoto(localAddress, String.valueOf(TextSecurePreferences.getProfileAvatarId(getContext())))) + .error(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(getContext(), getContext().getResources().getColor(R.color.grey_400))) + .circleCrop() + .diskCacheStrategy(DiskCacheStrategy.ALL) + .into(avatarView); if (!TextUtils.isEmpty(profileName)) { profileNameView.setText(profileName); diff --git a/src/org/thoughtcrime/securesms/profiles/AvatarPhotoUriLoader.java b/src/org/thoughtcrime/securesms/profiles/AvatarPhotoUriLoader.java deleted file mode 100644 index 9209f80c3e..0000000000 --- a/src/org/thoughtcrime/securesms/profiles/AvatarPhotoUriLoader.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.thoughtcrime.securesms.profiles; - - -import android.content.Context; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; - -import com.bumptech.glide.load.Key; -import com.bumptech.glide.load.Options; -import com.bumptech.glide.load.model.ModelLoader; -import com.bumptech.glide.load.model.ModelLoaderFactory; -import com.bumptech.glide.load.model.MultiModelLoaderFactory; - -import org.thoughtcrime.securesms.database.Address; - -import java.io.InputStream; -import java.security.MessageDigest; - -public class AvatarPhotoUriLoader implements ModelLoader { - - private final Context context; - - private AvatarPhotoUriLoader(Context context) { - this.context = context; - } - - @Nullable - @Override - public LoadData buildLoadData(AvatarPhotoUri avatarPhotoUri, int width, int height, Options options) { - return new LoadData<>(avatarPhotoUri, new AvatarPhotoUriFetcher(context, avatarPhotoUri.address)); - } - - @Override - public boolean handles(AvatarPhotoUri avatarPhotoUri) { - return true; - } - - public static class Factory implements ModelLoaderFactory { - - private final Context context; - - public Factory(Context context) { - this.context = context.getApplicationContext(); - } - - @Override - public ModelLoader build(MultiModelLoaderFactory multiFactory) { - return new AvatarPhotoUriLoader(context); - } - - @Override - public void teardown() {} - } - - public static class AvatarPhotoUri implements Key { - public @NonNull Address address; - - public AvatarPhotoUri(@NonNull Address address) { - this.address = address; - } - - @Override - public void updateDiskCacheKey(MessageDigest messageDigest) { - messageDigest.update(address.serialize().getBytes()); - } - - @Override - public boolean equals(Object other) { - if (other == null || !(other instanceof AvatarPhotoUri)) return false; - - return this.address.equals(((AvatarPhotoUri)other).address); - } - - @Override - public int hashCode() { - return address.hashCode(); - } - } - -} diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index 52332266dc..d2bb6c729e 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -18,6 +18,7 @@ package org.thoughtcrime.securesms.recipients; import android.content.Context; import android.content.Intent; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -26,7 +27,8 @@ import android.util.Log; import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.contacts.avatars.ContactColors; import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; +import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.TransparentContactPhoto; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings; @@ -62,15 +64,16 @@ public class Recipient implements RecipientModifiedListener { private boolean stale; private boolean resolving; - private ContactPhoto contactPhoto; - private Uri contactUri; - private @Nullable Uri ringtone = null; - private long mutedUntil = 0; - private boolean blocked = false; - private VibrateState vibrate = VibrateState.DEFAULT; - private int expireMessages = 0; - private Optional defaultSubscriptionId = Optional.absent(); - private @NonNull RegisteredState registered = RegisteredState.UNKNOWN; + private @Nullable ContactPhoto contactPhoto; + private @NonNull FallbackContactPhoto fallbackContactPhoto; + private Uri contactUri; + private @Nullable Uri ringtone = null; + private long mutedUntil = 0; + private boolean blocked = false; + private VibrateState vibrate = VibrateState.DEFAULT; + private int expireMessages = 0; + private Optional defaultSubscriptionId = Optional.absent(); + private @NonNull RegisteredState registered = RegisteredState.UNKNOWN; private @Nullable MaterialColor color; private boolean seenInviteReminder; @@ -101,15 +104,16 @@ public class Recipient implements RecipientModifiedListener { @NonNull Optional details, @NonNull ListenableFutureTask future) { - this.address = address; - this.contactPhoto = ContactPhotoFactory.getLoadingPhoto(); - this.color = null; - this.resolving = true; + this.address = address; + this.fallbackContactPhoto = new TransparentContactPhoto(); + this.color = null; + this.resolving = true; if (stale != null) { this.name = stale.name; this.contactUri = stale.contactUri; this.contactPhoto = stale.contactPhoto; + this.fallbackContactPhoto = stale.fallbackContactPhoto; this.color = stale.color; this.customLabel = stale.customLabel; this.ringtone = stale.ringtone; @@ -132,6 +136,7 @@ public class Recipient implements RecipientModifiedListener { if (details.isPresent()) { this.name = details.get().name; this.contactPhoto = details.get().avatar; + this.fallbackContactPhoto = details.get().fallbackAvatar; this.color = details.get().color; this.ringtone = details.get().ringtone; this.mutedUntil = details.get().mutedUntil; @@ -158,6 +163,7 @@ public class Recipient implements RecipientModifiedListener { Recipient.this.name = result.name; Recipient.this.contactUri = result.contactUri; Recipient.this.contactPhoto = result.avatar; + Recipient.this.fallbackContactPhoto = result.fallbackAvatar; Recipient.this.color = result.color; Recipient.this.customLabel = result.customLabel; Recipient.this.ringtone = result.ringtone; @@ -202,6 +208,7 @@ public class Recipient implements RecipientModifiedListener { this.contactUri = details.contactUri; this.name = details.name; this.contactPhoto = details.avatar; + this.fallbackContactPhoto = details.fallbackAvatar; this.color = details.color; this.customLabel = details.customLabel; this.ringtone = details.ringtone; @@ -345,7 +352,15 @@ public class Recipient implements RecipientModifiedListener { return (getName() == null ? address.serialize() : getName()); } - public synchronized @NonNull ContactPhoto getContactPhoto() { + public synchronized @NonNull Drawable getFallbackContactPhotoDrawable(Context context, boolean inverted) { + return getFallbackContactPhoto().asDrawable(context, getColor().toConversationColor(context), inverted); + } + + public synchronized @NonNull FallbackContactPhoto getFallbackContactPhoto() { + return fallbackContactPhoto; + } + + public synchronized @Nullable ContactPhoto getContactPhoto() { return contactPhoto; } @@ -361,7 +376,7 @@ public class Recipient implements RecipientModifiedListener { return ringtone; } - public void setRingtone(Uri ringtone) { + public void setRingtone(@Nullable Uri ringtone) { synchronized (this) { this.ringtone = ringtone; } diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java index c2cfe19373..dcd32c38d0 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -29,11 +29,16 @@ import android.util.Log; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; -import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; +import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.GroupRecordContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.SystemContactPhoto; +import org.thoughtcrime.securesms.contacts.avatars.TransparentContactPhoto; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; -import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings; import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState; import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState; @@ -61,13 +66,12 @@ class RecipientProvider { PhoneLookup.LOOKUP_KEY, PhoneLookup._ID, PhoneLookup.NUMBER, - PhoneLookup.LABEL + PhoneLookup.LABEL, + PhoneLookup.PHOTO_URI }; private static final Map STATIC_DETAILS = new HashMap() {{ - put("262966", new RecipientDetails("Amazon", null, null, - ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_amazon), - false, null, null)); + put("262966", new RecipientDetails("Amazon", null, null, null, new ResourceContactPhoto(R.drawable.ic_amazon), false, null, null)); }}; @NonNull Recipient getRecipient(Context context, Address address, Optional settings, Optional groupRecord, boolean asynchronous) { @@ -100,7 +104,7 @@ class RecipientProvider { if (address.isGroup() && settings.isPresent() && groupRecord.isPresent()) { return Optional.of(getGroupRecipientDetails(context, address, groupRecord, settings, true)); } else if (!address.isGroup() && settings.isPresent()) { - return Optional.of(new RecipientDetails(null, null, null, ContactPhotoFactory.getLoadingPhoto(), !TextUtils.isEmpty(settings.get().getSystemDisplayName()), settings.get(), null)); + return Optional.of(new RecipientDetails(null, null, null, null, new TransparentContactPhoto(), !TextUtils.isEmpty(settings.get().getSystemDisplayName()), settings.get(), null)); } return Optional.absent(); @@ -126,10 +130,17 @@ class RecipientProvider { } private @NonNull RecipientDetails getIndividualRecipientDetails(Context context, @NonNull Address address, Optional settings) { + ContactPhoto contactPhoto = null; + FallbackContactPhoto fallbackContactPhoto = new GeneratedContactPhoto("#"); + if (!settings.isPresent()) { settings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(address); } + if (settings.isPresent() && !TextUtils.isEmpty(settings.get().getProfileAvatar())) { + contactPhoto = new ProfileContactPhoto(address, settings.get().getProfileAvatar()); + } + if (address.isPhone() && !TextUtils.isEmpty(address.toPhoneString())) { Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(address.toPhoneString())); Cursor cursor = context.getContentResolver().query(uri, CALLER_ID_PROJECTION, null, null, null); @@ -138,14 +149,19 @@ class RecipientProvider { if (cursor != null && cursor.moveToFirst()) { final String resultNumber = cursor.getString(3); if (resultNumber != null) { - Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1)); - String name = resultNumber.equals(cursor.getString(0)) ? null : cursor.getString(0); - ContactPhoto contactPhoto = ContactPhotoFactory.getContactPhoto(context, - Uri.withAppendedPath(Contacts.CONTENT_URI, cursor.getLong(2) + ""), - address, - name); + Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1)); + String name = resultNumber.equals(cursor.getString(0)) ? null : cursor.getString(0); + String photoUri = cursor.getString(5); - return new RecipientDetails(cursor.getString(0), cursor.getString(4), contactUri, contactPhoto, true, settings.orNull(), null); + if (!TextUtils.isEmpty(photoUri)) { + contactPhoto = new SystemContactPhoto(address, Uri.parse(photoUri), 0); + } + + if (!TextUtils.isEmpty(name)) { + fallbackContactPhoto = new GeneratedContactPhoto(name); + } + + return new RecipientDetails(cursor.getString(0), cursor.getString(4), contactUri, contactPhoto, fallbackContactPhoto, true, settings.orNull(), null); } else { Log.w(TAG, "resultNumber is null"); } @@ -157,10 +173,13 @@ class RecipientProvider { } if (STATIC_DETAILS.containsKey(address.serialize())) return STATIC_DETAILS.get(address.serialize()); - else return new RecipientDetails(null, null, null, ContactPhotoFactory.getSignalAvatarContactPhoto(context, address, null, context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size)), false, settings.orNull(), null); + else return new RecipientDetails(null, null, null, contactPhoto, fallbackContactPhoto, false, settings.orNull(), null); } private @NonNull RecipientDetails getGroupRecipientDetails(Context context, Address groupId, Optional groupRecord, Optional settings, boolean asynchronous) { + ContactPhoto contactPhoto = null; + FallbackContactPhoto fallbackContactPhoto = new ResourceContactPhoto(R.drawable.ic_group_white_24dp, R.drawable.ic_group_large); + if (!groupRecord.isPresent()) { groupRecord = DatabaseFactory.getGroupDatabase(context).getGroup(groupId.toGroupString()); } @@ -170,7 +189,6 @@ class RecipientProvider { } if (groupRecord.isPresent()) { - ContactPhoto contactPhoto = ContactPhotoFactory.getGroupContactPhoto(groupRecord.get().getAvatar()); String title = groupRecord.get().getTitle(); List
memberAddresses = groupRecord.get().getMembers(); List members = new LinkedList<>(); @@ -183,40 +201,47 @@ class RecipientProvider { title = context.getString(R.string.RecipientProvider_unnamed_group);; } - return new RecipientDetails(title, null, null, contactPhoto, false, settings.orNull(), members); + if (groupRecord.get().getAvatar() != null) { + contactPhoto = new GroupRecordContactPhoto(groupId, groupRecord.get().getAvatarId()); + } + + return new RecipientDetails(title, null, null, contactPhoto, fallbackContactPhoto, false, settings.orNull(), members); } - return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), null, null, ContactPhotoFactory.getDefaultGroupPhoto(), false, settings.orNull(), null); + return new RecipientDetails(context.getString(R.string.RecipientProvider_unnamed_group), null, null, contactPhoto, fallbackContactPhoto, false, settings.orNull(), null); } static class RecipientDetails { - @Nullable public final String name; - @Nullable public final String customLabel; - @NonNull public final ContactPhoto avatar; - @Nullable public final Uri contactUri; - @Nullable public final MaterialColor color; - @Nullable public final Uri ringtone; - public final long mutedUntil; - @Nullable public final VibrateState vibrateState; - public final boolean blocked; - public final int expireMessages; - @NonNull public final List participants; - @Nullable public final String profileName; - public final boolean seenInviteReminder; - public final Optional defaultSubscriptionId; - @NonNull public final RegisteredState registered; - @Nullable public final byte[] profileKey; - @Nullable public final String profileAvatar; - public final boolean profileSharing; - public final boolean systemContact; + @Nullable public final String name; + @Nullable public final String customLabel; + @Nullable public final ContactPhoto avatar; + @NonNull public final FallbackContactPhoto fallbackAvatar; + @Nullable public final Uri contactUri; + @Nullable public final MaterialColor color; + @Nullable public final Uri ringtone; + public final long mutedUntil; + @Nullable public final VibrateState vibrateState; + public final boolean blocked; + public final int expireMessages; + @NonNull public final List participants; + @Nullable public final String profileName; + public final boolean seenInviteReminder; + public final Optional defaultSubscriptionId; + @NonNull public final RegisteredState registered; + @Nullable public final byte[] profileKey; + @Nullable public final String profileAvatar; + public final boolean profileSharing; + public final boolean systemContact; public RecipientDetails(@Nullable String name, @Nullable String customLabel, - @Nullable Uri contactUri, @NonNull ContactPhoto avatar, + @Nullable Uri contactUri, @Nullable ContactPhoto avatar, + @NonNull FallbackContactPhoto fallbackAvatar, boolean systemContact, @Nullable RecipientSettings settings, @Nullable List participants) { this.customLabel = customLabel; this.avatar = avatar; + this.fallbackAvatar = fallbackAvatar; this.contactUri = contactUri; this.color = settings != null ? settings.getColor() : null; this.ringtone = settings != null ? settings.getRingtone() : null; diff --git a/src/org/thoughtcrime/securesms/scribbles/ScribbleActivity.java b/src/org/thoughtcrime/securesms/scribbles/ScribbleActivity.java index d69fd3cf28..675ba9dd4c 100644 --- a/src/org/thoughtcrime/securesms/scribbles/ScribbleActivity.java +++ b/src/org/thoughtcrime/securesms/scribbles/ScribbleActivity.java @@ -18,6 +18,8 @@ import android.view.View; import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.mms.GlideApp; +import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.providers.PersistentBlobProvider; import org.thoughtcrime.securesms.scribbles.viewmodel.Font; import org.thoughtcrime.securesms.scribbles.viewmodel.Layer; @@ -48,22 +50,24 @@ public class ScribbleActivity extends PassphraseRequiredActionBarActivity implem private ScribbleToolbar toolbar; private ScribbleView scribbleView; private MasterSecret masterSecret; + private GlideRequests glideRequests; @Override protected void onCreate(Bundle savedInstanceState, @NonNull MasterSecret masterSecret) { setContentView(R.layout.scribble_activity); - this.masterSecret = masterSecret; - this.scribbleView = (ScribbleView) findViewById(R.id.scribble_view); - this.toolbar = (ScribbleToolbar) findViewById(R.id.toolbar); - this.colorPicker = (VerticalSlideColorPicker) findViewById(R.id.scribble_color_picker); + this.masterSecret = masterSecret; + this.glideRequests = GlideApp.with(this); + this.scribbleView = findViewById(R.id.scribble_view); + this.toolbar = findViewById(R.id.toolbar); + this.colorPicker = findViewById(R.id.scribble_color_picker); this.toolbar.setListener(this); this.toolbar.setToolColor(Color.RED); scribbleView.setMotionViewCallback(motionViewCallback); scribbleView.setDrawingMode(false); - scribbleView.setImage(getIntent().getData(), masterSecret); + scribbleView.setImage(masterSecret, glideRequests, getIntent().getData()); colorPicker.setOnColorChangeListener(this); colorPicker.setVisibility(View.GONE); @@ -214,7 +218,7 @@ public class ScribbleActivity extends PassphraseRequiredActionBarActivity implem @Override public void onSave() { - ListenableFuture future = scribbleView.getRenderedImage(); + ListenableFuture future = scribbleView.getRenderedImage(glideRequests); future.addListener(new ListenableFuture.Listener() { @Override diff --git a/src/org/thoughtcrime/securesms/scribbles/StickerSelectFragment.java b/src/org/thoughtcrime/securesms/scribbles/StickerSelectFragment.java index a029757557..6b07b2f51a 100644 --- a/src/org/thoughtcrime/securesms/scribbles/StickerSelectFragment.java +++ b/src/org/thoughtcrime/securesms/scribbles/StickerSelectFragment.java @@ -35,11 +35,13 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.mms.GlideApp; +import org.thoughtcrime.securesms.mms.GlideRequests; public class StickerSelectFragment extends Fragment implements LoaderManager.LoaderCallbacks { - private RecyclerView recyclerView; - private String assetDirectory; + private RecyclerView recyclerView; + private GlideRequests glideRequests; + private String assetDirectory; private StickerSelectionListener listener; public static StickerSelectFragment newInstance(String assetDirectory) { @@ -67,6 +69,7 @@ public class StickerSelectFragment extends Fragment implements LoaderManager.Loa public void onActivityCreated(Bundle bundle) { super.onActivityCreated(bundle); + this.glideRequests = GlideApp.with(this); this.assetDirectory = getArguments().getString("assetDirectory"); getLoaderManager().initLoader(0, null, this); @@ -80,7 +83,7 @@ public class StickerSelectFragment extends Fragment implements LoaderManager.Loa @Override public void onLoadFinished(Loader loader, String[] data) { - recyclerView.setAdapter(new StickersAdapter(getActivity(), data)); + recyclerView.setAdapter(new StickersAdapter(getActivity(), glideRequests, data)); } @Override @@ -94,12 +97,12 @@ public class StickerSelectFragment extends Fragment implements LoaderManager.Loa class StickersAdapter extends RecyclerView.Adapter { - private final Context context; + private final GlideRequests glideRequests; private final String[] stickerFiles; private final LayoutInflater layoutInflater; - StickersAdapter(@NonNull Context context, @NonNull String[] stickerFiles) { - this.context = context; + StickersAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests, @NonNull String[] stickerFiles) { + this.glideRequests = glideRequests; this.stickerFiles = stickerFiles; this.layoutInflater = LayoutInflater.from(context); } @@ -113,10 +116,9 @@ public class StickerSelectFragment extends Fragment implements LoaderManager.Loa public void onBindViewHolder(StickerViewHolder holder, int position) { holder.fileName = stickerFiles[position]; - GlideApp.with(context) - .load(Uri.parse("file:///android_asset/" + holder.fileName)) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .into(holder.image); + glideRequests.load(Uri.parse("file:///android_asset/" + holder.fileName)) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .into(holder.image); } @Override @@ -127,7 +129,7 @@ public class StickerSelectFragment extends Fragment implements LoaderManager.Loa @Override public void onViewRecycled(StickerViewHolder holder) { super.onViewRecycled(holder); - GlideApp.with(context).clear(holder.image); + glideRequests.clear(holder.image); } private void onStickerSelected(String fileName) { diff --git a/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java b/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java index 1363c8305d..6491009849 100644 --- a/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java +++ b/src/org/thoughtcrime/securesms/scribbles/widget/ScribbleView.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2016 Open Whisper Systems * * This program is free software: you can redistribute it and/or modify @@ -36,7 +36,7 @@ import com.bumptech.glide.request.target.Target; import org.thoughtcrime.securesms.R; 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.scribbles.widget.entity.MotionEntity; import org.thoughtcrime.securesms.scribbles.widget.entity.TextEntity; import org.thoughtcrime.securesms.util.Util; @@ -77,18 +77,17 @@ public class ScribbleView extends FrameLayout { initialize(context); } - public void setImage(@NonNull Uri uri, @NonNull MasterSecret masterSecret) { + public void setImage(@NonNull MasterSecret masterSecret, @NonNull GlideRequests glideRequests, @NonNull Uri uri) { this.imageUri = uri; this.masterSecret = masterSecret; - GlideApp.with(getContext()) - .load(new DecryptableUri(masterSecret, uri)) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .fitCenter() - .into(imageView); + glideRequests.load(new DecryptableUri(masterSecret, uri)) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .fitCenter() + .into(imageView); } - public @NonNull ListenableFuture getRenderedImage() { + public @NonNull ListenableFuture getRenderedImage(@NonNull GlideRequests glideRequests) { final SettableFuture future = new SettableFuture<>(); final Context context = getContext(); final boolean isLowMemory = Util.isLowMemory(context); @@ -110,13 +109,12 @@ public class ScribbleView extends FrameLayout { height = 768; } - return GlideApp.with(context) - .asBitmap() - .load(new DecryptableUri(masterSecret, imageUri)) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) - .into(width, height) - .get(); + return glideRequests.asBitmap() + .load(new DecryptableUri(masterSecret, imageUri)) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(true) + .into(width, height) + .get(); } catch (InterruptedException | ExecutionException e) { Log.w(TAG, e); return null; @@ -143,9 +141,9 @@ public class ScribbleView extends FrameLayout { private void initialize(@NonNull Context context) { inflate(context, R.layout.scribble_view, this); - this.imageView = (ImageView) findViewById(R.id.image_view); - this.motionView = (MotionView) findViewById(R.id.motion_view); - this.canvasView = (CanvasView) findViewById(R.id.canvas_view); + this.imageView = findViewById(R.id.image_view); + this.motionView = findViewById(R.id.motion_view); + this.canvasView = findViewById(R.id.canvas_view); } public void setMotionViewCallback(MotionView.MotionViewCallback callback) { diff --git a/src/org/thoughtcrime/securesms/service/DirectShareService.java b/src/org/thoughtcrime/securesms/service/DirectShareService.java index 99d41cf8d9..2998553343 100644 --- a/src/org/thoughtcrime/securesms/service/DirectShareService.java +++ b/src/org/thoughtcrime/securesms/service/DirectShareService.java @@ -5,7 +5,6 @@ import android.content.ComponentName; import android.content.IntentFilter; import android.database.Cursor; import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.Build; import android.os.Bundle; @@ -20,11 +19,13 @@ import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.model.ThreadRecord; +import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.BitmapUtil; import java.util.LinkedList; import java.util.List; +import java.util.concurrent.ExecutionException; @RequiresApi(api = Build.VERSION_CODES.M) public class DirectShareService extends ChooserTargetService { @@ -48,22 +49,40 @@ public class DirectShareService extends ChooserTargetService { ThreadRecord record; while ((record = reader.getNext()) != null && results.size() < 10) { - Recipient recipient = Recipient.from(this, record.getRecipient().getAddress(), false); - String name = recipient.toShortString(); - Drawable drawable = recipient.getContactPhoto().asDrawable(this, recipient.getColor().toConversationColor(this)); - Bitmap avatar = BitmapUtil.createFromDrawable(drawable, 500, 500); + try { + Recipient recipient = Recipient.from(this, record.getRecipient().getAddress(), false); + String name = recipient.toShortString(); - Parcel parcel = Parcel.obtain(); - parcel.writeParcelable(recipient.getAddress(), 0); + Bitmap avatar; - Bundle bundle = new Bundle(); - bundle.putLong(ShareActivity.EXTRA_THREAD_ID, record.getThreadId()); - bundle.putByteArray(ShareActivity.EXTRA_ADDRESS_MARSHALLED, parcel.marshall()); - bundle.putInt(ShareActivity.EXTRA_DISTRIBUTION_TYPE, record.getDistributionType()); - bundle.setClassLoader(getClassLoader()); + if (recipient.getContactPhoto() != null) { + avatar = GlideApp.with(this) + .asBitmap() + .load(recipient.getContactPhoto()) + .circleCrop() + .submit(getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width), + getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width)) + .get(); + } else { + avatar = BitmapUtil.createFromDrawable(recipient.getFallbackContactPhotoDrawable(this, false), + getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width), + getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height)); + } - results.add(new ChooserTarget(name, Icon.createWithBitmap(avatar), 1.0f, componentName, bundle)); - parcel.recycle(); + Parcel parcel = Parcel.obtain(); + parcel.writeParcelable(recipient.getAddress(), 0); + + Bundle bundle = new Bundle(); + bundle.putLong(ShareActivity.EXTRA_THREAD_ID, record.getThreadId()); + bundle.putByteArray(ShareActivity.EXTRA_ADDRESS_MARSHALLED, parcel.marshall()); + bundle.putInt(ShareActivity.EXTRA_DISTRIBUTION_TYPE, record.getDistributionType()); + bundle.setClassLoader(getClassLoader()); + + results.add(new ChooserTarget(name, Icon.createWithBitmap(avatar), 1.0f, componentName, bundle)); + parcel.recycle(); + } catch (InterruptedException | ExecutionException e) { + throw new AssertionError(e); + } } return results; diff --git a/src/org/thoughtcrime/securesms/util/BitmapUtil.java b/src/org/thoughtcrime/securesms/util/BitmapUtil.java index 9319b38cd5..891bae7451 100644 --- a/src/org/thoughtcrime/securesms/util/BitmapUtil.java +++ b/src/org/thoughtcrime/securesms/util/BitmapUtil.java @@ -10,8 +10,8 @@ import android.graphics.Rect; import android.graphics.YuvImage; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import android.support.annotation.*; +import android.support.annotation.WorkerThread; import android.util.Log; import android.util.Pair; @@ -42,6 +42,7 @@ public class BitmapUtil { private static final int MAX_COMPRESSION_ATTEMPTS = 5; private static final int MIN_COMPRESSION_QUALITY_DECREASE = 5; + @android.support.annotation.WorkerThread public static byte[] createScaledBytes(Context context, T model, MediaConstraints constraints) throws BitmapDecodingException { @@ -50,7 +51,7 @@ public class BitmapUtil { int attempts = 0; byte[] bytes; - Bitmap scaledBitmap = GlideApp.with(context) + Bitmap scaledBitmap = GlideApp.with(context.getApplicationContext()) .asBitmap() .load(model) .downsample(DownsampleStrategy.AT_MOST) @@ -91,11 +92,12 @@ public class BitmapUtil { } } + @WorkerThread public static Bitmap createScaledBitmap(Context context, T model, int maxWidth, int maxHeight) throws BitmapDecodingException { try { - return GlideApp.with(context) + return GlideApp.with(context.getApplicationContext()) .asBitmap() .load(model) .downsample(DownsampleStrategy.AT_MOST) @@ -106,11 +108,12 @@ public class BitmapUtil { } } + @WorkerThread public static Bitmap createScaledBitmap(Context context, T model, float scale) throws BitmapDecodingException { try { - return GlideApp.with(context) + return GlideApp.with(context.getApplicationContext()) .asBitmap() .load(model) .sizeMultiplier(scale) diff --git a/src/org/thoughtcrime/securesms/util/MediaUtil.java b/src/org/thoughtcrime/securesms/util/MediaUtil.java index 72ff876479..c887bc7e10 100644 --- a/src/org/thoughtcrime/securesms/util/MediaUtil.java +++ b/src/org/thoughtcrime/securesms/util/MediaUtil.java @@ -66,7 +66,7 @@ public class MediaUtil { { try { int maxSize = context.getResources().getDimensionPixelSize(R.dimen.media_bubble_height); - return GlideApp.with(context) + return GlideApp.with(context.getApplicationContext()) .asBitmap() .load(new DecryptableUri(masterSecret, uri)) .centerCrop() diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 1046616f79..2791094568 100644 --- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -112,6 +112,7 @@ public class TextSecurePreferences { private static final String ALWAYS_RELAY_CALLS_PREF = "pref_turn_only"; private static final String PROFILE_KEY_PREF = "pref_profile_key"; private static final String PROFILE_NAME_PREF = "pref_profile_name"; + private static final String PROFILE_AVATAR_ID_PREF = "pref_profile_avatar_id"; public static final String READ_RECEIPTS_PREF = "pref_read_receipts"; public static final String INCOGNITO_KEYBORAD_PREF = "pref_incognito_keyboard"; @@ -143,6 +144,14 @@ public class TextSecurePreferences { return getStringPreference(context, PROFILE_NAME_PREF, null); } + public static void setProfileAvatarId(Context context, int id) { + setIntegerPrefrence(context, PROFILE_AVATAR_ID_PREF, id); + } + + public static int getProfileAvatarId(Context context) { + return getIntegerPreference(context, PROFILE_AVATAR_ID_PREF, 0); + } + public static int getNotificationPriority(Context context) { return Integer.valueOf(getStringPreference(context, NOTIFICATION_PRIORITY_PREF, String.valueOf(NotificationCompat.PRIORITY_HIGH))); }