diff --git a/build.gradle b/build.gradle index 662d32a6ca..596a14fae4 100644 --- a/build.gradle +++ b/build.gradle @@ -132,7 +132,7 @@ android { defaultConfig { minSdkVersion 9 - targetSdkVersion 19 + targetSdkVersion 22 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" buildConfigField "long", "BUILD_TIMESTAMP", System.currentTimeMillis() + "L" diff --git a/res/drawable-hdpi-v11/icon_notification.png b/res/drawable-hdpi-v11/icon_notification.png index e0cea95c3e..aa31bf571b 100644 Binary files a/res/drawable-hdpi-v11/icon_notification.png and b/res/drawable-hdpi-v11/icon_notification.png differ diff --git a/res/drawable-hdpi-v9/icon_notification.png b/res/drawable-hdpi-v9/icon_notification.png index 14840b3663..ffa5235e2a 100644 Binary files a/res/drawable-hdpi-v9/icon_notification.png and b/res/drawable-hdpi-v9/icon_notification.png differ diff --git a/res/drawable-mdpi-v11/icon_notification.png b/res/drawable-mdpi-v11/icon_notification.png index fab48d4c50..01f9abda43 100644 Binary files a/res/drawable-mdpi-v11/icon_notification.png and b/res/drawable-mdpi-v11/icon_notification.png differ diff --git a/res/drawable-mdpi-v9/icon_notification.png b/res/drawable-mdpi-v9/icon_notification.png index 5886aa8400..6153b25c42 100644 Binary files a/res/drawable-mdpi-v9/icon_notification.png and b/res/drawable-mdpi-v9/icon_notification.png differ diff --git a/res/drawable-xhdpi-v11/icon_notification.png b/res/drawable-xhdpi-v11/icon_notification.png index 6cccf186a0..fb57ee4460 100644 Binary files a/res/drawable-xhdpi-v11/icon_notification.png and b/res/drawable-xhdpi-v11/icon_notification.png differ diff --git a/res/drawable-xxhdpi-v11/icon_notification.png b/res/drawable-xxhdpi-v11/icon_notification.png index 3f15308559..eef8f802c1 100644 Binary files a/res/drawable-xxhdpi-v11/icon_notification.png and b/res/drawable-xxhdpi-v11/icon_notification.png differ diff --git a/res/values/dimens.xml b/res/values/dimens.xml index c926c1f826..dbcaf72ee6 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -9,6 +9,7 @@ 200sp 0dp 1dp + 64dp 50dp 230dp 8dp diff --git a/res/values/strings.xml b/res/values/strings.xml index 18e909b185..a8fd663fb0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -435,8 +435,8 @@ Lock with passphrase - %d new messages - Most recent from: %s + %1$d messages in %2$d conversations + Most recent from: %1$s Encrypted message... Media message: %s (No subject) diff --git a/src/org/thoughtcrime/securesms/contacts/ContactPhotoFactory.java b/src/org/thoughtcrime/securesms/contacts/ContactPhotoFactory.java index c41d3bbe38..1ea3606023 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactPhotoFactory.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactPhotoFactory.java @@ -5,11 +5,16 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; +import android.os.Build.VERSION; +import android.os.Build.VERSION_CODES; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; +import android.util.Log; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.util.BitmapDecodingException; +import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.LRUCache; import java.io.InputStream; @@ -17,6 +22,7 @@ import java.util.Collections; import java.util.Map; public class ContactPhotoFactory { + private static final String TAG = ContactPhotoFactory.class.getSimpleName(); private static final Object defaultPhotoLock = new Object(); private static final Object defaultGroupPhotoLock = new Object(); @@ -86,12 +92,31 @@ public class ContactPhotoFactory { } public static Bitmap getContactPhoto(Context context, Uri uri) { - InputStream inputStream = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri); - - final Bitmap contactPhoto; - if (inputStream == null) contactPhoto = ContactPhotoFactory.getDefaultContactPhoto(context); - else contactPhoto = BitmapFactory.decodeStream(inputStream); + final InputStream inputStream = getContactPhotoStream(context, uri); + final int targetSize = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size); + Bitmap contactPhoto = null; + if (inputStream != null) { + try { + contactPhoto = BitmapUtil.createScaledBitmap(inputStream, + getContactPhotoStream(context, uri), + targetSize, + targetSize); + } catch (BitmapDecodingException bde) { + Log.w(TAG, bde); + } + } + if (contactPhoto == null) { + contactPhoto = ContactPhotoFactory.getDefaultContactPhoto(context); + } return contactPhoto; } + + private static InputStream getContactPhotoStream(Context context, Uri uri) { + if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) { + return ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri, true); + } else { + return ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri); + } + } } diff --git a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java index 123cee1fd9..e13f6ece7e 100644 --- a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java @@ -53,6 +53,7 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.service.KeyCachingService; +import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.SpanUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; @@ -181,14 +182,18 @@ public class MessageNotifier { Recipient recipient = notifications.get(0).getIndividualRecipient(); Bitmap recipientPhoto = recipient.getContactPhoto(); + if (recipientPhoto != null) builder.setLargeIcon(BitmapUtil.getCircleBitmap(recipientPhoto)); builder.setSmallIcon(R.drawable.icon_notification); - if (recipientPhoto != null) builder.setLargeIcon(recipientPhoto); + builder.setColor(context.getResources().getColor(R.color.textsecure_primary)); builder.setContentTitle(recipient.toShortString()); builder.setContentText(notifications.get(0).getText()); builder.setContentIntent(notifications.get(0).getPendingIntent(context)); builder.setContentInfo(String.valueOf(notificationState.getMessageCount())); + builder.setPriority(NotificationCompat.PRIORITY_HIGH); builder.setNumber(notificationState.getMessageCount()); + builder.setCategory(NotificationCompat.CATEGORY_MESSAGE); builder.setDeleteIntent(PendingIntent.getBroadcast(context, 0, new Intent(DeleteReceiver.DELETE_REMINDER_ACTION), 0)); + if (recipient.getContactUri() != null) builder.addPerson(recipient.getContactUri().toString()); if (masterSecret != null) { builder.addAction(R.drawable.check, context.getString(R.string.MessageNotifier_mark_as_read), @@ -224,17 +229,19 @@ public class MessageNotifier { List notifications = notificationState.getNotifications(); NotificationCompat.Builder builder = new NotificationCompat.Builder(context); + builder.setColor(context.getResources().getColor(R.color.textsecure_primary)); builder.setSmallIcon(R.drawable.icon_notification); - builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), - R.drawable.icon_notification)); - builder.setContentTitle(String.format(context.getString(R.string.MessageNotifier_d_new_messages), - notificationState.getMessageCount())); - builder.setContentText(String.format(context.getString(R.string.MessageNotifier_most_recent_from_s), - notifications.get(0).getIndividualRecipientName())); + builder.setContentTitle(context.getString(R.string.app_name)); + builder.setSubText(context.getString(R.string.MessageNotifier_d_messages_in_d_conversations, + notificationState.getMessageCount(), + notificationState.getThreadCount())); + builder.setContentText(context.getString(R.string.MessageNotifier_most_recent_from_s, + notifications.get(0).getIndividualRecipientName())); builder.setContentIntent(PendingIntent.getActivity(context, 0, new Intent(context, ConversationListActivity.class), 0)); builder.setContentInfo(String.valueOf(notificationState.getMessageCount())); builder.setNumber(notificationState.getMessageCount()); + builder.setCategory(NotificationCompat.CATEGORY_MESSAGE); builder.setDeleteIntent(PendingIntent.getBroadcast(context, 0, new Intent(DeleteReceiver.DELETE_REMINDER_ACTION), 0)); @@ -249,6 +256,9 @@ public class MessageNotifier { while(iterator.hasPrevious()) { NotificationItem item = iterator.previous(); style.addLine(item.getTickerText()); + if (item.getIndividualRecipient().getContactUri() != null) { + builder.addPerson(item.getIndividualRecipient().getContactUri().toString()); + } } builder.setStyle(style); diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationState.java b/src/org/thoughtcrime/securesms/notifications/NotificationState.java index 36db7a9f38..f0d51eec11 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationState.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationState.java @@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.notifications; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.graphics.Bitmap; import android.util.Log; import org.thoughtcrime.securesms.crypto.MasterSecret; @@ -30,6 +29,10 @@ public class NotificationState { return threads.size() > 1; } + public int getThreadCount() { + return threads.size(); + } + public int getMessageCount() { return notificationCount; } @@ -38,10 +41,6 @@ public class NotificationState { return notifications; } - public Bitmap getContactPhoto() { - return notifications.get(0).getIndividualRecipient().getContactPhoto(); - } - public PendingIntent getMarkAsReadIntent(Context context, MasterSecret masterSecret) { long[] threadArray = new long[threads.size()]; int index = 0; diff --git a/src/org/thoughtcrime/securesms/util/BitmapUtil.java b/src/org/thoughtcrime/securesms/util/BitmapUtil.java index 0a1c1a38bb..0b189f6ef3 100644 --- a/src/org/thoughtcrime/securesms/util/BitmapUtil.java +++ b/src/org/thoughtcrime/securesms/util/BitmapUtil.java @@ -5,27 +5,28 @@ import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; +import android.graphics.RectF; import android.net.Uri; import android.util.Log; import android.util.Pair; +import com.android.gallery3d.data.Exif; + import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.mms.PartAuthority; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import com.android.gallery3d.data.Exif; - public class BitmapUtil { private static final String TAG = BitmapUtil.class.getSimpleName(); @@ -230,4 +231,26 @@ public class BitmapUtil { bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); return stream.toByteArray(); } + + public static Bitmap getCircleBitmap(Bitmap bitmap) { + final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), + bitmap.getHeight(), Bitmap.Config.ARGB_8888); + final Canvas canvas = new Canvas(output); + + final int color = Color.RED; + final Paint paint = new Paint(); + final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); + final RectF rectF = new RectF(rect); + + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + paint.setColor(color); + canvas.drawOval(rectF, paint); + + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(bitmap, rect, rect, paint); + + return output; + } + }