ChatStateListener

Hi Guys,

I have implemented the ChatStateListener in my chat window which works fine for detecting new messages but the statechange method never seems to get fired, Any advice on how this should be implemented.

I add the message listener to the chat but do not see any way of adding a stateListener to a chat.

Best

Mark

Unfortunately, I have found the ChatStateListener to not work properly. If you look at Sparks source code, you see they check packets for chat states (lower level processing).

It would be great it ChatStateListener will be improved in the next version of smack…

ah i see, thats cool. Thanks for your reply. I was wondering why it was not working alright, makes sense now.

Thanks.

Mark

Hi Mark,

We have been successfully using the chat state system for about 10 months now. It has one quirk that I got stuck on for awhile until I looked at the source and I’m guessing it tripped you up too. Once the user is authenticated, you need to call ChatStateManager.getInstance(conn) in order to force the manager to setup all the required packet listeners. At the time I realized this, I requested that a note about it be added to the JavaDoc for ChatStateManager, which it since has been. Then, make sure the same object that implements MessageListener, which you add to the Chat object, also implements ChatStateListener. If that isn’t your problem let me know and I can probably provide a more thorough walkthrough.

Chris

Maybe you could provide an example.

In my case, I didn’t get the state notifications and it seemed to interfere with the MessageListener…

Hi ChrisW1229,

i added the instance of chatStatemanager as you advised to my conversation constructor as follows;

public XmppConversation(ImpBuddy buddy, Chat chat)

{

this.chat = chat;

this.buddy = buddy;

ChatStateManager.getInstance(XmppSession.xmppConnection);

chat.addMessageListener(this);

pcs = new SwingPropertyChangeSupport(this, true);

}

/code

My XmppConversation class implements ChatStateListener and i add MessageListener to my Chat which receives the messages. I dont see any way of adding the chatStateListener to my smack Chat object though. Do i need to create a chatState object perhaps?

Best

Mark

Actually, I just reviewed my code, and I am using ChatStateListener. The problems I had were with ChatStateManager

Here’s some snippets on how to use ChatStateListener:

