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;