diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 5ddd338b3..aeba1f14c 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -271,6 +271,17 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl return null; } + public Message findMessageWithUuid(final String uuid) { + synchronized (this.messages) { + for (final Message message : this.messages) { + if (message.getUuid().equals(uuid)) { + return message; + } + } + } + return null; + } + public boolean markAsDeleted(final List uuids) { boolean deleted = false; final PgpDecryptionService pgpDecryptionService = account.getPgpDecryptionService(); diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 6c53134aa..aa197aa44 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -984,13 +984,28 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable } if (conversation.getMode() == Conversation.MODE_MULTI) { final Jid nextCounterpart = conversation.getNextCounterpart(); - if (nextCounterpart != null) { - message.setCounterpart(nextCounterpart); - message.setTrueCounterpart(conversation.getMucOptions().getTrueCounterpart(nextCounterpart)); - message.setType(isFile ? Message.TYPE_PRIVATE_FILE : Message.TYPE_PRIVATE); - return true; - } + return configurePrivateMessage(conversation, message, nextCounterpart, isFile); } return false; } + + public static boolean configurePrivateMessage(final Message message, final Jid counterpart) { + final Conversation conversation; + if (message.conversation instanceof Conversation) { + conversation = (Conversation) message.conversation; + } else { + return false; + } + return configurePrivateMessage(conversation, message, counterpart, false); + } + + private static boolean configurePrivateMessage(final Conversation conversation, final Message message, final Jid counterpart, final boolean isFile) { + if (counterpart == null) { + return false; + } + message.setCounterpart(counterpart); + message.setTrueCounterpart(conversation.getMucOptions().getTrueCounterpart(counterpart)); + message.setType(isFile ? Message.TYPE_PRIVATE_FILE : Message.TYPE_PRIVATE); + return true; + } } diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index bbde8e904..2f6f36c59 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -35,6 +35,7 @@ import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.IconCompat; import com.google.common.base.Strings; +import com.google.common.collect.Iterables; import java.io.File; import java.io.IOException; @@ -407,7 +408,7 @@ public class NotificationService { currentInterruptionFilter = 1; //INTERRUPTION_FILTER_ALL } if (currentInterruptionFilter != 1) { - Log.d(Config.LOGTAG,"do not ring or vibrate because interruption filter has been set to "+currentInterruptionFilter); + Log.d(Config.LOGTAG, "do not ring or vibrate because interruption filter has been set to " + currentInterruptionFilter); return; } final ScheduledFuture currentVibrationFuture = this.vibrationFuture; @@ -424,13 +425,13 @@ public class NotificationService { final Resources resources = mXmppConnectionService.getResources(); final String ringtonePreference = preferences.getString("call_ringtone", resources.getString(R.string.incoming_call_ringtone)); if (Strings.isNullOrEmpty(ringtonePreference)) { - Log.d(Config.LOGTAG,"ringtone has been set to none"); + Log.d(Config.LOGTAG, "ringtone has been set to none"); return; } final Uri uri = Uri.parse(ringtonePreference); this.currentlyPlayingRingtone = RingtoneManager.getRingtone(mXmppConnectionService, uri); if (this.currentlyPlayingRingtone == null) { - Log.d(Config.LOGTAG,"unable to find ringtone for uri "+uri); + Log.d(Config.LOGTAG, "unable to find ringtone for uri " + uri); return; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { @@ -790,17 +791,18 @@ public class NotificationService { .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ) .setShowsUserInterface(false) .build(); - String replyLabel = mXmppConnectionService.getString(R.string.reply); - NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder( + final String replyLabel = mXmppConnectionService.getString(R.string.reply); + final String lastMessageUuid = Iterables.getLast(messages).getUuid(); + final NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder( R.drawable.ic_send_text_offline, replyLabel, - createReplyIntent(conversation, false)) + createReplyIntent(conversation, lastMessageUuid, false)) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY) .setShowsUserInterface(false) .addRemoteInput(remoteInput).build(); - NotificationCompat.Action wearReplyAction = new NotificationCompat.Action.Builder(R.drawable.ic_wear_reply, + final NotificationCompat.Action wearReplyAction = new NotificationCompat.Action.Builder(R.drawable.ic_wear_reply, replyLabel, - createReplyIntent(conversation, true)).addRemoteInput(remoteInput).build(); + createReplyIntent(conversation, lastMessageUuid, true)).addRemoteInput(remoteInput).build(); mBuilder.extend(new NotificationCompat.WearableExtender().addAction(wearReplyAction)); int addedActionsCount = 1; mBuilder.addAction(markReadAction); @@ -1066,13 +1068,14 @@ public class NotificationService { return PendingIntent.getService(mXmppConnectionService, 0, intent, 0); } - private PendingIntent createReplyIntent(Conversation conversation, boolean dismissAfterReply) { + private PendingIntent createReplyIntent(final Conversation conversation, final String lastMessageUuid, final boolean dismissAfterReply) { final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class); intent.setAction(XmppConnectionService.ACTION_REPLY_TO_CONVERSATION); intent.putExtra("uuid", conversation.getUuid()); intent.putExtra("dismiss_notification", dismissAfterReply); + intent.putExtra("last_message_uuid", lastMessageUuid); final int id = generateRequestCode(conversation, dismissAfterReply ? 12 : 14); - return PendingIntent.getService(mXmppConnectionService, id, intent, 0); + return PendingIntent.getService(mXmppConnectionService, id, intent, PendingIntent.FLAG_UPDATE_CURRENT); } private PendingIntent createReadPendingIntent(Conversation conversation) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 1c91c1ee8..4222b9faa 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -726,6 +726,7 @@ public class XmppConnectionService extends Service { } final CharSequence body = remoteInput.getCharSequence("text_reply"); final boolean dismissNotification = intent.getBooleanExtra("dismiss_notification", false); + final String lastMessageUuid = intent.getStringExtra("last_message_uuid"); if (body == null || body.length() <= 0) { break; } @@ -734,7 +735,7 @@ public class XmppConnectionService extends Service { restoredFromDatabaseLatch.await(); final Conversation c = findConversationByUuid(uuid); if (c != null) { - directReply(c, body.toString(), dismissNotification); + directReply(c, body.toString(), lastMessageUuid, dismissNotification); } } catch (InterruptedException e) { Log.d(Config.LOGTAG, "unable to process direct reply"); @@ -932,8 +933,12 @@ public class XmppConnectionService extends Service { } } - private void directReply(Conversation conversation, String body, final boolean dismissAfterReply) { - Message message = new Message(conversation, body, conversation.getNextEncryption()); + private void directReply(final Conversation conversation, final String body, final String lastMessageUuid, final boolean dismissAfterReply) { + final Message inReplyTo = lastMessageUuid == null ? null : conversation.findMessageWithUuid(lastMessageUuid); + final Message message = new Message(conversation, body, conversation.getNextEncryption()); + if (inReplyTo != null && inReplyTo.isPrivateMessage()) { + Message.configurePrivateMessage(message, inReplyTo.getCounterpart()); + } message.markUnread(); if (message.getEncryption() == Message.ENCRYPTION_PGP) { getPgpEngine().encrypt(message, new UiCallback() {