2015-07-31 15:05:24 -07:00
|
|
|
package org.thoughtcrime.securesms.notifications;
|
|
|
|
|
|
|
|
import android.app.Notification;
|
|
|
|
import android.app.PendingIntent;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import android.graphics.drawable.Drawable;
|
2015-07-31 16:46:17 -07:00
|
|
|
import android.net.Uri;
|
|
|
|
import android.os.Build;
|
2015-07-31 15:05:24 -07:00
|
|
|
import android.support.annotation.NonNull;
|
|
|
|
import android.support.annotation.Nullable;
|
|
|
|
import android.support.v4.app.NotificationCompat;
|
|
|
|
import android.support.v4.app.NotificationCompat.Action;
|
|
|
|
import android.support.v4.app.RemoteInput;
|
|
|
|
import android.text.SpannableStringBuilder;
|
2017-10-16 13:11:42 -07:00
|
|
|
import android.util.Log;
|
2015-07-31 16:46:17 -07:00
|
|
|
|
2016-10-16 19:05:07 -07:00
|
|
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
2015-07-31 15:05:24 -07:00
|
|
|
|
|
|
|
import org.thoughtcrime.securesms.R;
|
2017-07-26 09:59:15 -07:00
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
2017-10-16 13:11:42 -07:00
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
|
|
|
|
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
2015-07-31 15:05:24 -07:00
|
|
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
2015-07-31 16:46:17 -07:00
|
|
|
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
2017-10-11 17:12:46 -07:00
|
|
|
import org.thoughtcrime.securesms.mms.GlideApp;
|
2015-08-10 09:33:57 -07:00
|
|
|
import org.thoughtcrime.securesms.mms.Slide;
|
2015-07-31 16:46:17 -07:00
|
|
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
2017-09-21 10:03:05 -07:00
|
|
|
import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference;
|
2015-07-31 15:05:24 -07:00
|
|
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
|
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
2017-04-21 23:04:54 -07:00
|
|
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
2015-12-04 15:00:13 -08:00
|
|
|
import org.thoughtcrime.securesms.util.Util;
|
2015-07-31 15:05:24 -07:00
|
|
|
|
|
|
|
import java.util.LinkedList;
|
|
|
|
import java.util.List;
|
2015-07-31 16:46:17 -07:00
|
|
|
import java.util.concurrent.ExecutionException;
|
2015-07-31 15:05:24 -07:00
|
|
|
|
|
|
|
public class SingleRecipientNotificationBuilder extends AbstractNotificationBuilder {
|
|
|
|
|
2015-07-31 16:46:17 -07:00
|
|
|
private static final String TAG = SingleRecipientNotificationBuilder.class.getSimpleName();
|
|
|
|
|
2015-07-31 15:05:24 -07:00
|
|
|
private final List<CharSequence> messageBodies = new LinkedList<>();
|
|
|
|
|
2015-10-21 15:32:19 -07:00
|
|
|
private SlideDeck slideDeck;
|
|
|
|
private final MasterSecret masterSecret;
|
2015-07-31 16:46:17 -07:00
|
|
|
|
2017-11-26 16:32:18 -08:00
|
|
|
private CharSequence contentTitle;
|
|
|
|
private CharSequence contentText;
|
|
|
|
|
2015-07-31 16:46:17 -07:00
|
|
|
public SingleRecipientNotificationBuilder(@NonNull Context context,
|
|
|
|
@Nullable MasterSecret masterSecret,
|
|
|
|
@NonNull NotificationPrivacyPreference privacy)
|
|
|
|
{
|
2015-07-31 15:05:24 -07:00
|
|
|
super(context, privacy);
|
2015-07-31 16:46:17 -07:00
|
|
|
this.masterSecret = masterSecret;
|
2015-07-31 15:05:24 -07:00
|
|
|
|
|
|
|
setSmallIcon(R.drawable.icon_notification);
|
|
|
|
setColor(context.getResources().getColor(R.color.textsecure_primary));
|
2017-04-21 23:04:54 -07:00
|
|
|
setPriority(TextSecurePreferences.getNotificationPriority(context));
|
2015-07-31 15:05:24 -07:00
|
|
|
setCategory(NotificationCompat.CATEGORY_MESSAGE);
|
|
|
|
}
|
|
|
|
|
2017-08-01 08:56:00 -07:00
|
|
|
public void setThread(@NonNull Recipient recipient) {
|
2015-07-31 15:05:24 -07:00
|
|
|
if (privacy.isDisplayContact()) {
|
2017-08-01 08:56:00 -07:00
|
|
|
setContentTitle(recipient.toShortString());
|
2015-07-31 15:05:24 -07:00
|
|
|
|
2017-08-01 08:56:00 -07:00
|
|
|
if (recipient.getContactUri() != null) {
|
|
|
|
addPerson(recipient.getContactUri().toString());
|
2015-07-31 15:05:24 -07:00
|
|
|
}
|
|
|
|
|
2017-10-16 13:11:42 -07:00
|
|
|
ContactPhoto contactPhoto = recipient.getContactPhoto();
|
|
|
|
FallbackContactPhoto fallbackContactPhoto = recipient.getFallbackContactPhoto();
|
|
|
|
|
|
|
|
if (contactPhoto != null) {
|
|
|
|
try {
|
|
|
|
setLargeIcon(GlideApp.with(context.getApplicationContext())
|
|
|
|
.load(contactPhoto)
|
|
|
|
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
|
|
|
.circleCrop()
|
|
|
|
.submit(context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width),
|
|
|
|
context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height))
|
|
|
|
.get());
|
|
|
|
} catch (InterruptedException | ExecutionException e) {
|
|
|
|
Log.w(TAG, e);
|
|
|
|
setLargeIcon(fallbackContactPhoto.asDrawable(context, recipient.getColor().toConversationColor(context)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
setLargeIcon(fallbackContactPhoto.asDrawable(context, recipient.getColor().toConversationColor(context)));
|
|
|
|
}
|
|
|
|
|
2015-07-31 15:05:24 -07:00
|
|
|
} else {
|
2015-11-17 00:55:22 +01:00
|
|
|
setContentTitle(context.getString(R.string.SingleRecipientNotificationBuilder_signal));
|
2017-10-16 13:11:42 -07:00
|
|
|
setLargeIcon(new GeneratedContactPhoto("Unknown").asDrawable(context, ContactColors.UNKNOWN_COLOR.toConversationColor(context)));
|
2015-07-31 15:05:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setMessageCount(int messageCount) {
|
|
|
|
setContentInfo(String.valueOf(messageCount));
|
|
|
|
setNumber(messageCount);
|
|
|
|
}
|
|
|
|
|
2017-08-01 08:56:00 -07:00
|
|
|
public void setPrimaryMessageBody(@NonNull Recipient threadRecipients,
|
2015-12-04 15:00:13 -08:00
|
|
|
@NonNull Recipient individualRecipient,
|
|
|
|
@NonNull CharSequence message,
|
|
|
|
@Nullable SlideDeck slideDeck)
|
|
|
|
{
|
|
|
|
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
|
|
|
|
|
2017-08-01 08:56:00 -07:00
|
|
|
if (privacy.isDisplayContact() && threadRecipients.isGroupRecipient()) {
|
2015-12-04 15:00:13 -08:00
|
|
|
stringBuilder.append(Util.getBoldedString(individualRecipient.toShortString() + ": "));
|
|
|
|
}
|
|
|
|
|
2015-07-31 15:05:24 -07:00
|
|
|
if (privacy.isDisplayMessage()) {
|
2015-12-04 15:00:13 -08:00
|
|
|
setContentText(stringBuilder.append(message));
|
2015-07-31 16:46:17 -07:00
|
|
|
this.slideDeck = slideDeck;
|
2015-07-31 15:05:24 -07:00
|
|
|
} else {
|
2015-12-04 15:00:13 -08:00
|
|
|
setContentText(stringBuilder.append(context.getString(R.string.SingleRecipientNotificationBuilder_new_message)));
|
2015-07-31 15:05:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-14 23:58:24 +02:00
|
|
|
public void addAndroidAutoAction(@NonNull PendingIntent androidAutoReplyIntent,
|
|
|
|
@NonNull PendingIntent androidAutoHeardIntent, long timestamp)
|
|
|
|
{
|
|
|
|
|
2017-11-26 16:32:18 -08:00
|
|
|
if (contentTitle == null || contentText == null)
|
2016-09-14 23:58:24 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
RemoteInput remoteInput = new RemoteInput.Builder(AndroidAutoReplyReceiver.VOICE_REPLY_KEY)
|
|
|
|
.setLabel(context.getString(R.string.MessageNotifier_reply))
|
|
|
|
.build();
|
|
|
|
|
|
|
|
NotificationCompat.CarExtender.UnreadConversation.Builder unreadConversationBuilder =
|
2017-11-26 16:32:18 -08:00
|
|
|
new NotificationCompat.CarExtender.UnreadConversation.Builder(contentTitle.toString())
|
|
|
|
.addMessage(contentText.toString())
|
2016-09-14 23:58:24 +02:00
|
|
|
.setLatestTimestamp(timestamp)
|
|
|
|
.setReadPendingIntent(androidAutoHeardIntent)
|
|
|
|
.setReplyAction(androidAutoReplyIntent, remoteInput);
|
|
|
|
|
|
|
|
extend(new NotificationCompat.CarExtender().setUnreadConversation(unreadConversationBuilder.build()));
|
|
|
|
}
|
|
|
|
|
2015-07-31 15:05:24 -07:00
|
|
|
public void addActions(@Nullable MasterSecret masterSecret,
|
|
|
|
@NonNull PendingIntent markReadIntent,
|
|
|
|
@NonNull PendingIntent quickReplyIntent,
|
|
|
|
@NonNull PendingIntent wearableReplyIntent)
|
|
|
|
{
|
|
|
|
Action markAsReadAction = new Action(R.drawable.check,
|
|
|
|
context.getString(R.string.MessageNotifier_mark_read),
|
|
|
|
markReadIntent);
|
|
|
|
|
|
|
|
if (masterSecret != null) {
|
|
|
|
Action replyAction = new Action(R.drawable.ic_reply_white_36dp,
|
|
|
|
context.getString(R.string.MessageNotifier_reply),
|
|
|
|
quickReplyIntent);
|
|
|
|
|
2016-12-25 19:00:33 -08:00
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
|
|
replyAction = new Action.Builder(R.drawable.ic_reply_white_36dp,
|
|
|
|
context.getString(R.string.MessageNotifier_reply),
|
|
|
|
wearableReplyIntent)
|
|
|
|
.addRemoteInput(new RemoteInput.Builder(MessageNotifier.EXTRA_REMOTE_REPLY)
|
|
|
|
.setLabel(context.getString(R.string.MessageNotifier_reply)).build())
|
|
|
|
.build();
|
|
|
|
}
|
|
|
|
|
2015-07-31 15:05:24 -07:00
|
|
|
Action wearableReplyAction = new Action.Builder(R.drawable.ic_reply,
|
|
|
|
context.getString(R.string.MessageNotifier_reply),
|
|
|
|
wearableReplyIntent)
|
2016-12-25 19:00:33 -08:00
|
|
|
.addRemoteInput(new RemoteInput.Builder(MessageNotifier.EXTRA_REMOTE_REPLY)
|
2015-07-31 15:05:24 -07:00
|
|
|
.setLabel(context.getString(R.string.MessageNotifier_reply)).build())
|
|
|
|
.build();
|
|
|
|
|
|
|
|
addAction(markAsReadAction);
|
|
|
|
addAction(replyAction);
|
|
|
|
|
|
|
|
extend(new NotificationCompat.WearableExtender().addAction(markAsReadAction)
|
|
|
|
.addAction(wearableReplyAction));
|
|
|
|
} else {
|
|
|
|
addAction(markAsReadAction);
|
|
|
|
|
|
|
|
extend(new NotificationCompat.WearableExtender().addAction(markAsReadAction));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-01 08:56:00 -07:00
|
|
|
public void addMessageBody(@NonNull Recipient threadRecipient,
|
2015-12-04 15:00:13 -08:00
|
|
|
@NonNull Recipient individualRecipient,
|
|
|
|
@Nullable CharSequence messageBody)
|
|
|
|
{
|
|
|
|
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
|
|
|
|
|
2017-08-01 08:56:00 -07:00
|
|
|
if (privacy.isDisplayContact() && threadRecipient.isGroupRecipient()) {
|
2015-12-04 15:00:13 -08:00
|
|
|
stringBuilder.append(Util.getBoldedString(individualRecipient.toShortString() + ": "));
|
|
|
|
}
|
|
|
|
|
2015-07-31 15:05:24 -07:00
|
|
|
if (privacy.isDisplayMessage()) {
|
2015-12-04 15:00:13 -08:00
|
|
|
messageBodies.add(stringBuilder.append(messageBody == null ? "" : messageBody));
|
|
|
|
} else {
|
|
|
|
messageBodies.add(stringBuilder.append(context.getString(R.string.SingleRecipientNotificationBuilder_new_message)));
|
2015-07-31 15:05:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Notification build() {
|
|
|
|
if (privacy.isDisplayMessage()) {
|
2015-07-31 16:46:17 -07:00
|
|
|
if (messageBodies.size() == 1 && hasBigPictureSlide(slideDeck)) {
|
|
|
|
assert masterSecret != null;
|
|
|
|
setStyle(new NotificationCompat.BigPictureStyle()
|
|
|
|
.bigPicture(getBigPicture(masterSecret, slideDeck))
|
|
|
|
.setSummaryText(getBigText(messageBodies)));
|
|
|
|
} else {
|
|
|
|
setStyle(new NotificationCompat.BigTextStyle().bigText(getBigText(messageBodies)));
|
2015-07-31 15:05:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return super.build();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setLargeIcon(@Nullable Drawable drawable) {
|
|
|
|
if (drawable != null) {
|
|
|
|
int largeIconTargetSize = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size);
|
|
|
|
Bitmap recipientPhotoBitmap = BitmapUtil.createFromDrawable(drawable, largeIconTargetSize, largeIconTargetSize);
|
|
|
|
|
|
|
|
if (recipientPhotoBitmap != null) {
|
|
|
|
setLargeIcon(recipientPhotoBitmap);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-21 15:32:19 -07:00
|
|
|
private boolean hasBigPictureSlide(@Nullable SlideDeck slideDeck) {
|
|
|
|
if (masterSecret == null || slideDeck == null || Build.VERSION.SDK_INT < 16) {
|
2015-07-31 16:46:17 -07:00
|
|
|
return false;
|
|
|
|
}
|
2015-10-21 15:32:19 -07:00
|
|
|
|
|
|
|
Slide thumbnailSlide = slideDeck.getThumbnailSlide();
|
|
|
|
|
|
|
|
return thumbnailSlide != null &&
|
|
|
|
thumbnailSlide.hasImage() &&
|
|
|
|
!thumbnailSlide.isInProgress() &&
|
|
|
|
thumbnailSlide.getThumbnailUri() != null;
|
2015-07-31 16:46:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private Bitmap getBigPicture(@NonNull MasterSecret masterSecret,
|
2015-10-21 15:32:19 -07:00
|
|
|
@NonNull SlideDeck slideDeck)
|
2015-07-31 16:46:17 -07:00
|
|
|
{
|
|
|
|
try {
|
2015-10-21 15:32:19 -07:00
|
|
|
@SuppressWarnings("ConstantConditions")
|
|
|
|
Uri uri = slideDeck.getThumbnailSlide().getThumbnailUri();
|
2015-07-31 16:46:17 -07:00
|
|
|
|
2017-10-16 13:11:42 -07:00
|
|
|
return GlideApp.with(context.getApplicationContext())
|
2017-10-11 17:12:46 -07:00
|
|
|
.asBitmap()
|
|
|
|
.load(new DecryptableStreamUriLoader.DecryptableUri(masterSecret, uri))
|
|
|
|
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
|
|
|
.submit(500, 500)
|
|
|
|
.get();
|
2015-07-31 16:46:17 -07:00
|
|
|
} catch (InterruptedException | ExecutionException e) {
|
2018-01-18 10:11:33 -08:00
|
|
|
Log.w(TAG, e);
|
|
|
|
return Bitmap.createBitmap(500, 500, Bitmap.Config.RGB_565);
|
2015-07-31 16:46:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-26 16:32:18 -08:00
|
|
|
@Override
|
|
|
|
public NotificationCompat.Builder setContentTitle(CharSequence contentTitle) {
|
|
|
|
this.contentTitle = contentTitle;
|
|
|
|
return super.setContentTitle(contentTitle);
|
|
|
|
}
|
|
|
|
|
|
|
|
public NotificationCompat.Builder setContentText(CharSequence contentText) {
|
|
|
|
this.contentText = contentText;
|
|
|
|
return super.setContentText(contentText);
|
|
|
|
}
|
|
|
|
|
2015-07-31 16:46:17 -07:00
|
|
|
private CharSequence getBigText(List<CharSequence> messageBodies) {
|
|
|
|
SpannableStringBuilder content = new SpannableStringBuilder();
|
|
|
|
|
|
|
|
for (CharSequence message : messageBodies) {
|
|
|
|
content.append(message);
|
|
|
|
content.append('\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
return content;
|
|
|
|
}
|
|
|
|
|
2015-07-31 15:05:24 -07:00
|
|
|
}
|