public class ChatSessionMgr implements ChatManagerListener, ChatStateListener {     private static ChatManager chatManager;     public void reloadChatManager() {
        if (chatManager != null) {
            if (!chatManager.getChatListeners().isEmpty())                 chatManager.removeChatListener(this);
        }
                        try {
            chatManager = MainClass.getConnection().getConnection().getChatManager();
        } catch (NullPointerException e) {
            chatManager = null;
        }
                if (chatManager != null) {
            chatManager.addChatListener(this);
        }
    }     @Override
    public void stateChanged(Chat chat, ChatState chatState) {
        // find chat session in set
        final ChatSession chatsess = findSessionParticipant(chat.getParticipant());
                if (chatsess == null) return;
                switch (chatState) {
            case active: {
                chatsess.thisGUI.setParticipantOnlineStatus("online");
                break;
            }
            case composing: {
                chatsess.thisGUI.setParticipantOnlineStatus("composing");
                break;
            }
            case gone: {                 chatsess.thisGUI.setParticipantOnlineStatus("offline");
                chatsess.messageDo(chatsess.thisChat.getParticipant(),                         MSG_USER_GONE);
                break;
            }
            case inactive: break;
            case paused: {
                chatsess.thisGUI.setParticipantOnlineStatus("online");
                break;
            }
        }
    }

I never got the composing state to work, but the other “side” is JwChat. Might be that. It wasn’t an important feature anyway

Hi Op3racional,

Thanks for the code snippet, i seem to be doing it in a similar way but still dont seem to see the state method ever getting fired, ah well.

At least the messages work anyway

best

Mark

Mark,

Sorry I wasn’t more specific. When I said call ChatStateManager.getInstance(conn) once the user is authenticated, I meant do it as soon as the connection is made (you only need to do it one time). It must be done before the Chat object is created because it listens for the chatCreated events and adds listeners to the Chat object at that time. The way you have it now, the Chat is already created and so it misses the required callbacks.

As to your second question, you do not have to make a separate call to add the ChatStateListener. You just have to implement the ChatStateListener interface in the same object as your MessageListener. When a chat state is received the ChatStateManager calls getListeners() on the Chat object and then passes the chat state to any MessageListener that also implements ChatStateListener. So from what you said, I think you have this point covered already.

Another thing I had to do was ignore chat states in my MessageListener because chat states are really just a special form of chat message. I handle that by checking that a message has a body or a subject before proceeding to process it. That way you don’t get blank messages added to your chat window.

Then, just remember to send the chat states from one of the two clients. Keep in mind that the new state you are setting must be different than the current state or it will not send anything.

ChatStateManager mgr = ChatStateManager.getInstance(conn);

mgr.setCurrentState(ChatState.paused, chat);

/code

One final note, I am using Openfire for my server…I’m not sure if this works on other servers. I don’t have time at the moment to put a full example together, but hopefully it will work for you now.

Chris

Hi chrisw1229,

Thanks for the advice again, It makes sense and i have tried to get it working but have not had any luck yet, ill keep at it anyway.

best

Mark

Hi chris, I am Aneez. I have a related issue like this. I hope you can definitely help me. Kindly check the question which I have posted. Thanks in advance. http://community.igniterealtime.org/message/234908#234908 .

This is my code snippet

private class MMessageListener implements ChatMessageListener,ChatStateListener {

public MMessageListener(Context contxt) {

}

@Override
public void processMessage(final org.jivesoftware.smack.chat.Chat chat,

final Message message) {

Log.i(“MyXMPP_MESSAGE_LISTENER”, “Xmpp message received: '”

  • message);

if (message.getType() == Message.Type.chat
&& message.getBody() != null) {

final ChatMessage chatMessage = gson.fromJson(

message.getBody(), ChatMessage.class);

processMessage(chatMessage);

}

}

@Override
public void stateChanged(Chat chat, ChatState state) {

switch (state){

case active:

new Handler(Looper.getMainLooper()).post(new Runnable() {

@Override
public void run() {

// TODO Auto-generated method stub

// Toast.makeText(context, “active!”,
// Toast.LENGTH_SHORT).show();
MainActivity.txtStatus.setText(“active”);

}

});

Log.d(“state”,“active”);

break;

case composing:

new Handler(Looper.getMainLooper()).post(new Runnable() {

@Override
public void run() {

// TODO Auto-generated method stub
MainActivity.txtStatus.setText(“composing”);

// Toast.makeText(context, “composing!”,
// Toast.LENGTH_SHORT).show();

}

});

Log.d(“state”, “composing”);

break;

case paused:

new Handler(Looper.getMainLooper()).post(new Runnable() {

@Override
public void run() {

// TODO Auto-generated method stub
MainActivity.txtStatus.setText(“paused”);

// Toast.makeText(context, “composing!”,
// Toast.LENGTH_SHORT).show();

}

});

break;

case inactive:

new Handler(Looper.getMainLooper()).post(new Runnable() {

@Override
public void run() {

// TODO Auto-generated method stub
MainActivity.txtStatus.setText(“inactive”);

// Toast.makeText(context, “composing!”,
// Toast.LENGTH_SHORT).show();

}

});

break;

case gone:

new Handler(Looper.getMainLooper()).post(new Runnable() {

@Override
public void run() {

// TODO Auto-generated method stub
MainActivity.txtStatus.setText(“gone”);

// Toast.makeText(context, “composing!”,
// Toast.LENGTH_SHORT).show();

}

});

break;

}

}

private void processMessage(final ChatMessage chatMessage) {

chatMessage.isMine = false;

MainActivity.chatlist.add(chatMessage);

new Handler(Looper.getMainLooper()).post(new Runnable() {

@Override
public void run() {

MainActivity.chatAdapter.notifyDataSetChanged();

}

});

}

and i call stateManager.setCurrentState(ChatState.composing, Mychat); on edittext key listener but i would like to know is there any way that we don’t have to call current status explicitly. I mean statechanged should get called automatically

Just add ChatStateManager after ChatManager intalization

chatManager = ChatManager.getInstanceFor(getXmpptcpConnection());

ChatStateManager.getInstance(getXmpptcpConnection());

then you need add ChatStateListener during createChat(to,chatMesageListener)

chatManager.createChat(message.getTo(), chatMessageListener).sendMessage(message);

private ChatStateListener chatMessageListener = new ChatStateListener() {

@Override

public void stateChanged(Chat chat, ChatState state) {

//State Change composing,active,paused,gone,etc

Log.d(TAG, "ChatStateListener:::stateChanged -> " + chat.toString() + " \n -> " + state.toString());

}

@Override

public void processMessage(Chat chat, Message message) {

//Incoming Message

Log.d(TAG, "ChatStateListener:::processMessage -> " + chat.toString() + " \n -> " + message.toString());

}

};