Use Glide for all contact photo caching

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

View File

@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.Locale; import java.util.Locale;
@ -12,6 +13,7 @@ import java.util.Set;
public interface BindableConversationItem extends Unbindable { public interface BindableConversationItem extends Unbindable {
void bind(@NonNull MasterSecret masterSecret, void bind(@NonNull MasterSecret masterSecret,
@NonNull MessageRecord messageRecord, @NonNull MessageRecord messageRecord,
@NonNull GlideRequests glideRequests,
@NonNull Locale locale, @NonNull Locale locale,
@NonNull Set<MessageRecord> batchSelected, @NonNull Set<MessageRecord> batchSelected,
@NonNull Recipient recipients); @NonNull Recipient recipients);

View File

@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
@ -11,5 +12,6 @@ import java.util.Set;
public interface BindableConversationListItem extends Unbindable { public interface BindableConversationListItem extends Unbindable {
public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread, public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread,
@NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode); @NonNull GlideRequests glideRequests, @NonNull Locale locale,
@NonNull Set<Long> selectedThreads, boolean batchMode);
} }

View File

@ -5,6 +5,7 @@ import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment; import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
@ -19,6 +20,8 @@ import android.widget.ListView;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.loaders.BlockedContactsLoader; 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.preferences.BlockedContactListItem;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicLanguage;
@ -72,7 +75,7 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
@Override @Override
public void onCreate(Bundle bundle) { public void onCreate(Bundle bundle) {
super.onCreate(bundle); super.onCreate(bundle);
setListAdapter(new BlockedContactAdapter(getActivity(), null)); setListAdapter(new BlockedContactAdapter(getActivity(), GlideApp.with(this), null));
getLoaderManager().initLoader(0, null, this); getLoaderManager().initLoader(0, null, this);
} }
@ -112,8 +115,11 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
private static class BlockedContactAdapter extends CursorAdapter { 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); super(context, c);
this.glideRequests = glideRequests;
} }
@Override @Override
@ -127,7 +133,7 @@ public class BlockedContactsActivity extends PassphraseRequiredActionBarActivity
String address = cursor.getString(1); String address = cursor.getString(1);
Recipient recipient = Recipient.from(context, Address.fromSerialized(address), true); Recipient recipient = Recipient.from(context, Address.fromSerialized(address), true);
((BlockedContactListItem) view).set(recipient); ((BlockedContactListItem) view).set(glideRequests, recipient);
} }
} }

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2015 Open Whisper Systems * Copyright (C) 2015 Open Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.ContactSelectionListItem;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader; import org.thoughtcrime.securesms.contacts.ContactsCursorLoader;
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration; import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
@ -119,6 +120,7 @@ public class ContactSelectionListFragment extends Fragment
private void initializeCursor() { private void initializeCursor() {
ContactSelectionListAdapter adapter = new ContactSelectionListAdapter(getActivity(), ContactSelectionListAdapter adapter = new ContactSelectionListAdapter(getActivity(),
GlideApp.with(this),
null, null,
new ListClickListener(), new ListClickListener(),
isMulti()); isMulti());

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2011 Whisper Systems * Copyright (C) 2011 Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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;
import org.thoughtcrime.securesms.mms.AttachmentManager.MediaType; import org.thoughtcrime.securesms.mms.AttachmentManager.MediaType;
import org.thoughtcrime.securesms.mms.AudioSlide; 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.LocationSlide;
import org.thoughtcrime.securesms.mms.MediaConstraints; import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage; import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
@ -208,6 +210,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private static final int SMS_DEFAULT = 10; private static final int SMS_DEFAULT = 10;
private MasterSecret masterSecret; private MasterSecret masterSecret;
private GlideRequests glideRequests;
protected ComposeText composeText; protected ComposeText composeText;
private AnimatingToggle buttonToggle; private AnimatingToggle buttonToggle;
private SendButton sendButton; private SendButton sendButton;
@ -287,7 +290,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
if (!Util.isEmpty(composeText) || attachmentManager.isAttachmentPresent()) { if (!Util.isEmpty(composeText) || attachmentManager.isAttachmentPresent()) {
saveDraft(); saveDraft();
attachmentManager.clear(false); attachmentManager.clear(glideRequests, false);
composeText.setText(""); composeText.setText("");
} }
@ -323,7 +326,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
initializeIdentityRecords(); initializeIdentityRecords();
composeText.setTransport(sendButton.getSelectedTransport()); composeText.setTransport(sendButton.getSelectedTransport());
titleView.setTitle(recipient); titleView.setTitle(glideRequests, recipient);
setActionBarColor(recipient.getColor()); setActionBarColor(recipient.getColor());
setBlockedUserState(recipient, isSecureText, isDefaultSms); setBlockedUserState(recipient, isSecureText, isDefaultSms);
setGroupShareProfileReminder(recipient); setGroupShareProfileReminder(recipient);
@ -409,9 +412,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
addAttachmentContactInfo(data.getData()); addAttachmentContactInfo(data.getData());
break; break;
case GROUP_EDIT: 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); recipient.addListener(this);
titleView.setTitle(recipient); titleView.setTitle(glideRequests, recipient);
setBlockedUserState(recipient, isSecureText, isDefaultSms); setBlockedUserState(recipient, isSecureText, isDefaultSms);
supportInvalidateOptionsMenu(); supportInvalidateOptionsMenu();
break; break;
@ -1239,6 +1242,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1); threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
archived = getIntent().getBooleanExtra(IS_ARCHIVED_EXTRA, false); archived = getIntent().getBooleanExtra(IS_ARCHIVED_EXTRA, false);
distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT); distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
glideRequests = GlideApp.with(this);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
LinearLayout conversationContainer = ViewUtil.findById(this, R.id.conversation_container); LinearLayout conversationContainer = ViewUtil.findById(this, R.id.conversation_container);
@ -1263,7 +1267,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override @Override
public void onModified(final Recipient recipient) { public void onModified(final Recipient recipient) {
Util.runOnMain(() -> { Util.runOnMain(() -> {
titleView.setTitle(recipient); titleView.setTitle(glideRequests, recipient);
titleView.setVerified(identityRecords.isVerified()); titleView.setVerified(identityRecords.isVerified());
setBlockedUserState(recipient, isSecureText, isDefaultSms); setBlockedUserState(recipient, isSecureText, isDefaultSms);
setActionBarColor(recipient.getColor()); setActionBarColor(recipient.getColor());
@ -1338,7 +1342,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private void setMedia(@Nullable Uri uri, @NonNull MediaType mediaType) { private void setMedia(@Nullable Uri uri, @NonNull MediaType mediaType) {
if (uri == null) return; if (uri == null) return;
attachmentManager.setMedia(masterSecret, uri, mediaType, getCurrentMediaConstraints()); attachmentManager.setMedia(masterSecret, glideRequests, uri, mediaType, getCurrentMediaConstraints());
} }
private void addAttachmentContactInfo(Uri contactUri) { private void addAttachmentContactInfo(Uri contactUri) {
@ -1631,7 +1635,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
outgoingMessage = new OutgoingSecureMediaMessage(outgoingMessage); outgoingMessage = new OutgoingSecureMediaMessage(outgoingMessage);
} }
attachmentManager.clear(false); attachmentManager.clear(glideRequests, false);
composeText.setText(""); composeText.setText("");
final long id = fragment.stageOutgoingMessage(outgoingMessage); final long id = fragment.stageOutgoingMessage(outgoingMessage);

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2011 Whisper Systems * Copyright (C) 2011 Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Conversions; import org.thoughtcrime.securesms.util.Conversions;
@ -92,6 +93,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
private final @Nullable ItemClickListener clickListener; private final @Nullable ItemClickListener clickListener;
private final @NonNull MasterSecret masterSecret; private final @NonNull MasterSecret masterSecret;
private final @NonNull GlideRequests glideRequests;
private final @NonNull Locale locale; private final @NonNull Locale locale;
private final @NonNull Recipient recipient; private final @NonNull Recipient recipient;
private final @NonNull MmsSmsDatabase db; private final @NonNull MmsSmsDatabase db;
@ -130,7 +132,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
} }
public interface ItemClickListener { interface ItemClickListener {
void onItemClick(MessageRecord item); void onItemClick(MessageRecord item);
void onItemLongClick(MessageRecord item); void onItemLongClick(MessageRecord item);
} }
@ -141,6 +143,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
super(context, cursor); super(context, cursor);
try { try {
this.masterSecret = null; this.masterSecret = null;
this.glideRequests = null;
this.locale = null; this.locale = null;
this.clickListener = null; this.clickListener = null;
this.recipient = null; this.recipient = null;
@ -155,6 +158,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
public ConversationAdapter(@NonNull Context context, public ConversationAdapter(@NonNull Context context,
@NonNull MasterSecret masterSecret, @NonNull MasterSecret masterSecret,
@NonNull GlideRequests glideRequests,
@NonNull Locale locale, @NonNull Locale locale,
@Nullable ItemClickListener clickListener, @Nullable ItemClickListener clickListener,
@Nullable Cursor cursor, @Nullable Cursor cursor,
@ -164,6 +168,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
try { try {
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
this.glideRequests = glideRequests;
this.locale = locale; this.locale = locale;
this.clickListener = clickListener; this.clickListener = clickListener;
this.recipient = recipient; this.recipient = recipient;
@ -188,7 +193,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override @Override
protected void onBindItemViewHolder(ViewHolder viewHolder, @NonNull MessageRecord messageRecord) { protected void onBindItemViewHolder(ViewHolder viewHolder, @NonNull MessageRecord messageRecord) {
long start = System.currentTimeMillis(); 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)); Log.w(TAG, "Bind time: " + (System.currentTimeMillis() - start));
} }
@ -196,22 +201,16 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) { public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
final V itemView = ViewUtil.inflate(inflater, parent, getLayoutForViewType(viewType)); final V itemView = ViewUtil.inflate(inflater, parent, getLayoutForViewType(viewType));
itemView.setOnClickListener(new OnClickListener() { itemView.setOnClickListener(view -> {
@Override if (clickListener != null) {
public void onClick(View view) { clickListener.onItemClick(itemView.getMessageRecord());
if (clickListener != null) {
clickListener.onItemClick(itemView.getMessageRecord());
}
} }
}); });
itemView.setOnLongClickListener(new OnLongClickListener() { itemView.setOnLongClickListener(view -> {
@Override if (clickListener != null) {
public boolean onLongClick(View view) { clickListener.onItemLongClick(itemView.getMessageRecord());
if (clickListener != null) {
clickListener.onItemLongClick(itemView.getMessageRecord());
}
return true;
} }
return true;
}); });
Log.w(TAG, "Inflate time: " + (System.currentTimeMillis() - start)); Log.w(TAG, "Inflate time: " + (System.currentTimeMillis() - start));
return new ViewHolder(itemView); return new ViewHolder(itemView);

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2015 Open Whisper Systems * Copyright (C) 2015 Open Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.loaders.ConversationLoader;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord; import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.profiles.UnknownSenderView; 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;
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment; import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration; import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; 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); scrollToBottomButton = ViewUtil.findById(view, R.id.scroll_to_bottom_button);
scrollDateHeader = ViewUtil.findById(view, R.id.scroll_date_header); scrollDateHeader = ViewUtil.findById(view, R.id.scroll_date_header);
scrollToBottomButton.setOnClickListener(new OnClickListener() { scrollToBottomButton.setOnClickListener(v -> scrollToBottom());
@Override
public void onClick(final View view) {
scrollToBottom();
}
});
final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, true); final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, true);
list.setHasFixedSize(false); list.setHasFixedSize(false);
@ -185,7 +180,7 @@ public class ConversationFragment extends Fragment
} }
private void initializeResources() { 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.threadId = this.getActivity().getIntent().getLongExtra(ConversationActivity.THREAD_ID_EXTRA, -1);
this.lastSeen = this.getActivity().getIntent().getLongExtra(ConversationActivity.LAST_SEEN_EXTRA, -1); this.lastSeen = this.getActivity().getIntent().getLongExtra(ConversationActivity.LAST_SEEN_EXTRA, -1);
this.firstLoad = true; this.firstLoad = true;
@ -197,7 +192,7 @@ public class ConversationFragment extends Fragment
private void initializeListAdapter() { private void initializeListAdapter() {
if (this.recipient != null && this.threadId != -1) { 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.setAdapter(adapter);
list.addItemDecoration(new StickyHeaderDecoration(adapter, false, false)); list.addItemDecoration(new StickyHeaderDecoration(adapter, false, false));

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2011 Whisper Systems * Copyright (C) 2011 Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.util.TypedValue;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewStub;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; 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.MmsDownloadJob;
import org.thoughtcrime.securesms.jobs.MmsSendJob; import org.thoughtcrime.securesms.jobs.MmsSendJob;
import org.thoughtcrime.securesms.jobs.SmsSendJob; import org.thoughtcrime.securesms.jobs.SmsSendJob;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener; import org.thoughtcrime.securesms.mms.SlideClickListener;
@ -107,6 +107,7 @@ public class ConversationItem extends LinearLayout
private Locale locale; private Locale locale;
private boolean groupThread; private boolean groupThread;
private Recipient recipient; private Recipient recipient;
private GlideRequests glideRequests;
protected View bodyBubble; protected View bodyBubble;
private TextView bodyText; private TextView bodyText;
@ -155,22 +156,22 @@ public class ConversationItem extends LinearLayout
initializeAttributes(); initializeAttributes();
this.bodyText = (TextView) findViewById(R.id.conversation_item_body); this.bodyText = findViewById(R.id.conversation_item_body);
this.dateText = (TextView) findViewById(R.id.conversation_item_date); this.dateText = findViewById(R.id.conversation_item_date);
this.simInfoText = (TextView) findViewById(R.id.sim_info); this.simInfoText = findViewById(R.id.sim_info);
this.indicatorText = (TextView) findViewById(R.id.indicator_text); this.indicatorText = findViewById(R.id.indicator_text);
this.groupSender = (TextView) findViewById(R.id.group_message_sender); this.groupSender = findViewById(R.id.group_message_sender);
this.groupSenderProfileName = (TextView) findViewById(R.id.group_message_sender_profile); this.groupSenderProfileName = findViewById(R.id.group_message_sender_profile);
this.insecureImage = (ImageView) findViewById(R.id.insecure_indicator); this.insecureImage = findViewById(R.id.insecure_indicator);
this.deliveryStatusIndicator = (DeliveryStatusView) findViewById(R.id.delivery_status); this.deliveryStatusIndicator = findViewById(R.id.delivery_status);
this.alertView = (AlertView) findViewById(R.id.indicators_parent); this.alertView = findViewById(R.id.indicators_parent);
this.contactPhoto = (AvatarImageView) findViewById(R.id.contact_photo); this.contactPhoto = findViewById(R.id.contact_photo);
this.bodyBubble = findViewById(R.id.body_bubble); this.bodyBubble = findViewById(R.id.body_bubble);
this.mediaThumbnailStub = new Stub<>((ViewStub) findViewById(R.id.image_view_stub)); this.mediaThumbnailStub = new Stub<>(findViewById(R.id.image_view_stub));
this.audioViewStub = new Stub<>((ViewStub) findViewById(R.id.audio_view_stub)); this.audioViewStub = new Stub<>(findViewById(R.id.audio_view_stub));
this.documentViewStub = new Stub<>((ViewStub) findViewById(R.id.document_view_stub)); this.documentViewStub = new Stub<>(findViewById(R.id.document_view_stub));
this.expirationTimer = (ExpirationTimerView) findViewById(R.id.expiration_indicator); this.expirationTimer = findViewById(R.id.expiration_indicator);
this.groupSenderHolder = findViewById(R.id.group_sender_holder); this.groupSenderHolder = findViewById(R.id.group_sender_holder);
setOnClickListener(new ClickListener(null)); setOnClickListener(new ClickListener(null));
@ -183,6 +184,7 @@ public class ConversationItem extends LinearLayout
@Override @Override
public void bind(@NonNull MasterSecret masterSecret, public void bind(@NonNull MasterSecret masterSecret,
@NonNull MessageRecord messageRecord, @NonNull MessageRecord messageRecord,
@NonNull GlideRequests glideRequests,
@NonNull Locale locale, @NonNull Locale locale,
@NonNull Set<MessageRecord> batchSelected, @NonNull Set<MessageRecord> batchSelected,
@NonNull Recipient conversationRecipient) @NonNull Recipient conversationRecipient)
@ -190,6 +192,7 @@ public class ConversationItem extends LinearLayout
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
this.messageRecord = messageRecord; this.messageRecord = messageRecord;
this.locale = locale; this.locale = locale;
this.glideRequests = glideRequests;
this.batchSelected = batchSelected; this.batchSelected = batchSelected;
this.conversationRecipient = conversationRecipient; this.conversationRecipient = conversationRecipient;
this.groupThread = conversationRecipient.isGroupRecipient(); this.groupThread = conversationRecipient.isGroupRecipient();
@ -386,7 +389,7 @@ public class ConversationItem extends LinearLayout
if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE); if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
//noinspection ConstantConditions //noinspection ConstantConditions
mediaThumbnailStub.get().setImageResource(masterSecret, mediaThumbnailStub.get().setImageResource(masterSecret, glideRequests,
((MmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide(), ((MmsMessageRecord)messageRecord).getSlideDeck().getThumbnailSlide(),
showControls, false); showControls, false);
mediaThumbnailStub.get().setThumbnailClickListener(new ThumbnailClickListener()); mediaThumbnailStub.get().setThumbnailClickListener(new ThumbnailClickListener());
@ -409,7 +412,7 @@ public class ConversationItem extends LinearLayout
if (messageRecord.isOutgoing() || !groupThread) { if (messageRecord.isOutgoing() || !groupThread) {
contactPhoto.setVisibility(View.GONE); contactPhoto.setVisibility(View.GONE);
} else { } else {
contactPhoto.setAvatar(recipient, true); contactPhoto.setAvatar(glideRequests, recipient, true);
contactPhoto.setVisibility(View.VISIBLE); contactPhoto.setVisibility(View.VISIBLE);
} }
} }

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2011 Whisper Systems * Copyright (C) 2011 Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.thoughtcrime.securesms.crypto.MasterCipher; import org.thoughtcrime.securesms.crypto.MasterCipher;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.util.Conversions; import org.thoughtcrime.securesms.util.Conversions;
import java.security.MessageDigest; import java.security.MessageDigest;
@ -48,18 +46,19 @@ import java.util.Set;
* *
* @author Moxie Marlinspike * @author Moxie Marlinspike
*/ */
public class ConversationListAdapter extends CursorRecyclerViewAdapter<ConversationListAdapter.ViewHolder> { class ConversationListAdapter extends CursorRecyclerViewAdapter<ConversationListAdapter.ViewHolder> {
private static final int MESSAGE_TYPE_SWITCH_ARCHIVE = 1; private static final int MESSAGE_TYPE_SWITCH_ARCHIVE = 1;
private static final int MESSAGE_TYPE_THREAD = 2; private static final int MESSAGE_TYPE_THREAD = 2;
private final ThreadDatabase threadDatabase; private final @NonNull ThreadDatabase threadDatabase;
private final MasterSecret masterSecret; private final @NonNull MasterSecret masterSecret;
private final MasterCipher masterCipher; private final @NonNull MasterCipher masterCipher;
private final Locale locale; private final @NonNull GlideRequests glideRequests;
private final LayoutInflater inflater; private final @NonNull Locale locale;
private final ItemClickListener clickListener; private final @NonNull LayoutInflater inflater;
private final @NonNull MessageDigest digest; private final @Nullable ItemClickListener clickListener;
private final @NonNull MessageDigest digest;
private final Set<Long> batchSet = Collections.synchronizedSet(new HashSet<Long>()); private final Set<Long> batchSet = Collections.synchronizedSet(new HashSet<Long>());
private boolean batchMode = false; private boolean batchMode = false;
@ -82,16 +81,18 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
return Conversions.byteArrayToLong(digest.digest(record.getRecipient().getAddress().serialize().getBytes())); return Conversions.byteArrayToLong(digest.digest(record.getRecipient().getAddress().serialize().getBytes()));
} }
public ConversationListAdapter(@NonNull Context context, ConversationListAdapter(@NonNull Context context,
@NonNull MasterSecret masterSecret, @NonNull MasterSecret masterSecret,
@NonNull Locale locale, @NonNull GlideRequests glideRequests,
@Nullable Cursor cursor, @NonNull Locale locale,
@Nullable ItemClickListener clickListener) @Nullable Cursor cursor,
@Nullable ItemClickListener clickListener)
{ {
super(context, cursor); super(context, cursor);
try { try {
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
this.masterCipher = new MasterCipher(masterSecret); this.masterCipher = new MasterCipher(masterSecret);
this.glideRequests = glideRequests;
this.threadDatabase = DatabaseFactory.getThreadDatabase(context); this.threadDatabase = DatabaseFactory.getThreadDatabase(context);
this.locale = locale; this.locale = locale;
this.inflater = LayoutInflater.from(context); this.inflater = LayoutInflater.from(context);
@ -109,11 +110,8 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
ConversationListItemAction action = (ConversationListItemAction)inflater.inflate(R.layout.conversation_list_item_action, ConversationListItemAction action = (ConversationListItemAction)inflater.inflate(R.layout.conversation_list_item_action,
parent, false); parent, false);
action.setOnClickListener(new OnClickListener() { action.setOnClickListener(v -> {
@Override if (clickListener != null) clickListener.onSwitchToArchive();
public void onClick(View v) {
if (clickListener != null) clickListener.onSwitchToArchive();
}
}); });
return new ViewHolder(action); return new ViewHolder(action);
@ -121,19 +119,13 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
final ConversationListItem item = (ConversationListItem)inflater.inflate(R.layout.conversation_list_item_view, final ConversationListItem item = (ConversationListItem)inflater.inflate(R.layout.conversation_list_item_view,
parent, false); parent, false);
item.setOnClickListener(new OnClickListener() { item.setOnClickListener(view -> {
@Override if (clickListener != null) clickListener.onItemClick(item);
public void onClick(View view) {
if (clickListener != null) clickListener.onItemClick(item);
}
}); });
item.setOnLongClickListener(new OnLongClickListener() { item.setOnLongClickListener(view -> {
@Override if (clickListener != null) clickListener.onItemLongClick(item);
public boolean onLongClick(View view) { return true;
if (clickListener != null) clickListener.onItemLongClick(item);
return true;
}
}); });
return new ViewHolder(item); return new ViewHolder(item);
@ -147,7 +139,7 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
@Override @Override
public void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) { public void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) {
viewHolder.getItem().bind(masterSecret, getThreadRecord(cursor), locale, batchSet, batchMode); viewHolder.getItem().bind(masterSecret, getThreadRecord(cursor), glideRequests, locale, batchSet, batchMode);
} }
@Override @Override
@ -195,7 +187,7 @@ public class ConversationListAdapter extends CursorRecyclerViewAdapter<Conversat
this.notifyDataSetChanged(); this.notifyDataSetChanged();
} }
public interface ItemClickListener { interface ItemClickListener {
void onItemClick(ConversationListItem item); void onItemClick(ConversationListItem item);
void onItemLongClick(ConversationListItem item); void onItemLongClick(ConversationListItem item);
void onSwitchToArchive(); void onSwitchToArchive();

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2015 Open Whisper Systems * Copyright (C) 2015 Open Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -67,6 +67,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo; import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.loaders.ConversationListLoader; import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.notifications.MarkReadReceiver; import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
@ -201,7 +202,7 @@ public class ConversationListFragment extends Fragment
} }
private void initializeListAdapter() { private void initializeListAdapter() {
list.setAdapter(new ConversationListAdapter(getActivity(), masterSecret, locale, null, this)); list.setAdapter(new ConversationListAdapter(getActivity(), masterSecret, GlideApp.with(this), locale, null, this));
getLoaderManager().restartLoader(0, null, this); getLoaderManager().restartLoader(0, null, this);
} }

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2011 Whisper Systems * Copyright (C) 2011 Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -37,6 +37,7 @@ import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.components.ThumbnailView; import org.thoughtcrime.securesms.components.ThumbnailView;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.DateUtils;
@ -68,6 +69,7 @@ public class ConversationListItem extends RelativeLayout
private Set<Long> selectedThreads; private Set<Long> selectedThreads;
private Recipient recipient; private Recipient recipient;
private long threadId; private long threadId;
private GlideRequests glideRequests;
private TextView subjectView; private TextView subjectView;
private FromTextView fromView; private FromTextView fromView;
private TextView dateView; private TextView dateView;
@ -98,13 +100,13 @@ public class ConversationListItem extends RelativeLayout
@Override @Override
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
this.subjectView = (TextView) findViewById(R.id.subject); this.subjectView = findViewById(R.id.subject);
this.fromView = (FromTextView) findViewById(R.id.from); this.fromView = findViewById(R.id.from);
this.dateView = (TextView) findViewById(R.id.date); this.dateView = findViewById(R.id.date);
this.deliveryStatusIndicator = (DeliveryStatusView) findViewById(R.id.delivery_status); this.deliveryStatusIndicator = findViewById(R.id.delivery_status);
this.alertView = (AlertView) findViewById(R.id.indicators_parent); this.alertView = findViewById(R.id.indicators_parent);
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image); this.contactPhotoImage = findViewById(R.id.contact_photo_image);
this.thumbnailView = (ThumbnailView) findViewById(R.id.thumbnail); this.thumbnailView = findViewById(R.id.thumbnail);
this.archivedView = ViewUtil.findById(this, R.id.archived); this.archivedView = ViewUtil.findById(this, R.id.archived);
thumbnailView.setClickable(false); thumbnailView.setClickable(false);
@ -112,12 +114,15 @@ public class ConversationListItem extends RelativeLayout
ViewUtil.setTextViewGravityStart(this.subjectView, getContext()); ViewUtil.setTextViewGravityStart(this.subjectView, getContext());
} }
@Override
public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread, public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread,
@NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode) @NonNull GlideRequests glideRequests, @NonNull Locale locale,
@NonNull Set<Long> selectedThreads, boolean batchMode)
{ {
this.selectedThreads = selectedThreads; this.selectedThreads = selectedThreads;
this.recipient = thread.getRecipient(); this.recipient = thread.getRecipient();
this.threadId = thread.getThreadId(); this.threadId = thread.getThreadId();
this.glideRequests = glideRequests;
this.read = thread.isRead(); this.read = thread.isRead();
this.distributionType = thread.getDistributionType(); this.distributionType = thread.getDistributionType();
this.lastSeen = thread.getLastSeen(); this.lastSeen = thread.getLastSeen();
@ -145,7 +150,7 @@ public class ConversationListItem extends RelativeLayout
setBatchState(batchMode); setBatchState(batchMode);
setBackground(thread); setBackground(thread);
setRippleColor(recipient); setRippleColor(recipient);
this.contactPhotoImage.setAvatar(recipient, true); this.contactPhotoImage.setAvatar(glideRequests, recipient, true);
} }
@Override @Override
@ -180,7 +185,7 @@ public class ConversationListItem extends RelativeLayout
private void setThumbnailSnippet(MasterSecret masterSecret, ThreadRecord thread) { private void setThumbnailSnippet(MasterSecret masterSecret, ThreadRecord thread) {
if (thread.getSnippetUri() != null) { if (thread.getSnippetUri() != null) {
this.thumbnailView.setVisibility(View.VISIBLE); 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(); LayoutParams subjectParams = (RelativeLayout.LayoutParams)this.subjectView.getLayoutParams();
subjectParams.addRule(RelativeLayout.LEFT_OF, R.id.thumbnail); subjectParams.addRule(RelativeLayout.LEFT_OF, R.id.thumbnail);
@ -238,7 +243,7 @@ public class ConversationListItem extends RelativeLayout
public void onModified(final Recipient recipient) { public void onModified(final Recipient recipient) {
Util.runOnMain(() -> { Util.runOnMain(() -> {
fromView.setText(recipient, read); fromView.setText(recipient, read);
contactPhotoImage.setAvatar(recipient, true); contactPhotoImage.setAvatar(glideRequests, recipient, true);
setRippleColor(recipient); setRippleColor(recipient);
}); });
} }
@ -250,7 +255,7 @@ public class ConversationListItem extends RelativeLayout
private final View deliveryStatusView; private final View deliveryStatusView;
private final View dateView; 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.thumbnailView = thumbnailView;
this.archivedView = archivedView; this.archivedView = archivedView;
this.deliveryStatusView = deliveryStatusView; this.deliveryStatusView = deliveryStatusView;

View File

@ -10,6 +10,7 @@ import android.widget.TextView;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.Locale; import java.util.Locale;
@ -39,7 +40,7 @@ public class ConversationListItemAction extends LinearLayout implements Bindable
} }
@Override @Override
public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread, @NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode) { public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread, @NonNull GlideRequests glideRequests, @NonNull Locale locale, @NonNull Set<Long> selectedThreads, boolean batchMode) {
this.description.setText(getContext().getString(R.string.ConversationListItemAction_archived_conversations_d, thread.getCount())); this.description.setText(getContext().getString(R.string.ConversationListItemAction_archived_conversations_d, thread.getCount()));
} }

View File

@ -15,6 +15,7 @@ import com.annimon.stream.Collectors;
import com.annimon.stream.Stream; import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
@ -56,7 +57,7 @@ public class ConversationTitleView extends RelativeLayout {
ViewUtil.setTextViewGravityStart(this.subtitle, getContext()); ViewUtil.setTextViewGravityStart(this.subtitle, getContext());
} }
public void setTitle(@Nullable Recipient recipient) { public void setTitle(@NonNull GlideRequests glideRequests, @Nullable Recipient recipient) {
if (recipient == null) setComposeTitle(); if (recipient == null) setComposeTitle();
else setRecipientTitle(recipient); else setRecipientTitle(recipient);
@ -69,7 +70,7 @@ public class ConversationTitleView extends RelativeLayout {
} }
if (recipient != null) { if (recipient != null) {
this.avatar.setAvatar(recipient, false); this.avatar.setAvatar(glideRequests, recipient, false);
} }
} }

