contact: improve default contact picture

Change-Id: I02aaa6715995e2344a9227c2e3c3f70b74f5101f
diff --git a/ring-android/app/build.gradle b/ring-android/app/build.gradle
index 10349b4..8f74fe8 100644
--- a/ring-android/app/build.gradle
+++ b/ring-android/app/build.gradle
@@ -109,7 +109,8 @@
     compileOnly 'javax.annotation:jsr250-api:1.0'
 
     // Glide
-    implementation 'com.github.bumptech.glide:glide:3.8.0'
+    implementation 'com.github.bumptech.glide:glide:4.6.1'
+    annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'
 
     // RxAndroid
     implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
diff --git a/ring-android/app/proguard-rules.pro b/ring-android/app/proguard-rules.pro
index 9a5b12b..4df0287 100644
--- a/ring-android/app/proguard-rules.pro
+++ b/ring-android/app/proguard-rules.pro
@@ -9,7 +9,7 @@
 -keep,includedescriptorclasses class cx.ring.** { *; }
 -keepclassmembers class cx.ring.** { *; }
 
-#OrmLite uses reflection
+# ORMLite
 -keep class com.j256.**
 -keepclassmembers class com.j256.** { *; }
 -keep enum com.j256.**
@@ -17,22 +17,21 @@
 -keep interface com.j256.**
 -keepclassmembers interface com.j256.** { *; }
 
-# Keep the helper class and its constructor
 -keep class * extends com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper
 
-# Keep all model classes that are used by OrmLite
-# Also keep their field names and the constructor
 -keep @com.j256.ormlite.table.DatabaseTable class * {
     @com.j256.ormlite.field.DatabaseField <fields>;
     @com.j256.ormlite.field.ForeignCollectionField <fields>;
     <init>();
 }
 
--dontwarn ezvcard.io.json.JCardModule
+# other
 -dontwarn com.fasterxml.jackson.**
 -dontwarn org.jsoup.**
 -dontwarn freemarker.**
 
+# EZVcard
+-dontwarn ezvcard.io.json.JCardModule
 -keep,includedescriptorclasses class ezvcard.io.json.JCardModule { *; }
 -keepclassmembers class ezvcard.io.json.JCardModule { *; }
 -keep,includedescriptorclasses enum ezvcard.io.json.JCardModule { *; }
@@ -40,12 +39,15 @@
 -keep,includedescriptorclasses interface ezvcard.io.json.JCardModule { *; }
 -keepclassmembers interface ezvcard.io.json.JCardModule { *; }
 
+# barcodescanner
 -keep,includedescriptorclasses class com.journeyapps.barcodescanner.** { *; }
 -keepclassmembers class com.journeyapps.barcodescanner.** { *; }
 
+# stickylistheaders
 -keep,includedescriptorclasses class se.emilsjolander.stickylistheaders.** { *; }
 -keepclassmembers class se.emilsjolander.stickylistheaders.** { *; }
 
+# Butterknife
 -keep class butterknife.** { *; }
 -dontwarn butterknife.**
 -dontwarn butterknife.internal.**
@@ -55,4 +57,12 @@
 }
 -keepclasseswithmembernames class * {
     @butterknife.* <methods>;
+}
+
+# Glide
+-keep public class * implements com.bumptech.glide.module.GlideModule
+-keep public class * extends com.bumptech.glide.module.AppGlideModule
+-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
+  **[] $VALUES;
+  public *;
 }
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java b/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java
index 8750e2f..d27c1bd 100644
--- a/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java
@@ -110,7 +110,7 @@
 
         if (mPhotoView.getDrawable() == null) {
             if (mSourcePhoto == null) {
-                mSourcePhoto = BitmapFactory.decodeResource(getActivity().getResources(), R.drawable.ic_contact_picture);
+                mSourcePhoto = BitmapFactory.decodeResource(getActivity().getResources(), R.drawable.ic_contact_picture_fallback);
             }
             mPhotoView.setImageBitmap(BitmapUtils.cropImageToCircle(mSourcePhoto));
         }
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/ContactDetailsTask.java b/ring-android/app/src/main/java/cx/ring/adapters/ContactDetailsTask.java
index a78b8b0..aa372b9 100644
--- a/ring-android/app/src/main/java/cx/ring/adapters/ContactDetailsTask.java
+++ b/ring-android/app/src/main/java/cx/ring/adapters/ContactDetailsTask.java
@@ -219,14 +219,14 @@
             }
 
             if (photoBmp == null) {
-                photoBmp = decodeSampledBitmapFromResource(mContext.getResources(), R.drawable.ic_contact_picture, mViewWidth, mViewHeight);
+                photoBmp = decodeSampledBitmapFromResource(mContext.getResources(), R.drawable.ic_contact_picture_fallback, mViewWidth, mViewHeight);
             }
 
             mContact.setPhoto(BitmapUtils.bitmapToBytes(photoBmp));
             externalBMP = BitmapUtils.cropImageToCircle(photoBmp);
             photoBmp.recycle();
         } else {
-            externalBMP = decodeSampledBitmapFromResource(mContext.getResources(), R.drawable.ic_contact_picture, mViewWidth, mViewHeight);
+            externalBMP = decodeSampledBitmapFromResource(mContext.getResources(), R.drawable.ic_contact_picture_fallback, mViewWidth, mViewHeight);
         }
 
         synchronized (mCallbacks) {
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java
index 487bdee..4d34721 100644
--- a/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.java
@@ -21,6 +21,7 @@
 package cx.ring.adapters;
 
 import android.content.Context;
+import android.graphics.drawable.Drawable;
 import android.content.Intent;
 import android.os.Build;
 import android.support.annotation.Nullable;
@@ -32,7 +33,6 @@
 import android.view.ViewGroup;
 
 import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
 
 import java.io.File;
 import java.text.DateFormat;
@@ -40,8 +40,10 @@
 import java.util.Date;
 
 import cx.ring.R;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.conversation.ConversationPresenter;
 import cx.ring.fragments.ConversationFragment;
+import cx.ring.model.CallContact;
 import cx.ring.model.DataTransferEventCode;
 import cx.ring.model.HistoryCall;
 import cx.ring.model.DataTransfer;
@@ -261,10 +263,16 @@
             return;
         }
 
-        TextMessage ht = (TextMessage) convElement;
+        TextMessage textMessage = (TextMessage) convElement;
 
-        convViewHolder.mCid = ht.getContact().getId();
-        String message = ht.getMessage().trim();
+        CallContact contact = textMessage.getContact();
+        if (contact == null) {
+            Log.e(TAG, "Invalid contact, not able to display message correctly");
+            return;
+        }
+
+        convViewHolder.mCid = textMessage.getContact().getId();
+        String message = textMessage.getMessage().trim();
         if (isOnlyEmoticons(message)) {
             convViewHolder.mMsgTxt.getBackground().setAlpha(0);
             convViewHolder.mMsgTxt.setTextSize(24.f);
@@ -280,30 +288,30 @@
             convViewHolder.mPhoto.setImageBitmap(null);
         }
 
-        boolean shouldSeparateByDetails = this.shouldSeparateByDetails(ht, position);
-        boolean isConfigSameAsPreviousMsg = this.isMessageConfigSameAsPrevious(ht, position);
+        boolean shouldSeparateByDetails = this.shouldSeparateByDetails(textMessage, position);
+        boolean isConfigSameAsPreviousMsg = this.isMessageConfigSameAsPrevious(textMessage, position);
 
