From 7e4e7426eeaf2f958820845e48c0d24a92f9bc07 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Wed, 4 Jun 2014 18:44:15 +0200 Subject: [PATCH] received and displayed messages (xep 333) are now marked properly --- res/values/arrays.xml | 12 ---- res/values/strings.xml | 4 +- res/xml/preferences.xml | 12 ++-- .../conversations/entities/Conversation.java | 65 ++++++++++++------ .../siacs/conversations/entities/Message.java | 2 + .../conversations/parser/MessageParser.java | 16 ++++- .../services/XmppConnectionService.java | 66 ++++++++++++------- .../ui/ConversationActivity.java | 2 +- .../ui/ConversationFragment.java | 2 +- .../xmpp/stanzas/MessagePacket.java | 2 + 10 files changed, 116 insertions(+), 67 deletions(-) diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 15ec940f3..f9a198b2e 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -19,16 +19,4 @@ 524288 1048576 - - never - when received - when read - when received and when read - - - 0 - 1 - 2 - 3 - diff --git a/res/values/strings.xml b/res/values/strings.xml index d469caf30..6767568e5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -145,8 +145,8 @@ Advanced Options Never send crash reports By sending in stack traces you are helping the ongoing development of Conversations - Acknowledge Messages - Allows your contact to know whether or not you have received or read a specific message + Confirm Messages + Let your contact know when you have received and read a message OpenKeychain reporeted an error I/O Error decrypting file Error copying image file. diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index bf304161e..40039cd5c 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -22,13 +22,11 @@ android:entries="@array/filesizes" android:entryValues="@array/filesizes_values" android:defaultValue="524288"/> - messages = null; @@ -59,6 +61,8 @@ public class Conversation extends AbstractEntity { private transient MucOptions mucOptions = null; + private transient String latestMarkableMessageId; + public Conversation(String name, Account account, String contactJid, int mode) { this(java.util.UUID.randomUUID().toString(), name, null, account @@ -100,15 +104,26 @@ public class Conversation extends AbstractEntity { } public void markRead() { - if (this.messages == null) + if (this.messages == null) { return; + } for (int i = this.messages.size() - 1; i >= 0; --i) { - if (messages.get(i).isRead()) - return; + if (messages.get(i).isRead()) { + break; + } this.messages.get(i).markRead(); } } + public void markRead(XmppConnectionService service) { + markRead(); + if (service.confirmMessages() && this.latestMarkableMessageId != null) { + service.sendConfirmMessage(getAccount(), getContactJid(), + this.latestMarkableMessageId); + this.latestMarkableMessageId = null; + } + } + public Message getLatestMessage() { if ((this.messages == null) || (this.messages.size() == 0)) { Message message = new Message(this, "", Message.ENCRYPTION_NONE); @@ -126,7 +141,8 @@ public class Conversation extends AbstractEntity { } public String getName(boolean useSubject) { - if ((getMode() == MODE_MULTI) && (getMucOptions().getSubject() != null) && useSubject) { + if ((getMode() == MODE_MULTI) && (getMucOptions().getSubject() != null) + && useSubject) { return getMucOptions().getSubject(); } else { return this.getContact().getDisplayName(); @@ -208,14 +224,15 @@ public class Conversation extends AbstractEntity { this.mode = mode; } - public SessionImpl startOtrSession(Context context, String presence, boolean sendStart) { + public SessionImpl startOtrSession(Context context, String presence, + boolean sendStart) { if (this.otrSession != null) { return this.otrSession; } else { SessionID sessionId = new SessionID(this.getContactJid(), presence, "xmpp"); - this.otrSession = new SessionImpl(sessionId, getAccount().getOtrEngine( - context)); + this.otrSession = new SessionImpl(sessionId, getAccount() + .getOtrEngine(context)); try { if (sendStart) { this.otrSession.startSession(); @@ -226,13 +243,13 @@ public class Conversation extends AbstractEntity { return null; } } - + } public SessionImpl getOtrSession() { return this.otrSession; } - + public void resetOtrSession() { this.otrSession = null; } @@ -240,7 +257,8 @@ public class Conversation extends AbstractEntity { public void endOtrIfNeeded() { if (this.otrSession != null) { if (this.otrSession.getSessionStatus() == SessionStatus.ENCRYPTED) { - Log.d("xmppService","ending otr session with "+getContactJid()); + Log.d("xmppService", "ending otr session with " + + getContactJid()); try { this.otrSession.endSession(); this.resetOtrSession(); @@ -289,44 +307,51 @@ public class Conversation extends AbstractEntity { public void setContactJid(String jid) { this.contactJid = jid; } - + public void setNextPresence(String presence) { this.nextPresence = presence; } - + public String getNextPresence() { return this.nextPresence; } - + public int getLatestEncryption() { int latestEncryption = this.getLatestMessage().getEncryption(); - if ((latestEncryption == Message.ENCRYPTION_DECRYPTED) || (latestEncryption == Message.ENCRYPTION_DECRYPTION_FAILED)) { + if ((latestEncryption == Message.ENCRYPTION_DECRYPTED) + || (latestEncryption == Message.ENCRYPTION_DECRYPTION_FAILED)) { return Message.ENCRYPTION_PGP; } else { return latestEncryption; } } - + public int getNextEncryption() { if (this.nextMessageEncryption == -1) { return this.getLatestEncryption(); } return this.nextMessageEncryption; } - + public void setNextEncryption(int encryption) { this.nextMessageEncryption = encryption; } - + public String getNextMessage() { - if (this.nextMessage==null) { + if (this.nextMessage == null) { return ""; } else { return this.nextMessage; } } - + public void setNextMessage(String message) { this.nextMessage = message; } + + public void setLatestMarkableMessageId(String id) { + if (id != null) { + this.latestMarkableMessageId = id; + } + } } diff --git a/src/eu/siacs/conversations/entities/Message.java b/src/eu/siacs/conversations/entities/Message.java index 950e349e0..b468fef76 100644 --- a/src/eu/siacs/conversations/entities/Message.java +++ b/src/eu/siacs/conversations/entities/Message.java @@ -20,6 +20,8 @@ public class Message extends AbstractEntity { public static final int STATUS_SEND_FAILED = 3; public static final int STATUS_SEND_REJECTED = 4; public static final int STATUS_OFFERED = 6; + public static final int STATUS_SEND_RECEIVED = 7; + public static final int STATUS_SEND_DISPLAYED = 8; public static final int ENCRYPTION_NONE = 0; public static final int ENCRYPTION_PGP = 1; diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java index a6e43a66f..8e0997289 100644 --- a/src/eu/siacs/conversations/parser/MessageParser.java +++ b/src/eu/siacs/conversations/parser/MessageParser.java @@ -25,6 +25,7 @@ public class MessageParser { String[] fromParts = packet.getFrom().split("/"); Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, fromParts[0], false); + conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); String pgpBody = getPgpBody(packet); if (pgpBody != null) { return new Message(conversation, packet.getFrom(), pgpBody, @@ -104,6 +105,7 @@ public class MessageParser { if ((body == null) || (body.isEmpty())) { return null; } + conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); return new Message(conversation, packet.getFrom(), body, Message.ENCRYPTION_OTR, Message.STATUS_RECIEVED); } catch (Exception e) { @@ -138,6 +140,7 @@ public class MessageParser { status = Message.STATUS_RECIEVED; } String pgpBody = getPgpBody(packet); + conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); if (pgpBody == null) { return new Message(conversation, counterPart, packet.getBody(), Message.ENCRYPTION_NONE, status); @@ -174,6 +177,7 @@ public class MessageParser { String[] parts = fullJid.split("/"); Conversation conversation = mXmppConnectionService .findOrCreateConversation(account, parts[0], false); + conversation.setLatestMarkableMessageId(getMarkableMessageId(packet)); String pgpBody = getPgpBody(message); if (pgpBody != null) { return new Message(conversation, fullJid, pgpBody, @@ -191,12 +195,20 @@ public class MessageParser { packet.getId(), Message.STATUS_SEND_FAILED); } - private String getPgpBody(Element packet) { - Element child = packet.findChild("x", "jabber:x:encrypted"); + private String getPgpBody(Element message) { + Element child = message.findChild("x", "jabber:x:encrypted"); if (child == null) { return null; } else { return child.getContent(); } } + + private String getMarkableMessageId(Element message) { + if (message.hasChild("markable", "urn:xmpp:chat-markers:0")) { + return message.getAttribute("id"); + } else { + return null; + } + } } diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java index 7eb691386..223b14438 100644 --- a/src/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/eu/siacs/conversations/services/XmppConnectionService.java @@ -139,7 +139,6 @@ public class XmppConnectionService extends Service { "notification_grace_period_after_carbon_received", true)) { notify = (SystemClock.elapsedRealtime() - lastCarbonMessageReceived) > CARBON_GRACE_PERIOD; } - if ((packet.getType() == MessagePacket.TYPE_CHAT)) { if ((packet.getBody() != null) @@ -149,8 +148,7 @@ public class XmppConnectionService extends Service { message.markUnread(); } } else if (packet.hasChild("body")) { - message = mMessageParser - .parseChat(packet, account); + message = mMessageParser.parseChat(packet, account); message.markUnread(); } else if (packet.hasChild("received") || (packet.hasChild("sent"))) { @@ -182,7 +180,16 @@ public class XmppConnectionService extends Service { mMessageParser.parseError(packet, account); return; } else if (packet.getType() == MessagePacket.TYPE_NORMAL) { - if (packet.hasChild("x")) { + if (packet.hasChild("displayed","urn:xmpp:chat-markers:0")) { + String id = packet.findChild("displayed","urn:xmpp:chat-markers:0").getAttribute("id"); + String[] fromParts = packet.getFrom().split("/"); + markMessage(account,fromParts[0], id, Message.STATUS_SEND_DISPLAYED); + Log.d(LOGTAG,"message was displayed by contact"); + } else if (packet.hasChild("received","urn:xmpp:chat-markers:0")) { + String id = packet.findChild("received","urn:xmpp:chat-markers:0").getAttribute("id"); + String[] fromParts = packet.getFrom().split("/"); + markMessage(account,fromParts[0], id, Message.STATUS_SEND_RECEIVED); + } else if (packet.hasChild("x")) { Element x = packet.findChild("x"); if (x.hasChild("invite")) { findOrCreateConversation(account, packet.getFrom(), @@ -195,7 +202,7 @@ public class XmppConnectionService extends Service { } } else { - // Log.d(LOGTAG, "unparsed message " + packet.toString()); + //Log.d(LOGTAG, "unparsed message " + packet.toString()); } } if ((message == null) || (message.getBody() == null)) { @@ -213,9 +220,9 @@ public class XmppConnectionService extends Service { Log.d(LOGTAG, "error trying to parse date" + e.getMessage()); } } - if ((confirmReception()) && ((packet.getId() != null))) { + if ((confirmMessages()) && ((packet.getId() != null))) { MessagePacket receivedPacket = new MessagePacket(); - receivedPacket.setType(MessagePacket.TYPE_UNKNOWN); + receivedPacket.setType(MessagePacket.TYPE_NORMAL); receivedPacket.setTo(message.getCounterpart()); receivedPacket.setFrom(account.getFullJid()); if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) { @@ -416,8 +423,9 @@ public class XmppConnectionService extends Service { "urn:xmpp:jingle:transports:s5b:1"); query.addChild("feature").setAttribute("var", "urn:xmpp:jingle:transports:ibb:1"); - if (confirmReception()) { - query.addChild("feature").setAttribute("var", "urn:xmpp:receipts"); + if (confirmMessages()) { + query.addChild("feature").setAttribute("var", + "urn:xmpp:receipts"); } account.getXmppConnection().sendIqPacket(iqResponse, null); } else { @@ -968,8 +976,15 @@ public class XmppConnectionService extends Service { Collections.sort(this.conversations, new Comparator() { @Override public int compare(Conversation lhs, Conversation rhs) { - return (int) (rhs.getLatestMessage().getTimeSent() - lhs - .getLatestMessage().getTimeSent()); + Message left = lhs.getLatestMessage(); + Message right = rhs.getLatestMessage(); + if (left.getTimeSent() > right.getTimeSent()) { + return -1; + } else if (left.getTimeSent() < right.getTimeSent()) { + return 1; + } else { + return 0; + } } }); return this.conversations; @@ -1442,17 +1457,9 @@ public class XmppConnectionService extends Service { return PreferenceManager .getDefaultSharedPreferences(getApplicationContext()); } - - private boolean confirmReception() { - String autoAcks = getPreferences().getString( - "auto_acknowledge_messages", "2"); - int autoAcksValue; - try { - autoAcksValue = Integer.parseInt(autoAcks); - } catch (NumberFormatException e) { - autoAcksValue = 0; - } - return autoAcksValue == 1 || autoAcksValue == 3; + + public boolean confirmMessages() { + return getPreferences().getBoolean("confirm_messages", true); } public void updateUi(Conversation conversation, boolean notify) { @@ -1472,4 +1479,19 @@ public class XmppConnectionService extends Service { } return null; } + + public void markRead(Conversation conversation) { + conversation.markRead(this); + } + + public void sendConfirmMessage(Account account, String to, String id) { + MessagePacket receivedPacket = new MessagePacket(); + receivedPacket.setType(MessagePacket.TYPE_NORMAL); + receivedPacket.setTo(to); + receivedPacket.setFrom(account.getFullJid()); + Element received = receivedPacket.addChild("displayed", + "urn:xmpp:chat-markers:0"); + received.setAttribute("id", id); + account.getXmppConnection().sendMessagePacket(receivedPacket); + } } diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java index 05120a412..586eb1e0b 100644 --- a/src/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/eu/siacs/conversations/ui/ConversationActivity.java @@ -279,7 +279,7 @@ public class ConversationActivity extends XmppActivity { getSelectedConversation().getName(useSubject)); invalidateOptionsMenu(); if (!getSelectedConversation().isRead()) { - getSelectedConversation().markRead(); + xmppConnectionService.markRead(getSelectedConversation()); UIHelper.updateNotification(getApplicationContext(), getConversationList(), null, false); listView.invalidateViews(); diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java index b51d8e0aa..130cc3033 100644 --- a/src/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/eu/siacs/conversations/ui/ConversationFragment.java @@ -641,7 +641,7 @@ public class ConversationFragment extends Fragment { if (size >= 1) messagesView.setSelection(size - 1); if (!activity.shouldPaneBeOpen()) { - conversation.markRead(); + activity.xmppConnectionService.markRead(conversation); // TODO update notifications UIHelper.updateNotification(getActivity(), activity.getConversationList(), null, false); diff --git a/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java b/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java index 9086fda76..64a9edc36 100644 --- a/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java +++ b/src/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java @@ -39,6 +39,8 @@ public class MessagePacket extends AbstractStanza { break; case TYPE_UNKNOWN: break; + case TYPE_NORMAL: + break; default: this.setAttribute("type","chat"); break;