View File

@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.IdentityDatabase; import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord; import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DateUtils; import org.thoughtcrime.securesms.util.DateUtils;
@ -69,6 +70,7 @@ public class ConversationUpdateItem extends LinearLayout
@Override @Override
public void bind(@NonNull MasterSecret masterSecret, public void bind(@NonNull MasterSecret masterSecret,
@NonNull MessageRecord messageRecord, @NonNull MessageRecord messageRecord,
@NonNull GlideRequests glideRequests,
@NonNull Locale locale, @NonNull Locale locale,
@NonNull Set<MessageRecord> batchSelected, @NonNull Set<MessageRecord> batchSelected,
@NonNull Recipient conversationRecipient) @NonNull Recipient conversationRecipient)

View File

@ -17,7 +17,6 @@ import android.text.Editable;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.view.ViewAnimationUtils; 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.InputAwareLayout;
import org.thoughtcrime.securesms.components.emoji.EmojiDrawer; import org.thoughtcrime.securesms.components.emoji.EmojiDrawer;
import org.thoughtcrime.securesms.components.emoji.EmojiToggle; import org.thoughtcrime.securesms.components.emoji.EmojiToggle;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil; import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.jobs.MultiDeviceProfileKeyUpdateJob; import org.thoughtcrime.securesms.jobs.MultiDeviceProfileKeyUpdateJob;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.profiles.AvatarHelper; import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints; import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints;
import org.thoughtcrime.securesms.profiles.SystemProfileUtil; import org.thoughtcrime.securesms.profiles.SystemProfileUtil;
@ -56,6 +55,7 @@ import org.whispersystems.signalservice.api.util.StreamDetails;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.security.SecureRandom;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -135,8 +135,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
if (data != null && data.getBooleanExtra("delete", false)) { if (data != null && data.getBooleanExtra("delete", false)) {
avatarBytes = null; avatarBytes = null;
avatar.setImageDrawable(ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp) avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(this, getResources().getColor(R.color.grey_400)));
.asDrawable(this, getResources().getColor(R.color.grey_400)));
} else { } else {
new Crop(inputFile).output(outputFile).asSquare().start(this); new Crop(inputFile).output(outputFile).asSquare().start(this);
} }
@ -145,13 +144,30 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
break; break;
case Crop.REQUEST_CROP: case Crop.REQUEST_CROP:
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
try { new AsyncTask<Void, Void, byte[]>() {
avatarBytes = BitmapUtil.createScaledBytes(this, Crop.getOutput(data), new ProfileMediaConstraints()); @Override
avatar.setImageDrawable(ContactPhotoFactory.getGroupContactPhoto(avatarBytes).asDrawable(this, 0)); protected byte[] doInBackground(Void... params) {
} catch (BitmapDecodingException e) { try {
Log.w(TAG, e); return BitmapUtil.createScaledBytes(CreateProfileActivity.this, Crop.getOutput(data), new ProfileMediaConstraints());
Toast.makeText(this, R.string.CreateProfileActivity_error_setting_profile_photo, Toast.LENGTH_LONG).show(); } 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; break;
} }
@ -170,8 +186,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
this.reveal = ViewUtil.findById(this, R.id.reveal); this.reveal = ViewUtil.findById(this, R.id.reveal);
this.nextIntent = getIntent().getParcelableExtra(NEXT_INTENT); this.nextIntent = getIntent().getParcelableExtra(NEXT_INTENT);
this.avatar.setImageDrawable(ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp) this.avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(this, getResources().getColor(R.color.grey_400)));
.asDrawable(this, getResources().getColor(R.color.grey_400)));
this.avatar.setOnClickListener(view -> { this.avatar.setOnClickListener(view -> {
try { try {
@ -251,12 +266,11 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
Address ourAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)); Address ourAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(this));
if (AvatarHelper.getAvatarFile(this, ourAddress).exists() && AvatarHelper.getAvatarFile(this, ourAddress).length() > 0) { if (AvatarHelper.getAvatarFile(this, ourAddress).exists() && AvatarHelper.getAvatarFile(this, ourAddress).length() > 0) {
new AsyncTask<Void, Void, Pair<byte[], ContactPhoto>>() { new AsyncTask<Void, Void, byte[]>() {
@Override @Override
protected Pair<byte[], ContactPhoto> doInBackground(Void... params) { protected byte[] doInBackground(Void... params) {
try { try {
byte[] data =Util.readFully(AvatarHelper.getInputStreamFor(CreateProfileActivity.this, ourAddress)); return 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)));
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, e); Log.w(TAG, e);
return null; return null;
@ -264,10 +278,13 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
} }
@Override @Override
protected void onPostExecute(Pair<byte[], ContactPhoto> result) { protected void onPostExecute(byte[] result) {
if (result != null) { if (result != null) {
avatarBytes = result.first; avatarBytes = result;
avatar.setImageDrawable(result.second.asDrawable(CreateProfileActivity.this, 0)); GlideApp.with(CreateProfileActivity.this)
.load(result)
.circleCrop()
.into(avatar);
} }
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@ -277,7 +294,10 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
public void onSuccess(byte[] result) { public void onSuccess(byte[] result) {
if (result != null) { if (result != null) {
avatarBytes = result; 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 { try {
accountManager.setProfileAvatar(profileKey, avatar); accountManager.setProfileAvatar(profileKey, avatar);
AvatarHelper.setAvatar(CreateProfileActivity.this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), avatarBytes); AvatarHelper.setAvatar(CreateProfileActivity.this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), avatarBytes);
TextSecurePreferences.setProfileAvatarId(CreateProfileActivity.this, new SecureRandom().nextInt());
} catch (IOException e) { } catch (IOException e) {
Log.w(TAG, e); Log.w(TAG, e);
return false; return false;

View File

@ -38,9 +38,7 @@ import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy; 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.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition; import com.bumptech.glide.request.transition.Transition;
import com.soundcloud.android.crop.Crop; 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.components.PushRecipientsPanel.RecipientsPanelChangedListener;
import org.thoughtcrime.securesms.contacts.RecipientsEditor; import org.thoughtcrime.securesms.contacts.RecipientsEditor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors; 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.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
@ -193,8 +191,7 @@ public class GroupCreateActivity extends PassphraseRequiredActionBarActivity
recipientsEditor.setHint(R.string.recipients_panel__add_members); recipientsEditor.setHint(R.string.recipients_panel__add_members);
recipientsPanel.setPanelChangeListener(this); recipientsPanel.setPanelChangeListener(this);
findViewById(R.id.contacts_button).setOnClickListener(new AddRecipientButtonListener()); findViewById(R.id.contacts_button).setOnClickListener(new AddRecipientButtonListener());
avatar.setImageDrawable(ContactPhotoFactory.getDefaultGroupPhoto() avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_group_white_24dp).asDrawable(this, ContactColors.UNKNOWN_COLOR.toConversationColor(this)));
.asDrawable(this, ContactColors.UNKNOWN_COLOR.toConversationColor(this)));
avatar.setOnClickListener(new View.OnClickListener() { avatar.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2015 Open Whisper Systems * Copyright (C) 2015 Open Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.Context;
import android.content.Intent; import android.content.Intent;
import android.support.annotation.NonNull;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; 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.Address;
import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord; import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia; import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil;
import java.util.Locale; import java.util.Locale;
public class MediaGalleryAdapter extends StickyHeaderGridAdapter { class MediaGalleryAdapter extends StickyHeaderGridAdapter {
private static final String TAG = MediaGalleryAdapter.class.getSimpleName(); private static final String TAG = MediaGalleryAdapter.class.getSimpleName();
private final Context context; private final Context context;
private final MasterSecret masterSecret; private final MasterSecret masterSecret;
private final GlideRequests glideRequests;
private final Locale locale; private final Locale locale;
private final Address address; private final Address address;
@ -50,7 +54,7 @@ public class MediaGalleryAdapter extends StickyHeaderGridAdapter {
ViewHolder(View v) { ViewHolder(View v) {
super(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) { HeaderHolder(View itemView) {
super(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) { MediaGalleryAdapter(@NonNull Context context, @NonNull MasterSecret masterSecret, @NonNull GlideRequests glideRequests,
this.context = context; BucketedThreadMedia media, Locale locale, Address address)
this.masterSecret = masterSecret; {
this.locale = locale; this.context = context;
this.media = media; this.masterSecret = masterSecret;
this.address = address; this.glideRequests = glideRequests;
this.locale = locale;
this.media = media;
this.address = address;
} }
public void setMedia(BucketedThreadMedia media) { public void setMedia(BucketedThreadMedia media) {
@ -98,7 +105,7 @@ public class MediaGalleryAdapter extends StickyHeaderGridAdapter {
Slide slide = MediaUtil.getSlideForAttachment(context, mediaRecord.getAttachment()); Slide slide = MediaUtil.getSlideForAttachment(context, mediaRecord.getAttachment());
if (slide != null) { if (slide != null) {
thumbnailView.setImageResource(masterSecret, slide, false, false); thumbnailView.setImageResource(masterSecret, glideRequests, slide, false, false);
} }
thumbnailView.setOnClickListener(new OnMediaClickListener(mediaRecord)); thumbnailView.setOnClickListener(new OnMediaClickListener(mediaRecord));

View File

@ -45,6 +45,7 @@ import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader; import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader;
import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia; import org.thoughtcrime.securesms.database.loaders.BucketedThreadMediaLoader.BucketedThreadMedia;
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader; import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme; 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.noMedia = ViewUtil.findById(view, R.id.no_images);
this.gridManager = new StickyHeaderGridLayoutManager(getResources().getInteger(R.integer.media_overview_cols)); 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.setLayoutManager(gridManager);
this.recyclerView.setHasFixedSize(true); this.recyclerView.setHasFixedSize(true);

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2014 Open Whisper Systems * Copyright (C) 2014 Open Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -17,7 +17,6 @@
package org.thoughtcrime.securesms; package org.thoughtcrime.securesms;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
@ -36,6 +35,7 @@ import android.widget.Toast;
import org.thoughtcrime.securesms.components.ZoomingImageView; import org.thoughtcrime.securesms.components.ZoomingImageView;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.VideoSlide; import org.thoughtcrime.securesms.mms.VideoSlide;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
@ -143,8 +143,8 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
} }
private void initializeViews() { private void initializeViews() {
image = (ZoomingImageView) findViewById(R.id.image); image = findViewById(R.id.image);
video = (VideoPlayer) findViewById(R.id.video_player); video = findViewById(R.id.video_player);
} }
private void initializeResources() { private void initializeResources() {
@ -177,7 +177,7 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
if (mediaType != null && mediaType.startsWith("image/")) { if (mediaType != null && mediaType.startsWith("image/")) {
image.setVisibility(View.VISIBLE); image.setVisibility(View.VISIBLE);
video.setVisibility(View.GONE); video.setVisibility(View.GONE);
image.setImageUri(masterSecret, mediaUri, mediaType); image.setImageUri(masterSecret, GlideApp.with(this), mediaUri, mediaType);
} else if (mediaType != null && mediaType.startsWith("video/")) { } else if (mediaType != null && mediaType.startsWith("video/")) {
image.setVisibility(View.GONE); image.setVisibility(View.GONE);
video.setVisibility(View.VISIBLE); video.setVisibility(View.VISIBLE);
@ -210,13 +210,10 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity im
} }
private void saveToDisk() { private void saveToDisk() {
SaveAttachmentTask.showWarningDialog(this, new DialogInterface.OnClickListener() { SaveAttachmentTask.showWarningDialog(this, (dialogInterface, i) -> {
@Override SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this, masterSecret, image);
public void onClick(DialogInterface dialogInterface, int i) { long saveDate = (date > 0) ? date : System.currentTimeMillis();
SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this, masterSecret, image); saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaUri, mediaType, saveDate, null));
long saveDate = (date > 0) ? date : System.currentTimeMillis();
saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaUri, mediaType, saveDate, null));
}
}); });
} }

View File

@ -47,6 +47,8 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.loaders.MessageDetailsLoader; import org.thoughtcrime.securesms.database.loaders.MessageDetailsLoader;
import org.thoughtcrime.securesms.database.model.MessageRecord; 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.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
@ -78,6 +80,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
public final static String ADDRESS_EXTRA = "address"; public final static String ADDRESS_EXTRA = "address";
private MasterSecret masterSecret; private MasterSecret masterSecret;
private GlideRequests glideRequests;
private long threadId; private long threadId;
private boolean isPushGroup; private boolean isPushGroup;
private ConversationItem conversationItem; private ConversationItem conversationItem;
@ -166,6 +169,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
masterSecret = getIntent().getParcelableExtra(MASTER_SECRET_EXTRA); masterSecret = getIntent().getParcelableExtra(MASTER_SECRET_EXTRA);
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1); threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
isPushGroup = getIntent().getBooleanExtra(IS_PUSH_GROUP_EXTRA, false); isPushGroup = getIntent().getBooleanExtra(IS_PUSH_GROUP_EXTRA, false);
glideRequests = GlideApp.with(this);
itemParent = (ViewGroup) header.findViewById(R.id.item_container); itemParent = (ViewGroup) header.findViewById(R.id.item_container);
recipientsList = (ListView ) findViewById(R.id.recipients_list); recipientsList = (ListView ) findViewById(R.id.recipients_list);
metadataContainer = header.findViewById(R.id.metadata_container); metadataContainer = header.findViewById(R.id.metadata_container);
@ -249,9 +253,8 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
toFromRes = R.string.message_details_header__from; toFromRes = R.string.message_details_header__from;
} }
toFrom.setText(toFromRes); toFrom.setText(toFromRes);
conversationItem.bind(masterSecret, messageRecord, dynamicLanguage.getCurrentLocale(), new HashSet<>(), recipient); conversationItem.bind(masterSecret, messageRecord, glideRequests, dynamicLanguage.getCurrentLocale(), new HashSet<>(), recipient);
recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, masterSecret, messageRecord, recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, masterSecret, glideRequests, messageRecord, recipients, isPushGroup));
recipients, isPushGroup));
} }
private void inflateMessageViewIfAbsent(MessageRecord messageRecord) { private void inflateMessageViewIfAbsent(MessageRecord messageRecord) {

View File

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms; package org.thoughtcrime.securesms;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -9,6 +10,7 @@ import android.widget.BaseAdapter;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Conversions; import org.thoughtcrime.securesms.util.Conversions;
@ -20,18 +22,21 @@ class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.
private final Context context; private final Context context;
private final MasterSecret masterSecret; private final MasterSecret masterSecret;
private final GlideRequests glideRequests;
private final MessageRecord record; private final MessageRecord record;
private final List<RecipientDeliveryStatus> members; private final List<RecipientDeliveryStatus> members;
private final boolean isPushGroup; private final boolean isPushGroup;
MessageDetailsRecipientAdapter(Context context, MasterSecret masterSecret, MessageRecord record, MessageDetailsRecipientAdapter(@NonNull Context context, @NonNull MasterSecret masterSecret,
List<RecipientDeliveryStatus> members, boolean isPushGroup) @NonNull GlideRequests glideRequests, @NonNull MessageRecord record,
@NonNull List<RecipientDeliveryStatus> members, boolean isPushGroup)
{ {
this.context = context; this.context = context;
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
this.record = record; this.glideRequests = glideRequests;
this.isPushGroup = isPushGroup; this.record = record;
this.members = members; this.isPushGroup = isPushGroup;
this.members = members;
} }
@Override @Override
@ -61,7 +66,7 @@ class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.
RecipientDeliveryStatus member = members.get(position); RecipientDeliveryStatus member = members.get(position);
((MessageRecipientListItem)convertView).set(masterSecret, record, member, isPushGroup); ((MessageRecipientListItem)convertView).set(masterSecret, glideRequests, record, member, isPushGroup);
return convertView; return convertView;
} }

View File

@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure; import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.sms.MessageSender; import org.thoughtcrime.securesms.sms.MessageSender;
@ -51,6 +52,7 @@ public class MessageRecipientListItem extends RelativeLayout
private final static String TAG = MessageRecipientListItem.class.getSimpleName(); private final static String TAG = MessageRecipientListItem.class.getSimpleName();
private RecipientDeliveryStatus member; private RecipientDeliveryStatus member;
private GlideRequests glideRequests;
private FromTextView fromView; private FromTextView fromView;
private TextView errorDescription; private TextView errorDescription;
private TextView actionDescription; private TextView actionDescription;
@ -70,25 +72,27 @@ public class MessageRecipientListItem extends RelativeLayout
@Override @Override
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
this.fromView = (FromTextView) findViewById(R.id.from); this.fromView = findViewById(R.id.from);
this.errorDescription = (TextView) findViewById(R.id.error_description); this.errorDescription = findViewById(R.id.error_description);
this.actionDescription = (TextView) findViewById(R.id.action_description); this.actionDescription = findViewById(R.id.action_description);
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image); this.contactPhotoImage = findViewById(R.id.contact_photo_image);
this.conflictButton = (Button) findViewById(R.id.conflict_button); this.conflictButton = findViewById(R.id.conflict_button);
this.resendButton = (Button) findViewById(R.id.resend_button); this.resendButton = findViewById(R.id.resend_button);
this.deliveryStatusView = (DeliveryStatusView) findViewById(R.id.delivery_status); this.deliveryStatusView = findViewById(R.id.delivery_status);
} }
public void set(final MasterSecret masterSecret, public void set(final MasterSecret masterSecret,
final GlideRequests glideRequests,
final MessageRecord record, final MessageRecord record,
final RecipientDeliveryStatus member, final RecipientDeliveryStatus member,
final boolean isPushGroup) final boolean isPushGroup)
{ {
this.member = member; this.glideRequests = glideRequests;
this.member = member;
member.getRecipient().addListener(this); member.getRecipient().addListener(this);
fromView.setText(member.getRecipient()); fromView.setText(member.getRecipient());
contactPhotoImage.setAvatar(member.getRecipient(), false); contactPhotoImage.setAvatar(glideRequests, member.getRecipient(), false);
setIssueIndicators(masterSecret, record, isPushGroup); setIssueIndicators(masterSecret, record, isPushGroup);
} }
@ -177,7 +181,7 @@ public class MessageRecipientListItem extends RelativeLayout
public void onModified(final Recipient recipient) { public void onModified(final Recipient recipient) {
Util.runOnMain(() -> { Util.runOnMain(() -> {
fromView.setText(recipient); 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 MessageRecord record;
private final NetworkFailure failure; private final NetworkFailure failure;
public ResendAsyncTask(MasterSecret masterSecret, MessageRecord record, NetworkFailure failure) { ResendAsyncTask(MasterSecret masterSecret, MessageRecord record, NetworkFailure failure) {
this.context = getContext().getApplicationContext(); this.context = getContext().getApplicationContext();
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
this.record = record; this.record = record;

View File

@ -13,7 +13,6 @@ import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.Settings; import android.provider.Settings;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; 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.Preference;
import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceCategory;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
@ -35,11 +33,11 @@ import android.view.WindowManager;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.color.MaterialColors; import org.thoughtcrime.securesms.color.MaterialColors;
import org.thoughtcrime.securesms.components.ThreadPhotoRailView; 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.IdentityKeyParcelable;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.Address; 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.database.loaders.ThreadMediaLoader;
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob; import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob; 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.AdvancedRingtonePreference;
import org.thoughtcrime.securesms.preferences.widgets.ColorPickerPreference; import org.thoughtcrime.securesms.preferences.widgets.ColorPickerPreference;
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicLanguage;
@ -88,6 +88,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
private ImageView avatar; private ImageView avatar;
private MasterSecret masterSecret; private MasterSecret masterSecret;
private GlideRequests glideRequests;
private Address address; private Address address;
private TextView threadPhotoRailLabel; private TextView threadPhotoRailLabel;
private ThreadPhotoRailView threadPhotoRailView; private ThreadPhotoRailView threadPhotoRailView;
@ -103,8 +104,9 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override @Override
public void onCreate(Bundle instanceState, @NonNull MasterSecret masterSecret) { public void onCreate(Bundle instanceState, @NonNull MasterSecret masterSecret) {
setContentView(R.layout.recipient_preference_activity); setContentView(R.layout.recipient_preference_activity);
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
this.address = getIntent().getParcelableExtra(ADDRESS_EXTRA); this.glideRequests = GlideApp.with(this);
this.address = getIntent().getParcelableExtra(ADDRESS_EXTRA);
Recipient recipient = Recipient.from(this, address, true); Recipient recipient = Recipient.from(this, address, true);
@ -208,39 +210,17 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
} }
private void setHeader(@NonNull Recipient recipient) { private void setHeader(@NonNull Recipient recipient) {
new AsyncTask<Void, Void, ContactPhoto>() { glideRequests.load(recipient.getContactPhoto())
@Override .fallback(recipient.getFallbackContactPhoto().asCallCard(this))
protected @NonNull ContactPhoto doInBackground(Void... params) { .diskCacheStrategy(DiskCacheStrategy.ALL)
DisplayMetrics metrics = new DisplayMetrics(); .into(this.avatar);
WindowManager windowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
Uri contentUri = ContactsContract.Contacts.lookupContact(getContentResolver(), recipient.getContactUri());
windowManager.getDefaultDisplay().getMetrics(metrics);
if (recipient.isGroupRecipient()) { if (recipient.getContactPhoto() == null) this.avatar.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
Optional<GroupDatabase.GroupRecord> groupRecord = DatabaseFactory.getGroupDatabase(RecipientPreferenceActivity.this).getGroup(recipient.getAddress().toGroupString()); else this.avatar.setScaleType(ImageView.ScaleType.CENTER_CROP);
if (groupRecord.isPresent() && groupRecord.get().getAvatar() != null) { this.avatar.setBackgroundColor(recipient.getColor().toActionBarColor(this));
return ContactPhotoFactory.getGroupContactPhoto(groupRecord.get().getAvatar()); this.toolbarLayout.setTitle(recipient.toShortString());
} else { this.toolbarLayout.setContentScrimColor(recipient.getColor().toActionBarColor(this));
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);
} }
@Override @Override
@ -263,7 +243,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
this.threadPhotoRailView.setVisibility(View.GONE); this.threadPhotoRailView.setVisibility(View.GONE);
} }
this.threadPhotoRailView.setCursor(data, masterSecret); this.threadPhotoRailView.setCursor(masterSecret, glideRequests, data);
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelable(ADDRESS_EXTRA, address); bundle.putParcelable(ADDRESS_EXTRA, address);
@ -272,7 +252,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override @Override
public void onLoaderReset(Loader<Cursor> loader) { public void onLoaderReset(Loader<Cursor> loader) {
this.threadPhotoRailView.setCursor(null, masterSecret); this.threadPhotoRailView.setCursor(masterSecret, glideRequests, null);
} }
public static class RecipientPreferenceFragment public static class RecipientPreferenceFragment
@ -325,9 +305,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
} }
private void initializeRecipients() { private void initializeRecipients() {
this.recipient = Recipient.from(getActivity(), this.recipient = Recipient.from(getActivity(), getArguments().getParcelable(ADDRESS_EXTRA), true);
(Address)getArguments().getParcelable(ADDRESS_EXTRA),
true);
this.recipient.addListener(this); this.recipient.addListener(this);
@ -335,7 +313,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
recipient.removeListener(RecipientPreferenceFragment.this); 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); onModified(recipient);
} }
}; };
@ -508,12 +486,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
} }
private void handleMute() { private void handleMute() {
MuteDialog.show(getActivity(), new MuteDialog.MuteSelectionListener() { MuteDialog.show(getActivity(), until -> setMuted(recipient, until));
@Override
public void onMuted(long until) {
setMuted(recipient, until);
}
});
setSummaries(recipient); setSummaries(recipient);
} }

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2014 Open Whisper Systems * Copyright (C) 2014 Open Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.loaders.ConversationListLoader; import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
/** /**
@ -78,7 +79,7 @@ public class ShareFragment extends ListFragment implements LoaderManager.LoaderC
} }
private void initializeListAdapter() { private void initializeListAdapter() {
this.setListAdapter(new ShareListAdapter(getActivity(), null, masterSecret)); this.setListAdapter(new ShareListAdapter(getActivity(), masterSecret, GlideApp.with(this), null));
getListView().setRecyclerListener((ShareListAdapter) getListAdapter()); getListView().setRecyclerListener((ShareListAdapter) getListAdapter());
getLoaderManager().restartLoader(0, null, this); getLoaderManager().restartLoader(0, null, this);
} }

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2014 Open Whisper Systems * Copyright (C) 2014 Open Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.widget.CursorAdapter; import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AbsListView; 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.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.crypto.MasterCipher; import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.crypto.MasterSecret;
/** /**
* A CursorAdapter for building a list of open conversations * A CursorAdapter for building a list of open conversations
* *
* @author Jake McGinty * @author Jake McGinty
*/ */
public class ShareListAdapter extends CursorAdapter implements AbsListView.RecyclerListener { class ShareListAdapter extends CursorAdapter implements AbsListView.RecyclerListener {
private final ThreadDatabase threadDatabase; private final ThreadDatabase threadDatabase;
private final GlideRequests glideRequests;
private final MasterCipher masterCipher; private final MasterCipher masterCipher;
private final Context context;
private final LayoutInflater inflater; 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); super(context, cursor, 0);
if (masterSecret != null) this.masterCipher = new MasterCipher(masterSecret); if (masterSecret != null) this.masterCipher = new MasterCipher(masterSecret);
else this.masterCipher = null; else this.masterCipher = null;
this.context = context; this.glideRequests = glideRequests;
this.threadDatabase = DatabaseFactory.getThreadDatabase(context); this.threadDatabase = DatabaseFactory.getThreadDatabase(context);
this.inflater = LayoutInflater.from(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); ThreadDatabase.Reader reader = threadDatabase.readerFor(cursor, masterCipher);
ThreadRecord record = reader.getCurrent(); ThreadRecord record = reader.getCurrent();
((ShareListItem)view).set(record); ((ShareListItem)view).set(glideRequests, record);
} }
} }

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2014 Open Whisper Systems * Copyright (C) 2014 Open Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.os.Handler; import android.support.annotation.NonNull;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.FromTextView; import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
@ -39,10 +40,11 @@ public class ShareListItem extends RelativeLayout
{ {
private final static String TAG = ShareListItem.class.getSimpleName(); private final static String TAG = ShareListItem.class.getSimpleName();
private Context context; private Context context;
private Recipient recipient; private GlideRequests glideRequests;
private long threadId; private Recipient recipient;
private FromTextView fromView; private long threadId;
private FromTextView fromView;
private AvatarImageView contactPhotoImage; private AvatarImageView contactPhotoImage;
@ -61,11 +63,12 @@ public class ShareListItem extends RelativeLayout
@Override @Override
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
this.fromView = (FromTextView) findViewById(R.id.from); this.fromView = findViewById(R.id.from);
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image); 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.recipient = thread.getRecipient();
this.threadId = thread.getThreadId(); this.threadId = thread.getThreadId();
this.distributionType = thread.getDistributionType(); this.distributionType = thread.getDistributionType();
@ -74,7 +77,7 @@ public class ShareListItem extends RelativeLayout
this.fromView.setText(recipient); this.fromView.setText(recipient);
setBackground(); setBackground();
this.contactPhotoImage.setAvatar(this.recipient, false); this.contactPhotoImage.setAvatar(glideRequests, this.recipient, false);
} }
public void unbind() { public void unbind() {
@ -106,7 +109,7 @@ public class ShareListItem extends RelativeLayout
public void onModified(final Recipient recipient) { public void onModified(final Recipient recipient) {
Util.runOnMain(() -> { Util.runOnMain(() -> {
fromView.setText(recipient); fromView.setText(recipient);
contactPhotoImage.setAvatar(recipient, false); contactPhotoImage.setAvatar(glideRequests, recipient, false);
}); });
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,9 +18,6 @@
package org.thoughtcrime.securesms.components.webrtc; package org.thoughtcrime.securesms.components.webrtc;
import android.content.Context; 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.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton; import android.support.design.widget.FloatingActionButton;
@ -30,20 +27,19 @@ import android.text.Spanned;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button; import android.widget.Button;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.service.WebRtcCallService; import org.thoughtcrime.securesms.service.WebRtcCallService;
@ -285,24 +281,11 @@ public class WebRtcCallScreen extends FrameLayout implements RecipientModifiedLi
this.recipient = recipient; this.recipient = recipient;
this.recipient.addListener(this); this.recipient.addListener(this);
final Context context = getContext(); GlideApp.with(getContext().getApplicationContext())
.load(recipient.getContactPhoto())
new AsyncTask<Void, Void, ContactPhoto>() { .fallback(recipient.getFallbackContactPhoto().asCallCard(getContext()))
@Override .diskCacheStrategy(DiskCacheStrategy.ALL)
protected ContactPhoto doInBackground(Void... params) { .into(this.photo);
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);
this.name.setText(recipient.getName()); this.name.setText(recipient.getName());

View File

@ -29,16 +29,17 @@ import android.text.TextUtils;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller.FastScrollAdapter; 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.HeaderViewHolder;
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter.ViewHolder; import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter.ViewHolder;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter; 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 org.thoughtcrime.securesms.util.Util;
import java.util.HashMap; import java.util.HashMap;
@ -62,6 +63,7 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
private final LayoutInflater li; private final LayoutInflater li;
private final TypedArray drawables; private final TypedArray drawables;
private final ItemClickListener clickListener; private final ItemClickListener clickListener;
private final GlideRequests glideRequests;
private final HashMap<Long, String> selectedContacts = new HashMap<>(); private final HashMap<Long, String> selectedContacts = new HashMap<>();
@ -70,11 +72,8 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
@Nullable final ItemClickListener clickListener) @Nullable final ItemClickListener clickListener)
{ {
super(itemView); super(itemView);
itemView.setOnClickListener(new OnClickListener() { itemView.setOnClickListener(v -> {
@Override if (clickListener != null) clickListener.onItemClick(getView());
public void onClick(View v) {
if (clickListener != null) clickListener.onItemClick(getView());
}
}); });
} }
@ -90,14 +89,16 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
} }
public ContactSelectionListAdapter(@NonNull Context context, public ContactSelectionListAdapter(@NonNull Context context,
@NonNull GlideRequests glideRequests,
@Nullable Cursor cursor, @Nullable Cursor cursor,
@Nullable ItemClickListener clickListener, @Nullable ItemClickListener clickListener,
boolean multiSelect) boolean multiSelect)
{ {
super(context, cursor); super(context, cursor);
this.li = LayoutInflater.from(context); this.li = LayoutInflater.from(context);
this.drawables = context.obtainStyledAttributes(STYLE_ATTRIBUTES); this.glideRequests = glideRequests;
this.multiSelect = multiSelect; this.drawables = context.obtainStyledAttributes(STYLE_ATTRIBUTES);
this.multiSelect = multiSelect;
this.clickListener = clickListener; this.clickListener = clickListener;
} }
@ -127,8 +128,8 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
int color = (contactType == ContactsDatabase.PUSH_TYPE) ? drawables.getColor(0, 0xa0000000) : int color = (contactType == ContactsDatabase.PUSH_TYPE) ? drawables.getColor(0, 0xa0000000) :
drawables.getColor(1, 0xff000000); drawables.getColor(1, 0xff000000);
viewHolder.getView().unbind(); viewHolder.getView().unbind(glideRequests);
viewHolder.getView().set(id, contactType, name, number, labelText, color, multiSelect); viewHolder.getView().set(glideRequests, id, contactType, name, number, labelText, color, multiSelect);
viewHolder.getView().setChecked(selectedContacts.containsKey(id)); viewHolder.getView().setChecked(selectedContacts.containsKey(id));
} }
@ -142,6 +143,11 @@ public class ContactSelectionListAdapter extends CursorRecyclerViewAdapter<ViewH
((TextView)viewHolder.itemView).setText(getSpannedHeaderString(position)); ((TextView)viewHolder.itemView).setText(getSpannedHeaderString(position));
} }
@Override
public void onItemViewRecycled(ViewHolder holder) {
holder.getView().unbind(glideRequests);
}
@Override @Override
public CharSequence getBubbleText(int position) { public CharSequence getBubbleText(int position) {
return getHeaderString(position); return getHeaderString(position);

View File

@ -1,9 +1,9 @@
package org.thoughtcrime.securesms.contacts; package org.thoughtcrime.securesms.contacts;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.LinearLayout; import android.widget.LinearLayout;
@ -12,6 +12,8 @@ import android.widget.TextView;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.mms.GlideRequest;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
@ -27,9 +29,10 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
private TextView labelView; private TextView labelView;
private CheckBox checkBox; private CheckBox checkBox;
private long id; private long id;
private String number; private String number;
private Recipient recipient; private Recipient recipient;
private GlideRequests glideRequests;
public ContactSelectionListItem(Context context) { public ContactSelectionListItem(Context context) {
super(context); super(context);
@ -42,22 +45,23 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
@Override @Override
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image); this.contactPhotoImage = findViewById(R.id.contact_photo_image);
this.numberView = (TextView) findViewById(R.id.number); this.numberView = findViewById(R.id.number);
this.labelView = (TextView) findViewById(R.id.label); this.labelView = findViewById(R.id.label);
this.nameView = (TextView) findViewById(R.id.name); this.nameView = findViewById(R.id.name);
this.checkBox = (CheckBox) findViewById(R.id.check_box); this.checkBox = findViewById(R.id.check_box);
ViewUtil.setTextViewGravityStart(this.nameView, getContext()); ViewUtil.setTextViewGravityStart(this.nameView, getContext());
} }
public void set(long id, int type, String name, String number, String label, int color, boolean multiSelect) { public void set(@NonNull GlideRequests glideRequests, long id, int type, String name, String number, String label, int color, boolean multiSelect) {
this.id = id; this.glideRequests = glideRequests;
this.number = number; this.id = id;
this.number = number;
if (type == ContactsDatabase.NEW_TYPE) { if (type == ContactsDatabase.NEW_TYPE) {
this.recipient = null; this.recipient = null;
this.contactPhotoImage.setAvatar(Recipient.from(getContext(), Address.UNKNOWN, true), false); this.contactPhotoImage.setAvatar(glideRequests, Recipient.from(getContext(), Address.UNKNOWN, true), false);
} else if (!TextUtils.isEmpty(number)) { } else if (!TextUtils.isEmpty(number)) {
Address address = Address.fromExternal(getContext(), number); Address address = Address.fromExternal(getContext(), number);
this.recipient = Recipient.from(getContext(), address, true); this.recipient = Recipient.from(getContext(), address, true);
@ -70,7 +74,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
this.nameView.setTextColor(color); this.nameView.setTextColor(color);
this.numberView.setTextColor(color); this.numberView.setTextColor(color);
this.contactPhotoImage.setAvatar(recipient, false); this.contactPhotoImage.setAvatar(glideRequests, recipient, false);
setText(type, name, number, label); setText(type, name, number, label);
@ -82,11 +86,13 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
this.checkBox.setChecked(selected); this.checkBox.setChecked(selected);
} }
public void unbind() { public void unbind(GlideRequests glideRequests) {
if (recipient != null) { if (recipient != null) {
recipient.removeListener(this); recipient.removeListener(this);
recipient = null; recipient = null;
} }
contactPhotoImage.clear(glideRequests);
} }
private void setText(int type, String name, String number, String label) { private void setText(int type, String name, String number, String label) {
@ -120,7 +126,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
public void onModified(final Recipient recipient) { public void onModified(final Recipient recipient) {
if (this.recipient == recipient) { if (this.recipient == recipient) {
Util.runOnMain(() -> { Util.runOnMain(() -> {
contactPhotoImage.setAvatar(recipient, false); contactPhotoImage.setAvatar(glideRequests, recipient, false);
nameView.setText(recipient.toShortString()); nameView.setText(recipient.toShortString());
}); });
} }

View File

@ -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;
}
}

View File

@ -1,14 +1,16 @@
package org.thoughtcrime.securesms.contacts.avatars; package org.thoughtcrime.securesms.contacts.avatars;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable;
public interface ContactPhoto {
public Drawable asDrawable(Context context, int color); import com.bumptech.glide.load.Key;
public Drawable asDrawable(Context context, int color, boolean inverted);
public Drawable asCallCard(Context context); import java.io.IOException;
public boolean isGenerated(); import java.io.InputStream;
public boolean isResource();
public interface ContactPhoto extends Key {
InputStream openInputStream(Context context) throws IOException;
} }

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -11,11 +11,15 @@ import com.amulyakhare.textdrawable.TextDrawable;
import org.thoughtcrime.securesms.R; 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; private final String name;
GeneratedContactPhoto(@NonNull String name) { public GeneratedContactPhoto(@NonNull String name) {
this.name = name; this.name = name;
} }
@ -38,7 +42,7 @@ public class GeneratedContactPhoto implements ContactPhoto {
} }
private String getCharacter(String name) { 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()) { if (cleanedName.isEmpty()) {
return "#"; return "#";
@ -52,14 +56,4 @@ public class GeneratedContactPhoto implements ContactPhoto {
return AppCompatResources.getDrawable(context, R.drawable.ic_person_large); return AppCompatResources.getDrawable(context, R.drawable.ic_person_large);
} }
@Override
public boolean isGenerated() {
return true;
}
@Override
public boolean isResource() {
return false;
}
} }

View File

@ -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<GroupDatabase.GroupRecord> 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;
}
}

View File

@ -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();
}
}