-        if (ht.isIncoming() && !isConfigSameAsPreviousMsg) {
+        if (textMessage.isIncoming() && !isConfigSameAsPreviousMsg) {
+            Drawable contactPicture = AvatarFactory.getAvatar(
+                    convViewHolder.itemView.getContext(),
+                    mPhoto,
+                    contact.getUsername(),
+                    textMessage.getNumberUri().getHost());
+
             Glide.with(convViewHolder.itemView.getContext())
-                    .fromBytes()
-                    .diskCacheStrategy(DiskCacheStrategy.ALL)
-                    .skipMemoryCache(false)
-                    .load(mPhoto)
-                    .crossFade()
-                    .placeholder(R.drawable.ic_contact_picture)
-                    .transform(new CircleTransform(convViewHolder.itemView.getContext()))
-                    .error(R.drawable.ic_contact_picture)
+                    .load(contactPicture)
+                    .apply(AvatarFactory.getGlideOptions(true, true))
                     .into(convViewHolder.mPhoto);
         }
 
-        if (ht.getStatus() == TextMessage.Status.SENDING) {
+        if (textMessage.getStatus() == TextMessage.Status.SENDING) {
             convViewHolder.mMsgDetailTxt.setVisibility(View.VISIBLE);
             convViewHolder.mMsgDetailTxt.setText(R.string.message_sending);
         } else if (shouldSeparateByDetails) {
             convViewHolder.mMsgDetailTxt.setVisibility(View.VISIBLE);
             String timeSeparationString = computeTimeSeparationStringFromMsgTimeStamp(
                     convViewHolder.itemView.getContext(),
-                    ht.getDate());
+                    textMessage.getDate());
             convViewHolder.mMsgDetailTxt.setText(timeSeparationString);
         } else {
             convViewHolder.mMsgDetailTxt.setVisibility(View.GONE);
@@ -441,8 +449,8 @@
      * Helper method determining if a given conversationElement should be distinguished from the
      * previous ie. if their configuration is not the same.
      *
-     * @param textMessage       The conversationElement at the given position
-     * @param position The position of the current message
+     * @param textMessage The conversationElement at the given position
+     * @param position    The position of the current message
      * @return true if the configuration is the same as the previous message, false otherwise.
      */
     private boolean isMessageConfigSameAsPrevious(final TextMessage textMessage,
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/SmartListAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/SmartListAdapter.java
index 72e914d..a9f6765 100644
--- a/ring-android/app/src/main/java/cx/ring/adapters/SmartListAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/adapters/SmartListAdapter.java
@@ -21,6 +21,7 @@
 
 import android.content.Context;
 import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
 import android.support.v7.util.DiffUtil;
 import android.support.v7.widget.RecyclerView;
 import android.text.format.DateUtils;
@@ -29,15 +30,13 @@
 import android.view.ViewGroup;
 
 import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import com.bumptech.glide.signature.StringSignature;
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 
 import cx.ring.R;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.smartlist.SmartListViewModel;
-import cx.ring.utils.CircleTransform;
 import cx.ring.viewholders.SmartListViewHolder;
 
 public class SmartListAdapter extends RecyclerView.Adapter<SmartListViewHolder> {
@@ -89,26 +88,17 @@
             holder.convStatus.setTypeface(null, Typeface.NORMAL);
         }
 
-        if (smartListViewModel.getPhotoData() != null) {
-            Glide.with(holder.itemView.getContext())
-                    .fromBytes()
-                    .diskCacheStrategy(DiskCacheStrategy.NONE)
-                    .skipMemoryCache(false)
-                    .load(smartListViewModel.getPhotoData())
-                    .crossFade()
-                    .signature(new StringSignature(String.valueOf(Arrays.hashCode(smartListViewModel.getPhotoData()))))
-                    .placeholder(R.drawable.ic_contact_picture)
-                    .transform(new CircleTransform(holder.itemView.getContext()))
-                    .error(R.drawable.ic_contact_picture)
-                    .into(holder.photo);
-        } else {
-            Glide.with(holder.itemView.getContext())
-                    .load(R.drawable.ic_contact_picture)
-                    .crossFade()
-                    .signature(new StringSignature(smartListViewModel.getUuid()))
-                    .diskCacheStrategy(DiskCacheStrategy.ALL)
-                    .into(holder.photo);
-        }
+        Drawable contactPicture = AvatarFactory.getAvatar(
+                holder.itemView.getContext(),
+                smartListViewModel.getPhotoData(),
+                smartListViewModel.getContactName(),
+                smartListViewModel.getUuid());
+
+        Glide.with(holder.itemView.getContext())
+                .load(contactPicture)
+                .apply(AvatarFactory.getGlideOptions(true, true))
+                .transition(DrawableTransitionOptions.withCrossFade())
+                .into(holder.photo);
 
         holder.online.setVisibility(smartListViewModel.isOnline() ? View.VISIBLE : View.GONE);
 
@@ -129,7 +119,6 @@
         diffResult.dispatchUpdatesTo(this);
     }
 
-
     private String getLastInteractionSummary(int type, String lastInteraction, Context context) {
         switch (type) {
             case SmartListViewModel.TYPE_INCOMING_CALL:
diff --git a/ring-android/app/src/main/java/cx/ring/contactrequests/BlackListViewHolder.java b/ring-android/app/src/main/java/cx/ring/contactrequests/BlackListViewHolder.java
index 95105ce..d59a66d 100644
--- a/ring-android/app/src/main/java/cx/ring/contactrequests/BlackListViewHolder.java
+++ b/ring-android/app/src/main/java/cx/ring/contactrequests/BlackListViewHolder.java
@@ -19,6 +19,7 @@
  */
 package cx.ring.contactrequests;
 
+import android.graphics.drawable.Drawable;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
 import android.widget.ImageButton;
@@ -26,12 +27,13 @@
 import android.widget.TextView;
 
 import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
 
 import butterknife.BindView;
 import butterknife.ButterKnife;
 import cx.ring.R;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.model.CallContact;
-import cx.ring.utils.CircleTransform;
 
 public class BlackListViewHolder extends RecyclerView.ViewHolder {
     @BindView(R.id.unblock)
@@ -51,19 +53,18 @@
 
     public void bind(final BlackListListeners clickListener, final CallContact contact) {
         byte[] photo = contact.getPhoto();
-        if (photo != null && photo.length > 0) {
-            Glide.with(itemView.getContext())
-                    .load(photo)
-                    .placeholder(R.drawable.ic_contact_picture)
-                    .crossFade()
-                    .transform(new CircleTransform(itemView.getContext()))
-                    .error(R.drawable.ic_contact_picture)
-                    .into(mPhoto);
-        } else {
-            Glide.with(itemView.getContext())
-                    .load(R.drawable.ic_contact_picture)
-                    .into(mPhoto);
-        }
+
+        Drawable contactPicture = AvatarFactory.getAvatar(
+                itemView.getContext(),
+                photo,
+                contact.getUsername(),
+                contact.getPhones().get(0).getNumber().getHost());
+
+        Glide.with(itemView.getContext())
+                .load(contactPicture)
+                .apply(AvatarFactory.getGlideOptions(true, true))
+                .transition(DrawableTransitionOptions.withCrossFade())
+                .into(mPhoto);
 
         mDisplayname.setText(contact.getRingUsername());
 
diff --git a/ring-android/app/src/main/java/cx/ring/contactrequests/ContactRequestsAdapter.java b/ring-android/app/src/main/java/cx/ring/contactrequests/ContactRequestsAdapter.java
index 6f9d538..da4bb7e 100644
--- a/ring-android/app/src/main/java/cx/ring/contactrequests/ContactRequestsAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/contactrequests/ContactRequestsAdapter.java
@@ -18,6 +18,7 @@
  */
 package cx.ring.contactrequests;
 
+import android.graphics.drawable.Drawable;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
@@ -25,11 +26,12 @@
 import android.view.ViewGroup;
 
 import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
 
 import java.util.ArrayList;
 
 import cx.ring.R;
-import cx.ring.utils.CircleTransform;
+import cx.ring.contacts.AvatarFactory;
 import ezvcard.VCard;
 
 public class ContactRequestsAdapter extends RecyclerView.Adapter<ContactRequestViewHolder> {
@@ -60,26 +62,24 @@
     public void onBindViewHolder(ContactRequestViewHolder holder, int position) {
         final PendingContactRequestsViewModel viewModel = mContactRequestsViewModels.get(position);
         VCard vcard = viewModel.getVCard();
-        if (vcard != null) {
-            if (!vcard.getPhotos().isEmpty()) {
-                Glide.with(holder.itemView.getContext())
-                        .load(vcard.getPhotos().get(0).getData())
-                        .placeholder(R.drawable.ic_contact_picture)
-                        .crossFade()
-                        .transform(new CircleTransform(holder.itemView.getContext()))
-                        .error(R.drawable.ic_contact_picture)
-                        .into(holder.mPhoto);
-            } else {
-                Glide.with(holder.itemView.getContext())
-                        .load(R.drawable.ic_contact_picture)
-                        .into(holder.mPhoto);
-            }
-        } else {
-            Glide.with(holder.itemView.getContext())
-                    .load(R.drawable.ic_contact_picture)
-                    .into(holder.mPhoto);
+
+        byte[] contactPhoto = null;
+        if (vcard != null && !vcard.getPhotos().isEmpty()) {
+            contactPhoto = vcard.getPhotos().get(0).getData();
         }
 
+        Drawable contactPicture = AvatarFactory.getAvatar(
+                holder.itemView.getContext(),
+                contactPhoto,
+                viewModel.getUsername(),
+                viewModel.getUuid());
+
+        Glide.with(holder.itemView.getContext())
+                .load(contactPicture)
+                .apply(AvatarFactory.getGlideOptions(true, true))
+                .transition(DrawableTransitionOptions.withCrossFade())
+                .into(holder.mPhoto);
+
         String fullname = viewModel.getFullname();
         String username = viewModel.getUsername();
         if (!TextUtils.isEmpty(fullname)) {
diff --git a/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java b/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java
new file mode 100644
index 0000000..ab1f94e
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2004-2018 Savoir-faire Linux Inc.
+ *
+ * Author: Pierre Duchemin <pierre.duchemin@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package cx.ring.contacts;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.v4.content.ContextCompat;
+import android.util.Log;
+
+import com.bumptech.glide.request.RequestOptions;
+
+import cx.ring.R;
+import cx.ring.model.Uri;
+import cx.ring.utils.CircleTransform;
+import cx.ring.utils.HashUtils;
+import ezvcard.VCard;
+
+public class AvatarFactory {
+
+    private static final String TAG = AvatarFactory.class.getSimpleName();
+
+    // ordered to have the same colors on all clients
+    private static final int[] contactColors = {
+            R.color.red_500, R.color.pink_500,
+            R.color.purple_500, R.color.deep_purple_500,
+            R.color.indigo_500, R.color.blue_500,
+            R.color.cyan_500, R.color.teal_500,
+            R.color.green_500, R.color.light_green_500,
+            R.color.grey_500, R.color.lime_500,
+            R.color.amber_500, R.color.deep_orange_500,
+            R.color.brown_500, R.color.blue_grey_500
+    };
+    private static final int DEFAULT_AVATAR_SIZE = 128;
+    private static final RequestOptions GLIDE_OPTIONS = new RequestOptions()
+            .centerCrop()
+            .error(R.drawable.ic_contact_picture_fallback);
+
+    private AvatarFactory() {
+    }
+
+    public static Drawable getAvatar(Context context, VCard vcard, String username, String ringId) {
+        return getAvatar(context, vcard, username, ringId, Float.valueOf(context.getResources().getDisplayMetrics().density * 128).intValue());
+    }
+
+    public static Drawable getAvatar(Context context, VCard vcard, String username, String ringId, int pictureSize) {
+        if (vcard == null || pictureSize <= 0) {
+            throw new IllegalArgumentException();
+        }
+
+        byte[] contactPhoto = null;
+        if (vcard.getPhotos() != null && !vcard.getPhotos().isEmpty()) {
+            contactPhoto = vcard.getPhotos().get(0).getData();
+        }
+
+        return getAvatar(context, contactPhoto, username, ringId, pictureSize);
+    }
+
+    public static Drawable getAvatar(Context context, byte[] photo, String username, String ringId) {
+        return getAvatar(context, photo, username, ringId, Float.valueOf(context.getResources().getDisplayMetrics().density * DEFAULT_AVATAR_SIZE).intValue());
+    }
+
+    public static Drawable getAvatar(Context context, byte[] photo, String username, String ringId, int pictureSize) {
+        if (context == null || pictureSize <= 0) {
+            throw new IllegalArgumentException();
+        }
+        Log.d(TAG, "getAvatar: username=" + username + ", ringid=" + ringId + ", pictureSize=" + pictureSize);
+
+        if (photo != null && photo.length > 0) {
+            return new BitmapDrawable(context.getResources(), BitmapFactory.decodeByteArray(photo, 0, photo.length));
+        }
+
+        Uri uriUsername = new Uri(username);
+        Uri uri = new Uri(ringId);
+        Character firstCharacter = getFirstCharacter(uriUsername.getRawRingId());
+        if (uri.isEmpty() || uriUsername.isRingId() || firstCharacter == null) {
+            return createDefaultAvatar(context, generateAvatarColor(uri.getRawUriString()), pictureSize);
+        }
+
+        return createLetterAvatar(context, firstCharacter, generateAvatarColor(uri.getRawUriString()), pictureSize);
+    }
+
+    private static Drawable createDefaultAvatar(Context context, int backgroundColor, int pictureSize) {
+        if (context == null || pictureSize <= 0) {
+            throw new IllegalArgumentException();
+        }
+
+        Drawable backgroundDrawable = new ColorDrawable(Color.TRANSPARENT);
+        Bitmap canvasBitmap = Bitmap.createBitmap(pictureSize, pictureSize, Bitmap.Config.ARGB_8888);
+
+        Canvas backgroundCanvas = new Canvas(canvasBitmap);
+        backgroundDrawable.draw(backgroundCanvas);
+        backgroundCanvas.drawColor(context.getResources().getColor(backgroundColor));
+
+        Canvas avatarCanvas = new Canvas(canvasBitmap);
+        Drawable drawable = ContextCompat.getDrawable(context, R.drawable.ic_contact_picture_box_default);
+        if (drawable == null) {
+            Log.e(TAG, "Not able to get default drawable");
+        } else {
+            drawable.setBounds(0, 0, pictureSize, pictureSize);
+            drawable.draw(avatarCanvas);
+        }
+
+        return new BitmapDrawable(context.getResources(), canvasBitmap);
+    }
+
+    private static Drawable createLetterAvatar(Context context, char firstCharacter, int backgroundColor, int pictureSize) {
+        if (context == null || pictureSize <= 0) {
+            throw new IllegalArgumentException();
+        }
+
+        Drawable backgroundDrawable = new ColorDrawable(Color.TRANSPARENT);
+        Bitmap canvasBitmap = Bitmap.createBitmap(pictureSize, pictureSize, Bitmap.Config.ARGB_8888);
+
+        Canvas backgroundCanvas = new Canvas(canvasBitmap);
+        backgroundDrawable.draw(backgroundCanvas);
+        backgroundCanvas.drawColor(context.getResources().getColor(backgroundColor));
+
+        Canvas letterCanvas = new Canvas(canvasBitmap);
+        Paint paint = new Paint();
+        paint.setTextAlign(Paint.Align.CENTER);
+        paint.setTextSize(pictureSize / 2);
+        paint.setColor(Color.WHITE);
+        paint.setAntiAlias(true);
+        letterCanvas.drawText(Character.toString(firstCharacter), pictureSize * 0.51f, pictureSize * 0.7f, paint);
+
+        return new BitmapDrawable(context.getResources(), canvasBitmap);
+    }
+
+    private static int generateAvatarColor(String ringId) {
+        if (ringId == null) {
+            return R.color.grey_500;
+        }
+
+        String md5 = HashUtils.md5(ringId);
+        if (md5 == null) {
+            return R.color.grey_500;
+        }
+        int colorIndex = Integer.parseInt(md5.charAt(0) + "", 16);
+        Log.d(TAG, "generateAvatarColor: ringid=" + ringId + ", index=" + colorIndex + ", md5=" + md5);
+        return contactColors[colorIndex % contactColors.length];
+    }
+
+    private static Character getFirstCharacter(String name) {
+        if (name == null) {
+            return null;
+        }
+        String filteredName = name.replaceAll("\\W+", "");
+        if (filteredName.isEmpty()) {
+            return null;
+        }
+        return Character.toUpperCase(name.charAt(0));
+    }
+
+    public static RequestOptions getGlideOptions(boolean circle, boolean withPlaceholder) {
+        RequestOptions glideOptions = GLIDE_OPTIONS;
+        if (circle) {
+            glideOptions = glideOptions.transform(new CircleTransform());
+        }
+        if (withPlaceholder) {
+            glideOptions = glideOptions.placeholder(R.drawable.ic_contact_picture_fallback);
+        }
+        return glideOptions;
+    }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
index b70fa2d..d98a9d46 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
@@ -28,6 +28,7 @@
 import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.hardware.display.DisplayManager;
 import android.os.Build;
@@ -51,6 +52,7 @@
 import android.widget.TextView;
 
 import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
 import com.skyfishjy.library.RippleBackground;
 
 import java.util.ArrayList;
@@ -64,6 +66,7 @@
 import cx.ring.call.CallView;
 import cx.ring.client.ConversationActivity;
 import cx.ring.client.HomeActivity;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.dependencyinjection.RingInjectionComponent;
 import cx.ring.model.CallContact;
 import cx.ring.model.SipCall;
@@ -72,9 +75,9 @@
 import cx.ring.services.HardwareServiceImpl;
 import cx.ring.services.NotificationService;
 import cx.ring.utils.ActionHelper;
-import cx.ring.utils.CircleTransform;
 import cx.ring.utils.DeviceUtils;
 import cx.ring.utils.KeyboardVisibilityManager;
+import cx.ring.utils.Log;
 import cx.ring.utils.MediaButtonsHelper;
 
 public class CallFragment extends BaseFragment<CallPresenter> implements CallView, MediaButtonsHelper.MediaButtonsHelperCallback {
@@ -468,22 +471,26 @@
 
     @Override
     public void updateContactBubble(@NonNull final CallContact contact) {
-        getActivity().runOnUiThread(() -> {
-            byte[] photo = contact.getPhoto();
-            if (photo != null && photo.length > 0) {
-                Glide.with(getActivity())
-                        .load(photo)
-                        .transform(new CircleTransform(getActivity()))
-                        .error(R.drawable.ic_contact_picture)
-                        .into(contactBubbleView);
-            } else {
-                Glide.with(getActivity())
-                        .load(R.drawable.ic_contact_picture)
-                        .into(contactBubbleView);
-            }
+        String username = contact.getRingUsername();
+        String displayName = contact.getDisplayName();
 
-            String username = contact.getRingUsername();
-            String displayName = contact.getDisplayName();
+        String ringId = contact.getIds().get(0);
+        Drawable contactPicture = AvatarFactory.getAvatar(
+                getActivity(),
+                contact.getPhoto(),
+                username,
+                ringId);
+
+        Log.d(TAG, "updateContactBubble: username=" + username + ", ringId=" + ringId);
+
+        RequestOptions glideOptions = AvatarFactory.getGlideOptions(true, false);
+
+        getActivity().runOnUiThread(() -> {
+            Glide.with(getActivity())
+                    .load(contactPicture)
+                    .apply(glideOptions)
+                    .into(contactBubbleView);
+
             boolean hasProfileName = displayName != null && !displayName.contentEquals(username);
             boolean firstShow = contactBubbleTxt.getText() != null && contactBubbleTxt.getText().length() > 0;
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java
index 6abbb79..af1254c 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java
@@ -22,6 +22,7 @@
 
 import android.app.Activity;
 import android.content.Intent;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -46,6 +47,8 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
 import com.google.zxing.integration.android.IntentIntegrator;
 import com.google.zxing.integration.android.IntentResult;
 
@@ -59,6 +62,7 @@
 import cx.ring.client.ConversationActivity;
 import cx.ring.client.HomeActivity;
 import cx.ring.client.QRCodeScannerActivity;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.dependencyinjection.RingInjectionComponent;
 import cx.ring.model.CallContact;
 import cx.ring.model.Conversation;
@@ -183,10 +187,11 @@
                 );
                 return false;
             case R.id.menu_contact_dial:
-                if (mSearchView.getInputType() == EditorInfo.TYPE_CLASS_PHONE)
+                if (mSearchView.getInputType() == EditorInfo.TYPE_CLASS_PHONE) {
                     mSearchView.setInputType(EditorInfo.TYPE_CLASS_TEXT);
-                else
+                } else {
                     mSearchView.setInputType(EditorInfo.TYPE_CLASS_PHONE);
+                }
                 return true;
             case R.id.menu_scan_qr:
                 presenter.clickQRSearch();
@@ -363,12 +368,29 @@
     }
 
     @Override
-    public void displayNewContactRowWithName(final String name) {
+    public void displayContact(final CallContact contact) {
         getActivity().runOnUiThread(() -> {
             if (mNewContact == null) {
                 return;
             }
-            ((TextView) mNewContact.findViewById(R.id.display_name)).setText(name);
+
+            TextView display_name = mNewContact.findViewById(R.id.display_name);
+            display_name.setText(contact.getRingUsername());
+
+            ImageView photo = mNewContact.findViewById(R.id.photo);
+
+            Drawable contactPicture = AvatarFactory.getAvatar(
+                    getActivity(),
+                    contact.getPhoto(),
+                    contact.getRingUsername(),
+                    contact.getIds().get(0));
+
+            Glide.with(getActivity())
+                    .load(contactPicture)
+                    .apply(AvatarFactory.getGlideOptions(true, false))
+                    .transition(DrawableTransitionOptions.withCrossFade())
+                    .into(photo);
+
             mNewContact.setVisibility(View.VISIBLE);
         });
     }
diff --git a/ring-android/app/src/main/java/cx/ring/navigation/AccountAdapter.java b/ring-android/app/src/main/java/cx/ring/navigation/AccountAdapter.java
index ac44057..a9373de 100644
--- a/ring-android/app/src/main/java/cx/ring/navigation/AccountAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/navigation/AccountAdapter.java
@@ -21,6 +21,7 @@
 
 import android.content.Context;
 import android.graphics.Color;
+import android.graphics.drawable.Drawable;
 import android.support.v7.widget.RecyclerView;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -30,6 +31,7 @@
 import android.widget.TextView;
 
 import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -37,8 +39,8 @@
 import butterknife.BindView;
 import butterknife.ButterKnife;
 import cx.ring.R;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.model.Account;
-import cx.ring.utils.CircleTransform;
 import cx.ring.utils.VCardUtils;
 import ezvcard.VCard;
 
@@ -175,25 +177,23 @@
         public void update(final Account account) {
             final Context context = itemView.getContext();
             VCard vcard = VCardUtils.loadLocalProfileFromDisk(context.getFilesDir(), account.getAccountID());
-            if (!vcard.getPhotos().isEmpty()) {
-                Glide.with(context)
-                        .load(vcard.getPhotos().get(0).getData())
-                        .placeholder(R.drawable.ic_contact_picture)
-                        .crossFade()
-                        .transform(new CircleTransform(context))
-                        .error(R.drawable.ic_contact_picture)
-                        .into(photo);
-            } else {
-                Glide.with(context)
-                        .load(R.drawable.ic_contact_picture)
-                        .into(photo);
-            }
+
+            Drawable accountPicture = AvatarFactory.getAvatar(context, vcard,
+                    account.getRegisteredName(),
+                    account.getUri());
+
+            Glide.with(context)
+                    .load(accountPicture)
+                    .apply(AvatarFactory.getGlideOptions(true, true))
+                    .transition(DrawableTransitionOptions.withCrossFade())
+                    .into(photo);
+
             alias.setText(mRingNavigationPresenter.getAccountAlias(account));
             host.setText(mRingNavigationPresenter.getUri(account, context.getText(R.string.account_type_ip2ip)));
             itemView.setEnabled(account.isEnabled());
             disabled_flag.setVisibility(account.isEnabled() ? View.GONE : View.VISIBLE);
             if (account.isEnabled()) {
-                this.alias.setTextColor(context.getResources().getColor(R.color.text_color_primary));
+                alias.setTextColor(context.getResources().getColor(R.color.text_color_primary));
                 if (!account.isActive()) {
                     error.setImageResource(R.drawable.ic_network_disconnect_black_24dp);
                     error.setColorFilter(Color.BLACK);
@@ -218,7 +218,7 @@
                     loading.setVisibility(View.GONE);
                 }
             } else {
-                this.alias.setTextColor(context.getResources().getColor(R.color.text_color_secondary));
+                alias.setTextColor(context.getResources().getColor(R.color.text_color_secondary));
                 error.setVisibility(View.GONE);
                 loading.setVisibility(View.GONE);
             }
diff --git a/ring-android/app/src/main/java/cx/ring/navigation/RingNavigationFragment.java b/ring-android/app/src/main/java/cx/ring/navigation/RingNavigationFragment.java
index 5a45ea8..9308a5f 100644
--- a/ring-android/app/src/main/java/cx/ring/navigation/RingNavigationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/navigation/RingNavigationFragment.java
@@ -23,7 +23,6 @@
 import android.app.AlertDialog;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Color;
 import android.net.Uri;
 import android.os.Bundle;
@@ -32,7 +31,6 @@
 import android.support.v4.content.res.ResourcesCompat;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -45,6 +43,8 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import com.bumptech.glide.Glide;
+
 import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
 
@@ -55,6 +55,7 @@
 import cx.ring.adapters.ContactDetailsTask;
 import cx.ring.application.RingApplication;
 import cx.ring.client.HomeActivity;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.dependencyinjection.RingInjectionComponent;
 import cx.ring.model.Account;
 import cx.ring.mvp.BaseFragment;
@@ -62,7 +63,6 @@
 import cx.ring.utils.VCardUtils;
 import ezvcard.VCard;
 import ezvcard.parameter.ImageType;
-import ezvcard.property.FormattedName;
 import ezvcard.property.Photo;
 
 public class RingNavigationFragment extends BaseFragment<RingNavigationPresenter> implements NavigationAdapter.OnNavigationItemClicked,
@@ -235,29 +235,18 @@
         }
     }
 
-    public void updateUserView(VCard vcard) {
+    public void updateUserView(final VCard vcard, final Account account) {
         if (getActivity() == null || vcard == null) {
+            Log.e(TAG, "Not able to update navigation view");
             return;
         }
 
-        if (vcard != null && !vcard.getPhotos().isEmpty()) {
-            Photo tmp = vcard.getPhotos().get(0);
-            Bitmap bitmap = BitmapFactory.decodeByteArray(tmp.getData(), 0, tmp.getData().length);
-            mUserImage.setImageBitmap(BitmapUtils.cropImageToCircle(bitmap));
-        } else {
-            mUserImage.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_contact_picture, null));
-        }
-
-        if (vcard != null) {
-            FormattedName name = vcard.getFormattedName();
-            if (name != null) {
-                String name_value = name.getValue();
-                if (!TextUtils.isEmpty(name_value)) {
-                    mSelectedAccountAlias.setText(name_value);
-                }
-            }
-        }
-        Log.d(TAG, "updateUserView: User did change, updating user view.");
+        String username = account.getRegisteredName();
+        String ringId = account.getUri();
+        Glide.with(getActivity())
+                .load(AvatarFactory.getAvatar(getActivity(), vcard, username, ringId))
+                .apply(AvatarFactory.getGlideOptions(true, true))
+                .into(mUserImage);
     }
 
     public void updatePhoto(Uri uriImage) {
@@ -324,7 +313,7 @@
         builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
 
             ByteArrayOutputStream stream = new ByteArrayOutputStream();
-            if (mSourcePhoto != null && mProfilePhoto.getDrawable() != ResourcesCompat.getDrawable(getResources(), R.drawable.ic_contact_picture, null)) {
+            if (mSourcePhoto != null && mProfilePhoto.getDrawable() != ResourcesCompat.getDrawable(getResources(), R.drawable.ic_contact_picture_fallback, null)) {
                 //FIXME: Reduce the bitmap but not use it.
                 BitmapUtils.reduceBitmap(mSourcePhoto, VCardUtils.VCARD_PHOTO_SIZE);
                 mSourcePhoto.compress(Bitmap.CompressFormat.PNG, 100, stream);
@@ -383,7 +372,7 @@
     public void showViewModel(final RingNavigationViewModel viewModel) {
         RingApplication.uiHandler.post(() -> {
             mAccountAdapter.replaceAll(viewModel.getAccounts());
-            updateUserView(viewModel.getVcard(getActivity().getFilesDir()));
+            updateUserView(viewModel.getVcard(getActivity().getFilesDir()), viewModel.getAccount());
             updateSelectedAccountView(viewModel.getAccount());
 
             if (viewModel.getAccounts().isEmpty()) {
diff --git a/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.java b/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.java
index beda427..7eeb5af 100644
--- a/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.java
+++ b/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.java
@@ -26,9 +26,9 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
 import android.media.AudioAttributes;
 import android.media.RingtoneManager;
 import android.os.Build;
@@ -54,7 +54,7 @@
 import cx.ring.R;
 import cx.ring.client.HomeActivity;
 import cx.ring.contactrequests.ContactRequestsFragment;
-import cx.ring.facades.ConversationFacade;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.fragments.ConversationFragment;
 import cx.ring.model.Account;
 import cx.ring.model.CallContact;
@@ -72,6 +72,7 @@
 import cx.ring.utils.Log;
 import cx.ring.utils.Observable;
 import cx.ring.utils.Observer;
+import ezvcard.VCard;
 import ezvcard.property.Photo;
 
 public class NotificationServiceImpl extends NotificationService implements Observer<ServiceEvent> {
@@ -156,7 +157,7 @@
 
     @Override
     public void showCallNotification(Conference conference) {
-        if (conference.getParticipants().isEmpty()) {
+        if (conference == null || conference.getParticipants().isEmpty() || !(conference.isOnGoing() || conference.isRinging())) {
             return;
         }
 
@@ -214,23 +215,13 @@
                                                 .putExtra(KEY_CALL_ID, call.getCallId()),
                                         PendingIntent.FLAG_ONE_SHOT));
             }
-        } else {
-            return;
         }
 
         messageNotificationBuilder.setOngoing(true)
                 .setCategory(NotificationCompat.CATEGORY_CALL)
                 .setSmallIcon(R.drawable.ic_ring_logo_white);
 
-        if (contact.getPhoto() != null) {
-            Resources res = mContext.getResources();
-            int height = (int) res.getDimension(android.R.dimen.notification_large_icon_height);
-            int width = (int) res.getDimension(android.R.dimen.notification_large_icon_width);
-            Bitmap bmp = BitmapUtils.bytesToBitmap(contact.getPhoto());
-            if (bmp != null) {
-                messageNotificationBuilder.setLargeIcon(Bitmap.createScaledBitmap(bmp, width, height, false));
-            }
-        }
+        setContactPicture(contact, messageNotificationBuilder);
 
         messageNotificationBuilder.setColor(ResourcesCompat.getColor(mContext.getResources(),
                 R.color.color_primary_dark, null));
@@ -270,16 +261,8 @@
                 .setAutoCancel(true)
                 .setColor(ResourcesCompat.getColor(mContext.getResources(), R.color.color_primary_dark, null));
 
-        if (contact.getPhoto() != null) {
-            Resources res = mContext.getResources();
-            int height = (int) res.getDimension(android.R.dimen.notification_large_icon_height);
-            int width = (int) res.getDimension(android.R.dimen.notification_large_icon_width);
+        setContactPicture(contact, messageNotificationBuilder);
 
-            Bitmap bmp = BitmapUtils.bytesToBitmap(contact.getPhoto());
-            if (bmp != null) {
-                messageNotificationBuilder.setLargeIcon(Bitmap.createScaledBitmap(bmp, width, height, false));
-            }
-        }
         if (texts.size() == 1) {
             last.setNotified(true);
             messageNotificationBuilder.setStyle(null);
@@ -350,20 +333,15 @@
                                             .setClass(mContext, DRingService.class)
                                             .putExtras(info),
                                     PendingIntent.FLAG_ONE_SHOT));
-            Resources res = mContext.getResources();
-            int height = (int) res.getDimension(android.R.dimen.notification_large_icon_height);
-            int width = (int) res.getDimension(android.R.dimen.notification_large_icon_width);
-            List<Photo> photos = request.getVCard().getPhotos();
+
+
+            VCard vCard = request.getVCard();
+            List<Photo> photos = vCard.getPhotos();
+            byte[] data = null;
             if (photos != null && !photos.isEmpty()) {
-                Photo photo = photos.get(0);
-                messageNotificationBuilder.setLargeIcon(BitmapUtils.bytesToBitmap(photo.getData()));
-            } else {
-                Bitmap bmp;
-                bmp = BitmapFactory.decodeResource(res, R.drawable.ic_contact_picture);
-                if (bmp != null) {
-                    messageNotificationBuilder.setLargeIcon(Bitmap.createScaledBitmap(bmp, width, height, false));
-                }
+                data = photos.get(0).getData();
             }
+            setContactPicture(data, request.getDisplayname(), request.getContactId(), messageNotificationBuilder);
         } else {
             messageNotificationBuilder.setContentText(String.format(mContext.getString(R.string.contact_request_msg), Integer.toString(requests.size())));
             messageNotificationBuilder.setLargeIcon(null);
@@ -517,6 +495,27 @@
         return (NOTIF_FILE_TRANSFER + dataTransferId).hashCode();
     }
 
+    private void setContactPicture(CallContact contact, NotificationCompat.Builder messageNotificationBuilder) {
+        setContactPicture(contact.getPhoto(), contact.getUsername(),
+                contact.getPhones().get(0).getNumber().getHost(), messageNotificationBuilder);
+    }
+
+    private void setContactPicture(byte[] photo, String username, String ringId, NotificationCompat.Builder messageNotificationBuilder) {
+        Drawable contactPicture = AvatarFactory.getAvatar(mContext, photo, username, ringId);
+
+        Bitmap contactBitmap = BitmapUtils.drawableToBitmap(contactPicture);
+        if (contactBitmap == null) {
+            Log.d(TAG, "showCallNotification: not able to generate contactBitmap");
+            return;
+        }
+        Bitmap circleBitmap = BitmapUtils.cropImageToCircle(contactBitmap);
+        if (circleBitmap == null) {
+            Log.d(TAG, "showCallNotification: not able to generate circleBitmap");
+            return;
+        }
+        messageNotificationBuilder.setLargeIcon(circleBitmap);
+    }
+
     @Override
     public void update(Observable observable, ServiceEvent event) {
         if (observable instanceof AccountService && event != null) {
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java
index efc794f..9b429c0 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java
@@ -35,6 +35,9 @@
 import android.support.v4.app.ActivityCompat;
 import android.view.View;
 
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
+
 import java.util.List;
 
 import cx.ring.R;
@@ -45,8 +48,10 @@
 import cx.ring.account.RingAccountViewModelImpl;
 import cx.ring.adapters.ContactDetailsTask;
 import cx.ring.application.RingApplication;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.mvp.RingAccountViewModel;
 import cx.ring.tv.camera.CustomCameraActivity;
+import cx.ring.utils.BitmapUtils;
 
 public class TVProfileCreationFragment extends RingGuidedStepFragment<ProfileCreationPresenter>
         implements ProfileCreationView {
@@ -59,6 +64,7 @@
     private static final int GALLERY = 2;
     private static final int CAMERA = 3;
     private static final int NEXT = 4;
+    private final int DEFAULT_SIZE = 256;
 
     private Bitmap mSourcePhoto;
 
@@ -110,7 +116,7 @@
         String title = getString(R.string.account_create_title);
         String breadcrumb = "";
         String description = getString(R.string.profile_message_warning);
-        Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_contact_picture);
+        Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_contact_picture_fallback);
         return new GuidanceStylist.Guidance(title, description, breadcrumb, icon);
     }
 
@@ -194,8 +200,14 @@
     @Override
     public void photoUpdate(RingAccountViewModel ringAccountViewModel) {
         ((RingAccountViewModelImpl) ringAccountViewModel).setPhoto(mSourcePhoto);
+
         RingAccountViewModelImpl model = (RingAccountViewModelImpl) ringAccountViewModel;
-        getGuidanceStylist().getIconView().setImageBitmap(model.getPhoto());
+
+        Glide.with(getActivity())
+                .load(model.getPhoto())
+                .apply(AvatarFactory.getGlideOptions(true, false))
+                .transition(DrawableTransitionOptions.withCrossFade())
+                .into(getGuidanceStylist().getIconView());
     }
 
     public long onGuidedActionEditedAndProceed(GuidedAction action) {
@@ -215,9 +227,7 @@
     }
 
     public void updatePhoto(Bitmap image) {
-        mSourcePhoto = image;
+        mSourcePhoto = BitmapUtils.createScaledBitmap(image, DEFAULT_SIZE);
         presenter.photoUpdated();
     }
-
-
 }
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.java
index 47cbad5..9b31ea3 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.java
@@ -36,6 +36,9 @@
 import android.util.Log;
 import android.view.View;
 
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
+
 import java.io.ByteArrayOutputStream;
 import java.util.List;
 
@@ -43,6 +46,8 @@
 import cx.ring.account.ProfileCreationFragment;
 import cx.ring.adapters.ContactDetailsTask;
 import cx.ring.application.RingApplication;
+import cx.ring.contacts.AvatarFactory;
+import cx.ring.model.Account;
 import cx.ring.navigation.RingNavigationPresenter;
 import cx.ring.navigation.RingNavigationView;
 import cx.ring.navigation.RingNavigationViewModel;
@@ -112,7 +117,7 @@
         String title = getString(R.string.profile);
         String breadcrumb = "";
         String description = getString(R.string.profile_message_warning);
-        Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_contact_picture);
+        Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_contact_picture_fallback);
         return new GuidanceStylist.Guidance(title, description, breadcrumb, icon);
     }
 
@@ -157,17 +162,32 @@
     public void showViewModel(RingNavigationViewModel viewModel) {
         // displays account available info
         VCard vcard = viewModel.getVcard(getActivity().getFilesDir());
-        if (vcard == null || vcard.getPhotos().isEmpty()) {
-            getGuidanceStylist().getIconView().setImageDrawable(getActivity().getResources().getDrawable(R.drawable.ic_contact_picture));
-        } else {
-            if (!this.actions.isEmpty() && this.actions.get(0).getId() == USER_NAME) {
-                this.actions.get(0).setEditDescription(vcard.getFormattedName().getValue());
-            }
-
-            Photo tmp = vcard.getPhotos().get(0);
-            Bitmap bitmap = BitmapFactory.decodeByteArray(tmp.getData(), 0, tmp.getData().length);
-            getGuidanceStylist().getIconView().setImageBitmap(bitmap);
+        Account account = viewModel.getAccount();
+        if (account == null) {
+            Log.e(TAG, "Not able to get current account");
+            return;
         }
+
+        if (!this.actions.isEmpty() && this.actions.get(0).getId() == USER_NAME) {
+            this.actions.get(0).setEditDescription(account.getAlias());
+        }
+
+        if (vcard == null || vcard.getPhotos().isEmpty()) {
+            getGuidanceStylist().getIconView().setImageDrawable(getActivity().getResources().getDrawable(R.drawable.ic_contact_picture_fallback));
+            return;
+        }
+
+        Drawable contactPicture = AvatarFactory.getAvatar(
+                getActivity(),
+                vcard.getPhotos().get(0).getData(),
+                account.getDisplayUsername(),
+                account.getUri());
+
+        Glide.with(getActivity())
+                .load(contactPicture)
+                .apply(AvatarFactory.getGlideOptions(true, false))
+                .transition(DrawableTransitionOptions.withCrossFade())
+                .into(getGuidanceStylist().getIconView());
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
index 0b22dfc..97af089 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
@@ -29,6 +29,9 @@
 import android.view.ViewGroup;
 import android.widget.EditText;
 
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
+
 import java.util.List;
 
 import cx.ring.R;
@@ -37,6 +40,7 @@
 import cx.ring.account.RingAccountCreationView;
 import cx.ring.account.RingAccountViewModelImpl;
 import cx.ring.application.RingApplication;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.mvp.RingAccountViewModel;
 import cx.ring.utils.Log;
 import cx.ring.utils.StringUtils;
@@ -93,11 +97,19 @@
         super.onViewCreated(view, savedInstanceState);
 
         RingAccountViewModelImpl ringAccountViewModel = getArguments().getParcelable(RingAccountCreationFragment.KEY_RING_ACCOUNT);
+        if (ringAccountViewModel == null) {
+            Log.e(TAG, "Not able to get model");
+            return;
+        }
+
         presenter.init(ringAccountViewModel);
         presenter.ringCheckChanged(false);
-        if (ringAccountViewModel.getPhoto() != null) {
-            getGuidanceStylist().getIconView().setImageBitmap(ringAccountViewModel.getPhoto());
-        }
+
+        Glide.with(getActivity())
+                .load(ringAccountViewModel.getPhoto())
+                .apply(AvatarFactory.getGlideOptions(true, false))
+                .transition(DrawableTransitionOptions.withCrossFade())
+                .into(getGuidanceStylist().getIconView());
     }
 
     @Override
@@ -107,7 +119,7 @@
         String breadcrumb = "";
         String description = getString(R.string.help_ring);
 
-        Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_contact_picture);
+        Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_contact_picture_fallback);
         return new GuidanceStylist.Guidance(title, description, breadcrumb, icon);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java
index 6da5112..7649563 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java
@@ -71,7 +71,7 @@
         String breadcrumb = "";
         String description = getString(R.string.help_password_enter) + "\n" + getString(R.string.help_pin_enter);
 
-        Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_contact_picture);
+        Drawable icon = getActivity().getResources().getDrawable(R.drawable.ic_contact_picture_fallback);
         return new GuidanceStylist.Guidance(title, description, breadcrumb, icon);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java
index f7c2cd3..78ee8f1 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java
@@ -21,6 +21,7 @@
 
 import android.content.Context;
 import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -28,6 +29,7 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
@@ -49,12 +51,12 @@
 import cx.ring.R;
 import cx.ring.call.CallPresenter;
 import cx.ring.call.CallView;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.dependencyinjection.RingInjectionComponent;
 import cx.ring.model.CallContact;
 import cx.ring.model.SipCall;
 import cx.ring.mvp.BaseFragment;
 import cx.ring.services.HardwareServiceImpl;
-import cx.ring.utils.CircleTransform;
 
 public class TVCallFragment extends BaseFragment<CallPresenter> implements CallView {
 
@@ -319,20 +321,21 @@
     @Override
     public void updateContactBubble(@NonNull final CallContact contact) {
         getActivity().runOnUiThread(() -> {
-            byte[] photo = contact.getPhoto();
-            if (photo != null && photo.length > 0) {
-                Glide.with(getActivity())
-                        .load(photo)
-                        .transform(new CircleTransform(getActivity()))
-                        .error(R.drawable.ic_contact_picture)
-                        .into(contactBubbleView);
-            } else {
-                Glide.with(getActivity())
-                        .load(R.drawable.ic_contact_picture)
-                        .into(contactBubbleView);
-            }
-
             String username = contact.getRingUsername();
+            String ringId = contact.getIds().get(0);
+
+            Log.d(TAG, "updateContactBubble: username=" + username + ", ringId=" + ringId);
+
+            Drawable contactPicture = AvatarFactory.getAvatar(getActivity(),
+                    contact.getPhoto(),
+                    username,
+                    ringId);
+
+            Glide.with(getActivity())
+                    .load(contactPicture)
+                    .apply(AvatarFactory.getGlideOptions(true, true))
+                    .into(contactBubbleView);
+
             String displayName = contact.getDisplayName();
             boolean hasProfileName = displayName != null && !displayName.contentEquals(username);
             boolean firstShow = contactBubbleTxt.getText() != null && contactBubbleTxt.getText().length() > 0;
diff --git a/ring-android/app/src/main/java/cx/ring/tv/cards/contactrequests/ContactRequestCardPresenter.java b/ring-android/app/src/main/java/cx/ring/tv/cards/contactrequests/ContactRequestCardPresenter.java
index dcf9dd6..fc8ae56 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/cards/contactrequests/ContactRequestCardPresenter.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/cards/contactrequests/ContactRequestCardPresenter.java
@@ -20,18 +20,20 @@
 package cx.ring.tv.cards.contactrequests;
 
 import android.content.Context;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.support.v17.leanback.widget.ImageCardView;
 import android.view.ContextThemeWrapper;
 
 import cx.ring.R;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.tv.cards.AbstractCardPresenter;
 import cx.ring.tv.cards.Card;
+import cx.ring.tv.model.TVContactRequestViewModel;
 
 public class ContactRequestCardPresenter extends AbstractCardPresenter<ImageCardView> {
 
+    private static final String TAG = ContactRequestCardPresenter.class.getSimpleName();
+
     public ContactRequestCardPresenter(Context context, int resId) {
         super(new ContextThemeWrapper(context, resId));
     }
@@ -43,19 +45,30 @@
 
     @Override
     public void onBindViewHolder(Card card, ImageCardView cardView) {
-        cardView.setTitleText(card.getTitle());
-        cardView.setContentText(card.getDescription());
-        cardView.setBackgroundColor(cardView.getResources().getColor(R.color.color_primary_dark));
-
         ContactRequestCard contact = (ContactRequestCard) card;
-        if (contact.getPhoto() == null) {
-            cardView.setMainImage(getDefaultCardImage());
+
+        TVContactRequestViewModel model = contact.getModel();
+        if (model.getUserName().isEmpty() || model.getDisplayName().equals(model.getUserName())) {
+            cardView.setTitleText(model.getDisplayName());
+            cardView.setContentText("");
         } else {
-            cardView.setMainImage(new BitmapDrawable(cardView.getResources(), BitmapFactory.decodeByteArray(contact.getPhoto(), 0, contact.getPhoto().length)));
+            cardView.setTitleText(model.getUserName());
+            cardView.setContentText(model.getDisplayName());
         }
+
+        cardView.setBackgroundColor(cardView.getResources().getColor(R.color.color_primary_dark));
+        cardView.setMainImage(getCardImage(contact));
     }
 
-    public Drawable getDefaultCardImage() {
-        return getContext().getResources().getDrawable(R.drawable.ic_contact_picture);
+    public Drawable getCardImage(ContactRequestCard contact) {
+        String username = contact.getModel().getDisplayName();
+        if (username == null || username.isEmpty()) {
+            username = contact.getModel().getUserName();
+        }
+
+        return AvatarFactory.getAvatar(getContext(),
+                contact.getPhoto(),
+                username,
+                contact.getModel().getContactId());
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/tv/cards/contacts/ContactCardPresenter.java b/ring-android/app/src/main/java/cx/ring/tv/cards/contacts/ContactCardPresenter.java
index cf82ecc..60aa35d 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/cards/contacts/ContactCardPresenter.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/cards/contacts/ContactCardPresenter.java
@@ -20,18 +20,21 @@
 package cx.ring.tv.cards.contacts;
 
 import android.content.Context;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.support.v17.leanback.widget.ImageCardView;
 import android.view.ContextThemeWrapper;
 
 import cx.ring.R;
+import cx.ring.contacts.AvatarFactory;
+import cx.ring.model.CallContact;
 import cx.ring.tv.cards.AbstractCardPresenter;
 import cx.ring.tv.cards.Card;
+import cx.ring.tv.cards.contactrequests.ContactRequestCardPresenter;
 
 public class ContactCardPresenter extends AbstractCardPresenter<ImageCardView> {
 
+    private static final String TAG = ContactRequestCardPresenter.class.getSimpleName();
+
     public ContactCardPresenter(Context context, int resId) {
         super(new ContextThemeWrapper(context, resId));
     }
@@ -43,19 +46,36 @@
 
     @Override
     public void onBindViewHolder(Card card, ImageCardView cardView) {
-        cardView.setTitleText(card.getTitle());
-        cardView.setContentText(card.getDescription());
-        cardView.setBackgroundColor(cardView.getResources().getColor(R.color.color_primary_dark));
-
         ContactCard contact = (ContactCard) card;
-        if (contact.getPhoto() == null) {
-            cardView.setMainImage(getDefaultCardImage());
-        } else {
-            cardView.setMainImage(new BitmapDrawable(cardView.getResources(), BitmapFactory.decodeByteArray(contact.getPhoto(), 0, contact.getPhoto().length)));
+
+        CallContact model = contact.getModel().getCallContact();
+        String username = model.getUsername();
+
+        if (username == null) {
+            username = model.getIds().get(0);
         }
+
+        if (username!=null&&(username.isEmpty() || model.getDisplayName().equals(username))) {
+            cardView.setTitleText(username);
+            cardView.setContentText("");
+        } else {
+            cardView.setTitleText(model.getDisplayName());
+            cardView.setContentText(username);
+        }
+
+        cardView.setBackgroundColor(cardView.getResources().getColor(R.color.color_primary_dark));
+        cardView.setMainImage(getCardImage(contact));
     }
 
-    public Drawable getDefaultCardImage() {
-        return getContext().getResources().getDrawable(R.drawable.ic_contact_picture);
+    public Drawable getCardImage(ContactCard contact) {
+        String username = contact.getModel().getCallContact().getDisplayName();
+        if (username == null || username.isEmpty()) {
+            username = contact.getModel().getCallContact().getUsername();
+        }
+
+        return AvatarFactory.getAvatar(getContext(),
+                contact.getPhoto(),
+                username,
+                contact.getModel().getCallContact().getIds().get(0));
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/tv/contactrequest/TVContactRequestFragment.java b/ring-android/app/src/main/java/cx/ring/tv/contactrequest/TVContactRequestFragment.java
index 4a7be4b..9acd414 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/contactrequest/TVContactRequestFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/contactrequest/TVContactRequestFragment.java
@@ -20,7 +20,7 @@
 package cx.ring.tv.contactrequest;
 
 import android.content.res.Resources;
-import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.v17.leanback.app.BackgroundManager;
 import android.support.v17.leanback.widget.Action;
@@ -44,13 +44,13 @@
 import android.widget.ImageView;
 
 import com.bumptech.glide.Glide;
-import com.bumptech.glide.request.animation.GlideAnimation;
-import com.bumptech.glide.request.target.SimpleTarget;
 
 import cx.ring.R;
 import cx.ring.application.RingApplication;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.tv.main.BaseDetailFragment;
 import cx.ring.tv.model.TVContactRequestViewModel;
+import cx.ring.tv.views.DetailsOverviewRowTarget;
 
 public class TVContactRequestFragment extends BaseDetailFragment<TVContactRequestPresenter> implements TVContactRequestView {
 
@@ -131,37 +131,15 @@
     private void setupDetailsOverviewRow() {
         final DetailsOverviewRow row = new DetailsOverviewRow(mSelectedContactRequest);
 
-        byte[] photo = mSelectedContactRequest.getPhoto();
+        Drawable contactPicture = AvatarFactory.getAvatar(getActivity(),
+                mSelectedContactRequest.getPhoto(),
+                mSelectedContactRequest.getDisplayName(),
+                mSelectedContactRequest.getContactId());
 
-        if (photo != null && photo.length > 0) {
-            Glide.with(this)
-                    .load(mSelectedContactRequest.getPhoto())
-                    .asBitmap()
-                    .dontAnimate()
-                    .error(R.drawable.ic_contact_picture)
-                    .into(new SimpleTarget<Bitmap>() {
-                        @Override
-                        public void onResourceReady(final Bitmap resource,
-                                                    GlideAnimation glideAnimation) {
-                            row.setImageBitmap(getActivity(), resource);
-                            startEntranceTransition();
-                        }
-                    });
-        } else {
-            Glide.with(this)
-                    .load(R.drawable.ic_contact_picture)
-                    .asBitmap()
-                    .dontAnimate()
-                    .error(R.drawable.ic_contact_picture)
-                    .into(new SimpleTarget<Bitmap>() {
-                        @Override
-                        public void onResourceReady(final Bitmap resource,
-                                                    GlideAnimation glideAnimation) {
-                            row.setImageBitmap(getActivity(), resource);
-                            startEntranceTransition();
-                        }
-                    });
-        }
+        Glide.with(this)
+                .load(contactPicture)
+                .apply(AvatarFactory.getGlideOptions(false, true))
+                .into(new DetailsOverviewRowTarget(row, contactPicture));
 
         SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter();
 
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java b/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java
index 1deaa44..72772d1 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java
@@ -14,6 +14,7 @@
 package cx.ring.tv.main;
 
 import android.content.Intent;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.support.v17.leanback.app.BackgroundManager;
 import android.support.v17.leanback.app.GuidedStepFragment;
@@ -37,6 +38,7 @@
 
 import cx.ring.R;
 import cx.ring.application.RingApplication;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.navigation.RingNavigationViewModel;
 import cx.ring.tv.about.AboutActivity;
 import cx.ring.tv.account.TVAccountExport;
@@ -275,14 +277,19 @@
                 return;
             }
 
+            List<Photo> photos = vcard.getPhotos();
             FormattedName formattedName = vcard.getFormattedName();
             if (formattedName != null) {
                 titleView.setAlias(formattedName.getValue());
-            }
 
-            List<Photo> photos = vcard.getPhotos();
-            if (!photos.isEmpty() && photos.get(0) != null) {
-                titleView.setCurrentAccountPhoto(photos.get(0).getData());
+                if (!photos.isEmpty() && photos.get(0) != null) {
+                    Drawable contactPicture = AvatarFactory.getAvatar(getActivity(),
+                            photos.get(0).getData(),
+                            formattedName.getValue(),
+                            address);
+
+                    titleView.setCurrentAccountPhoto(contactPicture);
+                }
             }
         });
     }
diff --git a/ring-android/app/src/main/java/cx/ring/tv/model/TVContactRequestViewModel.java b/ring-android/app/src/main/java/cx/ring/tv/model/TVContactRequestViewModel.java
index 46add7d..ccb19f8 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/model/TVContactRequestViewModel.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/model/TVContactRequestViewModel.java
@@ -103,6 +103,7 @@
         return m instanceof TVContactRequestViewModel && contactId.equals(((TVContactRequestViewModel) m).contactId);
     }
 
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/ring-android/app/src/main/java/cx/ring/tv/views/CustomTitleView.java b/ring-android/app/src/main/java/cx/ring/tv/views/CustomTitleView.java
index 56c3d5d..0becf2a 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/views/CustomTitleView.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/views/CustomTitleView.java
@@ -26,6 +26,7 @@
 import com.bumptech.glide.Glide;
 
 import cx.ring.R;
+import cx.ring.contacts.AvatarFactory;
 
 /**
  * Custom title view to be used in {@link android.support.v17.leanback.app.BrowseFragment}.
@@ -101,17 +102,12 @@
         }
     }
 
-    public void setCurrentAccountPhoto(byte[] photo) {
-        if (photo != null && photo.length > 0) {
-            Glide.with(getContext())
-                    .load(photo)
-                    .error(R.drawable.ic_contact_picture)
-                    .into(mLogoView);
-        } else {
-            Glide.with(getContext())
-                    .load(R.drawable.ic_contact_picture)
-                    .into(mLogoView);
-        }
+    public void setCurrentAccountPhoto(Drawable photo) {
+        Glide.with(getContext())
+                .load(photo)
+                .apply(AvatarFactory.getGlideOptions(true, true))
+                .into(mLogoView);
+
         mLogoView.setVisibility(View.VISIBLE);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/tv/views/DetailsOverviewRowTarget.java b/ring-android/app/src/main/java/cx/ring/tv/views/DetailsOverviewRowTarget.java
new file mode 100644
index 0000000..b3a9456
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/tv/views/DetailsOverviewRowTarget.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2004-2018 Savoir-faire Linux Inc.
+ *
+ * Author: Pierre Duchemin <pierre.duchemin@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package cx.ring.tv.views;
+
+import android.graphics.drawable.Drawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v17.leanback.widget.DetailsOverviewRow;
+import android.util.Log;
+
+import com.bumptech.glide.request.target.BaseTarget;
+import com.bumptech.glide.request.target.SizeReadyCallback;
+import com.bumptech.glide.request.transition.Transition;
+
+public class DetailsOverviewRowTarget extends BaseTarget<Drawable> {
+
+    private static final String TAG = DetailsOverviewRowTarget.class.getSimpleName();
+    private DetailsOverviewRow detailsOverviewRow;
+    private Drawable drawable;
+
+    public DetailsOverviewRowTarget(DetailsOverviewRow detailsOverviewRow, Drawable drawable) {
+        if (detailsOverviewRow == null || drawable == null) {
+            Log.d(TAG, "DetailsOverviewRowTarget: invalid parameter");
+            return;
+        }
+        this.detailsOverviewRow = detailsOverviewRow;
+        this.drawable = drawable;
+    }
+
+    @Override
+    public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
+        this.detailsOverviewRow.setImageDrawable(resource);
+    }
+
+    @Override
+    public void getSize(@NonNull SizeReadyCallback cb) {
+        cb.onSizeReady(drawable.getMinimumWidth(), drawable.getMinimumHeight());
+    }
+
+    @Override
+    public void removeCallback(@NonNull SizeReadyCallback cb) {
+        // Do nothing, we never retain a reference to the callback
+    }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/utils/BitmapUtils.java b/ring-android/app/src/main/java/cx/ring/utils/BitmapUtils.java
index c386a17..34a5d06 100644
--- a/ring-android/app/src/main/java/cx/ring/utils/BitmapUtils.java
+++ b/ring-android/app/src/main/java/cx/ring/utils/BitmapUtils.java
@@ -27,6 +27,8 @@
 import android.graphics.Paint;
 import android.graphics.RectF;
 import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
@@ -104,4 +106,49 @@
         Log.d(TAG, "reduceBitmap: bitmap size after reduce " + bmp.getByteCount());
         return bmp;
     }
+
+    public static Bitmap createScaledBitmap(Bitmap bitmap, int maxSize) {
+        if (bitmap == null || maxSize < 0) {
+            throw new IllegalArgumentException();
+        }
+        int width = bitmap.getHeight();
+        int height = bitmap.getWidth();
+        if (width != height) {
+            if (width < height) {
+                // portrait
+                height = maxSize;
+                width = (maxSize * bitmap.getWidth()) / bitmap.getHeight();
+            } else {
+                // landscape
+                height = (maxSize * bitmap.getHeight()) / bitmap.getWidth();
+                width = maxSize;
+            }
+        }
+        return Bitmap.createScaledBitmap(bitmap, width, height, false);
+    }
+
+    public static Bitmap drawableToBitmap(Drawable drawable) {
+        if (drawable == null) {
+            throw new IllegalArgumentException();
+        }
+
+        Bitmap bitmap;
+        if (drawable instanceof BitmapDrawable) {
+            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+            if (bitmapDrawable.getBitmap() != null) {
+                return bitmapDrawable.getBitmap();
+            }
+        }
+
+        if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
+            bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
+        } else {
+            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+        }
+
+        Canvas canvas = new Canvas(bitmap);
+        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        drawable.draw(canvas);
+        return bitmap;
+    }
 }
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/utils/CircleTransform.java b/ring-android/app/src/main/java/cx/ring/utils/CircleTransform.java
index 92edd4b..7f5a4c4 100644
--- a/ring-android/app/src/main/java/cx/ring/utils/CircleTransform.java
+++ b/ring-android/app/src/main/java/cx/ring/utils/CircleTransform.java
@@ -19,20 +19,18 @@
  */
 package cx.ring.utils;
 
-import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.support.annotation.NonNull;
 
 import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
 import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
 
-public class CircleTransform extends BitmapTransformation {
+import java.security.MessageDigest;
 
-    public CircleTransform(Context context) {
-        super(context);
-    }
+public class CircleTransform extends BitmapTransformation {
 
     private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
         if (source == null) {
@@ -46,9 +44,6 @@
         Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
 
         Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
-        if (result == null) {
-            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
-        }
 
         Canvas canvas = new Canvas(result);
         Paint paint = new Paint();
@@ -65,8 +60,8 @@
     }
 
     @Override
-    public String getId() {
-        return getClass().getName();
+    public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
+        //do nothing
     }
 }
 
diff --git a/ring-android/app/src/main/java/cx/ring/utils/HashUtils.java b/ring-android/app/src/main/java/cx/ring/utils/HashUtils.java
new file mode 100644
index 0000000..02a36ea
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/utils/HashUtils.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2004-2018 Savoir-faire Linux Inc.
+ *
+ * Author: Pierre Duchemin <pierre.duchemin@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package cx.ring.utils;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class HashUtils {
+
+    private static final String TAG = HashUtils.class.getSimpleName();
+
+    private HashUtils() {
+    }
+
+    public static String md5(String s) {
+        String result = null;
+        try {
+            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
+            messageDigest.update(s.getBytes(), 0, s.length());
+            result = new BigInteger(1, messageDigest.digest()).toString(16);
+        } catch (NoSuchAlgorithmException e) {
+            android.util.Log.e(TAG, "Not able to find MD5 algorithm", e);
+        }
+        return result;
+    }
+}
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_contact_picture_fallback.png b/ring-android/app/src/main/res/drawable-hdpi/ic_contact_picture_fallback.png
new file mode 100644
index 0000000..4462c0b
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_contact_picture_fallback.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_contact_picture_fallback.png b/ring-android/app/src/main/res/drawable-mdpi/ic_contact_picture_fallback.png
new file mode 100644
index 0000000..bb9fdf9
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_contact_picture_fallback.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_contact_picture_fallback.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_contact_picture_fallback.png
new file mode 100644
index 0000000..07d7784
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_contact_picture_fallback.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_contact_picture_fallback.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_contact_picture_fallback.png
new file mode 100644
index 0000000..f364847
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_contact_picture_fallback.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_contact_picture_fallback.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_contact_picture_fallback.png
new file mode 100644
index 0000000..994e513
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_contact_picture_fallback.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable/ic_contact_picture.png b/ring-android/app/src/main/res/drawable/ic_contact_picture.png
deleted file mode 100644
index b84a951..0000000
--- a/ring-android/app/src/main/res/drawable/ic_contact_picture.png
+++ /dev/null
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable/ic_contact_picture_box_default.xml b/ring-android/app/src/main/res/drawable/ic_contact_picture_box_default.xml
new file mode 100644
index 0000000..86fdcb3
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/ic_contact_picture_box_default.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:viewportWidth="32"
+    android:viewportHeight="32"
+    android:width="32dp"
+    android:height="32dp">
+    <path
+        android:pathData="M8.013766 23.107838l0.00465 -0.810382 0.033095 -0.133474c0.1495327 -0.603099 0.50107 -1.099452 1.1411917 -1.611311 0.1690725 -0.135195 0.5493165 -0.388522 0.7866284 -0.524069 1.4449359 -0.825313 3.6497829 -1.439907 5.5693029 -1.552424 0.268992 -0.01577 0.866138 -0.0085 1.131356 0.01373 1.873734 0.157215 3.884055 0.729268 5.262712 1.497544 1.031356 0.574739 1.70347 1.254543 1.937152 1.959316 0.101301 0.305518 0.100213 0.293393 0.105924 1.180132l0.0051 0.791314 -7.990878 0 -7.990878 0 0.00465 -0.810381z"
+        android:fillColor="#ffffff" />
+    <path
+        android:pathData="M15.641818 15.906151c-0.512638 -0.04757 -0.970838 -0.177847 -1.424519 -0.40503 -0.534623 -0.267715 -0.972855 -0.622072 -1.344489 -1.087162 -0.500329 -0.626146 -0.797007 -1.385268 -0.858271 -2.196087 -0.01377 -0.182277 -0.0068 -0.568261 0.01341 -0.738308 0.137062 -1.155519 0.73576 -2.1602655 1.685808 -2.8291565 1.010233 -0.711264 2.333521 -0.90809 3.519055 -0.523424 0.511977 0.166119 0.9845 0.434474 1.39324 0.791249 0.103105 0.09 0.316993 0.304905 0.402137 0.404056 0.848222 0.9877635 1.16007 2.3144245 0.843044 3.5864705 -0.116312 0.466694 -0.339476 0.947863 -0.621858 1.340798 -0.695617 0.967955 -1.761735 1.568261 -2.95044 1.661324 -0.155481 0.01217 -0.501821 0.0097 -0.657113 -0.0047z"
+        android:fillColor="#ffffff" />
+</vector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout-land/frag_acc_profile_create.xml b/ring-android/app/src/main/res/layout-land/frag_acc_profile_create.xml
index a27aebb..172e8cc 100644
--- a/ring-android/app/src/main/res/layout-land/frag_acc_profile_create.xml
+++ b/ring-android/app/src/main/res/layout-land/frag_acc_profile_create.xml
@@ -65,7 +65,7 @@
                         android:layout_centerHorizontal="true"
                         android:layout_margin="10dp"
                         android:scaleType="fitCenter"
-                        tools:src="@drawable/ic_contact_picture" />
+                        tools:src="@drawable/ic_contact_picture_fallback" />
 
                     <android.support.design.widget.FloatingActionButton
                         android:id="@+id/camera"
diff --git a/ring-android/app/src/main/res/layout-land/frag_call.xml b/ring-android/app/src/main/res/layout-land/frag_call.xml
index dade377..88de67c 100644
--- a/ring-android/app/src/main/res/layout-land/frag_call.xml
+++ b/ring-android/app/src/main/res/layout-land/frag_call.xml
@@ -66,7 +66,7 @@
                 android:layout_width="160dp"
                 android:layout_height="160dp"
                 android:layout_centerInParent="true"
-                tools:src="@drawable/ic_contact_picture" />
+                tools:src="@drawable/ic_contact_picture_fallback" />
         </com.skyfishjy.library.RippleBackground>
 
         <LinearLayout
diff --git a/ring-android/app/src/main/res/layout-w720dp-land/tv_frag_call.xml b/ring-android/app/src/main/res/layout-w720dp-land/tv_frag_call.xml
index d6f516e..a7fba6a 100644
--- a/ring-android/app/src/main/res/layout-w720dp-land/tv_frag_call.xml
+++ b/ring-android/app/src/main/res/layout-w720dp-land/tv_frag_call.xml
@@ -68,7 +68,7 @@
                 android:layout_width="160dp"
                 android:layout_height="160dp"
                 android:layout_centerInParent="true"
-                tools:src="@drawable/ic_contact_picture" />
+                tools:src="@drawable/ic_contact_picture_fallback" />
         </com.skyfishjy.library.RippleBackground>
 
         <LinearLayout
diff --git a/ring-android/app/src/main/res/layout/dialog_profile.xml b/ring-android/app/src/main/res/layout/dialog_profile.xml
index a19fe9e..b146220 100644
--- a/ring-android/app/src/main/res/layout/dialog_profile.xml
+++ b/ring-android/app/src/main/res/layout/dialog_profile.xml
@@ -35,7 +35,7 @@
                 android:layout_centerHorizontal="true"
                 android:layout_margin="15dp"
                 android:scaleType="fitCenter"
-                app:srcCompat="@drawable/ic_contact_picture" />
+                app:srcCompat="@drawable/ic_contact_picture_fallback" />
 
             <android.support.design.widget.FloatingActionButton
                 android:id="@+id/gallery"
diff --git a/ring-android/app/src/main/res/layout/frag_acc_profile_create.xml b/ring-android/app/src/main/res/layout/frag_acc_profile_create.xml
index f4cf94a..1a636ef 100644
--- a/ring-android/app/src/main/res/layout/frag_acc_profile_create.xml
+++ b/ring-android/app/src/main/res/layout/frag_acc_profile_create.xml
@@ -58,7 +58,7 @@
                     android:layout_centerHorizontal="true"
                     android:layout_margin="10dp"
                     android:scaleType="fitCenter"
-                    tools:src="@drawable/ic_contact_picture" />
+                    tools:src="@drawable/ic_contact_picture_fallback" />
 
                 <android.support.design.widget.FloatingActionButton
                     android:id="@+id/camera"
diff --git a/ring-android/app/src/main/res/layout/frag_call.xml b/ring-android/app/src/main/res/layout/frag_call.xml
index e874674..2b3c670 100644
--- a/ring-android/app/src/main/res/layout/frag_call.xml
+++ b/ring-android/app/src/main/res/layout/frag_call.xml
@@ -65,7 +65,7 @@
                 android:layout_width="160dp"
                 android:layout_height="160dp"
                 android:layout_centerInParent="true"
-                tools:src="@drawable/ic_contact_picture" />
+                tools:src="@drawable/ic_contact_picture_fallback" />
         </com.skyfishjy.library.RippleBackground>
 
         <TextView
diff --git a/ring-android/app/src/main/res/layout/frag_navigation.xml b/ring-android/app/src/main/res/layout/frag_navigation.xml
index 1515674..61968b6 100644
--- a/ring-android/app/src/main/res/layout/frag_navigation.xml
+++ b/ring-android/app/src/main/res/layout/frag_navigation.xml
@@ -31,7 +31,7 @@
                     android:layout_height="80dp"
                     android:layout_alignParentTop="true"
                     android:layout_centerHorizontal="true"
-                    tools:src="@drawable/ic_contact_picture" />
+                    tools:src="@drawable/ic_contact_picture_fallback" />
 
                 <View
                     android:id="@+id/anchor"
diff --git a/ring-android/app/src/main/res/layout/item_account.xml b/ring-android/app/src/main/res/layout/item_account.xml
index 3960d91..5daec42 100644
--- a/ring-android/app/src/main/res/layout/item_account.xml
+++ b/ring-android/app/src/main/res/layout/item_account.xml
@@ -31,7 +31,7 @@
         android:layout_height="40dp"
         android:layout_centerVertical="true"
         android:layout_marginEnd="16dp"
-        tools:src="@drawable/ic_contact_picture" />
+        tools:src="@drawable/ic_contact_picture_fallback" />
 
     <TextView
         android:id="@+id/account_alias"
diff --git a/ring-android/app/src/main/res/layout/item_contact.xml b/ring-android/app/src/main/res/layout/item_contact.xml
index f468901..c34e3e0 100644
--- a/ring-android/app/src/main/res/layout/item_contact.xml
+++ b/ring-android/app/src/main/res/layout/item_contact.xml
@@ -38,7 +38,7 @@
         android:layout_marginRight="16dp"
         android:contentDescription="@string/contact_picture_description"
         android:scaleType="centerCrop"
-        app:srcCompat="@drawable/ic_contact_picture" />
+        app:srcCompat="@drawable/ic_contact_picture_fallback" />
 
     <TextView
         android:id="@+id/display_name"
diff --git a/ring-android/app/src/main/res/layout/item_contact_blacklist.xml b/ring-android/app/src/main/res/layout/item_contact_blacklist.xml
index 928d3fd..c6e83eb 100644
--- a/ring-android/app/src/main/res/layout/item_contact_blacklist.xml
+++ b/ring-android/app/src/main/res/layout/item_contact_blacklist.xml
@@ -16,7 +16,7 @@
         android:layout_marginRight="16dp"
         android:contentDescription="@string/contact_picture_description"
         android:scaleType="centerCrop"
-        app:srcCompat="@drawable/ic_contact_picture" />
+        app:srcCompat="@drawable/ic_contact_picture_fallback" />
 
     <TextView
         android:id="@+id/display_name"
diff --git a/ring-android/app/src/main/res/layout/item_contact_request.xml b/ring-android/app/src/main/res/layout/item_contact_request.xml
index 9907f42..4839dc7 100644
--- a/ring-android/app/src/main/res/layout/item_contact_request.xml
+++ b/ring-android/app/src/main/res/layout/item_contact_request.xml
@@ -21,7 +21,7 @@
         android:paddingEnd="4dp"
         android:paddingStart="0dp"
         android:scaleType="fitCenter"
-        app:srcCompat="@drawable/ic_contact_picture" />
+        app:srcCompat="@drawable/ic_contact_picture_fallback" />
 
     <TextView
         android:id="@+id/display_name"
diff --git a/ring-android/app/src/main/res/layout/item_smartlist.xml b/ring-android/app/src/main/res/layout/item_smartlist.xml
index 97b6e9e..d1f10db 100644
--- a/ring-android/app/src/main/res/layout/item_smartlist.xml
+++ b/ring-android/app/src/main/res/layout/item_smartlist.xml
@@ -42,7 +42,7 @@
         android:paddingEnd="4dp"
         android:paddingStart="0dp"
         android:scaleType="fitCenter"
-        app:srcCompat="@drawable/ic_contact_picture" />
+        app:srcCompat="@drawable/ic_contact_picture_fallback" />
 
     <ImageView
         android:id="@+id/online"
diff --git a/ring-android/app/src/main/res/layout/tv_titleview.xml b/ring-android/app/src/main/res/layout/tv_titleview.xml
index 2d686d9..ca51798 100644
--- a/ring-android/app/src/main/res/layout/tv_titleview.xml
+++ b/ring-android/app/src/main/res/layout/tv_titleview.xml
@@ -54,5 +54,5 @@
         android:layout_gravity="center_vertical|end"
         android:layout_marginEnd="24dp"
         android:padding="6dp"
-        app:srcCompat="@drawable/ic_contact_picture" />
+        app:srcCompat="@drawable/ic_contact_picture_fallback" />
 </merge>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/values/material_colors.xml b/ring-android/app/src/main/res/values/material_colors.xml
new file mode 100644
index 0000000..2815510
--- /dev/null
+++ b/ring-android/app/src/main/res/values/material_colors.xml
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="red_50">#FFEBEE</color>
+    <color name="red_100">#FFCDD2</color>
+    <color name="red_200">#EF9A9A</color>
+    <color name="red_300">#E57373</color>
+    <color name="red_400">#EF5350</color>
+    <color name="red_500">#F44336</color>
+    <color name="red_600">#E53935</color>
+    <color name="red_700">#D32F2F</color>
+    <color name="red_800">#C62828</color>
+    <color name="red_900">#B71C1C</color>
+    <color name="red_A100">#FF8A80</color>
+    <color name="red_A200">#FF5252</color>
+    <color name="red_A400">#FF1744</color>
+    <color name="red_A700">#D50000</color>
+
+    <color name="deep_purple_50">#EDE7F6</color>
+    <color name="deep_purple_100">#D1C4E9</color>
+    <color name="deep_purple_200">#B39DDB</color>
+    <color name="deep_purple_300">#9575CD</color>
+    <color name="deep_purple_400">#7E57C2</color>
+    <color name="deep_purple_500">#673AB7</color>
+    <color name="deep_purple_600">#5E35B1</color>
+    <color name="deep_purple_700">#512DA8</color>
+    <color name="deep_purple_800">#4527A0</color>
+    <color name="deep_purple_900">#311B92</color>
+    <color name="deep_purple_A100">#B388FF</color>
+    <color name="deep_purple_A200">#7C4DFF</color>
+    <color name="deep_purple_A400">#651FFF</color>
+    <color name="deep_purple_A700">#6200EA</color>
+
+    <color name="light_blue_50">#E1F5FE</color>
+    <color name="light_blue_100">#B3E5FC</color>
+    <color name="light_blue_200">#81D4FA</color>
+    <color name="light_blue_300">#4FC3F7</color>
+    <color name="light_blue_400">#29B6F6</color>
+    <color name="light_blue_500">#03A9F4</color>
+    <color name="light_blue_600">#039BE5</color>
+    <color name="light_blue_700">#0288D1</color>
+    <color name="light_blue_800">#0277BD</color>
+    <color name="light_blue_900">#01579B</color>
+    <color name="light_blue_A100">#80D8FF</color>
+    <color name="light_blue_A200">#40C4FF</color>
+    <color name="light_blue_A400">#00B0FF</color>
+    <color name="light_blue_A700">#0091EA</color>
+
+    <color name="green_50">#E8F5E9</color>
+    <color name="green_100">#C8E6C9</color>
+    <color name="green_200">#A5D6A7</color>
+    <color name="green_300">#81C784</color>
+    <color name="green_400">#66BB6A</color>
+    <color name="green_500">#4CAF50</color>
+    <color name="green_600">#43A047</color>
+    <color name="green_700">#388E3C</color>
+    <color name="green_800">#2E7D32</color>
+    <color name="green_900">#1B5E20</color>
+    <color name="green_A100">#B9F6CA</color>
+    <color name="green_A200">#69F0AE</color>
+    <color name="green_A400">#00E676</color>
+    <color name="green_A700">#00C853</color>
+
+    <color name="yellow_50">#FFFDE7</color>
+    <color name="yellow_100">#FFF9C4</color>
+    <color name="yellow_200">#FFF59D</color>
+    <color name="yellow_300">#FFF176</color>
+    <color name="yellow_400">#FFEE58</color>
+    <color name="yellow_500">#FFEB3B</color>
+    <color name="yellow_600">#FDD835</color>
+    <color name="yellow_700">#FBC02D</color>
+    <color name="yellow_800">#F9A825</color>
+    <color name="yellow_900">#F57F17</color>
+    <color name="yellow_A100">#FFFF8D</color>
+    <color name="yellow_A200">#FFFF00</color>
+    <color name="yellow_A400">#FFEA00</color>
+    <color name="yellow_A700">#FFD600</color>
+
+    <color name="deep_orange_50">#FBE9E7</color>
+    <color name="deep_orange_100">#FFCCBC</color>
+    <color name="deep_orange_200">#FFAB91</color>
+    <color name="deep_orange_300">#FF8A65</color>
+    <color name="deep_orange_400">#FF7043</color>
+    <color name="deep_orange_500">#FF5722</color>
+    <color name="deep_orange_600">#F4511E</color>
+    <color name="deep_orange_700">#E64A19</color>
+    <color name="deep_orange_800">#D84315</color>
+    <color name="deep_orange_900">#BF360C</color>
+    <color name="deep_orange_A100">#FF9E80</color>
+    <color name="deep_orange_A200">#FF6E40</color>
+    <color name="deep_orange_A400">#FF3D00</color>
+    <color name="deep_orange_A700">#DD2C00</color>
+
+    <color name="blue_grey_50">#ECEFF1</color>
+    <color name="blue_grey_100">#CFD8DC</color>
+    <color name="blue_grey_200">#B0BEC5</color>
+    <color name="blue_grey_300">#90A4AE</color>
+    <color name="blue_grey_400">#78909C</color>
+    <color name="blue_grey_500">#607D8B</color>
+    <color name="blue_grey_600">#546E7A</color>
+    <color name="blue_grey_700">#455A64</color>
+    <color name="blue_grey_800">#37474F</color>
+    <color name="blue_grey_900">#263238</color>
+
+    <color name="pink_50">#FCE4EC</color>
+    <color name="pink_100">#F8BBD0</color>
+    <color name="pink_200">#F48FB1</color>
+    <color name="pink_300">#F06292</color>
+    <color name="pink_400">#EC407A</color>
+    <color name="pink_500">#E91E63</color>
+    <color name="pink_600">#D81B60</color>
+    <color name="pink_700">#C2185B</color>
+    <color name="pink_800">#AD1457</color>
+    <color name="pink_900">#880E4F</color>
+    <color name="pink_A100">#FF80AB</color>
+    <color name="pink_A200">#FF4081</color>
+    <color name="pink_A400">#F50057</color>
+    <color name="pink_A700">#C51162</color>
+
+    <color name="indigo_50">#E8EAF6</color>
+    <color name="indigo_100">#C5CAE9</color>
+    <color name="indigo_200">#9FA8DA</color>
+    <color name="indigo_300">#7986CB</color>
+    <color name="indigo_400">#5C6BC0</color>
+    <color name="indigo_500">#3F51B5</color>
+    <color name="indigo_600">#3949AB</color>
+    <color name="indigo_700">#303F9F</color>
+    <color name="indigo_800">#283593</color>
+    <color name="indigo_900">#1A237E</color>
+    <color name="indigo_A100">#8C9EFF</color>
+    <color name="indigo_A200">#536DFE</color>
+    <color name="indigo_A400">#3D5AFE</color>
+    <color name="indigo_A700">#304FFE</color>
+
+    <color name="cyan_50">#E0F7FA</color>
+    <color name="cyan_100">#B2EBF2</color>
+    <color name="cyan_200">#80DEEA</color>
+    <color name="cyan_300">#4DD0E1</color>
+    <color name="cyan_400">#26C6DA</color>
+    <color name="cyan_500">#00BCD4</color>
+    <color name="cyan_600">#00ACC1</color>
+    <color name="cyan_700">#0097A7</color>
+    <color name="cyan_800">#00838F</color>
+    <color name="cyan_900">#006064</color>
+    <color name="cyan_A100">#84FFFF</color>
+    <color name="cyan_A200">#18FFFF</color>
+    <color name="cyan_A400">#00E5FF</color>
+    <color name="cyan_A700">#00B8D4</color>
+
+    <color name="light_green_50">#F1F8E9</color>
+    <color name="light_green_100">#DCEDC8</color>
+    <color name="light_green_200">#C5E1A5</color>
+    <color name="light_green_300">#AED581</color>
+    <color name="light_green_400">#9CCC65</color>
+    <color name="light_green_500">#8BC34A</color>
+    <color name="light_green_600">#7CB342</color>
+    <color name="light_green_700">#689F38</color>
+    <color name="light_green_800">#558B2F</color>
+    <color name="light_green_900">#33691E</color>
+    <color name="light_green_A100">#CCFF90</color>
+    <color name="light_green_A200">#B2FF59</color>
+    <color name="light_green_A400">#76FF03</color>
+    <color name="light_green_A700">#64DD17</color>
+
+    <color name="amber_50">#FFF8E1</color>
+    <color name="amber_100">#FFECB3</color>
+    <color name="amber_200">#FFE082</color>
+    <color name="amber_300">#FFD54F</color>
+    <color name="amber_400">#FFCA28</color>
+    <color name="amber_500">#FFC107</color>
+    <color name="amber_600">#FFB300</color>
+    <color name="amber_700">#FFA000</color>
+    <color name="amber_800">#FF8F00</color>
+    <color name="amber_900">#FF6F00</color>
+    <color name="amber_A100">#FFE57F</color>
+    <color name="amber_A200">#FFD740</color>
+    <color name="amber_A400">#FFC400</color>
+    <color name="amber_A700">#FFAB00</color>
+
+    <color name="brown_50">#EFEBE9</color>
+    <color name="brown_100">#D7CCC8</color>
+    <color name="brown_200">#BCAAA4</color>
+    <color name="brown_300">#A1887F</color>
+    <color name="brown_400">#8D6E63</color>
+    <color name="brown_500">#795548</color>
+    <color name="brown_600">#6D4C41</color>
+    <color name="brown_700">#5D4037</color>
+    <color name="brown_800">#4E342E</color>
+    <color name="brown_900">#3E2723</color>
+
+    <color name="purple_50">#F3E5F5</color>
+    <color name="purple_100">#E1BEE7</color>
+    <color name="purple_200">#CE93D8</color>
+    <color name="purple_300">#BA68C8</color>
+    <color name="purple_400">#AB47BC</color>
+    <color name="purple_500">#9C27B0</color>
+    <color name="purple_600">#8E24AA</color>
+    <color name="purple_700">#7B1FA2</color>
+    <color name="purple_800">#6A1B9A</color>
+    <color name="purple_900">#4A148C</color>
+    <color name="purple_A100">#EA80FC</color>
+    <color name="purple_A200">#E040FB</color>
+    <color name="purple_A400">#D500F9</color>
+    <color name="purple_A700">#AA00FF</color>
+
+    <color name="blue_50">#E3F2FD</color>
+    <color name="blue_100">#BBDEFB</color>
+    <color name="blue_200">#90CAF9</color>
+    <color name="blue_300">#64B5F6</color>
+    <color name="blue_400">#42A5F5</color>
+    <color name="blue_500">#2196F3</color>
+    <color name="blue_600">#1E88E5</color>
+    <color name="blue_700">#1976D2</color>
+    <color name="blue_800">#1565C0</color>
+    <color name="blue_900">#0D47A1</color>
+    <color name="blue_A100">#82B1FF</color>
+    <color name="blue_A200">#448AFF</color>
+    <color name="blue_A400">#2979FF</color>
+    <color name="blue_A700">#2962FF</color>
+
+    <color name="teal_50">#E0F2F1</color>
+    <color name="teal_100">#B2DFDB</color>
+    <color name="teal_200">#80CBC4</color>
+    <color name="teal_300">#4DB6AC</color>
+    <color name="teal_400">#26A69A</color>
+    <color name="teal_500">#009688</color>
+    <color name="teal_600">#00897B</color>
+    <color name="teal_700">#00796B</color>
+    <color name="teal_800">#00695C</color>
+    <color name="teal_900">#004D40</color>
+    <color name="teal_A100">#A7FFEB</color>
+    <color name="teal_A200">#64FFDA</color>
+    <color name="teal_A400">#1DE9B6</color>
+    <color name="teal_A700">#00BFA5</color>
+
+    <color name="lime_50">#F9FBE7</color>
+    <color name="lime_100">#F0F4C3</color>
+    <color name="lime_200">#E6EE9C</color>
+    <color name="lime_300">#DCE775</color>
+    <color name="lime_400">#D4E157</color>
+    <color name="lime_500">#CDDC39</color>
+    <color name="lime_600">#C0CA33</color>
+    <color name="lime_700">#AFB42B</color>
+    <color name="lime_800">#9E9D24</color>
+    <color name="lime_900">#827717</color>
+    <color name="lime_A100">#F4FF81</color>
+    <color name="lime_A200">#EEFF41</color>
+    <color name="lime_A400">#C6FF00</color>
+    <color name="lime_A700">#AEEA00</color>
+
+    <color name="orange_50">#FFF3E0</color>
+    <color name="orange_100">#FFE0B2</color>
+    <color name="orange_200">#FFCC80</color>
+    <color name="orange_300">#FFB74D</color>
+    <color name="orange_400">#FFA726</color>
+    <color name="orange_500">#FF9800</color>
+    <color name="orange_600">#FB8C00</color>
+    <color name="orange_700">#F57C00</color>
+    <color name="orange_800">#EF6C00</color>
+    <color name="orange_900">#E65100</color>
+    <color name="orange_A100">#FFD180</color>
+    <color name="orange_A200">#FFAB40</color>
+    <color name="orange_A400">#FF9100</color>
+    <color name="orange_A700">#FF6D00</color>
+
+    <color name="grey_50">#FAFAFA</color>
+    <color name="grey_100">#F5F5F5</color>
+    <color name="grey_200">#EEEEEE</color>
+    <color name="grey_300">#E0E0E0</color>
+    <color name="grey_400">#BDBDBD</color>
+    <color name="grey_500">#9E9E9E</color>
+    <color name="grey_600">#757575</color>
+    <color name="grey_700">#616161</color>
+    <color name="grey_800">#424242</color>
+    <color name="grey_900">#212121</color>
+
+</resources>
\ No newline at end of file