Android XMPP Chat Sample

Ask tech team
From QuickBlox Developers (API docs, code samples, SDK)
Jump to: navigation, search

Contents

Sources

Project homepage on GIT — https://github.com/QuickBlox/quickblox-android-sdk/tree/master/sample-chat

Download ZIP - https://github.com/QuickBlox/quickblox-android-sdk/archive/master.zip


Overview

This sample demonstrates how to work with QuickBlox Chat API.
It allows you to organize chat in room & chat 1 on 1

It gives examples of how to:

  1. Organize chat between 2 users
  2. Organize chat in room

Setup

This sample depends on pull-to-refresh and appcompat lib projects. Import sample and configure it according to guides below.

Android Studio IDE

Doesn't require additional configuration. Gradle does it for you.

IDEA IDE

If you don't use Gradle:

  1. Open Module Settings
  2. Import “appcompat” module from <android-sdk>/extras/android/support/v7
  3. Import <quickblox-android-sdk>/jar/quickblox-android-1.2.jar
  4. Select “sample-chat” module
  5. Add dependency to module “appcompat”
  6. Add dependency to libraries pack (android-support-v4.jar, android-support-v7-appcompat.jar) they were imported with appcompat project
  7. Add dependency to library quickblox-android-1.2.jar

Note: When you import sample IDE automatically adds pull-to-refresh as module and as a dependency, but if not then do it yourself.

Eclipse IDE

  1. Import “appcompat” lib project from <android-sdk>/extras/android/support/v7
  2. Configure appcompat and pull-to-refresh. Project->Properties->Android:
    - set Project Build Target 4.4.2
    - check “Is Library” should be set
  3. Configure sample. Project->Properties->Android:
    - add pull-to-refresh and appcompat
    - set Project Build Target 4.4.2
  4. Project->Properties->Java Build Path->Libraries, “Add External JARs…” <quickblox-android-sdk>/jar/quickblox-android-1.2.jar
  5. Go to Order&Export tab and check quickblox-android-1.2.jar
  6. Clean and rebuild project


Guide: Getting Started with Chat API

Getting a QuickBlox account

http://admin.quickblox.com/register

Creating applications in the Admin panel

http://admin.quickblox.com/apps/new

In addition, there is this helpful 5 minute guide.

Adding Chat to your application

Logging in to the Chat

Note: In order to login to the chat please read the information about Chat login/password formation.

In order to use QuickBlox Chat APIs you must:

  • Create session & Sign In to QuickBlox OR just create session with user
  • Sign In to QuickBlox Chat

Please follow the lines below:

Create session with User & Sign In to QuickBlox Chat

// initialize SMACK
SmackAndroid.init(this);
 
final QBUser user = new QBUser("garry", "garry2892pass");
QBAuth.createSession(user, new QBCallbackImpl() {
    @Override
    public void onComplete(Result result) {
        if (result.isSuccess()) {
            QBSessionResult res = (QBSessionResult)result;
            user.setId(res.getSession().getUserId());
            //
            QBChatService.getInstance().loginWithUser(user, LoginActivity.this);
            Log.d(TAG, "Session was successfully created");
        } else {
            Log.e(TAG, "Errors " + result.getErrors().toString());
        }
    }
});
 
@Override
public void onLoginSuccess() {
    Log.d(TAG, "success when login");
}
 
@Override
public void onLoginError(String error) {
    Log.e(TAG, "error when login");
}

Keep in mind that the QuickBlox Chat is a standard XMPP chat and you need to send presence periodically to remain available. Just create a timer that will send presence each 60 seconds:

QBChatService.getInstance().startAutoSendPresence(60);

To handle different connection states use ConnectionListener:

ConnectionListener connectionListener = new ConnectionListener() {
    @Override
    public void connectionClosed() {
        //connection closed
    }
 
    @Override
    public void connectionClosedOnError(Exception e) {
        // connection closed on error. It will be established soon
    }
 
    @Override
    public void reconnectingIn(int seconds) {
 
    }
 
    @Override
    public void reconnectionSuccessful() {
 
    }
 
    @Override
    public void reconnectionFailed(Exception e) {
 
    }
};
 