View File

@ -12,16 +12,16 @@ import android.widget.ImageView;
import com.amulyakhare.textdrawable.TextDrawable; import com.amulyakhare.textdrawable.TextDrawable;
import com.makeramen.roundedimageview.RoundedDrawable; import com.makeramen.roundedimageview.RoundedDrawable;
public class ResourceContactPhoto implements ContactPhoto { public class ResourceContactPhoto implements FallbackContactPhoto {
private final int resourceId; private final int resourceId;
private final int callCardResourceId; private final int callCardResourceId;
ResourceContactPhoto(@DrawableRes int resourceId) { public ResourceContactPhoto(@DrawableRes int resourceId) {
this(resourceId, resourceId); this(resourceId, resourceId);
} }
ResourceContactPhoto(@DrawableRes int resourceId, @DrawableRes int callCardResourceId) { public ResourceContactPhoto(@DrawableRes int resourceId, @DrawableRes int callCardResourceId) {
this.resourceId = resourceId; this.resourceId = resourceId;
this.callCardResourceId = callCardResourceId; this.callCardResourceId = callCardResourceId;
} }
@ -50,16 +50,6 @@ public class ResourceContactPhoto implements ContactPhoto {
return AppCompatResources.getDrawable(context, callCardResourceId); return AppCompatResources.getDrawable(context, callCardResourceId);
} }
@Override
public boolean isGenerated() {
return false;
}
@Override
public boolean isResource() {
return true;
}
private static class ExpandingLayerDrawable extends LayerDrawable { private static class ExpandingLayerDrawable extends LayerDrawable {
public ExpandingLayerDrawable(Drawable[] layers) { public ExpandingLayerDrawable(Drawable[] layers) {
super(layers); super(layers);

View File

@ -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;
}
}

View File

@ -8,9 +8,9 @@ import com.makeramen.roundedimageview.RoundedDrawable;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
public class TransparentContactPhoto implements ContactPhoto { public class TransparentContactPhoto implements FallbackContactPhoto {
TransparentContactPhoto() {} public TransparentContactPhoto() {}
@Override @Override
public Drawable asDrawable(Context context, int color) { 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); return ContextCompat.getDrawable(context, R.drawable.ic_contact_picture_large);
} }
@Override
public boolean isGenerated() {
return false;
}
@Override
public boolean isResource() {
return false;
}
} }

View File

@ -13,7 +13,6 @@ import android.util.Log;
import com.annimon.stream.Stream; import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.libsignal.util.Pair; import org.whispersystems.libsignal.util.Pair;
@ -467,7 +466,7 @@ public class RecipientDatabase extends Database {
} }
public Optional<Integer> getDefaultSubscriptionId() { public Optional<Integer> getDefaultSubscriptionId() {
return defaultSubscriptionId != -1 ? Optional.of(defaultSubscriptionId) : Optional.<Integer>absent(); return defaultSubscriptionId != -1 ? Optional.of(defaultSubscriptionId) : Optional.absent();
} }
public int getExpireMessages() { public int getExpireMessages() {

View File

@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.giph.model.GiphyImage; import org.thoughtcrime.securesms.giph.model.GiphyImage;
import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
@ -33,12 +34,14 @@ import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
public class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHolder> { class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHolder> {
private static final String TAG = GiphyAdapter.class.getSimpleName(); private static final String TAG = GiphyAdapter.class.getSimpleName();
private final Context context;
private final GlideRequests glideRequests;
private List<GiphyImage> images; private List<GiphyImage> images;
private Context context;
private OnItemClickListener listener; private OnItemClickListener listener;
class GiphyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, RequestListener<Drawable> { class GiphyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, RequestListener<Drawable> {
@ -73,7 +76,6 @@ public class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHol
} }
return false; return false;
} }
@Override @Override
@ -108,9 +110,10 @@ public class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHol
} }
} }
GiphyAdapter(Context context, List<GiphyImage> images) { GiphyAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests, @NonNull List<GiphyImage> images) {
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
this.images = images; this.glideRequests = glideRequests;
this.images = images;
} }
public void setImages(@NonNull List<GiphyImage> images) { public void setImages(@NonNull List<GiphyImage> images) {
@ -145,21 +148,19 @@ public class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHol
.diskCacheStrategy(DiskCacheStrategy.ALL); .diskCacheStrategy(DiskCacheStrategy.ALL);
if (Util.isLowMemory(context)) { if (Util.isLowMemory(context)) {
GlideApp.with(context) glideRequests.load(image.getStillUrl())
.load(image.getStillUrl()) .placeholder(new ColorDrawable(Util.getRandomElement(MaterialColor.values()).toConversationColor(context)))
.placeholder(new ColorDrawable(Util.getRandomElement(MaterialColor.values()).toConversationColor(context))) .diskCacheStrategy(DiskCacheStrategy.ALL)
.diskCacheStrategy(DiskCacheStrategy.ALL) .into(holder.thumbnail);
.into(holder.thumbnail);
holder.setModelReady(); holder.setModelReady();
} else { } else {
GlideApp.with(context) glideRequests.load(image.getGifUrl())
.load(image.getGifUrl()) .thumbnail(thumbnailRequest)
.thumbnail(thumbnailRequest) .placeholder(new ColorDrawable(Util.getRandomElement(MaterialColor.values()).toConversationColor(context)))
.placeholder(new ColorDrawable(Util.getRandomElement(MaterialColor.values()).toConversationColor(context))) .diskCacheStrategy(DiskCacheStrategy.ALL)
.diskCacheStrategy(DiskCacheStrategy.ALL) .listener(holder)
.listener(holder) .into(holder.thumbnail);
.into(holder.thumbnail);
} }
} }

