From 467a0821a037d314d7c1351a72ae02823dfd9ae4 Mon Sep 17 00:00:00 2001 From: Eng ChonMeng Date: Wed, 27 Nov 2019 19:40:04 +0100 Subject: [PATCH] Add Chat State Notifications support for group chat --- .../smackx/chatstates/ChatStateManager.java | 76 +++++++++++++++---- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java index e341e6a37..e03bc517d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/chatstates/ChatStateManager.java @@ -33,18 +33,23 @@ import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.chat2.Chat; import org.jivesoftware.smack.chat2.ChatManager; -import org.jivesoftware.smack.chat2.OutgoingChatMessageListener; import org.jivesoftware.smack.filter.AndFilter; -import org.jivesoftware.smack.filter.FromTypeFilter; import org.jivesoftware.smack.filter.MessageTypeFilter; +import org.jivesoftware.smack.filter.MessageWithBodiesFilter; import org.jivesoftware.smack.filter.NotFilter; +import org.jivesoftware.smack.filter.OrFilter; import org.jivesoftware.smack.filter.StanzaExtensionFilter; import org.jivesoftware.smack.filter.StanzaFilter; +import org.jivesoftware.smack.filter.StanzaTypeFilter; +import org.jivesoftware.smack.filter.ToTypeFilter; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smackx.chatstates.packet.ChatStateExtension; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; +import org.jivesoftware.smackx.muc.MultiUserChat; +import org.jivesoftware.smackx.muc.MultiUserChatManager; +import org.jivesoftware.smackx.xhtmlim.packet.XHTMLExtension; import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.EntityFullJid; @@ -60,6 +65,7 @@ import org.jxmpp.jid.EntityFullJid; * * @author Alexander Wenckus * @author Paul Schaub + * @author Eng ChongMeng * @see org.jivesoftware.smackx.chatstates.ChatState * @see org.jivesoftware.smackx.chatstates.packet.ChatStateExtension */ @@ -72,9 +78,18 @@ public final class ChatStateManager extends Manager { private static final Map INSTANCES = new WeakHashMap<>(); private static final StanzaFilter filter = new NotFilter(new StanzaExtensionFilter(NAMESPACE)); - private static final StanzaFilter INCOMING_MESSAGE_FILTER = - new AndFilter(MessageTypeFilter.NORMAL_OR_CHAT, FromTypeFilter.ENTITY_FULL_JID); - private static final StanzaFilter INCOMING_CHAT_STATE_FILTER = new AndFilter(INCOMING_MESSAGE_FILTER, new StanzaExtensionFilter(NAMESPACE)); + private static final StanzaFilter INCOMING_CHAT_STATE_FILTER = + new AndFilter(StanzaTypeFilter.MESSAGE, new StanzaExtensionFilter(NAMESPACE) + ); + + private static final StanzaFilter MESSAGE_FILTER = new AndFilter( + new OrFilter(MessageTypeFilter.NORMAL_OR_CHAT, MessageTypeFilter.GROUPCHAT), + new OrFilter(MessageWithBodiesFilter.INSTANCE, new StanzaExtensionFilter(XHTMLExtension.ELEMENT, XHTMLExtension.NAMESPACE)) + ); + + private static final StanzaFilter OUTGOING_MESSAGE_FILTER = + new AndFilter( MESSAGE_FILTER, ToTypeFilter.ENTITY_FULL_OR_BARE_JID + ); /** * Registered ChatStateListeners @@ -82,9 +97,9 @@ public final class ChatStateManager extends Manager { private final Set chatStateListeners = new HashSet<>(); /** - * Maps chat to last chat state. + * Maps chat/mucChat to last chat state. */ - private final Map chatStates = new WeakHashMap<>(); + private final Map chatStates = new WeakHashMap<>(); private final AsyncButOrdered asyncButOrdered = new AsyncButOrdered<>(); @@ -113,24 +128,32 @@ public final class ChatStateManager extends Manager { private ChatStateManager(XMPPConnection connection) { super(connection); ChatManager chatManager = ChatManager.getInstanceFor(connection); - chatManager.addOutgoingListener(new OutgoingChatMessageListener() { + MultiUserChatManager multiUserChatManager = MultiUserChatManager.getInstanceFor(connection); + + connection.addStanzaInterceptor(new StanzaListener() { @Override - public void newOutgoingMessage(EntityBareJid to, Message message, Chat chat) { - if (chat == null) { - return; - } + public void processStanza(Stanza stanza) throws NotConnectedException, InterruptedException { + Message message = (Message) stanza; // if message already has a chatStateExtension, then do nothing, if (!filter.accept(message)) { return; } + Object chat; + EntityBareJid entityBareJid = message.getTo().asEntityBareJidIfPossible(); + if (message.getType() == Message.Type.groupchat) { + chat = multiUserChatManager.getMultiUserChat(entityBareJid); + } else { + chat = chatManager.chatWith(entityBareJid); + } + // otherwise add a chatState extension if necessary. if (updateChatState(chat, ChatState.active)) { message.addExtension(new ChatStateExtension(ChatState.active)); } } - }); + }, OUTGOING_MESSAGE_FILTER); connection.addSyncStanzaListener(new StanzaListener() { @Override @@ -199,7 +222,6 @@ public final class ChatStateManager extends Manager { } } - /** * Sets the current state of the provided chat. This method will send an empty bodied Message * stanza with the state attached as a {@link org.jivesoftware.smack.packet.ExtensionElement}, if @@ -224,6 +246,29 @@ public final class ChatStateManager extends Manager { chat.send(message); } + /** + * Sets the current state of the provided mucchat. This method will send an empty bodied Message + * stanza with the state attached as a {@link org.jivesoftware.smack.packet.ExtensionElement}, if + * and only if the new chat state is different than the last state. + * + * @param newState the new state of the chat + * @param mucChat the MultiUserChat instance + * @throws NotConnectedException if the XMPP connection is not connected. + * @throws InterruptedException if the calling thread was interrupted. + */ + public void setCurrentState(ChatState newState, MultiUserChat mucChat) throws NotConnectedException, InterruptedException { + if (mucChat == null || newState == null) { + throw new IllegalArgumentException("Arguments cannot be null."); + } + if (!updateChatState(mucChat, newState)) { + return; + } + Message message = new Message(); + ChatStateExtension extension = new ChatStateExtension(newState); + message.addExtension(extension); + + mucChat.sendMessage(message); + } @Override public boolean equals(Object o) { @@ -241,7 +286,7 @@ public final class ChatStateManager extends Manager { return connection().hashCode(); } - private synchronized boolean updateChatState(Chat chat, ChatState newState) { + private synchronized boolean updateChatState(Object chat, ChatState newState) { ChatState lastChatState = chatStates.get(chat); if (lastChatState != newState) { chatStates.put(chat, newState); @@ -249,5 +294,4 @@ public final class ChatStateManager extends Manager { } return false; } - }