QBChatService.getInstance().addConnectionListener(connectionListener);

1 to 1 Chat

Text chat

1 to 1 Chat is very easy to set up. Just send a message to the opponent & receive messages from them in return:

// Create 1-1 chat
QBPrivateChat chat = QBChatService.getInstance().createChat();
chat.addChatMessageListener(new ChatMessageListener() {
    @Override
    public void processMessage(Message message) {
        Log.d(TAG, "Messags: " + message.getBody());
    }
 
    @Override
    public boolean accept(Message.Type type) {
        switch (messageType) {
            case chat: 
                return true; // process 1-1 chat messages
            default:
                return false;
        }
    }
});
 
// send message    
chat.sendMessage(546, "Hi mate!");


Custom parameters

You can use custom parameters for the messages you send in the chat, for example to send some additional info or to send control messages:

DefaultPacketExtension extension = new DefaultPacketExtension("state", "jabber:state:event");
extension.setValue("delivered", "true");
 
Message message = new Message();
message.setType(Message.Type.chat); // 1-1 chat message
message.addExtension(extension);
 
chat.sendMessage(546, message);


Chat State Notifications

Many instant messaging systems include notifications about the state of one's conversation partner in a one-to-one chat (or, sometimes, in a many-to-many chat). In essence, chat state notifications can be thought of as a form of chat-specific presence.

This section describes how to integrate chat states notifications into your application.

Here is a list of common Chat State Notifications:

  1. composing: The user is composing a message. The user is actively interacting with a message input interface specific to this chat session (e.g., by typing in the input area of a chat window)
  2. paused: The user had been composing but now has stopped. The user was composing but has not interacted with the message input interface for a short period of time (e.g., 30 seconds)
  3. inactive: The user has not been actively participating in the chat session. The user has not interacted with the chat session interface for an intermediate period of time (e.g., 2 minutes)

With QuickBlox you can use any of these chat status notifications and integrate any others as well. It's purely dependent on the developer's imagination.

Here is an example of how to implement the composing (typing) notification.

To produce this notification we should implement a TextWatcher and add it to editText:

private EditText messageEditText;
 
...
 
messageEditText.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
 
    }
 
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        DefaultPacketExtension extension = new DefaultPacketExtension("state", "jabber:state:event");
 
        if (s.length() > 0) {
            extension.setValue("composing", "true");
        } else {
            extension.setValue("composing", "false");
        }
 
        Message message = new Message();
        message.setType(Message.Type.chat); // 1-1 chat message
        message.addExtension(extension);
 
        try {
            chat.sendMessage(546, message);
        } catch (XMPPException e) {
            e.printStackTrace();
        }
    }
 
    @Override
    public void afterTextChanged(Editable s) {
 
    }
});

On the opponent's side we can track this notification and update the UI:

public class Sample implements ChatMessageListener {
 
...
 
    @Override
    public void processMessage(Message message) {
        PacketExtension extension = message.getExtension("state", "jabber:state:event");
        if (extension != null) {
            String value = ((DefaultPacketExtension) extension).getValue("composing");
            if (value.equals("true")) {
                // opponent is composing - update UI
            } else {
                // opponent has stopped compose - update UI
            }
        }
    }
 
    @Override
    public boolean accept(Message.Type messageType) {
        switch (messageType) {
            case chat:
                return true;
            default:
                return false;
        }
    }
...
 
}


Sending files