View File

@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.giph.model.GiphyImage; import org.thoughtcrime.securesms.giph.model.GiphyImage;
import org.thoughtcrime.securesms.giph.net.GiphyLoader; import org.thoughtcrime.securesms.giph.net.GiphyLoader;
import org.thoughtcrime.securesms.giph.util.InfiniteScrollListener; import org.thoughtcrime.securesms.giph.util.InfiniteScrollListener;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.LinkedList; import java.util.LinkedList;
@ -52,7 +53,7 @@ public abstract class GiphyFragment extends Fragment implements LoaderManager.Lo
public void onActivityCreated(Bundle bundle) { public void onActivityCreated(Bundle bundle) {
super.onActivityCreated(bundle); super.onActivityCreated(bundle);
this.giphyAdapter = new GiphyAdapter(getActivity(), new LinkedList<GiphyImage>()); this.giphyAdapter = new GiphyAdapter(getActivity(), GlideApp.with(this), new LinkedList<>());
this.giphyAdapter.setListener(this); this.giphyAdapter.setListener(this);
this.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); this.recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

View File

@ -1,4 +1,4 @@
package org.thoughtcrime.securesms.profiles; package org.thoughtcrime.securesms.glide;
import android.content.Context; import android.content.Context;
@ -8,27 +8,27 @@ import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.data.DataFetcher; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
class AvatarPhotoUriFetcher implements DataFetcher<InputStream> { class ContactPhotoFetcher implements DataFetcher<InputStream> {
private final Context context; private final Context context;
private final Address address; private final ContactPhoto contactPhoto;
private InputStream inputStream; private InputStream inputStream;
AvatarPhotoUriFetcher(@NonNull Context context, @NonNull Address address) { ContactPhotoFetcher(@NonNull Context context, @NonNull ContactPhoto contactPhoto) {
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
this.address = address; this.contactPhoto = contactPhoto;
} }
@Override @Override
public void loadData(Priority priority, DataCallback<? super InputStream> callback) { public void loadData(Priority priority, DataCallback<? super InputStream> callback) {
try { try {
inputStream = AvatarHelper.getInputStreamFor(context, address); inputStream = contactPhoto.openInputStream(context);
callback.onDataReady(inputStream); callback.onDataReady(inputStream);
} catch (IOException e) { } catch (IOException e) {
callback.onLoadFailed(e); callback.onLoadFailed(e);

View File

@ -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<ContactPhoto, InputStream> {
private final Context context;
private ContactPhotoLoader(Context context) {
this.context = context;
}
@Nullable
@Override
public LoadData<InputStream> 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<ContactPhoto, InputStream> {
private final Context context;
public Factory(Context context) {
this.context = context.getApplicationContext();
}
@Override
public ModelLoader<ContactPhoto, InputStream> build(MultiModelLoaderFactory multiFactory) {
return new ContactPhotoLoader(context);
}
@Override
public void teardown() {}
}
}

View File

@ -5,8 +5,7 @@ import android.content.Context;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.dependencies.InjectableType;
@ -85,8 +84,8 @@ public class RetrieveProfileAvatarJob extends ContextJob implements InjectableTy
database.setProfileAvatar(recipient, profileAvatar); database.setProfileAvatar(recipient, profileAvatar);
if (recipient.resolve().getContactPhoto().isGenerated()) { if (recipient.resolve().getContactPhoto() == null) {
recipient.setContactPhoto(ContactPhotoFactory.getSignalAvatarContactPhoto(context, recipient.getAddress(), recipient.getName(), context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size))); recipient.setContactPhoto(new ProfileContactPhoto(recipient.getAddress(), profileAvatar));
} }
} }

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2011 Whisper Systems * Copyright (C) 2011 Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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 (attachmentViewStub.resolved()) {
if (animate) { if (animate) {
ViewUtil.fadeOut(attachmentViewStub.get(), 200).addListener(new Listener<Boolean>() { ViewUtil.fadeOut(attachmentViewStub.get(), 200).addListener(new Listener<Boolean>() {
@Override @Override
public void onSuccess(Boolean result) { public void onSuccess(Boolean result) {
thumbnail.clear(); thumbnail.clear(glideRequests);
attachmentViewStub.get().setVisibility(View.GONE); attachmentViewStub.get().setVisibility(View.GONE);
attachmentListener.onAttachmentChanged(); attachmentListener.onAttachmentChanged();
} }
@ -125,7 +125,7 @@ public class AttachmentManager {
} }
}); });
} else { } else {
thumbnail.clear(); thumbnail.clear(glideRequests);
attachmentViewStub.get().setVisibility(View.GONE); attachmentViewStub.get().setVisibility(View.GONE);
attachmentListener.onAttachmentChanged(); attachmentListener.onAttachmentChanged();
} }
@ -200,6 +200,7 @@ public class AttachmentManager {
} }
public void setMedia(@NonNull final MasterSecret masterSecret, public void setMedia(@NonNull final MasterSecret masterSecret,
@NonNull final GlideRequests glideRequests,
@NonNull final Uri uri, @NonNull final Uri uri,
@NonNull final MediaType mediaType, @NonNull final MediaType mediaType,
@NonNull final MediaConstraints constraints) @NonNull final MediaConstraints constraints)
@ -209,7 +210,7 @@ public class AttachmentManager {
new AsyncTask<Void, Void, Slide>() { new AsyncTask<Void, Void, Slide>() {
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
thumbnail.clear(); thumbnail.clear(glideRequests);
thumbnail.showProgressSpinner(); thumbnail.showProgressSpinner();
attachmentViewStub.get().setVisibility(View.VISIBLE); attachmentViewStub.get().setVisibility(View.VISIBLE);
} }
@ -254,7 +255,7 @@ public class AttachmentManager {
documentView.setDocument((DocumentSlide) slide, false); documentView.setDocument((DocumentSlide) slide, false);
removableMediaView.display(documentView, false); removableMediaView.display(documentView, false);
} else { } else {
thumbnail.setImageResource(masterSecret, slide, false, true); thumbnail.setImageResource(masterSecret, glideRequests, slide, false, true);
removableMediaView.display(thumbnail, mediaType == MediaType.IMAGE); removableMediaView.display(thumbnail, mediaType == MediaType.IMAGE);
} }
@ -433,7 +434,7 @@ public class AttachmentManager {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
cleanup(); cleanup();
clear(true); clear(GlideApp.with(context.getApplicationContext()), true);
} }
} }

