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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/**
/*
* Copyright (C) 2015 Open Whisper Systems
*
* 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.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.database.loaders.ConversationListLoader;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -201,7 +202,7 @@ public class ConversationListFragment extends Fragment
}
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);
}

View File

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

View File

@ -10,6 +10,7 @@ import android.widget.TextView;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.Locale;
@ -39,7 +40,7 @@ public class ConversationListItemAction extends LinearLayout implements Bindable
}
@Override
public void bind(@NonNull MasterSecret masterSecret, @NonNull ThreadRecord thread, @NonNull Locale locale, @NonNull Set<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()));
}

View File

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

View File

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

View File

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

View File

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

View File

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

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.BucketedThreadMedia;
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
@ -204,7 +205,7 @@ public class MediaOverviewActivity extends PassphraseRequiredActionBarActivity
this.noMedia = ViewUtil.findById(view, R.id.no_images);
this.gridManager = new StickyHeaderGridLayoutManager(getResources().getInteger(R.integer.media_overview_cols));
this.recyclerView.setAdapter(new MediaGalleryAdapter(getContext(), masterSecret, new BucketedThreadMedia(getContext()), locale, recipient.getAddress()));
this.recyclerView.setAdapter(new MediaGalleryAdapter(getContext(), masterSecret, GlideApp.with(this), new BucketedThreadMedia(getContext()), locale, recipient.getAddress()));
this.recyclerView.setLayoutManager(gridManager);
this.recyclerView.setHasFixedSize(true);

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,9 @@
package org.thoughtcrime.securesms.contacts;
import android.content.Context;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.LinearLayout;
@ -12,6 +12,8 @@ import android.widget.TextView;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView;
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.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.Util;
@ -27,9 +29,10 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
private TextView labelView;
private CheckBox checkBox;
private long id;
private String number;
private Recipient recipient;
private long id;
private String number;
private Recipient recipient;
private GlideRequests glideRequests;
public ContactSelectionListItem(Context context) {
super(context);
@ -42,22 +45,23 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
@Override
protected void onFinishInflate() {
super.onFinishInflate();
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
this.numberView = (TextView) findViewById(R.id.number);
this.labelView = (TextView) findViewById(R.id.label);
this.nameView = (TextView) findViewById(R.id.name);
this.checkBox = (CheckBox) findViewById(R.id.check_box);
this.contactPhotoImage = findViewById(R.id.contact_photo_image);
this.numberView = findViewById(R.id.number);
this.labelView = findViewById(R.id.label);
this.nameView = findViewById(R.id.name);
this.checkBox = findViewById(R.id.check_box);
ViewUtil.setTextViewGravityStart(this.nameView, getContext());
}
public void set(long id, int type, String name, String number, String label, int color, boolean multiSelect) {
this.id = id;
this.number = number;
public void set(@NonNull GlideRequests glideRequests, long id, int type, String name, String number, String label, int color, boolean multiSelect) {
this.glideRequests = glideRequests;
this.id = id;
this.number = number;
if (type == ContactsDatabase.NEW_TYPE) {
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)) {
Address address = Address.fromExternal(getContext(), number);
this.recipient = Recipient.from(getContext(), address, true);
@ -70,7 +74,7 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
this.nameView.setTextColor(color);
this.numberView.setTextColor(color);
this.contactPhotoImage.setAvatar(recipient, false);
this.contactPhotoImage.setAvatar(glideRequests, recipient, false);
setText(type, name, number, label);
@ -82,11 +86,13 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM
this.checkBox.setChecked(selected);
}
public void unbind() {
public void unbind(GlideRequests glideRequests) {
if (recipient != null) {
recipient.removeListener(this);
recipient = null;
}
contactPhotoImage.clear(glideRequests);
}
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) {
if (this.recipient == recipient) {
Util.runOnMain(() -> {
contactPhotoImage.setAvatar(recipient, false);
contactPhotoImage.setAvatar(glideRequests, recipient, false);
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;
import android.content.Context;
import android.graphics.drawable.Drawable;
public interface ContactPhoto {
public Drawable asDrawable(Context context, int color);
public Drawable asDrawable(Context context, int color, boolean inverted);
public Drawable asCallCard(Context context);
public boolean isGenerated();
public boolean isResource();
import com.bumptech.glide.load.Key;
import java.io.IOException;
import java.io.InputStream;
public interface ContactPhoto extends Key {
InputStream openInputStream(Context context) throws IOException;
}

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;
public class GeneratedContactPhoto implements ContactPhoto {
import java.util.regex.Pattern;
public class GeneratedContactPhoto implements FallbackContactPhoto {
private static final Pattern PATTERN = Pattern.compile("[^\\p{L}\\p{Nd}\\p{P}\\p{S}]+");
private final String name;
GeneratedContactPhoto(@NonNull String name) {
public GeneratedContactPhoto(@NonNull String name) {
this.name = name;
}
@ -38,7 +42,7 @@ public class GeneratedContactPhoto implements ContactPhoto {
}
private String getCharacter(String name) {
String cleanedName = name.replaceFirst("[^\\p{L}\\p{Nd}\\p{P}\\p{S}]+", "");
String cleanedName = PATTERN.matcher(name).replaceFirst("");
if (cleanedName.isEmpty()) {
return "#";
@ -52,14 +56,4 @@ public class GeneratedContactPhoto implements ContactPhoto {
return AppCompatResources.getDrawable(context, R.drawable.ic_person_large);
}
@Override
public boolean isGenerated() {
return true;
}
@Override
public boolean isResource() {
return false;
}
}

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.makeramen.roundedimageview.RoundedDrawable;
public class ResourceContactPhoto implements ContactPhoto {
public class ResourceContactPhoto implements FallbackContactPhoto {
private final int resourceId;
private final int callCardResourceId;
ResourceContactPhoto(@DrawableRes int resourceId) {
public ResourceContactPhoto(@DrawableRes int resourceId) {
this(resourceId, resourceId);
}
ResourceContactPhoto(@DrawableRes int resourceId, @DrawableRes int callCardResourceId) {
public ResourceContactPhoto(@DrawableRes int resourceId, @DrawableRes int callCardResourceId) {
this.resourceId = resourceId;
this.callCardResourceId = callCardResourceId;
}
@ -50,16 +50,6 @@ public class ResourceContactPhoto implements ContactPhoto {
return AppCompatResources.getDrawable(context, callCardResourceId);
}
@Override
public boolean isGenerated() {
return false;
}
@Override
public boolean isResource() {
return true;
}
private static class ExpandingLayerDrawable extends LayerDrawable {
public ExpandingLayerDrawable(Drawable[] layers) {
super(layers);

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;
public class TransparentContactPhoto implements ContactPhoto {
public class TransparentContactPhoto implements FallbackContactPhoto {
TransparentContactPhoto() {}
public TransparentContactPhoto() {}
@Override
public Drawable asDrawable(Context context, int color) {
@ -27,13 +27,4 @@ public class TransparentContactPhoto implements ContactPhoto {
return ContextCompat.getDrawable(context, R.drawable.ic_contact_picture_large);
}
@Override
public boolean isGenerated() {
return false;
}
@Override
public boolean isResource() {
return false;
}
}

View File

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

View File

@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.giph.model.GiphyImage;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
@ -33,12 +34,14 @@ import java.util.List;
import java.util.concurrent.ExecutionException;
public class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHolder> {
class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHolder> {
private static final String TAG = GiphyAdapter.class.getSimpleName();
private final Context context;
private final GlideRequests glideRequests;
private List<GiphyImage> images;
private Context context;
private OnItemClickListener listener;
class GiphyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, RequestListener<Drawable> {
@ -73,7 +76,6 @@ public class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHol
}
return false;
}
@Override
@ -108,9 +110,10 @@ public class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHol
}
}
GiphyAdapter(Context context, List<GiphyImage> images) {
this.context = context.getApplicationContext();
this.images = images;
GiphyAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests, @NonNull List<GiphyImage> images) {
this.context = context.getApplicationContext();
this.glideRequests = glideRequests;
this.images = images;
}
public void setImages(@NonNull List<GiphyImage> images) {
@ -145,21 +148,19 @@ public class GiphyAdapter extends RecyclerView.Adapter<GiphyAdapter.GiphyViewHol
.diskCacheStrategy(DiskCacheStrategy.ALL);
if (Util.isLowMemory(context)) {
GlideApp.with(context)
.load(image.getStillUrl())
.placeholder(new ColorDrawable(Util.getRandomElement(MaterialColor.values()).toConversationColor(context)))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(holder.thumbnail);
glideRequests.load(image.getStillUrl())
.placeholder(new ColorDrawable(Util.getRandomElement(MaterialColor.values()).toConversationColor(context)))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(holder.thumbnail);
holder.setModelReady();
} else {
GlideApp.with(context)
.load(image.getGifUrl())
.thumbnail(thumbnailRequest)
.placeholder(new ColorDrawable(Util.getRandomElement(MaterialColor.values()).toConversationColor(context)))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.listener(holder)
.into(holder.thumbnail);
glideRequests.load(image.getGifUrl())
.thumbnail(thumbnailRequest)
.placeholder(new ColorDrawable(Util.getRandomElement(MaterialColor.values()).toConversationColor(context)))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.listener(holder)
.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.net.GiphyLoader;
import org.thoughtcrime.securesms.giph.util.InfiniteScrollListener;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.LinkedList;
@ -52,7 +53,7 @@ public abstract class GiphyFragment extends Fragment implements LoaderManager.Lo
public void onActivityCreated(Bundle 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.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;
@ -8,27 +8,27 @@ import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.data.DataFetcher;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import java.io.IOException;
import java.io.InputStream;
class AvatarPhotoUriFetcher implements DataFetcher<InputStream> {
class ContactPhotoFetcher implements DataFetcher<InputStream> {
private final Context context;
private final Address address;
private final Context context;
private final ContactPhoto contactPhoto;
private InputStream inputStream;
AvatarPhotoUriFetcher(@NonNull Context context, @NonNull Address address) {
this.context = context.getApplicationContext();
this.address = address;
ContactPhotoFetcher(@NonNull Context context, @NonNull ContactPhoto contactPhoto) {
this.context = context.getApplicationContext();
this.contactPhoto = contactPhoto;
}
@Override
public void loadData(Priority priority, DataCallback<? super InputStream> callback) {
try {
inputStream = AvatarHelper.getInputStreamFor(context, address);
inputStream = contactPhoto.openInputStream(context);
callback.onDataReady(inputStream);
} catch (IOException 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.util.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory;
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.dependencies.InjectableType;
@ -85,8 +84,8 @@ public class RetrieveProfileAvatarJob extends ContextJob implements InjectableTy
database.setProfileAvatar(recipient, profileAvatar);
if (recipient.resolve().getContactPhoto().isGenerated()) {
recipient.setContactPhoto(ContactPhotoFactory.getSignalAvatarContactPhoto(context, recipient.getAddress(), recipient.getName(), context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size)));
if (recipient.resolve().getContactPhoto() == null) {
recipient.setContactPhoto(new ProfileContactPhoto(recipient.getAddress(), profileAvatar));
}
}

View File

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

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,6 @@ import android.content.ComponentName;
import android.content.IntentFilter;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Bundle;
@ -20,11 +19,13 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.BitmapUtil;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
@RequiresApi(api = Build.VERSION_CODES.M)
public class DirectShareService extends ChooserTargetService {
@ -48,22 +49,40 @@ public class DirectShareService extends ChooserTargetService {
ThreadRecord record;
while ((record = reader.getNext()) != null && results.size() < 10) {
Recipient recipient = Recipient.from(this, record.getRecipient().getAddress(), false);
String name = recipient.toShortString();
Drawable drawable = recipient.getContactPhoto().asDrawable(this, recipient.getColor().toConversationColor(this));
Bitmap avatar = BitmapUtil.createFromDrawable(drawable, 500, 500);
try {
Recipient recipient = Recipient.from(this, record.getRecipient().getAddress(), false);
String name = recipient.toShortString();
Parcel parcel = Parcel.obtain();
parcel.writeParcelable(recipient.getAddress(), 0);
Bitmap avatar;
Bundle bundle = new Bundle();
bundle.putLong(ShareActivity.EXTRA_THREAD_ID, record.getThreadId());
bundle.putByteArray(ShareActivity.EXTRA_ADDRESS_MARSHALLED, parcel.marshall());
bundle.putInt(ShareActivity.EXTRA_DISTRIBUTION_TYPE, record.getDistributionType());
bundle.setClassLoader(getClassLoader());
if (recipient.getContactPhoto() != null) {
avatar = GlideApp.with(this)
.asBitmap()
.load(recipient.getContactPhoto())
.circleCrop()
.submit(getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width),
getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width))
.get();
} else {
avatar = BitmapUtil.createFromDrawable(recipient.getFallbackContactPhotoDrawable(this, false),
getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width),
getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height));
}
results.add(new ChooserTarget(name, Icon.createWithBitmap(avatar), 1.0f, componentName, bundle));
parcel.recycle();
Parcel parcel = Parcel.obtain();
parcel.writeParcelable(recipient.getAddress(), 0);
Bundle bundle = new Bundle();
bundle.putLong(ShareActivity.EXTRA_THREAD_ID, record.getThreadId());
bundle.putByteArray(ShareActivity.EXTRA_ADDRESS_MARSHALLED, parcel.marshall());
bundle.putInt(ShareActivity.EXTRA_DISTRIBUTION_TYPE, record.getDistributionType());
bundle.setClassLoader(getClassLoader());
results.add(new ChooserTarget(name, Icon.createWithBitmap(avatar), 1.0f, componentName, bundle));
parcel.recycle();
} catch (InterruptedException | ExecutionException e) {
throw new AssertionError(e);
}
}
return results;

View File

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

View File

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

View File

@ -112,6 +112,7 @@ public class TextSecurePreferences {
private static final String ALWAYS_RELAY_CALLS_PREF = "pref_turn_only";
private static final String PROFILE_KEY_PREF = "pref_profile_key";
private static final String PROFILE_NAME_PREF = "pref_profile_name";
private static final String PROFILE_AVATAR_ID_PREF = "pref_profile_avatar_id";
public static final String READ_RECEIPTS_PREF = "pref_read_receipts";
public static final String INCOGNITO_KEYBORAD_PREF = "pref_incognito_keyboard";
@ -143,6 +144,14 @@ public class TextSecurePreferences {
return getStringPreference(context, PROFILE_NAME_PREF, null);
}
public static void setProfileAvatarId(Context context, int id) {
setIntegerPrefrence(context, PROFILE_AVATAR_ID_PREF, id);
}
public static int getProfileAvatarId(Context context) {
return getIntegerPreference(context, PROFILE_AVATAR_ID_PREF, 0);
}
public static int getNotificationPriority(Context context) {
return Integer.valueOf(getStringPreference(context, NOTIFICATION_PRIORITY_PREF, String.valueOf(NotificationCompat.PRIORITY_HIGH)));
}