diff --git a/assets/fonts/Roboto-Light.ttf b/assets/fonts/Roboto-Light.ttf
new file mode 100644
index 0000000000..13bf13af00
Binary files /dev/null and b/assets/fonts/Roboto-Light.ttf differ
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index b8b25120a3..c9de19381a 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -39,6 +39,20 @@
- Ukrainian Український
+
+ - #6dcaec
+ - #cf9fe7
+ - #b6db49
+ - #ffd060
+ - #ff7979
+
+ - #2cb1e1
+ - #c182e0
+ - #92c500
+ - #ffb61c
+ - #f83a3a
+
+
- zz
- en
diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java
index fbb007f9cc..6db7dd0f54 100644
--- a/src/org/thoughtcrime/securesms/ConversationItem.java
+++ b/src/org/thoughtcrime/securesms/ConversationItem.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
@@ -40,6 +41,7 @@ import android.widget.Toast;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
+import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
@@ -405,7 +407,15 @@ public class ConversationItem extends LinearLayout {
private void setContactPhotoForRecipient(final Recipient recipient) {
if (contactPhoto == null) return;
- contactPhoto.setImageBitmap(recipient.getCircleCroppedContactPhoto());
+ Bitmap contactPhotoBitmap;
+
+ if ((recipient.getContactPhoto() == ContactPhotoFactory.getDefaultContactPhoto(context)) && (groupThread)) {
+ contactPhotoBitmap = recipient.getGeneratedAvatar(context);
+ } else {
+ contactPhotoBitmap = recipient.getCircleCroppedContactPhoto();
+ }
+
+ contactPhoto.setImageBitmap(contactPhotoBitmap);
contactPhoto.setOnClickListener(new View.OnClickListener() {
@Override
diff --git a/src/org/thoughtcrime/securesms/recipients/AvatarGenerator.java b/src/org/thoughtcrime/securesms/recipients/AvatarGenerator.java
new file mode 100644
index 0000000000..188514435c
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/recipients/AvatarGenerator.java
@@ -0,0 +1,120 @@
+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 BitmapUtil.getCircleCroppedBitmap(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 9efb4b70ef..b4a1160fc8 100644
--- a/src/org/thoughtcrime/securesms/recipients/Recipient.java
+++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java
@@ -54,6 +54,7 @@ public class Recipient implements Parcelable {
private Bitmap contactPhoto;
private Bitmap circleCroppedContactPhoto;
+ private Bitmap generatedAvatar;
private Uri contactUri;
@@ -64,6 +65,7 @@ public class Recipient implements Parcelable {
this.circleCroppedContactPhoto = circleCroppedContactPhoto;
this.contactPhoto = contactPhoto;
this.recipientId = recipientId;
+ this.generatedAvatar = null;
future.addListener(new FutureTaskListener() {
@Override
@@ -187,6 +189,13 @@ public class Recipient implements Parcelable {
return this.circleCroppedContactPhoto;
}
+ 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),