View File

@ -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<ContactPhotoUri, InputStream> {
private final Context context;
private ContactPhotoUriLoader(Context context) {
this.context = context;
}
@Nullable
@Override
public LoadData<InputStream> 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<ContactPhotoUri, InputStream> {
private final Context context;
Factory(Context context) {
this.context = context.getApplicationContext();
}
@Override
public ModelLoader<ContactPhotoUri, InputStream> 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();
}
}
}

View File

@ -12,12 +12,11 @@ import com.bumptech.glide.load.engine.cache.DiskCacheAdapter;
import com.bumptech.glide.load.model.GlideUrl; import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.AppGlideModule; 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.glide.OkHttpUrlLoader;
import org.thoughtcrime.securesms.mms.AttachmentStreamUriLoader.AttachmentModel; 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.mms.DecryptableStreamUriLoader.DecryptableUri;
import org.thoughtcrime.securesms.profiles.AvatarPhotoUriLoader;
import org.thoughtcrime.securesms.profiles.AvatarPhotoUriLoader.AvatarPhotoUri;
import java.io.InputStream; import java.io.InputStream;
@ -37,11 +36,10 @@ public class SignalGlideModule extends AppGlideModule {
@Override @Override
public void registerComponents(Context context, Glide glide, Registry registry) { 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(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.append(AttachmentModel.class, InputStream.class, new AttachmentStreamUriLoader.Factory());
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.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 { public static class NoopDiskCacheFactory implements DiskCache.Factory {

View File

@ -13,12 +13,15 @@ import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Action; import android.support.v4.app.NotificationCompat.Action;
import android.support.v4.app.RemoteInput; import android.support.v4.app.RemoteInput;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.util.Log;
import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors; 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.crypto.MasterSecret;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideApp;
@ -64,13 +67,29 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
addPerson(recipient.getContactUri().toString()); addPerson(recipient.getContactUri().toString());
} }
setLargeIcon(recipient.getContactPhoto() ContactPhoto contactPhoto = recipient.getContactPhoto();
.asDrawable(context, recipient.getColor() FallbackContactPhoto fallbackContactPhoto = recipient.getFallbackContactPhoto();
.toConversationColor(context)));
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 { } else {
setContentTitle(context.getString(R.string.SingleRecipientNotificationBuilder_signal)); setContentTitle(context.getString(R.string.SingleRecipientNotificationBuilder_signal));
setLargeIcon(ContactPhotoFactory.getDefaultContactPhoto("Unknown") setLargeIcon(new GeneratedContactPhoto("Unknown").asDrawable(context, ContactColors.UNKNOWN_COLOR.toConversationColor(context)));
.asDrawable(context, ContactColors.UNKNOWN_COLOR.toConversationColor(context)));
} }
} }
@ -225,7 +244,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
Uri uri = slideDeck.getThumbnailSlide().getThumbnailUri(); Uri uri = slideDeck.getThumbnailSlide().getThumbnailUri();
return GlideApp.with(context) return GlideApp.with(context.getApplicationContext())
.asBitmap() .asBitmap()
.load(new DecryptableStreamUriLoader.DecryptableUri(masterSecret, uri)) .load(new DecryptableStreamUriLoader.DecryptableUri(masterSecret, uri))
.diskCacheStrategy(DiskCacheStrategy.NONE) .diskCacheStrategy(DiskCacheStrategy.NONE)

