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