delay notification until after pgp decryption

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java  | 37 
src/main/java/eu/siacs/conversations/entities/Conversation.java        |  2 
src/main/java/eu/siacs/conversations/entities/Message.java             |  2 
src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java  |  5 
src/main/java/eu/siacs/conversations/parser/MessageParser.java         | 14 
src/main/java/eu/siacs/conversations/ui/ConversationFragment.java      |  2 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java | 11 
7 files changed, 51 insertions(+), 22 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java 🔗

@@ -14,6 +14,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URL;
 import java.util.ArrayDeque;
+import java.util.HashSet;
 import java.util.List;
 
 import eu.siacs.conversations.entities.Conversation;
@@ -28,6 +29,7 @@ public class PgpDecryptionService {
     private OpenPgpApi openPgpApi = null;
 
 	protected final ArrayDeque<Message> messages = new ArrayDeque();
+    protected final HashSet<Message> pendingNotifications = new HashSet<>();
 	Message currentMessage;
     private PendingIntent pendingIntent;
 
@@ -36,9 +38,16 @@ public class PgpDecryptionService {
         this.mXmppConnectionService = service;
     }
 
-	public synchronized void decrypt(final Message message) {
+	public synchronized boolean decrypt(final Message message, boolean notify) {
         messages.add(message);
-		continueDecryption();
+        if (notify && pendingIntent == null) {
+            pendingNotifications.add(message);
+            continueDecryption();
+            return false;
+        } else {
+            continueDecryption();
+            return notify;
+        }
 	}
 
     public synchronized void decrypt(final List<Message> list) {
@@ -52,6 +61,7 @@ public class PgpDecryptionService {
 
     public synchronized void discard(List<Message> discards) {
         this.messages.removeAll(discards);
+        this.pendingNotifications.removeAll(discards);
     }
 
 	protected synchronized void decryptNext() {
@@ -113,9 +123,11 @@ public class PgpDecryptionService {
                     mXmppConnectionService.updateMessage(message);
                     break;
                 case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
-                    messages.addFirst(message);
-                    currentMessage = null;
-                    storePendingIntent((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
+                    synchronized (PgpDecryptionService.this) {
+                        messages.addFirst(message);
+                        currentMessage = null;
+                        storePendingIntent((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
+                    }
                     break;
                 case OpenPgpApi.RESULT_CODE_ERROR:
                     message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
@@ -141,9 +153,11 @@ public class PgpDecryptionService {
                         mXmppConnectionService.updateMessage(message);
                         break;
                     case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
-                        messages.addFirst(message);
-                        currentMessage = null;
-                        storePendingIntent((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
+                        synchronized (PgpDecryptionService.this) {
+                            messages.addFirst(message);
+                            currentMessage = null;
+                            storePendingIntent((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT));
+                        }
                         break;
                     case OpenPgpApi.RESULT_CODE_ERROR:
                         message.setEncryption(Message.ENCRYPTION_DECRYPTION_FAILED);
@@ -155,6 +169,13 @@ public class PgpDecryptionService {
                 mXmppConnectionService.updateMessage(message);
             }
         }
+        notifyIfPending(message);
+    }
+
+    private synchronized void notifyIfPending(Message message) {
+        if (pendingNotifications.remove(message)) {
+            mXmppConnectionService.getNotificationService().push(message);
+        }
     }
 
     private void storePendingIntent(PendingIntent pendingIntent) {

src/main/java/eu/siacs/conversations/entities/Conversation.java 🔗

@@ -774,7 +774,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
 	public boolean hasDuplicateMessage(Message message) {
 		synchronized (this.messages) {
 			for (int i = this.messages.size() - 1; i >= 0; --i) {
-				if (this.messages.get(i).equals(message)) {
+				if (this.messages.get(i).similar(message)) {
 					return true;
 				}
 			}

src/main/java/eu/siacs/conversations/entities/Message.java 🔗

@@ -377,7 +377,7 @@ public class Message extends AbstractEntity {
 		this.transferable = transferable;
 	}
 
-	public boolean equals(Message message) {
+	public boolean similar(Message message) {
 		if (this.serverMsgId != null && message.getServerMsgId() != null) {
 			return this.serverMsgId.equals(message.getServerMsgId());
 		} else if (this.body == null || this.counterpart == null) {

src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java 🔗

@@ -126,11 +126,12 @@ public class HttpDownloadConnection implements Transferable {
 		mXmppConnectionService.getFileBackend().updateMediaScanner(file);
 		message.setTransferable(null);
 		mHttpConnectionManager.finishConnection(this);
+		boolean notify = acceptedAutomatically && !message.isRead();
 		if (message.getEncryption() == Message.ENCRYPTION_PGP) {
-			message.getConversation().getAccount().getPgpDecryptionService().decrypt(message);
+			notify = message.getConversation().getAccount().getPgpDecryptionService().decrypt(message, notify);
 		}
 		mXmppConnectionService.updateConversationUi();
-		if (acceptedAutomatically) {
+		if (notify) {
 			mXmppConnectionService.getNotificationService().push(message);
 		}
 	}

src/main/java/eu/siacs/conversations/parser/MessageParser.java 🔗

@@ -342,6 +342,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
 		final Jid to = packet.getTo();
 		final Jid from = packet.getFrom();
 		final String remoteMsgId = packet.getId();
+		boolean notify = false;
 
 		if (from == null) {
 			Log.d(Config.LOGTAG,"no from in: "+packet.toString());
@@ -482,7 +483,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
 							sendMessageReceipts(account, packet);
 						}
 						if (replacedMessage.getEncryption() == Message.ENCRYPTION_PGP) {
-							conversation.getAccount().getPgpDecryptionService().decrypt(replacedMessage);
+							conversation.getAccount().getPgpDecryptionService().decrypt(replacedMessage, false);
 						}
 						return;
 					} else {
@@ -505,10 +506,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
 				conversation.add(message);
 			}
 
-			if (message.getEncryption() == Message.ENCRYPTION_PGP) {
-				conversation.getAccount().getPgpDecryptionService().decrypt(message);
-			}
-
 			if (query == null || query.getWith() == null) { //either no mam or catchup
 				if (status == Message.STATUS_SEND || status == Message.STATUS_SEND_RECEIVED) {
 					mXmppConnectionService.markRead(conversation);
@@ -517,9 +514,14 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
 					}
 				} else {
 					message.markUnread();
+					notify = true;
 				}
 			}
 
+			if (message.getEncryption() == Message.ENCRYPTION_PGP) {
+				notify = conversation.getAccount().getPgpDecryptionService().decrypt(message, notify);
+			}
+
 			if (query == null) {
 				mXmppConnectionService.updateConversationUi();
 			}
@@ -541,7 +543,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
 			final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
 			if (message.trusted() && message.treatAsDownloadable() != Message.Decision.NEVER && manager.getAutoAcceptFileSize() > 0) {
 				manager.createNewDownloadConnection(message);
-			} else if (!message.isRead()) {
+			} else if (notify) {
 				if (query == null) {
 					mXmppConnectionService.getNotificationService().push(message);
 				} else if (query.getWith() == null) { // mam catchup

src/main/java/eu/siacs/conversations/ui/ConversationFragment.java 🔗

@@ -695,7 +695,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
 		message.setEncryption(Message.ENCRYPTION_PGP);
 		activity.updateConversationList();
 		updateMessages();
-		conversation.getAccount().getPgpDecryptionService().decrypt(message);
+		conversation.getAccount().getPgpDecryptionService().decrypt(message, false);
 	}
 
 	protected void privateMessageWith(final Jid counterpart) {

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java 🔗

@@ -99,9 +99,16 @@ public class JingleConnection implements Transferable {
 				mXmppConnectionService.markMessage(message,Message.STATUS_RECEIVED);
 				if (acceptedAutomatically) {
 					message.markUnread();
-					JingleConnection.this.mXmppConnectionService.getNotificationService().push(message);
+					if (message.getEncryption() == Message.ENCRYPTION_PGP) {
+						account.getPgpDecryptionService().decrypt(message, true);
+					} else {
+						JingleConnection.this.mXmppConnectionService.getNotificationService().push(message);
+					}
 				}
 			} else {
+				if (message.getEncryption() == Message.ENCRYPTION_PGP) {
+					account.getPgpDecryptionService().decrypt(message, false);
+				}
 				if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
 					file.delete();
 				}
@@ -109,8 +116,6 @@ public class JingleConnection implements Transferable {
 			Log.d(Config.LOGTAG,"successfully transmitted file:" + file.getAbsolutePath()+" ("+file.getSha1Sum()+")");
 			if (message.getEncryption() != Message.ENCRYPTION_PGP) {
 				mXmppConnectionService.getFileBackend().updateMediaScanner(file);
-			} else {
-				account.getPgpDecryptionService().decrypt(message);
 			}
 		}