View File

@ -1,12 +1,14 @@
package org.thoughtcrime.securesms.preferences; package org.thoughtcrime.securesms.preferences;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener; import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
@ -15,6 +17,7 @@ public class BlockedContactListItem extends RelativeLayout implements RecipientM
private AvatarImageView contactPhotoImage; private AvatarImageView contactPhotoImage;
private TextView nameView; private TextView nameView;
private GlideRequests glideRequests;
private Recipient recipient; private Recipient recipient;
public BlockedContactListItem(Context context) { public BlockedContactListItem(Context context) {
@ -32,12 +35,13 @@ public class BlockedContactListItem extends RelativeLayout implements RecipientM
@Override @Override
public void onFinishInflate() { public void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
this.contactPhotoImage = (AvatarImageView)findViewById(R.id.contact_photo_image); this.contactPhotoImage = findViewById(R.id.contact_photo_image);
this.nameView = (TextView) findViewById(R.id.name); this.nameView = findViewById(R.id.name);
} }
public void set(Recipient recipients) { public void set(@NonNull GlideRequests glideRequests, @NonNull Recipient recipients) {
this.recipient = recipients; this.glideRequests = glideRequests;
this.recipient = recipients;
onModified(recipients); onModified(recipients);
recipients.addListener(this); recipients.addListener(this);
@ -48,12 +52,9 @@ public class BlockedContactListItem extends RelativeLayout implements RecipientM
final AvatarImageView contactPhotoImage = this.contactPhotoImage; final AvatarImageView contactPhotoImage = this.contactPhotoImage;
final TextView nameView = this.nameView; final TextView nameView = this.nameView;
Util.runOnMain(new Runnable() { Util.runOnMain(() -> {
@Override contactPhotoImage.setAvatar(glideRequests, recipients, false);
public void run() { nameView.setText(recipients.toShortString());
contactPhotoImage.setAvatar(recipients, false);
nameView.setText(recipients.toShortString());
}
}); });
} }

View File

@ -2,26 +2,23 @@ package org.thoughtcrime.securesms.preferences.widgets;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi; import android.support.annotation.RequiresApi;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder; import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.R; 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.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.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
public class ProfilePreference extends Preference { public class ProfilePreference extends Preference {
@ -70,24 +67,12 @@ public class ProfilePreference extends Preference {
final Address localAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(getContext())); final Address localAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(getContext()));
final String profileName = TextSecurePreferences.getProfileName(getContext()); final String profileName = TextSecurePreferences.getProfileName(getContext());
new AsyncTask<Void, Void, Drawable>() { GlideApp.with(getContext().getApplicationContext())
@Override .load(new ProfileContactPhoto(localAddress, String.valueOf(TextSecurePreferences.getProfileAvatarId(getContext()))))
protected @NonNull Drawable doInBackground(Void... params) { .error(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(getContext(), getContext().getResources().getColor(R.color.grey_400)))
if (AvatarHelper.getAvatarFile(getContext(), localAddress).exists()) { .circleCrop()
return ContactPhotoFactory.getSignalAvatarContactPhoto(getContext(), localAddress, profileName, .diskCacheStrategy(DiskCacheStrategy.ALL)
getContext().getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size)) .into(avatarView);
.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);
if (!TextUtils.isEmpty(profileName)) { if (!TextUtils.isEmpty(profileName)) {
profileNameView.setText(profileName); profileNameView.setText(profileName);

View File

@ -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<AvatarPhotoUriLoader.AvatarPhotoUri, InputStream> {
private final Context context;
private AvatarPhotoUriLoader(Context context) {
this.context = context;
}
@Nullable
@Override
public LoadData<InputStream> 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<AvatarPhotoUri, InputStream> {
private final Context context;
public Factory(Context context) {
this.context = context.getApplicationContext();
}
@Override
public ModelLoader<AvatarPhotoUri, InputStream> 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();
}
}
}

View File

@ -18,6 +18,7 @@ package org.thoughtcrime.securesms.recipients;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -26,7 +27,8 @@ import android.util.Log;
import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors; import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; 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.Address;
import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings; import org.thoughtcrime.securesms.database.RecipientDatabase.RecipientSettings;
@ -62,15 +64,16 @@ public class Recipient implements RecipientModifiedListener {
private boolean stale; private boolean stale;
private boolean resolving; private boolean resolving;
private ContactPhoto contactPhoto; private @Nullable ContactPhoto contactPhoto;
private Uri contactUri; private @NonNull FallbackContactPhoto fallbackContactPhoto;
private @Nullable Uri ringtone = null; private Uri contactUri;
private long mutedUntil = 0; private @Nullable Uri ringtone = null;
private boolean blocked = false; private long mutedUntil = 0;
private VibrateState vibrate = VibrateState.DEFAULT; private boolean blocked = false;
private int expireMessages = 0; private VibrateState vibrate = VibrateState.DEFAULT;
private Optional<Integer> defaultSubscriptionId = Optional.absent(); private int expireMessages = 0;
private @NonNull RegisteredState registered = RegisteredState.UNKNOWN; private Optional<Integer> defaultSubscriptionId = Optional.absent();
private @NonNull RegisteredState registered = RegisteredState.UNKNOWN;
private @Nullable MaterialColor color; private @Nullable MaterialColor color;
private boolean seenInviteReminder; private boolean seenInviteReminder;
@ -101,15 +104,16 @@ public class Recipient implements RecipientModifiedListener {
@NonNull Optional<RecipientDetails> details, @NonNull Optional<RecipientDetails> details,
@NonNull ListenableFutureTask<RecipientDetails> future) @NonNull ListenableFutureTask<RecipientDetails> future)
{ {
this.address = address; this.address = address;
this.contactPhoto = ContactPhotoFactory.getLoadingPhoto(); this.fallbackContactPhoto = new TransparentContactPhoto();
this.color = null; this.color = null;
this.resolving = true; this.resolving = true;
if (stale != null) { if (stale != null) {
this.name = stale.name; this.name = stale.name;
this.contactUri = stale.contactUri; this.contactUri = stale.contactUri;
this.contactPhoto = stale.contactPhoto; this.contactPhoto = stale.contactPhoto;
this.fallbackContactPhoto = stale.fallbackContactPhoto;
this.color = stale.color; this.color = stale.color;
this.customLabel = stale.customLabel; this.customLabel = stale.customLabel;
this.ringtone = stale.ringtone; this.ringtone = stale.ringtone;
@ -132,6 +136,7 @@ public class Recipient implements RecipientModifiedListener {
if (details.isPresent()) { if (details.isPresent()) {
this.name = details.get().name; this.name = details.get().name;
this.contactPhoto = details.get().avatar; this.contactPhoto = details.get().avatar;
this.fallbackContactPhoto = details.get().fallbackAvatar;
this.color = details.get().color; this.color = details.get().color;
this.ringtone = details.get().ringtone; this.ringtone = details.get().ringtone;
this.mutedUntil = details.get().mutedUntil; this.mutedUntil = details.get().mutedUntil;
@ -158,6 +163,7 @@ public class Recipient implements RecipientModifiedListener {
Recipient.this.name = result.name; Recipient.this.name = result.name;
Recipient.this.contactUri = result.contactUri; Recipient.this.contactUri = result.contactUri;
Recipient.this.contactPhoto = result.avatar; Recipient.this.contactPhoto = result.avatar;
Recipient.this.fallbackContactPhoto = result.fallbackAvatar;
Recipient.this.color = result.color; Recipient.this.color = result.color;
Recipient.this.customLabel = result.customLabel; Recipient.this.customLabel = result.customLabel;
Recipient.this.ringtone = result.ringtone; Recipient.this.ringtone = result.ringtone;
@ -202,6 +208,7 @@ public class Recipient implements RecipientModifiedListener {
this.contactUri = details.contactUri; this.contactUri = details.contactUri;
this.name = details.name; this.name = details.name;
this.contactPhoto = details.avatar; this.contactPhoto = details.avatar;
this.fallbackContactPhoto = details.fallbackAvatar;
this.color = details.color; this.color = details.color;
this.customLabel = details.customLabel; this.customLabel = details.customLabel;
this.ringtone = details.ringtone; this.ringtone = details.ringtone;
@ -345,7 +352,15 @@ public class Recipient implements RecipientModifiedListener {
return (getName() == null ? address.serialize() : getName()); 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; return contactPhoto;
} }
@ -361,7 +376,7 @@ public class Recipient implements RecipientModifiedListener {
return ringtone; return ringtone;
} }
public void setRingtone(Uri ringtone) { public void setRingtone(@Nullable Uri ringtone) {
synchronized (this) { synchronized (this) {
this.ringtone = ringtone; this.ringtone = ringtone;
} }

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2011 Whisper Systems * Copyright (C) 2011 Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.R;
import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; 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.Address;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord; 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.RecipientSettings;
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState; import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState; import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
@ -61,13 +66,12 @@ class RecipientProvider {
PhoneLookup.LOOKUP_KEY, PhoneLookup.LOOKUP_KEY,
PhoneLookup._ID, PhoneLookup._ID,
PhoneLookup.NUMBER, PhoneLookup.NUMBER,
PhoneLookup.LABEL PhoneLookup.LABEL,
PhoneLookup.PHOTO_URI
}; };
private static final Map<String, RecipientDetails> STATIC_DETAILS = new HashMap<String, RecipientDetails>() {{ private static final Map<String, RecipientDetails> STATIC_DETAILS = new HashMap<String, RecipientDetails>() {{
put("262966", new RecipientDetails("Amazon", null, null, put("262966", new RecipientDetails("Amazon", null, null, null, new ResourceContactPhoto(R.drawable.ic_amazon), false, null, null));
ContactPhotoFactory.getResourceContactPhoto(R.drawable.ic_amazon),
false, null, null));
}}; }};
@NonNull Recipient getRecipient(Context context, Address address, Optional<RecipientSettings> settings, Optional<GroupRecord> groupRecord, boolean asynchronous) { @NonNull Recipient getRecipient(Context context, Address address, Optional<RecipientSettings> settings, Optional<GroupRecord> groupRecord, boolean asynchronous) {
@ -100,7 +104,7 @@ class RecipientProvider {
if (address.isGroup() && settings.isPresent() && groupRecord.isPresent()) { if (address.isGroup() && settings.isPresent() && groupRecord.isPresent()) {
return Optional.of(getGroupRecipientDetails(context, address, groupRecord, settings, true)); return Optional.of(getGroupRecipientDetails(context, address, groupRecord, settings, true));
} else if (!address.isGroup() && settings.isPresent()) { } 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(); return Optional.absent();
@ -126,10 +130,17 @@ class RecipientProvider {
} }
private @NonNull RecipientDetails getIndividualRecipientDetails(Context context, @NonNull Address address, Optional<RecipientSettings> settings) { private @NonNull RecipientDetails getIndividualRecipientDetails(Context context, @NonNull Address address, Optional<RecipientSettings> settings) {
ContactPhoto contactPhoto = null;
FallbackContactPhoto fallbackContactPhoto = new GeneratedContactPhoto("#");
if (!settings.isPresent()) { if (!settings.isPresent()) {
settings = DatabaseFactory.getRecipientDatabase(context).getRecipientSettings(address); 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())) { if (address.isPhone() && !TextUtils.isEmpty(address.toPhoneString())) {
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(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); Cursor cursor = context.getContentResolver().query(uri, CALLER_ID_PROJECTION, null, null, null);
@ -138,14 +149,19 @@ class RecipientProvider {
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
final String resultNumber = cursor.getString(3); final String resultNumber = cursor.getString(3);
if (resultNumber != null) { if (resultNumber != null) {
Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1)); Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1));
String name = resultNumber.equals(cursor.getString(0)) ? null : cursor.getString(0); String name = resultNumber.equals(cursor.getString(0)) ? null : cursor.getString(0);
ContactPhoto contactPhoto = ContactPhotoFactory.getContactPhoto(context, String photoUri = cursor.getString(5);
Uri.withAppendedPath(Contacts.CONTENT_URI, cursor.getLong(2) + ""),
address,
name);
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 { } else {
Log.w(TAG, "resultNumber is null"); Log.w(TAG, "resultNumber is null");
} }
@ -157,10 +173,13 @@ class RecipientProvider {
} }
if (STATIC_DETAILS.containsKey(address.serialize())) return STATIC_DETAILS.get(address.serialize()); 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> groupRecord, Optional<RecipientSettings> settings, boolean asynchronous) { private @NonNull RecipientDetails getGroupRecipientDetails(Context context, Address groupId, Optional<GroupRecord> groupRecord, Optional<RecipientSettings> settings, boolean asynchronous) {
ContactPhoto contactPhoto = null;
FallbackContactPhoto fallbackContactPhoto = new ResourceContactPhoto(R.drawable.ic_group_white_24dp, R.drawable.ic_group_large);
if (!groupRecord.isPresent()) { if (!groupRecord.isPresent()) {
groupRecord = DatabaseFactory.getGroupDatabase(context).getGroup(groupId.toGroupString()); groupRecord = DatabaseFactory.getGroupDatabase(context).getGroup(groupId.toGroupString());
} }
@ -170,7 +189,6 @@ class RecipientProvider {
} }
if (groupRecord.isPresent()) { if (groupRecord.isPresent()) {
ContactPhoto contactPhoto = ContactPhotoFactory.getGroupContactPhoto(groupRecord.get().getAvatar());
String title = groupRecord.get().getTitle(); String title = groupRecord.get().getTitle();
List<Address> memberAddresses = groupRecord.get().getMembers(); List<Address> memberAddresses = groupRecord.get().getMembers();
List<Recipient> members = new LinkedList<>(); List<Recipient> members = new LinkedList<>();
@ -183,40 +201,47 @@ class RecipientProvider {
title = context.getString(R.string.RecipientProvider_unnamed_group);; 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 { static class RecipientDetails {
@Nullable public final String name; @Nullable public final String name;
@Nullable public final String customLabel; @Nullable public final String customLabel;
@NonNull public final ContactPhoto avatar; @Nullable public final ContactPhoto avatar;
@Nullable public final Uri contactUri; @NonNull public final FallbackContactPhoto fallbackAvatar;
@Nullable public final MaterialColor color; @Nullable public final Uri contactUri;
@Nullable public final Uri ringtone; @Nullable public final MaterialColor color;
public final long mutedUntil; @Nullable public final Uri ringtone;
@Nullable public final VibrateState vibrateState; public final long mutedUntil;
public final boolean blocked; @Nullable public final VibrateState vibrateState;
public final int expireMessages; public final boolean blocked;
@NonNull public final List<Recipient> participants; public final int expireMessages;
@Nullable public final String profileName; @NonNull public final List<Recipient> participants;
public final boolean seenInviteReminder; @Nullable public final String profileName;
public final Optional<Integer> defaultSubscriptionId; public final boolean seenInviteReminder;
@NonNull public final RegisteredState registered; public final Optional<Integer> defaultSubscriptionId;
@Nullable public final byte[] profileKey; @NonNull public final RegisteredState registered;
@Nullable public final String profileAvatar; @Nullable public final byte[] profileKey;
public final boolean profileSharing; @Nullable public final String profileAvatar;
public final boolean systemContact; public final boolean profileSharing;
public final boolean systemContact;
public RecipientDetails(@Nullable String name, @Nullable String customLabel, 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, boolean systemContact, @Nullable RecipientSettings settings,
@Nullable List<Recipient> participants) @Nullable List<Recipient> participants)
{ {
this.customLabel = customLabel; this.customLabel = customLabel;
this.avatar = avatar; this.avatar = avatar;
this.fallbackAvatar = fallbackAvatar;
this.contactUri = contactUri; this.contactUri = contactUri;
this.color = settings != null ? settings.getColor() : null; this.color = settings != null ? settings.getColor() : null;
this.ringtone = settings != null ? settings.getRingtone() : null; this.ringtone = settings != null ? settings.getRingtone() : null;

View File

@ -18,6 +18,8 @@ import android.view.View;
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity; import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterSecret; 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.providers.PersistentBlobProvider;
import org.thoughtcrime.securesms.scribbles.viewmodel.Font; import org.thoughtcrime.securesms.scribbles.viewmodel.Font;
import org.thoughtcrime.securesms.scribbles.viewmodel.Layer; import org.thoughtcrime.securesms.scribbles.viewmodel.Layer;
@ -48,22 +50,24 @@ public class ScribbleActivity extends PassphraseRequiredActionBarActivity implem
private ScribbleToolbar toolbar; private ScribbleToolbar toolbar;
private ScribbleView scribbleView; private ScribbleView scribbleView;
private MasterSecret masterSecret; private MasterSecret masterSecret;
private GlideRequests glideRequests;
@Override @Override
protected void onCreate(Bundle savedInstanceState, @NonNull MasterSecret masterSecret) { protected void onCreate(Bundle savedInstanceState, @NonNull MasterSecret masterSecret) {
setContentView(R.layout.scribble_activity); setContentView(R.layout.scribble_activity);
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
this.scribbleView = (ScribbleView) findViewById(R.id.scribble_view); this.glideRequests = GlideApp.with(this);
this.toolbar = (ScribbleToolbar) findViewById(R.id.toolbar); this.scribbleView = findViewById(R.id.scribble_view);
this.colorPicker = (VerticalSlideColorPicker) findViewById(R.id.scribble_color_picker); this.toolbar = findViewById(R.id.toolbar);
this.colorPicker = findViewById(R.id.scribble_color_picker);
this.toolbar.setListener(this); this.toolbar.setListener(this);
this.toolbar.setToolColor(Color.RED); this.toolbar.setToolColor(Color.RED);
scribbleView.setMotionViewCallback(motionViewCallback); scribbleView.setMotionViewCallback(motionViewCallback);
scribbleView.setDrawingMode(false); scribbleView.setDrawingMode(false);
scribbleView.setImage(getIntent().getData(), masterSecret); scribbleView.setImage(masterSecret, glideRequests, getIntent().getData());
colorPicker.setOnColorChangeListener(this); colorPicker.setOnColorChangeListener(this);
colorPicker.setVisibility(View.GONE); colorPicker.setVisibility(View.GONE);
@ -214,7 +218,7 @@ public class ScribbleActivity extends PassphraseRequiredActionBarActivity implem
@Override @Override
public void onSave() { public void onSave() {
ListenableFuture<Bitmap> future = scribbleView.getRenderedImage(); ListenableFuture<Bitmap> future = scribbleView.getRenderedImage(glideRequests);
future.addListener(new ListenableFuture.Listener<Bitmap>() { future.addListener(new ListenableFuture.Listener<Bitmap>() {
@Override @Override

View File

@ -35,11 +35,13 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
public class StickerSelectFragment extends Fragment implements LoaderManager.LoaderCallbacks<String[]> { public class StickerSelectFragment extends Fragment implements LoaderManager.LoaderCallbacks<String[]> {
private RecyclerView recyclerView; private RecyclerView recyclerView;
private String assetDirectory; private GlideRequests glideRequests;
private String assetDirectory;
private StickerSelectionListener listener; private StickerSelectionListener listener;
public static StickerSelectFragment newInstance(String assetDirectory) { public static StickerSelectFragment newInstance(String assetDirectory) {
@ -67,6 +69,7 @@ public class StickerSelectFragment extends Fragment implements LoaderManager.Loa
public void onActivityCreated(Bundle bundle) { public void onActivityCreated(Bundle bundle) {
super.onActivityCreated(bundle); super.onActivityCreated(bundle);
this.glideRequests = GlideApp.with(this);
this.assetDirectory = getArguments().getString("assetDirectory"); this.assetDirectory = getArguments().getString("assetDirectory");
getLoaderManager().initLoader(0, null, this); getLoaderManager().initLoader(0, null, this);
@ -80,7 +83,7 @@ public class StickerSelectFragment extends Fragment implements LoaderManager.Loa
@Override @Override
public void onLoadFinished(Loader<String[]> loader, String[] data) { public void onLoadFinished(Loader<String[]> loader, String[] data) {
recyclerView.setAdapter(new StickersAdapter(getActivity(), data)); recyclerView.setAdapter(new StickersAdapter(getActivity(), glideRequests, data));
} }
@Override @Override
@ -94,12 +97,12 @@ public class StickerSelectFragment extends Fragment implements LoaderManager.Loa
class StickersAdapter extends RecyclerView.Adapter<StickersAdapter.StickerViewHolder> { class StickersAdapter extends RecyclerView.Adapter<StickersAdapter.StickerViewHolder> {
private final Context context; private final GlideRequests glideRequests;
private final String[] stickerFiles; private final String[] stickerFiles;
private final LayoutInflater layoutInflater; private final LayoutInflater layoutInflater;
StickersAdapter(@NonNull Context context, @NonNull String[] stickerFiles) { StickersAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests, @NonNull String[] stickerFiles) {
this.context = context; this.glideRequests = glideRequests;
this.stickerFiles = stickerFiles; this.stickerFiles = stickerFiles;
this.layoutInflater = LayoutInflater.from(context); this.layoutInflater = LayoutInflater.from(context);
} }
@ -113,10 +116,9 @@ public class StickerSelectFragment extends Fragment implements LoaderManager.Loa
public void onBindViewHolder(StickerViewHolder holder, int position) { public void onBindViewHolder(StickerViewHolder holder, int position) {
holder.fileName = stickerFiles[position]; holder.fileName = stickerFiles[position];
GlideApp.with(context) glideRequests.load(Uri.parse("file:///android_asset/" + holder.fileName))
.load(Uri.parse("file:///android_asset/" + holder.fileName)) .diskCacheStrategy(DiskCacheStrategy.NONE)
.diskCacheStrategy(DiskCacheStrategy.NONE) .into(holder.image);
.into(holder.image);
} }
@Override @Override
@ -127,7 +129,7 @@ public class StickerSelectFragment extends Fragment implements LoaderManager.Loa
@Override @Override
public void onViewRecycled(StickerViewHolder holder) { public void onViewRecycled(StickerViewHolder holder) {
super.onViewRecycled(holder); super.onViewRecycled(holder);
GlideApp.with(context).clear(holder.image); glideRequests.clear(holder.image);
} }
private void onStickerSelected(String fileName) { private void onStickerSelected(String fileName) {

View File

@ -1,4 +1,4 @@
/** /*
* Copyright (C) 2016 Open Whisper Systems * Copyright (C) 2016 Open Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * 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.R;
import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri; 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.MotionEntity;
import org.thoughtcrime.securesms.scribbles.widget.entity.TextEntity; import org.thoughtcrime.securesms.scribbles.widget.entity.TextEntity;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
@ -77,18 +77,17 @@ public class ScribbleView extends FrameLayout {
initialize(context); 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.imageUri = uri;
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
GlideApp.with(getContext()) glideRequests.load(new DecryptableUri(masterSecret, uri))
.load(new DecryptableUri(masterSecret, uri)) .diskCacheStrategy(DiskCacheStrategy.NONE)
.diskCacheStrategy(DiskCacheStrategy.NONE) .fitCenter()
.fitCenter() .into(imageView);
.into(imageView);
} }
public @NonNull ListenableFuture<Bitmap> getRenderedImage() { public @NonNull ListenableFuture<Bitmap> getRenderedImage(@NonNull GlideRequests glideRequests) {
final SettableFuture<Bitmap> future = new SettableFuture<>(); final SettableFuture<Bitmap> future = new SettableFuture<>();
final Context context = getContext(); final Context context = getContext();
final boolean isLowMemory = Util.isLowMemory(context); final boolean isLowMemory = Util.isLowMemory(context);
@ -110,13 +109,12 @@ public class ScribbleView extends FrameLayout {
height = 768; height = 768;
} }
return GlideApp.with(context) return glideRequests.asBitmap()
.asBitmap() .load(new DecryptableUri(masterSecret, imageUri))
.load(new DecryptableUri(masterSecret, imageUri)) .diskCacheStrategy(DiskCacheStrategy.NONE)
.diskCacheStrategy(DiskCacheStrategy.NONE) .skipMemoryCache(true)
.skipMemoryCache(true) .into(width, height)
.into(width, height) .get();
.get();
} catch (InterruptedException | ExecutionException e) { } catch (InterruptedException | ExecutionException e) {
Log.w(TAG, e); Log.w(TAG, e);
return null; return null;
@ -143,9 +141,9 @@ public class ScribbleView extends FrameLayout {
private void initialize(@NonNull Context context) { private void initialize(@NonNull Context context) {
inflate(context, R.layout.scribble_view, this); inflate(context, R.layout.scribble_view, this);
this.imageView = (ImageView) findViewById(R.id.image_view); this.imageView = findViewById(R.id.image_view);
this.motionView = (MotionView) findViewById(R.id.motion_view); this.motionView = findViewById(R.id.motion_view);
this.canvasView = (CanvasView) findViewById(R.id.canvas_view); this.canvasView = findViewById(R.id.canvas_view);
} }
public void setMotionViewCallback(MotionView.MotionViewCallback callback) { public void setMotionViewCallback(MotionView.MotionViewCallback callback) {

View File

@ -5,7 +5,6 @@ import android.content.ComponentName;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon; import android.graphics.drawable.Icon;
import android.os.Build; import android.os.Build;
import android.os.Bundle; 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.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.ThreadRecord; import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.BitmapUtil;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
@RequiresApi(api = Build.VERSION_CODES.M) @RequiresApi(api = Build.VERSION_CODES.M)
public class DirectShareService extends ChooserTargetService { public class DirectShareService extends ChooserTargetService {
@ -48,22 +49,40 @@ public class DirectShareService extends ChooserTargetService {
ThreadRecord record; ThreadRecord record;
while ((record = reader.getNext()) != null && results.size() < 10) { while ((record = reader.getNext()) != null && results.size() < 10) {
Recipient recipient = Recipient.from(this, record.getRecipient().getAddress(), false); try {
String name = recipient.toShortString(); Recipient recipient = Recipient.from(this, record.getRecipient().getAddress(), false);
Drawable drawable = recipient.getContactPhoto().asDrawable(this, recipient.getColor().toConversationColor(this)); String name = recipient.toShortString();
Bitmap avatar = BitmapUtil.createFromDrawable(drawable, 500, 500);
Parcel parcel = Parcel.obtain(); Bitmap avatar;
parcel.writeParcelable(recipient.getAddress(), 0);
Bundle bundle = new Bundle(); if (recipient.getContactPhoto() != null) {
bundle.putLong(ShareActivity.EXTRA_THREAD_ID, record.getThreadId()); avatar = GlideApp.with(this)
bundle.putByteArray(ShareActivity.EXTRA_ADDRESS_MARSHALLED, parcel.marshall()); .asBitmap()
bundle.putInt(ShareActivity.EXTRA_DISTRIBUTION_TYPE, record.getDistributionType()); .load(recipient.getContactPhoto())
bundle.setClassLoader(getClassLoader()); .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 parcel = Parcel.obtain();
parcel.recycle(); 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; return results;

View File

@ -10,8 +10,8 @@ import android.graphics.Rect;
import android.graphics.YuvImage; import android.graphics.YuvImage;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull; import android.support.annotation.*;
import android.support.annotation.Nullable; import android.support.annotation.WorkerThread;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@ -42,6 +42,7 @@ public class BitmapUtil {
private static final int MAX_COMPRESSION_ATTEMPTS = 5; private static final int MAX_COMPRESSION_ATTEMPTS = 5;
private static final int MIN_COMPRESSION_QUALITY_DECREASE = 5; private static final int MIN_COMPRESSION_QUALITY_DECREASE = 5;
@android.support.annotation.WorkerThread
public static <T> byte[] createScaledBytes(Context context, T model, MediaConstraints constraints) public static <T> byte[] createScaledBytes(Context context, T model, MediaConstraints constraints)
throws BitmapDecodingException throws BitmapDecodingException
{ {
@ -50,7 +51,7 @@ public class BitmapUtil {
int attempts = 0; int attempts = 0;
byte[] bytes; byte[] bytes;
Bitmap scaledBitmap = GlideApp.with(context) Bitmap scaledBitmap = GlideApp.with(context.getApplicationContext())
.asBitmap() .asBitmap()
.load(model) .load(model)
.downsample(DownsampleStrategy.AT_MOST) .downsample(DownsampleStrategy.AT_MOST)
@ -91,11 +92,12 @@ public class BitmapUtil {
} }
} }
@WorkerThread
public static <T> Bitmap createScaledBitmap(Context context, T model, int maxWidth, int maxHeight) public static <T> Bitmap createScaledBitmap(Context context, T model, int maxWidth, int maxHeight)
throws BitmapDecodingException throws BitmapDecodingException
{ {
try { try {
return GlideApp.with(context) return GlideApp.with(context.getApplicationContext())
.asBitmap() .asBitmap()
.load(model) .load(model)
.downsample(DownsampleStrategy.AT_MOST) .downsample(DownsampleStrategy.AT_MOST)
@ -106,11 +108,12 @@ public class BitmapUtil {
} }
} }
@WorkerThread
public static <T> Bitmap createScaledBitmap(Context context, T model, float scale) public static <T> Bitmap createScaledBitmap(Context context, T model, float scale)
throws BitmapDecodingException throws BitmapDecodingException
{ {
try { try {
return GlideApp.with(context) return GlideApp.with(context.getApplicationContext())
.asBitmap() .asBitmap()
.load(model) .load(model)
.sizeMultiplier(scale) .sizeMultiplier(scale)

View File

@ -66,7 +66,7 @@ public class MediaUtil {
{ {
try { try {
int maxSize = context.getResources().getDimensionPixelSize(R.dimen.media_bubble_height); int maxSize = context.getResources().getDimensionPixelSize(R.dimen.media_bubble_height);
return GlideApp.with(context) return GlideApp.with(context.getApplicationContext())
.asBitmap() .asBitmap()
.load(new DecryptableUri(masterSecret, uri)) .load(new DecryptableUri(masterSecret, uri))
.centerCrop() .centerCrop()

View File

@ -112,6 +112,7 @@ public class TextSecurePreferences {
private static final String ALWAYS_RELAY_CALLS_PREF = "pref_turn_only"; 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_KEY_PREF = "pref_profile_key";
private static final String PROFILE_NAME_PREF = "pref_profile_name"; 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 READ_RECEIPTS_PREF = "pref_read_receipts";
public static final String INCOGNITO_KEYBORAD_PREF = "pref_incognito_keyboard"; public static final String INCOGNITO_KEYBORAD_PREF = "pref_incognito_keyboard";
@ -143,6 +144,14 @@ public class TextSecurePreferences {
return getStringPreference(context, PROFILE_NAME_PREF, null); 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) { public static int getNotificationPriority(Context context) {
return Integer.valueOf(getStringPreference(context, NOTIFICATION_PRIORITY_PREF, String.valueOf(NotificationCompat.PRIORITY_HIGH))); return Integer.valueOf(getStringPreference(context, NOTIFICATION_PRIORITY_PREF, String.valueOf(NotificationCompat.PRIORITY_HIGH)));
} }