To send file you should perform the following steps:

  1. Upload new file to Content module:
    // Upload file to Content module
    File image = new File("path to image");
    QBContent.uploadFileTask(image, false, new QBCallbackImpl() {
        @Override
        public void onComplete(Result result) {
            if (result.isSuccess()) {
                // get uploaded file ID
                QBFileUploadTaskResult res = (QBFileUploadTaskResult) result;
                String uid = res.getFile().getUid();
     
            }
        }
    });
  2. Send a link to a file through chat messages:
    DefaultPacketExtension extension = new DefaultPacketExtension("attachment", "jabber:attachment:event");
    extension.setValue("fileID", value);
     
    Message message = new Message();
    message.setType(Message.Type.chat); // 1-1 chat message
    message.addExtension(extension);
     
    chat.sendMessage(546, message);
  3. Receive message and download file:
    @Override
    public void processMessage(Message message) {
        PacketExtension extension = message.getExtension("attachment", "jabber:attachment:event");
        if (extension != null) {
            String uid = ((DefaultPacketExtension) extension).getValue("fileID");
            // download file by ID    
            QBContent.downloadFile(uid, new QBCallbackImpl() {
                @Override
                public void onComplete(Result result) {
                    // extract image
                    QBFileDownloadResult downloadResult = (QBFileDownloadResult) result;
                    InputStream s = downloadResult.getContentStream();
                    Bitmap bitmap = BitmapFactory.decodeStream(s);
                }
            });
        }
    }
     
    @Override
    public boolean accept(Message.Type messageType) {
        switch (messageType) {
            case chat:
                return true;
            default:
                return false;
        }
    }

Chatrooms

Creating a room

You can create 4 types of rooms:

  • members-only vs. open:
    • open - A room that non-banned users are allowed to enter without being on the member list
    • members-only - A room that a user cannot enter without being on the member list
  • persistent vs. temporary:
    • persistent - A room that is not destroyed if the last user exits
    • temporary - A room that is destroyed if the last occupant exits

Creating an open & persistent room

QBChatService.getInstance().createRoom(roomName, false, true, new RoomListener() {
    @Override
    public void onCreatedRoom(QBChatRoom qbChatRoom) {
        Log.d(TAG, "room was created");
        chatRoom.addMessageListener(this);         
    }
 
    @Override
    public void onJoinedRoom(QBChatRoom qbChatRoom) {
        Log.d(TAG, "joined to room");
        chatRoom.addMessageListener(this);
    }
 
    @Override
    public void onError(String s) {
        Log.d(TAG, "error joining to room");
    }
});

Creating a members-only & temporary room

QBChatService.getInstance().createRoom(roomName, true, false, new RoomListener() {
    @Override
    public void onCreatedRoom(QBChatRoom room) {
        Log.d(TAG, "room was created");
        chatRoom.addMessageListener(this);
    }
 
    @Override
    public void onJoinedRoom(QBChatRoom room) {
        Log.d(TAG, "joined to room");
        chatRoom.addMessageListener(this);
        // Add users to this room
        List<Integer> userIds = new ArrayList<Integer>();
        userIds.add(300);
        userIds.add(357);
        chatRoom.addMembers(userIds);
    }
 
    @Override
    public void onError(String msg) {
        Log.d(TAG, "error joining to room");
    }
});

Manage members

Add users to only-members room

List<Integer> users = new ArrayList<Integer>();
users.add(298);
 
chatRoom.addRoomUsers(users);

Delete users from only-members rooms

List<Integer> users = new ArrayList<Integer>();
users.add(298);
 
chatRoom.removeRoomUsers(users);

Retrieve users who can join an only-members room

Collection<String> roomUsers = chatRoom.getRoomUsers();

Retrieve online users

Collection<String> roomUsers = chatRoom.getOnlineRoomUsers();

Handle online room users

chatRoom.addParticipantListener(new PacketListener() {
 
    @Override
    public void processPacket(Packet packet) {
        Presence presence = (Presence) packet;
 
        String user = QBChatUtils.parseQBUser(presence.getFrom());
        if (presence.getType() == Presence.Type.available) {
            // user entered the room
        } else if (presence.getType() == Presence.Type.unavailable) {
            // user left the room
        }
 
        Collection<String> roomUsers = chatRoom.getOnlineRoomUsers();
    }
});

Send custom presence

You can send custom presence to room:

