From a3f9737e6390d98252661d6e8e8142f7f989c6cd Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Tue, 2 Jun 2020 17:34:50 -0300 Subject: [PATCH] Make notifications and chat previews for media messages more descriptive. --- .../components/emoji/EmojiStrings.java | 6 ++ .../ConversationListItem.java | 17 ++-- .../securesms/database/ThreadBodyUtil.java | 84 +++++++++++++++++++ .../securesms/database/ThreadDatabase.java | 11 +-- .../notifications/DefaultMessageNotifier.java | 30 +++---- app/src/main/res/values/strings.xml | 6 ++ 6 files changed, 113 insertions(+), 41 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/ThreadBodyUtil.java diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiStrings.java b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiStrings.java index e43fe4cc75..0e09e621c6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiStrings.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/emoji/EmojiStrings.java @@ -2,4 +2,10 @@ package org.thoughtcrime.securesms.components.emoji; public final class EmojiStrings { public static final String BUST_IN_SILHOUETTE = "\uD83D\uDC64"; + public static final String PHOTO = "\uD83D\uDCF7"; + public static final String VIDEO = "\uD83C\uDFA5"; + public static final String GIF = "\uD83C\uDFA1"; + public static final String AUDIO = "\uD83C\uDFA4"; + public static final String FILE = "\uD83D\uDCCE"; + public static final String STICKER = "\u2B50"; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListItem.java index 18be1b02a4..95d6bfcf46 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversationlist/ConversationListItem.java @@ -24,7 +24,6 @@ import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.text.Spannable; import android.text.SpannableString; -import android.text.TextUtils; import android.text.style.StyleSpan; import android.util.AttributeSet; import android.view.View; @@ -441,17 +440,11 @@ public class ConversationListItem extends RelativeLayout } else if (SmsDatabase.Types.isUnsupportedMessageType(thread.getType())) { return emphasisAdded(context.getString(R.string.ThreadRecord_message_could_not_be_processed)); } else { - if (TextUtils.isEmpty(thread.getBody())) { - ThreadDatabase.Extra extra = thread.getExtra(); - if (extra != null && extra.isSticker()) { - return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_sticker))); - } else if (extra != null && extra.isViewOnce()) { - return new SpannableString(emphasisAdded(getViewOnceDescription(context, thread.getContentType()))); - } else if (extra != null && extra.isRemoteDelete()) { - return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_this_message_was_deleted))); - } else { - return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_media_message))); - } + ThreadDatabase.Extra extra = thread.getExtra(); + if (extra != null && extra.isViewOnce()) { + return new SpannableString(emphasisAdded(getViewOnceDescription(context, thread.getContentType()))); + } else if (extra != null && extra.isRemoteDelete()) { + return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_this_message_was_deleted))); } else { return new SpannableString(thread.getBody()); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadBodyUtil.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadBodyUtil.java new file mode 100644 index 0000000000..55074bb942 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadBodyUtil.java @@ -0,0 +1,84 @@ +package org.thoughtcrime.securesms.database; + +import android.content.Context; +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.components.emoji.EmojiStrings; +import org.thoughtcrime.securesms.contactshare.Contact; +import org.thoughtcrime.securesms.contactshare.ContactUtil; +import org.thoughtcrime.securesms.database.model.MessageRecord; +import org.thoughtcrime.securesms.database.model.MmsMessageRecord; +import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.mms.GifSlide; +import org.thoughtcrime.securesms.mms.Slide; +import org.thoughtcrime.securesms.util.MessageRecordUtil; + +public final class ThreadBodyUtil { + + private static final String TAG = Log.tag(ThreadBodyUtil.class); + + private ThreadBodyUtil() { + } + + public static @NonNull String getFormattedBodyFor(@NonNull Context context, @NonNull MessageRecord record) { + if (record.isMms()) { + return getFormattedBodyForMms(context, (MmsMessageRecord) record); + } + + return record.getBody(); + } + + private static @NonNull String getFormattedBodyForMms(@NonNull Context context, @NonNull MmsMessageRecord record) { + if (record.getSharedContacts().size() > 0) { + Contact contact = record.getSharedContacts().get(0); + + return ContactUtil.getStringSummary(context, contact).toString(); + } else if (record.getSlideDeck().getDocumentSlide() != null) { + return format(context, record, EmojiStrings.FILE, R.string.ThreadRecord_file); + } else if (record.getSlideDeck().getAudioSlide() != null) { + return format(context, record, EmojiStrings.AUDIO, R.string.ThreadRecord_voice_message); + } else if (MessageRecordUtil.hasSticker(record)) { + return format(context, record, EmojiStrings.STICKER, R.string.ThreadRecord_sticker); + } + + boolean hasImage = false; + boolean hasVideo = false; + boolean hasGif = false; + + for (Slide slide : record.getSlideDeck().getSlides()) { + hasVideo |= slide.hasVideo(); + hasImage |= slide.hasImage(); + hasGif |= slide instanceof GifSlide; + } + + if (hasGif) { + return format(context, record, EmojiStrings.GIF, R.string.ThreadRecord_gif); + } else if (hasVideo) { + return format(context, record, EmojiStrings.VIDEO, R.string.ThreadRecord_video); + } else if (hasImage) { + return format(context, record, EmojiStrings.PHOTO, R.string.ThreadRecord_photo); + } else if (TextUtils.isEmpty(record.getBody())) { + Log.w(TAG, "Got a media message without a body of a type we were not able to process. [contains media slide]:" + record.containsMediaSlide()); + return context.getString(R.string.ThreadRecord_media_message); + } else { + Log.w(TAG, "Got a media message with a body of a type we were not able to process. [contains media slide]:" + record.containsMediaSlide()); + return record.getBody(); + } + } + + private static @NonNull String format(@NonNull Context context, @NonNull MessageRecord record, @NonNull String emoji, @StringRes int defaultStringRes) { + return String.format("%s %s", emoji, getBodyOrDefault(context, record, defaultStringRes)); + } + + private static @NonNull String getBodyOrDefault(@NonNull Context context, @NonNull MessageRecord record, @StringRes int defaultStringRes) { + if (TextUtils.isEmpty(record.getBody())) { + return context.getString(defaultStringRes); + } else { + return record.getBody(); + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java index af8bdf88c0..f98ebf8523 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -757,7 +757,7 @@ public class ThreadDatabase extends Database { MessageRecord record; if (reader != null && (record = reader.getNext()) != null) { - updateThread(threadId, count, getFormattedBodyFor(record), getAttachmentUriFor(record), + updateThread(threadId, count, ThreadBodyUtil.getFormattedBodyFor(context, record), getAttachmentUriFor(record), getContentTypeFor(record), getExtrasFor(record), record.getTimestamp(), record.getDeliveryStatus(), record.getDeliveryReceiptCount(), record.getType(), unarchive, record.getExpiresIn(), record.getReadReceiptCount()); @@ -774,15 +774,6 @@ public class ThreadDatabase extends Database { } } - private @NonNull String getFormattedBodyFor(@NonNull MessageRecord messageRecord) { - if (messageRecord.isMms() && ((MmsMessageRecord) messageRecord).getSharedContacts().size() > 0) { - Contact contact = ((MmsMessageRecord) messageRecord).getSharedContacts().get(0); - return ContactUtil.getStringSummary(context, contact).toString(); - } - - return messageRecord.getBody(); - } - private @Nullable Uri getAttachmentUriFor(MessageRecord record) { if (!record.isMms() || record.isMmsNotification() || record.isGroupAction()) return null; diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java index 173d8f83b2..626d5dac3e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java @@ -16,12 +16,10 @@ */ package org.thoughtcrime.securesms.notifications; -import android.annotation.SuppressLint; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.database.Cursor; @@ -32,14 +30,14 @@ import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.service.notification.StatusBarNotification; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; + import androidx.annotation.NonNull; import androidx.annotation.StringRes; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; -import android.text.SpannableStringBuilder; -import android.text.TextUtils; - import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.contactshare.Contact; import org.thoughtcrime.securesms.contactshare.ContactUtil; @@ -48,25 +46,24 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo; import org.thoughtcrime.securesms.database.MmsSmsColumns; import org.thoughtcrime.securesms.database.MmsSmsDatabase; +import org.thoughtcrime.securesms.database.ThreadBodyUtil; import org.thoughtcrime.securesms.database.ThreadDatabase; -import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord; import org.thoughtcrime.securesms.database.model.ReactionRecord; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.messages.IncomingMessageObserver; import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientUtil; -import org.thoughtcrime.securesms.messages.IncomingMessageObserver; import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MessageRecordUtil; import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.SpanUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.util.concurrent.SignalExecutors; import org.thoughtcrime.securesms.webrtc.CallNotificationBuilder; import org.whispersystems.signalservice.internal.util.Util; @@ -521,21 +518,16 @@ public class DefaultMessageNotifier implements MessageNotifier { } else if (record.isMms() && !((MmsMessageRecord) record).getSharedContacts().isEmpty()) { Contact contact = ((MmsMessageRecord) record).getSharedContacts().get(0); body = ContactUtil.getStringSummary(context, contact); - } else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) { - body = SpanUtil.italic(context.getString(R.string.MessageNotifier_sticker)); - slideDeck = ((MmsMessageRecord) record).getSlideDeck(); } else if (record.isMms() && ((MmsMessageRecord) record).isViewOnce()) { body = SpanUtil.italic(context.getString(getViewOnceDescription((MmsMessageRecord) record))); } else if (record.isRemoteDelete()) { body = SpanUtil.italic(context.getString(R.string.MessageNotifier_this_message_was_deleted));; - } else if (record.isMms() && TextUtils.isEmpty(body) && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) { - body = SpanUtil.italic(context.getString(R.string.MessageNotifier_media_message)); - slideDeck = ((MediaMmsMessageRecord) record).getSlideDeck(); - } else if (record.isMms() && !record.isMmsNotification() && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) { - String message = context.getString(R.string.MessageNotifier_media_message_with_text, body); - int italicLength = message.length() - body.length(); - body = SpanUtil.italic(message, italicLength); - slideDeck = ((MediaMmsMessageRecord) record).getSlideDeck(); + } else if (!record.isMmsNotification()) { + body = ThreadBodyUtil.getFormattedBodyFor(context, record); + + if (record.isMms() && !((MmsMessageRecord) record).getSlideDeck().getSlides().isEmpty()) { + slideDeck = ((MmsMessageRecord) record).getSlideDeck(); + } } if (threadRecipients == null || !threadRecipients.isMuted()) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 26040bb761..905e03bba1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1117,6 +1117,12 @@ Message Request %1$s added you to the group %1$s invited you to the group + Photo + Gif + Voice Message + Contact + File + Video Signal update