mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-25 17:27:45 +00:00
Support for images in notifications.
Closes #3859 Fixes #1858 // FREEBIE
This commit is contained in:
parent
120cde9917
commit
f8bb065ffd
@ -12,6 +12,7 @@ import org.thoughtcrime.securesms.database.PartDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.PartDatabase.PartId;
|
import org.thoughtcrime.securesms.database.PartDatabase.PartId;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||||
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.jobqueue.JobParameters;
|
import org.whispersystems.jobqueue.JobParameters;
|
||||||
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
|
||||||
@ -66,6 +67,8 @@ public class AttachmentDownloadJob extends MasterSecretJob implements Injectable
|
|||||||
retrievePart(masterSecret, part, messageId);
|
retrievePart(masterSecret, part, messageId);
|
||||||
Log.w(TAG, "Got part: " + part.getPartId());
|
Log.w(TAG, "Got part: " + part.getPartId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessageNotifier.updateNotification(context, masterSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,13 +42,17 @@ import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.PushDatabase;
|
import org.thoughtcrime.securesms.database.PushDatabase;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
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.MessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||||
|
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||||
import org.thoughtcrime.securesms.util.SpanUtil;
|
import org.thoughtcrime.securesms.util.SpanUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||||
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
|
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -187,12 +191,12 @@ public class MessageNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context));
|
SingleRecipientNotificationBuilder builder = new SingleRecipientNotificationBuilder(context, masterSecret, TextSecurePreferences.getNotificationPrivacy(context));
|
||||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||||
|
|
||||||
builder.setSender(notifications.get(0).getIndividualRecipient());
|
builder.setSender(notifications.get(0).getIndividualRecipient());
|
||||||
builder.setMessageCount(notificationState.getMessageCount());
|
builder.setMessageCount(notificationState.getMessageCount());
|
||||||
builder.setPrimaryMessageBody(notifications.get(0).getText());
|
builder.setPrimaryMessageBody(notifications.get(0).getText(), notifications.get(0).getSlideDeck());
|
||||||
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
|
builder.setContentIntent(notifications.get(0).getPendingIntent(context));
|
||||||
|
|
||||||
long timestamp = notifications.get(0).getTimestamp();
|
long timestamp = notifications.get(0).getTimestamp();
|
||||||
@ -318,7 +322,7 @@ public class MessageNotifier {
|
|||||||
body.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, body.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
body.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, body.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
if (!recipients.isMuted()) {
|
if (!recipients.isMuted()) {
|
||||||
notificationState.addNotification(new NotificationItem(recipient, recipients, null, threadId, body, 0));
|
notificationState.addNotification(new NotificationItem(recipient, recipients, null, threadId, body, 0, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@ -344,6 +348,7 @@ public class MessageNotifier {
|
|||||||
long threadId = record.getThreadId();
|
long threadId = record.getThreadId();
|
||||||
CharSequence body = record.getDisplayBody();
|
CharSequence body = record.getDisplayBody();
|
||||||
Recipients threadRecipients = null;
|
Recipients threadRecipients = null;
|
||||||
|
ListenableFutureTask<SlideDeck> slideDeck = null;
|
||||||
long timestamp;
|
long timestamp;
|
||||||
|
|
||||||
if (record.isPush()) timestamp = record.getDateSent();
|
if (record.isPush()) timestamp = record.getDateSent();
|
||||||
@ -357,14 +362,16 @@ public class MessageNotifier {
|
|||||||
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_locked_message));
|
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_locked_message));
|
||||||
} else if (record.isMms() && TextUtils.isEmpty(body)) {
|
} else if (record.isMms() && TextUtils.isEmpty(body)) {
|
||||||
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_media_message));
|
body = SpanUtil.italic(context.getString(R.string.MessageNotifier_media_message));
|
||||||
|
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeckFuture();
|
||||||
} else if (record.isMms() && !record.isMmsNotification()) {
|
} else if (record.isMms() && !record.isMmsNotification()) {
|
||||||
String message = context.getString(R.string.MessageNotifier_media_message_with_text, body);
|
String message = context.getString(R.string.MessageNotifier_media_message_with_text, body);
|
||||||
int italicLength = message.length() - body.length();
|
int italicLength = message.length() - body.length();
|
||||||
body = SpanUtil.italic(message, italicLength);
|
body = SpanUtil.italic(message, italicLength);
|
||||||
|
slideDeck = ((MediaMmsMessageRecord)record).getSlideDeckFuture();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (threadRecipients == null || !threadRecipients.isMuted()) {
|
if (threadRecipients == null || !threadRecipients.isMuted()) {
|
||||||
notificationState.addNotification(new NotificationItem(recipient, recipients, threadRecipients, threadId, body, timestamp));
|
notificationState.addNotification(new NotificationItem(recipient, recipients, threadRecipients, threadId, body, timestamp, slideDeck));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,14 @@ import android.app.PendingIntent;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ConversationActivity;
|
import org.thoughtcrime.securesms.ConversationActivity;
|
||||||
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||||
|
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||||
|
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
public class NotificationItem {
|
public class NotificationItem {
|
||||||
|
|
||||||
@ -17,10 +21,12 @@ public class NotificationItem {
|
|||||||
private final long threadId;
|
private final long threadId;
|
||||||
private final CharSequence text;
|
private final CharSequence text;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
|
private final ListenableFutureTask<SlideDeck> slideDeck;
|
||||||
|
|
||||||
public NotificationItem(Recipient individualRecipient, Recipients recipients,
|
public NotificationItem(Recipient individualRecipient, Recipients recipients,
|
||||||
Recipients threadRecipients, long threadId,
|
Recipients threadRecipients, long threadId,
|
||||||
CharSequence text, long timestamp)
|
CharSequence text, long timestamp,
|
||||||
|
@Nullable ListenableFutureTask<SlideDeck> slideDeck)
|
||||||
{
|
{
|
||||||
this.individualRecipient = individualRecipient;
|
this.individualRecipient = individualRecipient;
|
||||||
this.recipients = recipients;
|
this.recipients = recipients;
|
||||||
@ -28,6 +34,7 @@ public class NotificationItem {
|
|||||||
this.text = text;
|
this.text = text;
|
||||||
this.threadId = threadId;
|
this.threadId = threadId;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
|
this.slideDeck = slideDeck;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Recipients getRecipients() {
|
public Recipients getRecipients() {
|
||||||
@ -50,6 +57,10 @@ public class NotificationItem {
|
|||||||
return threadId;
|
return threadId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable ListenableFutureTask<SlideDeck> getSlideDeck() {
|
||||||
|
return slideDeck;
|
||||||
|
}
|
||||||
|
|
||||||
public PendingIntent getPendingIntent(Context context) {
|
public PendingIntent getPendingIntent(Context context) {
|
||||||
Intent intent = new Intent(context, ConversationActivity.class);
|
Intent intent = new Intent(context, ConversationActivity.class);
|
||||||
Recipients notifyRecipients = threadRecipients != null ? threadRecipients : recipients;
|
Recipients notifyRecipients = threadRecipients != null ? threadRecipients : recipients;
|
||||||
|
@ -6,28 +6,46 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.app.NotificationCompat.Action;
|
import android.support.v4.app.NotificationCompat.Action;
|
||||||
import android.support.v4.app.RemoteInput;
|
import android.support.v4.app.RemoteInput;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||||
|
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
||||||
|
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||||
import org.thoughtcrime.securesms.preferences.NotificationPrivacyPreference;
|
import org.thoughtcrime.securesms.preferences.NotificationPrivacyPreference;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
public class SingleRecipientNotificationBuilder extends AbstractNotificationBuilder {
|
public class SingleRecipientNotificationBuilder extends AbstractNotificationBuilder {
|
||||||
|
|
||||||
|
private static final String TAG = SingleRecipientNotificationBuilder.class.getSimpleName();
|
||||||
|
|
||||||
private final List<CharSequence> messageBodies = new LinkedList<>();
|
private final List<CharSequence> messageBodies = new LinkedList<>();
|
||||||
|
|
||||||
public SingleRecipientNotificationBuilder(@NonNull Context context, @NonNull NotificationPrivacyPreference privacy) {
|
private ListenableFutureTask<SlideDeck> slideDeck;
|
||||||
|
private final MasterSecret masterSecret;
|
||||||
|
|
||||||
|
public SingleRecipientNotificationBuilder(@NonNull Context context,
|
||||||
|
@Nullable MasterSecret masterSecret,
|
||||||
|
@NonNull NotificationPrivacyPreference privacy)
|
||||||
|
{
|
||||||
super(context, privacy);
|
super(context, privacy);
|
||||||
|
this.masterSecret = masterSecret;
|
||||||
|
|
||||||
setSmallIcon(R.drawable.icon_notification);
|
setSmallIcon(R.drawable.icon_notification);
|
||||||
setColor(context.getResources().getColor(R.color.textsecure_primary));
|
setColor(context.getResources().getColor(R.color.textsecure_primary));
|
||||||
@ -62,9 +80,10 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
|
|||||||
setNumber(messageCount);
|
setNumber(messageCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPrimaryMessageBody(CharSequence message) {
|
public void setPrimaryMessageBody(CharSequence message, @Nullable ListenableFutureTask<SlideDeck> slideDeck) {
|
||||||
if (privacy.isDisplayMessage()) {
|
if (privacy.isDisplayMessage()) {
|
||||||
setContentText(message);
|
setContentText(message);
|
||||||
|
this.slideDeck = slideDeck;
|
||||||
} else {
|
} else {
|
||||||
setContentText(context.getString(R.string.SingleRecipientNotificationBuilder_contents_hidden));
|
setContentText(context.getString(R.string.SingleRecipientNotificationBuilder_contents_hidden));
|
||||||
}
|
}
|
||||||
@ -122,14 +141,14 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
|
|||||||
@Override
|
@Override
|
||||||
public Notification build() {
|
public Notification build() {
|
||||||
if (privacy.isDisplayMessage()) {
|
if (privacy.isDisplayMessage()) {
|
||||||
SpannableStringBuilder content = new SpannableStringBuilder();
|
if (messageBodies.size() == 1 && hasBigPictureSlide(slideDeck)) {
|
||||||
|
assert masterSecret != null;
|
||||||
for (CharSequence message : messageBodies) {
|
setStyle(new NotificationCompat.BigPictureStyle()
|
||||||
content.append(message);
|
.bigPicture(getBigPicture(masterSecret, slideDeck))
|
||||||
content.append('\n');
|
.setSummaryText(getBigText(messageBodies)));
|
||||||
|
} else {
|
||||||
|
setStyle(new NotificationCompat.BigTextStyle().bigText(getBigText(messageBodies)));
|
||||||
}
|
}
|
||||||
|
|
||||||
setStyle(new NotificationCompat.BigTextStyle().bigText(content));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.build();
|
return super.build();
|
||||||
@ -146,4 +165,45 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasBigPictureSlide(@Nullable ListenableFutureTask<SlideDeck> slideDeck) {
|
||||||
|
try {
|
||||||
|
return masterSecret != null &&
|
||||||
|
slideDeck != null &&
|
||||||
|
Build.VERSION.SDK_INT >= 16 &&
|
||||||
|
slideDeck.get().getThumbnailSlide(context).hasImage() &&
|
||||||
|
!slideDeck.get().getThumbnailSlide(context).isInProgress() &&
|
||||||
|
slideDeck.get().getThumbnailSlide(context).getThumbnailUri() != null;
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap getBigPicture(@NonNull MasterSecret masterSecret,
|
||||||
|
@NonNull ListenableFutureTask<SlideDeck> slideDeck)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Uri uri = slideDeck.get().getThumbnailSlide(context).getThumbnailUri();
|
||||||
|
|
||||||
|
return Glide.with(context)
|
||||||
|
.load(new DecryptableStreamUriLoader.DecryptableUri(masterSecret, uri))
|
||||||
|
.asBitmap()
|
||||||
|
.into(500, 500)
|
||||||
|
.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CharSequence getBigText(List<CharSequence> messageBodies) {
|
||||||
|
SpannableStringBuilder content = new SpannableStringBuilder();
|
||||||
|
|
||||||
|
for (CharSequence message : messageBodies) {
|
||||||
|
content.append(message);
|
||||||
|
content.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user