Map<String, String> params = new HashMap<String, String>();
params.put("status", "online");
params.put("job", "doctor");
QBChatService.getInstance().sendPresenceToRoomWithParameters(Presence.Type.available, ROOM_NAME, CURRENT_USER_ID, params);

This will notify ParticipantListener and other room occupants will be able to get your custom status through extension in presence.

DefaultPacketExtension extension = (DefaultPacketExtension) presence.getExtension("x", "http://chat.quickblox.com/presence_extension");

Joining/leaving rooms

Join room

QBChatService.getInstance().joinRoom(“Real Madrid fans”, new RoomListener() {
    @Override
    public void onCreatedRoom(QBChatRoom qbChatRoom) {
        Log.d(TAG, "room was created");
        chatRoom.addMessageListener(this);         
    }
 
    @Override
    public void onJoinedRoom(QBChatRoom qbChatRoom) {
        Log.d(TAG, "joined to room");
        chatRoom.addMessageListener(this);
    }
 
    @Override
    public void onError(String s) {
        Log.d(TAG, "error joining to room");
    }
});

Leaving a room

QBChatService.getInstance().leaveRoom(chatRoom);
chatRoom.removeMessageListener(this);

Sending & receiving messages

In order to send & receive messages you must have joined a room.

Sending a message

chatRoom.sendMessage(message);

Receiving a message

@Override
public void processMessage(Message message) {
    Log.d(TAG, "Messags: " + message.getBody());
}
 
@Override
public boolean accept(Message.Type messageType) {
    switch (messageType) {
        case groupchat:
            return true; // process room chat messages
        default:
            return false;
        }
    }
}

Destroying a room

Room owners can destroy rooms like this.

QBChatService.getInstance().destroyRoom(testRoom);

Retrieve rooms

QBChatService.getInstance().getRooms(new RoomReceivingListener() {
    @Override
    public void onReceiveRooms(List<QBChatRoom> qbChatRooms) {
        for (QBChatRoom room : qbChatRooms) {
            Log.d(TAG, "Received room " + room.getName());
        }
    }
});

Retrieve room info

RoomInfo roomInfo = QBChatService.getInstance().getRoomInfo("myroom");
if(roomInfo != null) {
    Log.i(TAG, "roomInfo: " + roomInfo.getRoom() + ", " + roomInfo.getDescription() + ", "
             + roomInfo.getOccupantsCount() + ", "
             + roomInfo.isMembersOnly() + ", "  + roomInfo.isPersistent());
}

Managing rooms in the Admin panel

You can create rooms through the Admin panel, Chat module

  1. Just Sign In on Admin panel, go to Chat module page
  2. Enter your password from Admin panel again.
  3. Press the New Room button - a New room form will appear
  4. Enter the room's name and press the Create button
  5. QBChatAdmin createRoom.png

  6. Your room will appear in the List of rooms. Now you can discover it & join
  7. If you want to set some of the room's options - click on it - and a page with room's details will be opened

Managing the Chat History

1 to 1 Chat history

There are 2 ways to organise a 1 to 1 chat history:

  1. Storing the history on client side (e.g. using local SQLite database or similar features)
  2. Store 1 to 1 Chat history in QuickBlox Custom Objects module. See CustomObjects Android code sample to figure out how to work with CustomObjects module.


Room history

After you have joined an existing room you will receive the history as regular messages.

@Override
public void processMessage(Message message) {
    Log.d(TAG, "Messags: " + message.getBody());
}
 
@Override
public boolean accept(Message.Type messageType) {
    switch (messageType) {
        case groupchat:
            return true; // process room chat messages
        default:
            return false;
        }
    }
}

By default, the maximum number of history messages returned by a room is 50. There is currently no way to change this value.

Connecting to Web XMPP Chat

Coming soon.

Conclusion

Now you can play around QuickBlox Chat API, integrate Chat to your own applications and more & more with QuickBlox!

Comments

Feel free to comment on this page using the form below.

blog comments powered by Disqus