diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 344f4282e3..e8d5599d06 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -5,6 +5,8 @@
android:versionCode="113"
android:versionName="2.13.0">
+
+
diff --git a/build.gradle b/build.gradle
index a7b845c23c..b8f14ce291 100644
--- a/build.gradle
+++ b/build.gradle
@@ -26,6 +26,9 @@ repositories {
maven {
url "https://raw.github.com/whispersystems/maven/master/shortcutbadger/releases/"
}
+ maven { // textdrawable
+ url 'https://dl.bintray.com/amulyakhare/maven'
+ }
jcenter()
mavenLocal()
}
@@ -64,6 +67,7 @@ dependencies {
compile 'org.whispersystems:jobmanager:0.11.0'
compile 'org.whispersystems:libpastelog:1.0.6'
compile 'org.whispersystems:textsecure-android:1.3.0'
+ compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
@@ -104,6 +108,7 @@ dependencyVerification {
'org.whispersystems:jobmanager:ea9cb943c4892fb90c1eea1be30efeb85cefca213d52c788419553b58d0ed70d',
'org.whispersystems:libpastelog:550d33c565380d90f4c671e7b8ed5f3a6da55a9fda468373177106b2eb5220b2',
'org.whispersystems:textsecure-android:df4c1ac9ee8f7cd43c8c07d64b16e31875e04632afc3fe73f2a47292a86c79a1',
+ 'com.amulyakhare:com.amulyakhare.textdrawable:54c92b5fba38cfd316a07e5a30528068f45ce8515a6890f1297df4c401af5dcb',
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
diff --git a/res/layout/conversation_item_received.xml b/res/layout/conversation_item_received.xml
index 0ca454c25e..b41f77390b 100644
--- a/res/layout/conversation_item_received.xml
+++ b/res/layout/conversation_item_received.xml
@@ -26,17 +26,15 @@
android:layout_marginBottom="6dp"
android:layout_marginRight="0dp">
-
+ android:contentDescription="@string/conversation_item_received__contact_photo_description" />
-
-
-
@@ -38,7 +36,8 @@
android:layout_height="wrap_content"
android:orientation="vertical">
-
-
-
-
+
diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java
index 3f389192ee..a413c17a51 100644
--- a/src/org/thoughtcrime/securesms/ConversationItem.java
+++ b/src/org/thoughtcrime/securesms/ConversationItem.java
@@ -21,9 +21,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.QuickContact;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -38,9 +35,9 @@ import android.widget.Toast;
import com.afollestad.materialdialogs.AlertDialogWrapper;
import org.thoughtcrime.securesms.ConversationFragment.SelectionClickListener;
+import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.BubbleContainer;
import org.thoughtcrime.securesms.components.ThumbnailView;
-import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsDatabase;
@@ -85,7 +82,7 @@ public class ConversationItem extends LinearLayout {
private TextView groupStatusText;
private ImageView secureImage;
private ImageView failedImage;
- private ImageView contactPhoto;
+ private AvatarImageView contactPhoto;
private ImageView deliveryImage;
private ImageView pendingIndicator;
private BubbleContainer bubbleContainer;
@@ -123,7 +120,7 @@ public class ConversationItem extends LinearLayout {
this.failedImage = (ImageView)findViewById(R.id.sms_failed_indicator);
this.mmsDownloadButton = (Button) findViewById(R.id.mms_download_button);
this.mmsDownloadingLabel = (TextView) findViewById(R.id.mms_label_downloading);
- this.contactPhoto = (ImageView)findViewById(R.id.contact_photo);
+ this.contactPhoto = (AvatarImageView) findViewById(R.id.contact_photo);
this.deliveryImage = (ImageView)findViewById(R.id.delivered_indicator);
this.bodyBubble = findViewById(R.id.body_bubble);
this.pendingIndicator = (ImageView)findViewById(R.id.pending_approval_indicator);
@@ -369,30 +366,7 @@ public class ConversationItem extends LinearLayout {
private void setContactPhotoForRecipient(final Recipient recipient) {
if (contactPhoto == null) return;
- Bitmap contactPhotoBitmap;
-
- if ((recipient.getContactPhoto() == ContactPhotoFactory.getDefaultContactPhoto(context)) && (groupThread)) {
- contactPhotoBitmap = recipient.getGeneratedAvatar(context);
- } else {
- contactPhotoBitmap = recipient.getContactPhoto();
- }
-
- contactPhoto.setImageBitmap(contactPhotoBitmap);
-
- contactPhoto.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (recipient.getContactUri() != null) {
- QuickContact.showQuickContact(context, contactPhoto, recipient.getContactUri(), QuickContact.MODE_LARGE, null);
- } else {
- final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
- intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getNumber());
- intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
- context.startActivity(intent);
- }
- }
- });
-
+ contactPhoto.setAvatar(recipient, true);
contactPhoto.setVisibility(View.VISIBLE);
}
diff --git a/src/org/thoughtcrime/securesms/ConversationListItem.java b/src/org/thoughtcrime/securesms/ConversationListItem.java
index daf867c42c..ff3b9664a8 100644
--- a/src/org/thoughtcrime/securesms/ConversationListItem.java
+++ b/src/org/thoughtcrime/securesms/ConversationListItem.java
@@ -22,16 +22,16 @@ import android.graphics.Typeface;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
-import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import org.thoughtcrime.securesms.components.AvatarImageView;
+import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.Emoji;
-import org.thoughtcrime.securesms.util.RecipientViewUtil;
import java.util.Locale;
import java.util.Set;
@@ -53,15 +53,15 @@ public class ConversationListItem extends RelativeLayout
private final static Typeface BOLD_TYPEFACE = Typeface.create("sans-serif", Typeface.BOLD);
private final static Typeface LIGHT_TYPEFACE = Typeface.create("sans-serif-light", Typeface.NORMAL);
- private Context context;
- private Set selectedThreads;
- private Recipients recipients;
- private long threadId;
- private TextView subjectView;
- private TextView fromView;
- private TextView dateView;
- private boolean read;
- private ImageView contactPhotoImage;
+ private Context context;
+ private Set selectedThreads;
+ private Recipients recipients;
+ private long threadId;
+ private TextView subjectView;
+ private FromTextView fromView;
+ private TextView dateView;
+ private boolean read;
+ private AvatarImageView contactPhotoImage;
private final Handler handler = new Handler();
private int distributionType;
@@ -79,10 +79,9 @@ public class ConversationListItem extends RelativeLayout
@Override
protected void onFinishInflate() {
this.subjectView = (TextView) findViewById(R.id.subject);
- this.fromView = (TextView) findViewById(R.id.from);
+ this.fromView = (FromTextView) findViewById(R.id.from);
this.dateView = (TextView) findViewById(R.id.date);
-
- this.contactPhotoImage = (ImageView) findViewById(R.id.contact_photo_image);
+ this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
initializeContactWidgetVisibility();
}
@@ -95,7 +94,7 @@ public class ConversationListItem extends RelativeLayout
this.distributionType = thread.getDistributionType();
this.recipients.addListener(this);
- this.fromView.setText(RecipientViewUtil.formatFrom(context, recipients, read));
+ this.fromView.setText(recipients, read);
this.subjectView.setText(Emoji.getInstance(context).emojify(thread.getDisplayBody(),
Emoji.EMOJI_SMALL,
@@ -110,7 +109,7 @@ public class ConversationListItem extends RelativeLayout
}
setBackground(read, batchMode);
- RecipientViewUtil.setContactPhoto(context, contactPhotoImage, recipients.getPrimaryRecipient(), true);
+ this.contactPhotoImage.setAvatar(recipients.getPrimaryRecipient(), true);
}
public void unbind() {
@@ -157,8 +156,8 @@ public class ConversationListItem extends RelativeLayout
handler.post(new Runnable() {
@Override
public void run() {
- ConversationListItem.this.fromView.setText(RecipientViewUtil.formatFrom(context, recipients, read));
- RecipientViewUtil.setContactPhoto(context, contactPhotoImage, recipients.getPrimaryRecipient(), true);
+ fromView.setText(recipients, read);
+ contactPhotoImage.setAvatar(recipients.getPrimaryRecipient(), true);
}
});
}
diff --git a/src/org/thoughtcrime/securesms/MessageRecipientListItem.java b/src/org/thoughtcrime/securesms/MessageRecipientListItem.java
index 06547fe982..c3c81741f2 100644
--- a/src/org/thoughtcrime/securesms/MessageRecipientListItem.java
+++ b/src/org/thoughtcrime/securesms/MessageRecipientListItem.java
@@ -23,10 +23,11 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
-import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import org.thoughtcrime.securesms.components.AvatarImageView;
+import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsDatabase;
@@ -35,7 +36,6 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.MessageSender;
-import org.thoughtcrime.securesms.util.RecipientViewUtil;
/**
* A simple view to show the recipients of a message
@@ -47,12 +47,12 @@ public class MessageRecipientListItem extends RelativeLayout
{
private final static String TAG = MessageRecipientListItem.class.getSimpleName();
- private Recipient recipient;
- private TextView fromView;
- private TextView errorDescription;
- private Button conflictButton;
- private Button resendButton;
- private ImageView contactPhotoImage;
+ private Recipient recipient;
+ private FromTextView fromView;
+ private TextView errorDescription;
+ private Button conflictButton;
+ private Button resendButton;
+ private AvatarImageView contactPhotoImage;
private final Handler handler = new Handler();
@@ -66,11 +66,11 @@ public class MessageRecipientListItem extends RelativeLayout
@Override
protected void onFinishInflate() {
- this.fromView = (TextView) findViewById(R.id.from);
- this.errorDescription = (TextView) findViewById(R.id.error_description);
- this.contactPhotoImage = (ImageView) findViewById(R.id.contact_photo_image);
- this.conflictButton = (Button) findViewById(R.id.conflict_button);
- this.resendButton = (Button) findViewById(R.id.resend_button);
+ this.fromView = (FromTextView) findViewById(R.id.from);
+ this.errorDescription = (TextView) findViewById(R.id.error_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);
}
public void set(final MasterSecret masterSecret,
@@ -81,9 +81,8 @@ public class MessageRecipientListItem extends RelativeLayout
this.recipient = recipient;
recipient.addListener(this);
- fromView.setText(RecipientViewUtil.formatFrom(getContext(), recipient));
-
- RecipientViewUtil.setContactPhoto(getContext(), contactPhotoImage, recipient, false);
+ fromView.setText(recipient);
+ contactPhotoImage.setAvatar(recipient, false);
setIssueIndicators(masterSecret, record, isPushGroup);
}
@@ -160,8 +159,8 @@ public class MessageRecipientListItem extends RelativeLayout
handler.post(new Runnable() {
@Override
public void run() {
- fromView.setText(RecipientViewUtil.formatFrom(getContext(), recipient));
- RecipientViewUtil.setContactPhoto(getContext(), contactPhotoImage, recipient, false);
+ fromView.setText(recipient);
+ contactPhotoImage.setAvatar(recipient, false);
}
});
}
diff --git a/src/org/thoughtcrime/securesms/ShareListItem.java b/src/org/thoughtcrime/securesms/ShareListItem.java
index aa8769520f..0a739c6e15 100644
--- a/src/org/thoughtcrime/securesms/ShareListItem.java
+++ b/src/org/thoughtcrime/securesms/ShareListItem.java
@@ -20,17 +20,13 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.util.AttributeSet;
-import android.view.View;
-import android.widget.ImageView;
import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import com.makeramen.RoundedImageView;
+import org.thoughtcrime.securesms.components.AvatarImageView;
+import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients;
-import org.thoughtcrime.securesms.util.RecipientViewUtil;
/**
* A simple view to show the recipients of an open conversation
@@ -42,12 +38,12 @@ public class ShareListItem extends RelativeLayout
{
private final static String TAG = ShareListItem.class.getSimpleName();
- private Context context;
- private Recipients recipients;
- private long threadId;
- private TextView fromView;
+ private Context context;
+ private Recipients recipients;
+ private long threadId;
+ private FromTextView fromView;
- private RoundedImageView contactPhotoImage;
+ private AvatarImageView contactPhotoImage;
private final Handler handler = new Handler();
private int distributionType;
@@ -64,8 +60,8 @@ public class ShareListItem extends RelativeLayout
@Override
protected void onFinishInflate() {
- this.fromView = (TextView) findViewById(R.id.from);
- this.contactPhotoImage = (RoundedImageView) findViewById(R.id.contact_photo_image);
+ this.fromView = (FromTextView) findViewById(R.id.from);
+ this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
}
public void set(ThreadRecord thread) {
@@ -74,10 +70,10 @@ public class ShareListItem extends RelativeLayout
this.distributionType = thread.getDistributionType();
this.recipients.addListener(this);
- this.fromView.setText(RecipientViewUtil.formatFrom(getContext(), recipients));
+ this.fromView.setText(recipients);
setBackground();
- RecipientViewUtil.setContactPhoto(getContext(), contactPhotoImage, this.recipients.getPrimaryRecipient(), false);
+ this.contactPhotoImage.setAvatar(this.recipients.getPrimaryRecipient(), false);
}
public void unbind() {
@@ -110,8 +106,8 @@ public class ShareListItem extends RelativeLayout
handler.post(new Runnable() {
@Override
public void run() {
- fromView.setText(RecipientViewUtil.formatFrom(getContext(), recipients));
- RecipientViewUtil.setContactPhoto(getContext(), contactPhotoImage, recipients.getPrimaryRecipient(), false);
+ fromView.setText(recipients);
+ contactPhotoImage.setAvatar(recipients.getPrimaryRecipient(), false);
}
});
}
diff --git a/src/org/thoughtcrime/securesms/components/AvatarImageView.java b/src/org/thoughtcrime/securesms/components/AvatarImageView.java
new file mode 100644
index 0000000000..90bb807a62
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/components/AvatarImageView.java
@@ -0,0 +1,49 @@
+package org.thoughtcrime.securesms.components;
+
+import android.content.Context;
+import android.content.Intent;
+import android.provider.ContactsContract;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+
+import org.thoughtcrime.securesms.recipients.Recipient;
+
+public class AvatarImageView extends ImageView {
+
+ public AvatarImageView(Context context) {
+ super(context);
+ setScaleType(ScaleType.CENTER_INSIDE);
+ }
+
+ public AvatarImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setScaleType(ScaleType.CENTER_INSIDE);
+ }
+
+ public void setAvatar(Recipient recipient, boolean quickContactEnabled) {
+ setImageDrawable(recipient.getContactPhoto());
+ setAvatarClickHandler(recipient, quickContactEnabled);
+ }
+
+ private void setAvatarClickHandler(final Recipient recipient, boolean quickContactEnabled) {
+ if (!recipient.isGroupRecipient() && quickContactEnabled) {
+ setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (recipient.getContactUri() != null) {
+ ContactsContract.QuickContact.showQuickContact(getContext(), AvatarImageView.this, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
+ } else {
+ final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
+ intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getNumber());
+ intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
+ getContext().startActivity(intent);
+ }
+ }
+ });
+ } else {
+ setOnClickListener(null);
+ }
+ }
+
+}
diff --git a/src/org/thoughtcrime/securesms/components/FromTextView.java b/src/org/thoughtcrime/securesms/components/FromTextView.java
new file mode 100644
index 0000000000..225fbfb12e
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/components/FromTextView.java
@@ -0,0 +1,69 @@
+package org.thoughtcrime.securesms.components;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Typeface;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.style.StyleSpan;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import org.thoughtcrime.securesms.R;
+import org.thoughtcrime.securesms.recipients.Recipient;
+import org.thoughtcrime.securesms.recipients.Recipients;
+
+public class FromTextView extends TextView {
+
+ public FromTextView(Context context) {
+ super(context);
+ }
+
+ public FromTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setText(Recipient recipient) {
+ setText(new Recipients(recipient));
+ }
+
+ public void setText(Recipients recipients) {
+ setText(recipients, true);
+ }
+
+ public void setText(Recipients recipients, boolean read) {
+ int attributes[] = new int[]{R.attr.conversation_list_item_count_color};
+ TypedArray colors = getContext().obtainStyledAttributes(attributes);
+ boolean isUnnamedGroup = recipients.isGroupRecipient() && TextUtils.isEmpty(recipients.getPrimaryRecipient().getName());
+
+ String fromString;
+
+ if (isUnnamedGroup) {
+ fromString = getContext().getString(R.string.ConversationActivity_unnamed_group);
+ } else {
+ fromString = recipients.toShortString();
+ }
+
+ int typeface;
+
+ if (isUnnamedGroup) {
+ if (!read) typeface = Typeface.BOLD_ITALIC;
+ else typeface = Typeface.ITALIC;
+ } else if (!read) {
+ typeface = Typeface.BOLD;
+ } else {
+ typeface = Typeface.NORMAL;
+ }
+
+ SpannableStringBuilder builder = new SpannableStringBuilder(fromString);
+ builder.setSpan(new StyleSpan(typeface), 0, builder.length(),
+ Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+
+ colors.recycle();
+
+ setText(builder);
+ }
+
+
+}
diff --git a/src/org/thoughtcrime/securesms/contacts/ContactPhotoFactory.java b/src/org/thoughtcrime/securesms/contacts/ContactPhotoFactory.java
index 1ea3606023..37cee29e76 100644
--- a/src/org/thoughtcrime/securesms/contacts/ContactPhotoFactory.java
+++ b/src/org/thoughtcrime/securesms/contacts/ContactPhotoFactory.java
@@ -1,15 +1,31 @@
package org.thoughtcrime.securesms.contacts;
import android.content.Context;
-import android.database.Cursor;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.provider.ContactsContract;
-import android.provider.ContactsContract.Contacts;
+import android.support.annotation.Nullable;
import android.util.Log;
+import android.view.Gravity;
+import android.widget.ImageView;
+
+import com.amulyakhare.textdrawable.TextDrawable;
+import com.amulyakhare.textdrawable.util.ColorGenerator;
+import com.makeramen.RoundedDrawable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.Recipient;
@@ -24,62 +40,56 @@ import java.util.Map;
public class ContactPhotoFactory {
private static final String TAG = ContactPhotoFactory.class.getSimpleName();
+ private static final ColorGenerator COLOR_GENERATOR = ColorGenerator.MATERIAL;
+ private static final int UNKNOWN_COLOR = 0xff9E9E9E;
+
private static final Object defaultPhotoLock = new Object();
private static final Object defaultGroupPhotoLock = new Object();
+ private static final Object loadingPhotoLock = new Object();
- private static Bitmap defaultContactPhoto;
- private static Bitmap defaultGroupContactPhoto;
+ private static Drawable defaultContactPhoto;
+ private static Drawable defaultGroupContactPhoto;
+ private static Drawable loadingPhoto;
private static final Map localUserContactPhotoCache =
Collections.synchronizedMap(new LRUCache(2));
- private static final String[] CONTENT_URI_PROJECTION = new String[] {
- ContactsContract.Contacts._ID,
- ContactsContract.Contacts.DISPLAY_NAME,
- ContactsContract.Contacts.LOOKUP_KEY
- };
+ public static Drawable getLoadingPhoto(Context context) {
+ synchronized (loadingPhotoLock) {
+ if (loadingPhoto == null)
+ loadingPhoto = RoundedDrawable.fromDrawable(context.getResources().getDrawable(android.R.color.transparent));
+
+ return loadingPhoto;
+ }
+ }
+
+ public static Drawable getDefaultContactPhoto(@Nullable String name) {
+ if (name != null && !name.isEmpty()) {
+ return TextDrawable.builder().buildRound(String.valueOf(name.charAt(0)),
+ COLOR_GENERATOR.getColor(name));
+ }
- public static Bitmap getDefaultContactPhoto(Context context) {
synchronized (defaultPhotoLock) {
if (defaultContactPhoto == null)
- defaultContactPhoto = BitmapFactory.decodeResource(context.getResources(),
- R.drawable.ic_contact_picture);
+ defaultContactPhoto = TextDrawable.builder().buildRound("#", UNKNOWN_COLOR);
+
return defaultContactPhoto;
}
}
- public static Bitmap getDefaultGroupPhoto(Context context) {
+ public static Drawable getDefaultGroupPhoto(Context context) {
synchronized (defaultGroupPhotoLock) {
- if (defaultGroupContactPhoto == null)
- defaultGroupContactPhoto = BitmapFactory.decodeResource(context.getResources(),
- R.drawable.ic_group_photo);
- return defaultGroupContactPhoto;
- }
- }
+ if (defaultGroupContactPhoto == null) {
+ Drawable background = TextDrawable.builder().buildRound(" ", UNKNOWN_COLOR);
+ RoundedDrawable foreground = (RoundedDrawable) RoundedDrawable.fromDrawable(context.getResources().getDrawable(R.drawable.ic_group_white_24dp));
+ foreground.setScaleType(ImageView.ScaleType.CENTER);
- public static Bitmap getLocalUserContactPhoto(Context context, Uri uri) {
- if (uri == null) return getDefaultContactPhoto(context);
- Bitmap contactPhoto = localUserContactPhotoCache.get(uri);
-
- if (contactPhoto == null) {
- Cursor cursor = context.getContentResolver().query(uri, CONTENT_URI_PROJECTION,
- null, null, null);
- try {
- if (cursor != null && cursor.moveToFirst()) {
- contactPhoto = getContactPhoto(context, Uri.withAppendedPath(Contacts.CONTENT_URI,
- cursor.getLong(0) + ""));
- } else {
- contactPhoto = getDefaultContactPhoto(context);
- }
- } finally {
- if (cursor != null) cursor.close();
+ defaultGroupContactPhoto = new ExpandingLayerDrawable(new Drawable[] {background, foreground});
}
- localUserContactPhotoCache.put(uri, contactPhoto);
+ return defaultGroupContactPhoto;
}
-
- return contactPhoto;
}
public static void clearCache() {
@@ -91,25 +101,32 @@ public class ContactPhotoFactory {
localUserContactPhotoCache.remove(recipient.getContactUri());
}
- public static Bitmap getContactPhoto(Context context, Uri uri) {
+ public static Drawable getContactPhoto(Context context, Uri uri, String name) {
final InputStream inputStream = getContactPhotoStream(context, uri);
final int targetSize = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size);
- Bitmap contactPhoto = null;
+
if (inputStream != null) {
try {
- contactPhoto = BitmapUtil.createScaledBitmap(inputStream,
- getContactPhotoStream(context, uri),
- targetSize,
- targetSize);
+ return RoundedDrawable.fromBitmap(BitmapUtil.createScaledBitmap(inputStream,
+ getContactPhotoStream(context, uri),
+ targetSize,
+ targetSize))
+ .setScaleType(ImageView.ScaleType.CENTER_CROP)
+ .setOval(true);
} catch (BitmapDecodingException bde) {
Log.w(TAG, bde);
}
}
- if (contactPhoto == null) {
- contactPhoto = ContactPhotoFactory.getDefaultContactPhoto(context);
- }
- return contactPhoto;
+ return getDefaultContactPhoto(name);
+ }
+
+ public static Drawable getGroupContactPhoto(Context context, @Nullable byte[] avatar) {
+ if (avatar == null) return getDefaultGroupPhoto(context);
+
+ return RoundedDrawable.fromBitmap(BitmapFactory.decodeByteArray(avatar, 0, avatar.length))
+ .setScaleType(ImageView.ScaleType.CENTER_CROP)
+ .setOval(true);
}
private static InputStream getContactPhotoStream(Context context, Uri uri) {
@@ -119,4 +136,21 @@ public class ContactPhotoFactory {
return ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri);
}
}
+
+ private static class ExpandingLayerDrawable extends LayerDrawable {
+
+ public ExpandingLayerDrawable(Drawable[] layers) {
+ super(layers);
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return -1;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return -1;
+ }
+ }
}
diff --git a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java
index 95e1d7f9e9..fe14322be4 100644
--- a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java
+++ b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListAdapter.java
@@ -19,7 +19,6 @@ package org.thoughtcrime.securesms.contacts;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.Cursor;
-import android.graphics.Bitmap;
import android.provider.ContactsContract;
import android.support.v4.widget.CursorAdapter;
import android.text.Spannable;
@@ -73,7 +72,6 @@ public class ContactSelectionListAdapter extends CursorAdapter
private final boolean multiSelect;
private final LayoutInflater li;
private final TypedArray drawables;
- private final Bitmap defaultPhoto;
private final int scaledPhotoSize;
private final HashMap selectedContacts = new HashMap<>();
@@ -84,7 +82,6 @@ public class ContactSelectionListAdapter extends CursorAdapter
this.li = LayoutInflater.from(context);
this.drawables = context.obtainStyledAttributes(STYLE_ATTRIBUTES);
this.multiSelect = multiSelect;
- this.defaultPhoto = ContactPhotoFactory.getDefaultContactPhoto(context);
this.scaledPhotoSize = context.getResources().getDimensionPixelSize(R.dimen.contact_selection_photo_size);
}
@@ -180,7 +177,7 @@ public class ContactSelectionListAdapter extends CursorAdapter
numberLabelSpan.setSpan(new ForegroundColorSpan(drawables.getColor(2, 0xff444444)), contactData.number.length(), numberWithLabel.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
holder.number.setText(numberLabelSpan);
}
- holder.contactPhoto.setImageBitmap(defaultPhoto);
+ holder.contactPhoto.setImageDrawable(ContactPhotoFactory.getLoadingPhoto(context));
if (contactData.id > -1) loadBitmap(contactData.number, holder.contactPhoto);
}
@@ -229,11 +226,14 @@ public class ContactSelectionListAdapter extends CursorAdapter
return true;
}
+ // FIXME -- It should be unnecessary to duplicate the existing asynchronous resolution
+ // infrastructure we've built for Recipient objects here.
+
public void loadBitmap(String number, ImageView imageView) {
if (cancelPotentialWork(number, imageView)) {
- final BitmapWorkerRunnable runnable = new BitmapWorkerRunnable(context, imageView, defaultPhoto, number, scaledPhotoSize);
+ final BitmapWorkerRunnable runnable = new BitmapWorkerRunnable(context, imageView, number, scaledPhotoSize);
final TaggedFutureTask> task = new TaggedFutureTask(runnable, null, number);
- final AsyncDrawable asyncDrawable = new AsyncDrawable(defaultPhoto, task);
+ final AsyncDrawable asyncDrawable = new AsyncDrawable(task);
imageView.setImageDrawable(asyncDrawable);
if (!task.isCancelled()) photoResolver.execute(new FutureTask(task, null));
diff --git a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java
index 6a7123f494..6ac1e0a8e4 100644
--- a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java
+++ b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
import android.util.Log;
import org.thoughtcrime.securesms.Release;
@@ -74,7 +75,7 @@ public class AvatarDownloadJob extends MasterSecretJob {
Recipient groupRecipient = RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(groupId), true)
.getPrimaryRecipient();
- groupRecipient.setContactPhoto(avatar);
+ groupRecipient.setContactPhoto(new BitmapDrawable(avatar));
}
} catch (InvalidMessageException | BitmapDecodingException | NonSuccessfulResponseCodeException e) {
Log.w(TAG, e);
diff --git a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java
index 12af949543..12b92c084d 100644
--- a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java
+++ b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java
@@ -24,9 +24,9 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
-import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
+import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
@@ -181,9 +181,9 @@ public class MessageNotifier {
List notifications = notificationState.getNotifications();
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
Recipient recipient = notifications.get(0).getIndividualRecipient();
- Bitmap recipientPhoto = recipient.getContactPhoto();
+ Drawable recipientPhoto = recipient.getContactPhoto();
- if (recipientPhoto != null) builder.setLargeIcon(BitmapUtil.getCircleBitmap(recipientPhoto));
+ if (recipientPhoto != null) builder.setLargeIcon(BitmapUtil.createFromDrawable(recipientPhoto));
builder.setSmallIcon(R.drawable.icon_notification);
builder.setColor(context.getResources().getColor(R.color.textsecure_primary));
builder.setContentTitle(recipient.toShortString());
diff --git a/src/org/thoughtcrime/securesms/recipients/AvatarGenerator.java b/src/org/thoughtcrime/securesms/recipients/AvatarGenerator.java
deleted file mode 100644
index 142f238613..0000000000
--- a/src/org/thoughtcrime/securesms/recipients/AvatarGenerator.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package org.thoughtcrime.securesms.recipients;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-
-import org.thoughtcrime.securesms.R;
-import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
-import org.thoughtcrime.securesms.util.BitmapUtil;
-
-/**
- * Utility class to generate avatars for contacts who don't have a contact
- * picture set.
- *
- * @author Lukas Barth
- */
-public class AvatarGenerator {
-
- public static Bitmap generateFor(Context context, Recipient recipient) {
- if ((recipient == null) || (recipient.getName() == null)) {
- return ContactPhotoFactory.getDefaultContactPhoto(context);
- }
-
- final int size = ContactPhotoFactory.getDefaultContactPhoto(context).getHeight();
- final Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(output);
- final int color = getColorForRecipient(recipient, context);
- final Paint paint = new Paint();
- final int innerRectOffset = (int) Math.ceil((size - Math.sqrt(2) * (size / 2)) / 2);
- final Rect innerRect = new Rect(innerRectOffset, innerRectOffset,
- size - innerRectOffset, size - innerRectOffset);
-
- paint.setAntiAlias(true);
- paint.setColor(color);
- canvas.drawCircle(size / 2, size / 2, size / 2, paint);
-
- paint.setColor(Color.WHITE);
- Typeface robotoLightTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Light.ttf");
- paint.setTypeface(robotoLightTypeface);
- setFontSize(innerRect, paint);
-
- paint.setTextAlign(Paint.Align.CENTER);
-
- int initialIndex = 0;
- char[] contactName = recipient.getName().toCharArray();
-
- if (contactName.length == 0) {
- contactName = new char[]{'?'};
- initialIndex = 0;
- } else {
- while ((! Character.isLetter(contactName[initialIndex]))) {
- initialIndex ++;
-
- if (initialIndex >= contactName.length) {
- contactName[0] = '?';
- initialIndex = 0;
- break;
- }
- }
- }
-
- Rect textBounds = new Rect();
- paint.getTextBounds(contactName, initialIndex, 1, textBounds);
-
- int bottomOffset = (innerRect.height() - textBounds.height()) / 2;
-
- canvas.drawText(Character.toString(contactName[initialIndex]),
- innerRect.centerX(), innerRect.bottom - bottomOffset, paint);
-
- return output;
- }
-
-
- private static int getColorForRecipient(Recipient recipient, Context context) {
- if ((recipient == null) || (recipient.getName() == null)) {
- return Color.WHITE;
- }
-
- long nameHash = recipient.getName().hashCode();
- Resources res = context.getResources();
- TypedArray colorArray = res.obtainTypedArray(R.array.avatar_colors);
- int index = Math.abs((int) (nameHash % colorArray.length()));
- int color = colorArray.getColor(index, Color.BLACK);
-
- colorArray.recycle();
-
- return color;
- }
-
- private static int setFontSize(Rect textRect, Paint paint) {
- boolean overflow = false;
- int currentSize = 0;
-
- while (!overflow) {
- currentSize++;
- paint.setTextSize(currentSize);
-
- Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
- int textHeight = fontMetrics.descent - fontMetrics.ascent;
-
- if (textHeight > textRect.height()) {
- overflow = true;
- }
- }
-
- currentSize--;
-
- currentSize *= 1.2;
-
- paint.setTextSize(currentSize);
-
- return currentSize;
- }
-}
diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java
index cde6e9c262..c14cdc862f 100644
--- a/src/org/thoughtcrime/securesms/recipients/Recipient.java
+++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java
@@ -18,13 +18,14 @@ package org.thoughtcrime.securesms.recipients;
import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.Log;
import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
-import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.FutureTaskListener;
+import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import java.util.HashSet;
@@ -33,25 +34,22 @@ public class Recipient {
private final static String TAG = Recipient.class.getSimpleName();
- private final HashSet listeners = new HashSet();
+ private final HashSet listeners = new HashSet<>();
private final long recipientId;
private String number;
private String name;
- private Bitmap contactPhoto;
- private Bitmap generatedAvatar;
+ private Drawable contactPhoto;
+ private Uri contactUri;
- private Uri contactUri;
-
- Recipient(String number, Bitmap contactPhoto,
+ Recipient(String number, Drawable contactPhoto,
long recipientId, ListenableFutureTask future)
{
this.number = number;
this.contactPhoto = contactPhoto;
this.recipientId = recipientId;
- this.generatedAvatar = null;
future.addListener(new FutureTaskListener() {
@Override
@@ -81,7 +79,7 @@ public class Recipient {
});
}
- Recipient(String name, String number, long recipientId, Uri contactUri, Bitmap contactPhoto) {
+ Recipient(String name, String number, long recipientId, Uri contactUri, Drawable contactPhoto) {
this.number = number;
this.recipientId = recipientId;
this.contactUri = contactUri;
@@ -93,7 +91,7 @@ public class Recipient {
return this.contactUri;
}
- public synchronized void setContactPhoto(Bitmap bitmap) {
+ public synchronized void setContactPhoto(Drawable bitmap) {
this.contactPhoto = bitmap;
notifyListeners();
}
@@ -143,20 +141,13 @@ public class Recipient {
return (name == null ? number : name);
}
- public synchronized Bitmap getContactPhoto() {
+ public synchronized Drawable getContactPhoto() {
return contactPhoto;
}
- public synchronized Bitmap getGeneratedAvatar(Context context) {
- if (this.generatedAvatar == null)
- this.generatedAvatar = AvatarGenerator.generateFor(context, this);
-
- return this.generatedAvatar;
- }
-
public static Recipient getUnknownRecipient(Context context) {
return new Recipient("Unknown", "Unknown", -1, null,
- ContactPhotoFactory.getDefaultContactPhoto(context));
+ ContactPhotoFactory.getDefaultContactPhoto(null));
}
@Override
@@ -174,7 +165,7 @@ public class Recipient {
return 31 + (int)this.recipientId;
}
- public static interface RecipientModifiedListener {
+ public interface RecipientModifiedListener {
public void onModified(Recipient recipient);
}
}
diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java
index a0a941221e..39c3a44e4e 100644
--- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java
+++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java
@@ -18,8 +18,7 @@ package org.thoughtcrime.securesms.recipients;
import android.content.Context;
import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.PhoneLookup;
@@ -29,11 +28,10 @@ import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.CanonicalAddressDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
-import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.thoughtcrime.securesms.util.LRUCache;
-import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
+import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
import java.util.Collections;
@@ -75,9 +73,9 @@ public class RecipientProvider {
if (details != null) {
recipient = new Recipient(details.name, details.number, recipientId, details.contactUri, details.avatar);
} else {
- final Bitmap defaultPhoto = isGroupRecipient
+ final Drawable defaultPhoto = isGroupRecipient
? ContactPhotoFactory.getDefaultGroupPhoto(context)
- : ContactPhotoFactory.getDefaultContactPhoto(context);
+ : ContactPhotoFactory.getDefaultContactPhoto(null);
recipient = new Recipient(null, number, recipientId, null, defaultPhoto);
}
@@ -100,16 +98,16 @@ public class RecipientProvider {
}
};
- ListenableFutureTask future = new ListenableFutureTask(task);
+ ListenableFutureTask future = new ListenableFutureTask<>(task);
asyncRecipientResolver.submit(future);
- Bitmap contactPhoto;
+ Drawable contactPhoto;
if (isGroupRecipient) {
contactPhoto = ContactPhotoFactory.getDefaultGroupPhoto(context);
} else {
- contactPhoto = ContactPhotoFactory.getDefaultContactPhoto(context);
+ contactPhoto = ContactPhotoFactory.getLoadingPhoto(context);
}
Recipient recipient = new Recipient(number, contactPhoto, recipientId, future);
@@ -134,9 +132,10 @@ public class RecipientProvider {
try {
if (cursor != null && cursor.moveToFirst()) {
- Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1));
- Bitmap contactPhoto = ContactPhotoFactory.getContactPhoto(context, Uri.withAppendedPath(Contacts.CONTENT_URI,
- cursor.getLong(2)+""));
+ Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1));
+ Drawable contactPhoto = ContactPhotoFactory.getContactPhoto(context,
+ Uri.withAppendedPath(Contacts.CONTENT_URI, cursor.getLong(2)+""),
+ cursor.getString(0));
return new RecipientDetails(cursor.getString(0), cursor.getString(3), contactUri, contactPhoto);
}
} finally {
@@ -144,7 +143,7 @@ public class RecipientProvider {
cursor.close();
}
- return null;
+ return new RecipientDetails(null, number, null, ContactPhotoFactory.getDefaultContactPhoto(null));
}
private RecipientDetails getGroupRecipientDetails(Context context, String groupId) {
@@ -153,12 +152,7 @@ public class RecipientProvider {
.getGroup(GroupUtil.getDecodedId(groupId));
if (record != null) {
- byte[] avatarBytes = record.getAvatar();
- Bitmap avatar;
-
- if (avatarBytes == null) avatar = ContactPhotoFactory.getDefaultGroupPhoto(context);
- else avatar = BitmapFactory.decodeByteArray(avatarBytes, 0, avatarBytes.length);
-
+ Drawable avatar = ContactPhotoFactory.getGroupContactPhoto(context, record.getAvatar());
return new RecipientDetails(record.getTitle(), groupId, null, avatar);
}
@@ -170,12 +164,12 @@ public class RecipientProvider {
}
public static class RecipientDetails {
- public final String name;
- public final String number;
- public final Bitmap avatar;
- public final Uri contactUri;
+ public final String name;
+ public final String number;
+ public final Drawable avatar;
+ public final Uri contactUri;
- public RecipientDetails(String name, String number, Uri contactUri, Bitmap avatar) {
+ public RecipientDetails(String name, String number, Uri contactUri, Drawable avatar) {
this.name = name;
this.number = number;
this.avatar = avatar;
@@ -183,4 +177,5 @@ public class RecipientProvider {
}
}
+
}
\ No newline at end of file
diff --git a/src/org/thoughtcrime/securesms/util/BitmapUtil.java b/src/org/thoughtcrime/securesms/util/BitmapUtil.java
index 0b189f6ef3..3b7b8a091b 100644
--- a/src/org/thoughtcrime/securesms/util/BitmapUtil.java
+++ b/src/org/thoughtcrime/securesms/util/BitmapUtil.java
@@ -12,6 +12,8 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.Log;
import android.util.Pair;
@@ -253,4 +255,23 @@ public class BitmapUtil {
return output;
}
+ public static Bitmap createFromDrawable(Drawable drawable) {
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable)drawable).getBitmap();
+ }
+
+ int width = drawable.getIntrinsicWidth();
+ width = width > 0 ? width : 1;
+
+ int height = drawable.getIntrinsicHeight();
+ height = height > 0 ? height : 1;
+
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+
+ return bitmap;
+ }
+
}
diff --git a/src/org/thoughtcrime/securesms/util/BitmapWorkerRunnable.java b/src/org/thoughtcrime/securesms/util/BitmapWorkerRunnable.java
index ef45bfdf40..1018050a73 100644
--- a/src/org/thoughtcrime/securesms/util/BitmapWorkerRunnable.java
+++ b/src/org/thoughtcrime/securesms/util/BitmapWorkerRunnable.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
import android.widget.ImageView;
import com.makeramen.RoundedDrawable;
@@ -38,49 +39,42 @@ import java.lang.ref.WeakReference;
public class BitmapWorkerRunnable implements Runnable {
private final static String TAG = BitmapWorkerRunnable.class.getSimpleName();
- private final Bitmap defaultPhoto;
-
private final WeakReference imageViewReference;
private final Context context;
private final int size;
public final String number;
- public BitmapWorkerRunnable(Context context, ImageView imageView, Bitmap defaultPhoto, String number, int size) {
+ public BitmapWorkerRunnable(Context context, ImageView imageView, String number, int size) {
this.imageViewReference = new WeakReference<>(imageView);
this.context = context;
- this.defaultPhoto = defaultPhoto;
this.size = size;
this.number = number;
}
@Override
public void run() {
- final Recipient recipient = RecipientFactory.getRecipientsFromString(context, number, false).getPrimaryRecipient();
- final Bitmap contactPhoto = recipient.getContactPhoto();
- if (defaultPhoto == contactPhoto) {
- return;
- }
- if (recipient.getContactPhoto() != null) {
+ final Recipient recipient = RecipientFactory.getRecipientsFromString(context, number, false).getPrimaryRecipient();
+ final Drawable contactPhoto = recipient.getContactPhoto();
+
+ if (contactPhoto != null) {
final ImageView imageView = imageViewReference.get();
final TaggedFutureTask> bitmapWorkerTask = AsyncDrawable.getBitmapWorkerTask(imageView);
if (bitmapWorkerTask.getTag().equals(number) && imageView != null) {
- final BitmapDrawable drawable = new BitmapDrawable(context.getResources(), recipient.getContactPhoto());
imageView.post(new Runnable() {
@Override
public void run() {
- imageView.setImageDrawable(drawable);
+ imageView.setImageDrawable(contactPhoto);
}
});
}
}
}
- public static class AsyncDrawable extends RoundedDrawable {
+ public static class AsyncDrawable extends BitmapDrawable {
private final WeakReference> bitmapWorkerTaskReference;
- public AsyncDrawable(Bitmap bitmap, TaggedFutureTask> bitmapWorkerTask) {
- super(bitmap);
+ public AsyncDrawable(TaggedFutureTask> bitmapWorkerTask) {
bitmapWorkerTaskReference =
new WeakReference>(bitmapWorkerTask);
}
diff --git a/src/org/thoughtcrime/securesms/util/RecipientViewUtil.java b/src/org/thoughtcrime/securesms/util/RecipientViewUtil.java
deleted file mode 100644
index 3660a8ed08..0000000000
--- a/src/org/thoughtcrime/securesms/util/RecipientViewUtil.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package org.thoughtcrime.securesms.util;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.TypedArray;
-import android.graphics.Typeface;
-import android.net.Uri;
-import android.provider.Contacts.Intents;
-import android.provider.ContactsContract.QuickContact;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.TextUtils;
-import android.text.style.StyleSpan;
-import android.view.View;
-import android.widget.ImageView;
-
-import org.thoughtcrime.securesms.R;
-import org.thoughtcrime.securesms.recipients.Recipient;
-import org.thoughtcrime.securesms.recipients.Recipients;
-
-public class RecipientViewUtil {
- public static CharSequence formatFrom(Context context, Recipient recipient) {
- return formatFrom(context, new Recipients(recipient));
- }
-
- public static CharSequence formatFrom(Context context, Recipients from) {
- return formatFrom(context, from, true);
- }
-
- public static CharSequence formatFrom(Context context, Recipients from, boolean read) {
- int attributes[] = new int[] {R.attr.conversation_list_item_count_color};
- TypedArray colors = context.obtainStyledAttributes(attributes);
-
- final String fromString;
- final boolean isUnnamedGroup = from.isGroupRecipient() && TextUtils.isEmpty(from.getPrimaryRecipient().getName());
- if (isUnnamedGroup) {
- fromString = context.getString(R.string.ConversationActivity_unnamed_group);
- } else {
- fromString = from.toShortString();
- }
- SpannableStringBuilder builder = new SpannableStringBuilder(fromString);
-
- final int typeface;
- if (isUnnamedGroup) {
- if (!read) typeface = Typeface.BOLD_ITALIC;
- else typeface = Typeface.ITALIC;
- } else if (!read) {
- typeface = Typeface.BOLD;
- } else {
- typeface = Typeface.NORMAL;
- }
-
- builder.setSpan(new StyleSpan(typeface), 0, builder.length(),
- Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
-
-
- colors.recycle();
- return builder;
- }
-
- public static void setContactPhoto(final Context context, final ImageView imageView, final Recipient recipient, boolean showQuickContact) {
- if (recipient == null) return;
-
- imageView.setImageBitmap(recipient.getContactPhoto());
-
- if (!recipient.isGroupRecipient() && showQuickContact) {
- imageView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (recipient.getContactUri() != null) {
- QuickContact.showQuickContact(context, imageView, recipient.getContactUri(), QuickContact.MODE_LARGE, null);
- } else {
- Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, Uri.fromParts("tel", recipient.getNumber(), null));
- context.startActivity(intent);
- }
- }
- });
- } else {
- imageView.setOnClickListener(null);
- }
- }
-
-}